mirror of
https://github.com/shishantbiswas/bknd.git
synced 2026-03-15 20:17:22 +00:00
added format command and added trailing commas to reduce conflicts
This commit is contained in:
@@ -19,8 +19,8 @@ describe("Api", async () => {
|
|||||||
const token = await sign({ foo: "bar" }, "1234");
|
const token = await sign({ foo: "bar" }, "1234");
|
||||||
const request = new Request("http://example.com/test", {
|
const request = new Request("http://example.com/test", {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${token}`
|
Authorization: `Bearer ${token}`,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
const api = new Api({ request });
|
const api = new Api({ request });
|
||||||
expect(api.isAuthVerified()).toBe(false);
|
expect(api.isAuthVerified()).toBe(false);
|
||||||
@@ -35,8 +35,8 @@ describe("Api", async () => {
|
|||||||
const token = await sign({ foo: "bar" }, "1234");
|
const token = await sign({ foo: "bar" }, "1234");
|
||||||
const request = new Request("http://example.com/test", {
|
const request = new Request("http://example.com/test", {
|
||||||
headers: {
|
headers: {
|
||||||
Cookie: `auth=${token}`
|
Cookie: `auth=${token}`,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
const api = new Api({ request });
|
const api = new Api({ request });
|
||||||
expect(api.isAuthVerified()).toBe(false);
|
expect(api.isAuthVerified()).toBe(false);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ describe("DataApi", () => {
|
|||||||
|
|
||||||
it("returns result", async () => {
|
it("returns result", async () => {
|
||||||
const schema = proto.em({
|
const schema = proto.em({
|
||||||
posts: proto.entity("posts", { title: proto.text() })
|
posts: proto.entity("posts", { title: proto.text() }),
|
||||||
});
|
});
|
||||||
const em = schemaToEm(schema);
|
const em = schemaToEm(schema);
|
||||||
await em.schema().sync({ force: true });
|
await em.schema().sync({ force: true });
|
||||||
@@ -60,7 +60,7 @@ describe("DataApi", () => {
|
|||||||
select: ["title"],
|
select: ["title"],
|
||||||
limit: 100000,
|
limit: 100000,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
sort: "id"
|
sort: "id",
|
||||||
});
|
});
|
||||||
expect(req.request.method).toBe("POST");
|
expect(req.request.method).toBe("POST");
|
||||||
const res = await req;
|
const res = await req;
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ const mockedBackend = new Hono()
|
|||||||
return new Response(file, {
|
return new Response(file, {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": file.type,
|
"Content-Type": file.type,
|
||||||
"Content-Length": file.size.toString()
|
"Content-Length": file.size.toString(),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ describe("MediaApi", () => {
|
|||||||
// @ts-ignore tests
|
// @ts-ignore tests
|
||||||
const api = new MediaApi({
|
const api = new MediaApi({
|
||||||
host,
|
host,
|
||||||
basepath
|
basepath,
|
||||||
});
|
});
|
||||||
expect(api.getFileUploadUrl({ path: "path" })).toBe(`${host}${basepath}/upload/path`);
|
expect(api.getFileUploadUrl({ path: "path" })).toBe(`${host}${basepath}/upload/path`);
|
||||||
});
|
});
|
||||||
@@ -38,7 +38,7 @@ describe("MediaApi", () => {
|
|||||||
it("should have correct upload headers", () => {
|
it("should have correct upload headers", () => {
|
||||||
// @ts-ignore tests
|
// @ts-ignore tests
|
||||||
const api = new MediaApi({
|
const api = new MediaApi({
|
||||||
token: "token"
|
token: "token",
|
||||||
});
|
});
|
||||||
expect(api.getUploadHeaders().get("Authorization")).toBe("Bearer token");
|
expect(api.getUploadHeaders().get("Authorization")).toBe("Bearer token");
|
||||||
});
|
});
|
||||||
@@ -139,7 +139,7 @@ describe("MediaApi", () => {
|
|||||||
const response = (await mockedBackend.request(url)) as Response;
|
const response = (await mockedBackend.request(url)) as Response;
|
||||||
await matches(
|
await matches(
|
||||||
await api.upload(response.body!, { filename: "readable.png" }),
|
await api.upload(response.body!, { filename: "readable.png" }),
|
||||||
"readable.png"
|
"readable.png",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ describe("ModuleApi", () => {
|
|||||||
|
|
||||||
it("adds additional headers from options", () => {
|
it("adds additional headers from options", () => {
|
||||||
const headers = new Headers({
|
const headers = new Headers({
|
||||||
"X-Test": "123"
|
"X-Test": "123",
|
||||||
});
|
});
|
||||||
const api = new Api({ host, headers });
|
const api = new Api({ host, headers });
|
||||||
expect(api.get("/").request.headers.get("X-Test")).toEqual("123");
|
expect(api.get("/").request.headers.get("X-Test")).toEqual("123");
|
||||||
@@ -75,7 +75,7 @@ describe("ModuleApi", () => {
|
|||||||
it("uses search params", () => {
|
it("uses search params", () => {
|
||||||
const api = new Api({ host });
|
const api = new Api({ host });
|
||||||
const search = new URLSearchParams({
|
const search = new URLSearchParams({
|
||||||
foo: "bar"
|
foo: "bar",
|
||||||
});
|
});
|
||||||
expect(api.get("/", search).request.url).toEqual("http://localhost/?" + search.toString());
|
expect(api.get("/", search).request.url).toEqual("http://localhost/?" + search.toString());
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ describe("repros", async () => {
|
|||||||
adapter: {
|
adapter: {
|
||||||
type: "local",
|
type: "local",
|
||||||
config: {
|
config: {
|
||||||
path: "./"
|
path: "./",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(config.enabled).toBe(true);
|
expect(config.enabled).toBe(true);
|
||||||
@@ -38,9 +38,9 @@ describe("repros", async () => {
|
|||||||
"entities.test",
|
"entities.test",
|
||||||
proto
|
proto
|
||||||
.entity("test", {
|
.entity("test", {
|
||||||
content: proto.text()
|
content: proto.text(),
|
||||||
})
|
})
|
||||||
.toJSON()
|
.toJSON(),
|
||||||
);
|
);
|
||||||
expect(app.em.entities.map((e) => e.name)).toContain("test");
|
expect(app.em.entities.map((e) => e.name)).toContain("test");
|
||||||
}
|
}
|
||||||
@@ -54,8 +54,8 @@ describe("repros", async () => {
|
|||||||
hidden: false,
|
hidden: false,
|
||||||
mime_types: [],
|
mime_types: [],
|
||||||
virtual: true,
|
virtual: true,
|
||||||
entity: "test"
|
entity: "test",
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
@@ -63,8 +63,8 @@ describe("repros", async () => {
|
|||||||
type: "poly",
|
type: "poly",
|
||||||
source: "test",
|
source: "test",
|
||||||
target: "media",
|
target: "media",
|
||||||
config: { mappedBy: "files" }
|
config: { mappedBy: "files" },
|
||||||
})
|
}),
|
||||||
).resolves.toBeDefined();
|
).resolves.toBeDefined();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,17 +75,17 @@ describe("repros", async () => {
|
|||||||
const schema = proto.em(
|
const schema = proto.em(
|
||||||
{
|
{
|
||||||
products: proto.entity("products", {
|
products: proto.entity("products", {
|
||||||
title: proto.text()
|
title: proto.text(),
|
||||||
}),
|
}),
|
||||||
product_likes: proto.entity("product_likes", {
|
product_likes: proto.entity("product_likes", {
|
||||||
created_at: proto.date()
|
created_at: proto.date(),
|
||||||
}),
|
}),
|
||||||
users: proto.entity("users", {})
|
users: proto.entity("users", {}),
|
||||||
},
|
},
|
||||||
(fns, schema) => {
|
(fns, schema) => {
|
||||||
fns.relation(schema.product_likes).manyToOne(schema.products, { inversedBy: "likes" });
|
fns.relation(schema.product_likes).manyToOne(schema.products, { inversedBy: "likes" });
|
||||||
fns.relation(schema.product_likes).manyToOne(schema.users);
|
fns.relation(schema.product_likes).manyToOne(schema.users);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
const app = createApp({ initialConfig: { data: schema.toJSON() } });
|
const app = createApp({ initialConfig: { data: schema.toJSON() } });
|
||||||
await app.build();
|
await app.build();
|
||||||
@@ -96,8 +96,8 @@ describe("repros", async () => {
|
|||||||
expect(info.relations.listable).toEqual([
|
expect(info.relations.listable).toEqual([
|
||||||
{
|
{
|
||||||
entity: "product_likes",
|
entity: "product_likes",
|
||||||
ref: "likes"
|
ref: "likes",
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ describe("authorize", () => {
|
|||||||
["read", "write"],
|
["read", "write"],
|
||||||
{
|
{
|
||||||
admin: {
|
admin: {
|
||||||
permissions: ["read", "write"]
|
permissions: ["read", "write"],
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{ enabled: true }
|
},
|
||||||
|
{ enabled: true },
|
||||||
);
|
);
|
||||||
const user = {
|
const user = {
|
||||||
role: "admin"
|
role: "admin",
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(guard.granted("read", user)).toBe(true);
|
expect(guard.granted("read", user)).toBe(true);
|
||||||
@@ -27,21 +27,21 @@ describe("authorize", () => {
|
|||||||
["read", "write"],
|
["read", "write"],
|
||||||
{
|
{
|
||||||
admin: {
|
admin: {
|
||||||
permissions: ["read", "write"]
|
permissions: ["read", "write"],
|
||||||
},
|
},
|
||||||
guest: {
|
guest: {
|
||||||
permissions: ["read"],
|
permissions: ["read"],
|
||||||
is_default: true
|
is_default: true,
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{ enabled: true }
|
},
|
||||||
|
{ enabled: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(guard.granted("read")).toBe(true);
|
expect(guard.granted("read")).toBe(true);
|
||||||
expect(guard.granted("write")).toBe(false);
|
expect(guard.granted("write")).toBe(false);
|
||||||
|
|
||||||
const user = {
|
const user = {
|
||||||
role: "admin"
|
role: "admin",
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(guard.granted("read", user)).toBe(true);
|
expect(guard.granted("read", user)).toBe(true);
|
||||||
@@ -58,12 +58,12 @@ describe("authorize", () => {
|
|||||||
test("role implicit allow", async () => {
|
test("role implicit allow", async () => {
|
||||||
const guard = Guard.create(["read", "write"], {
|
const guard = Guard.create(["read", "write"], {
|
||||||
admin: {
|
admin: {
|
||||||
implicit_allow: true
|
implicit_allow: true,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const user = {
|
const user = {
|
||||||
role: "admin"
|
role: "admin",
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(guard.granted("read", user)).toBe(true);
|
expect(guard.granted("read", user)).toBe(true);
|
||||||
@@ -74,8 +74,8 @@ describe("authorize", () => {
|
|||||||
const guard = Guard.create(["read", "write"], {
|
const guard = Guard.create(["read", "write"], {
|
||||||
guest: {
|
guest: {
|
||||||
implicit_allow: true,
|
implicit_allow: true,
|
||||||
is_default: true
|
is_default: true,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(guard.getUserRole()?.name).toBe("guest");
|
expect(guard.getUserRole()?.name).toBe("guest");
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ describe("OAuthStrategy", async () => {
|
|||||||
type: "oidc",
|
type: "oidc",
|
||||||
client: {
|
client: {
|
||||||
client_id: process.env.OAUTH_CLIENT_ID,
|
client_id: process.env.OAUTH_CLIENT_ID,
|
||||||
client_secret: process.env.OAUTH_CLIENT_SECRET
|
client_secret: process.env.OAUTH_CLIENT_SECRET,
|
||||||
},
|
},
|
||||||
name: "google"
|
name: "google",
|
||||||
});
|
});
|
||||||
const state = "---";
|
const state = "---";
|
||||||
const redirect_uri = "http://localhost:3000/auth/google/callback";
|
const redirect_uri = "http://localhost:3000/auth/google/callback";
|
||||||
@@ -21,7 +21,7 @@ describe("OAuthStrategy", async () => {
|
|||||||
|
|
||||||
const request = await strategy.request({
|
const request = await strategy.request({
|
||||||
redirect_uri,
|
redirect_uri,
|
||||||
state
|
state,
|
||||||
});
|
});
|
||||||
|
|
||||||
const server = Bun.serve({
|
const server = Bun.serve({
|
||||||
@@ -31,13 +31,13 @@ describe("OAuthStrategy", async () => {
|
|||||||
console.log("req", req);
|
console.log("req", req);
|
||||||
const user = await strategy.callback(url, {
|
const user = await strategy.callback(url, {
|
||||||
redirect_uri,
|
redirect_uri,
|
||||||
state
|
state,
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("---user", user);
|
console.log("---user", user);
|
||||||
}
|
}
|
||||||
return new Response("Bun!");
|
return new Response("Bun!");
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
console.log("request", request);
|
console.log("request", request);
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ class ReturnEvent extends Event<{ foo: string }, string> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return this.clone({
|
return this.clone({
|
||||||
foo: [this.params.foo, value].join("-")
|
foo: [this.params.foo, value].join("-"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,7 +52,7 @@ describe("EventManager", async () => {
|
|||||||
await new Promise((resolve) => setTimeout(resolve, 50));
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
||||||
delayed();
|
delayed();
|
||||||
},
|
},
|
||||||
"sync"
|
"sync",
|
||||||
);
|
);
|
||||||
|
|
||||||
// don't allow unknown
|
// don't allow unknown
|
||||||
@@ -83,8 +83,8 @@ describe("EventManager", async () => {
|
|||||||
const emgr = new EventManager(
|
const emgr = new EventManager(
|
||||||
{ InformationalEvent },
|
{ InformationalEvent },
|
||||||
{
|
{
|
||||||
asyncExecutor
|
asyncExecutor,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
emgr.onEvent(InformationalEvent, async () => {});
|
emgr.onEvent(InformationalEvent, async () => {});
|
||||||
@@ -98,8 +98,8 @@ describe("EventManager", async () => {
|
|||||||
const emgr = new EventManager(
|
const emgr = new EventManager(
|
||||||
{ ReturnEvent, InformationalEvent },
|
{ ReturnEvent, InformationalEvent },
|
||||||
{
|
{
|
||||||
onInvalidReturn
|
onInvalidReturn,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// @ts-expect-error InformationalEvent has no return value
|
// @ts-expect-error InformationalEvent has no return value
|
||||||
@@ -140,7 +140,7 @@ describe("EventManager", async () => {
|
|||||||
expect(slug).toBe("informational-event");
|
expect(slug).toBe("informational-event");
|
||||||
call();
|
call();
|
||||||
},
|
},
|
||||||
{ mode: "sync", once: true }
|
{ mode: "sync", once: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(emgr.getListeners().length).toBe(1);
|
expect(emgr.getListeners().length).toBe(1);
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ describe("Registry", () => {
|
|||||||
first: {
|
first: {
|
||||||
cls: What,
|
cls: What,
|
||||||
schema: Type.Object({ type: Type.String(), what: Type.String() }),
|
schema: Type.Object({ type: Type.String(), what: Type.String() }),
|
||||||
enabled: true
|
enabled: true,
|
||||||
}
|
},
|
||||||
} satisfies Record<string, Test1>);
|
} satisfies Record<string, Test1>);
|
||||||
|
|
||||||
const item = registry.get("first");
|
const item = registry.get("first");
|
||||||
@@ -42,7 +42,7 @@ describe("Registry", () => {
|
|||||||
registry.add("second", {
|
registry.add("second", {
|
||||||
cls: What2,
|
cls: What2,
|
||||||
schema: second,
|
schema: second,
|
||||||
enabled: true
|
enabled: true,
|
||||||
});
|
});
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
expect(registry.get("second").schema).toEqual(second);
|
expect(registry.get("second").schema).toEqual(second);
|
||||||
@@ -52,7 +52,7 @@ describe("Registry", () => {
|
|||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
cls: NotAllowed,
|
cls: NotAllowed,
|
||||||
schema: third,
|
schema: third,
|
||||||
enabled: true
|
enabled: true,
|
||||||
});
|
});
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
expect(registry.get("third").schema).toEqual(third);
|
expect(registry.get("third").schema).toEqual(third);
|
||||||
@@ -62,7 +62,7 @@ describe("Registry", () => {
|
|||||||
cls: What,
|
cls: What,
|
||||||
// @ts-expect-error
|
// @ts-expect-error
|
||||||
schema: fourth,
|
schema: fourth,
|
||||||
enabled: true
|
enabled: true,
|
||||||
});
|
});
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
expect(registry.get("fourth").schema).toEqual(fourth);
|
expect(registry.get("fourth").schema).toEqual(fourth);
|
||||||
@@ -75,7 +75,7 @@ describe("Registry", () => {
|
|||||||
return {
|
return {
|
||||||
cls: a,
|
cls: a,
|
||||||
schema: a.prototype.getType(),
|
schema: a.prototype.getType(),
|
||||||
enabled: true
|
enabled: true,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { after, beforeEach, describe, test } from "node:test";
|
|||||||
import { Miniflare } from "miniflare";
|
import { Miniflare } from "miniflare";
|
||||||
import {
|
import {
|
||||||
CloudflareKVCacheItem,
|
CloudflareKVCacheItem,
|
||||||
CloudflareKVCachePool
|
CloudflareKVCachePool,
|
||||||
} from "../../../src/core/cache/adapters/CloudflareKvCache";
|
} from "../../../src/core/cache/adapters/CloudflareKvCache";
|
||||||
import { runTests } from "./cache-test-suite";
|
import { runTests } from "./cache-test-suite";
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ describe("CloudflareKv", async () => {
|
|||||||
mf = new Miniflare({
|
mf = new Miniflare({
|
||||||
modules: true,
|
modules: true,
|
||||||
script: "export default { async fetch() { return new Response(null); } }",
|
script: "export default { async fetch() { return new Response(null); } }",
|
||||||
kvNamespaces: ["TEST"]
|
kvNamespaces: ["TEST"],
|
||||||
});
|
});
|
||||||
const kv = await mf.getKVNamespace("TEST");
|
const kv = await mf.getKVNamespace("TEST");
|
||||||
return new CloudflareKVCachePool(kv as any);
|
return new CloudflareKVCachePool(kv as any);
|
||||||
@@ -45,10 +45,10 @@ describe("CloudflareKv", async () => {
|
|||||||
},
|
},
|
||||||
toBeUndefined() {
|
toBeUndefined() {
|
||||||
assert.equal(actual, undefined);
|
assert.equal(actual, undefined);
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
after(async () => {
|
after(async () => {
|
||||||
|
|||||||
4
app/__test__/core/cache/MemoryCache.spec.ts
vendored
4
app/__test__/core/cache/MemoryCache.spec.ts
vendored
@@ -9,7 +9,7 @@ describe("MemoryCache", () => {
|
|||||||
tester: {
|
tester: {
|
||||||
test,
|
test,
|
||||||
beforeEach,
|
beforeEach,
|
||||||
expect
|
expect,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { checksum, hash } from "../../src/core/utils";
|
|||||||
describe("crypto", async () => {
|
describe("crypto", async () => {
|
||||||
test("sha256", async () => {
|
test("sha256", async () => {
|
||||||
expect(await hash.sha256("test")).toBe(
|
expect(await hash.sha256("test")).toBe(
|
||||||
"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
|
"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
test("sha1", async () => {
|
test("sha1", async () => {
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ describe("SchemaObject", async () => {
|
|||||||
Type.Object({ a: Type.String({ default: "b" }) }),
|
Type.Object({ a: Type.String({ default: "b" }) }),
|
||||||
{ a: "test" },
|
{ a: "test" },
|
||||||
{
|
{
|
||||||
forceParse: true
|
forceParse: true,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(m.get()).toEqual({ a: "test" });
|
expect(m.get()).toEqual({ a: "test" });
|
||||||
@@ -30,14 +30,14 @@ describe("SchemaObject", async () => {
|
|||||||
b: Type.Object(
|
b: Type.Object(
|
||||||
{
|
{
|
||||||
c: Type.String({ default: "d" }),
|
c: Type.String({ default: "d" }),
|
||||||
e: Type.String({ default: "f" })
|
e: Type.String({ default: "f" }),
|
||||||
},
|
},
|
||||||
{ default: {} }
|
{ default: {} },
|
||||||
)
|
),
|
||||||
},
|
},
|
||||||
{ default: {}, additionalProperties: false }
|
{ default: {}, additionalProperties: false },
|
||||||
)
|
),
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
expect(m.get()).toEqual({ s: { a: "b", b: { c: "d", e: "f" } } });
|
expect(m.get()).toEqual({ s: { a: "b", b: { c: "d", e: "f" } } });
|
||||||
|
|
||||||
@@ -59,8 +59,8 @@ describe("SchemaObject", async () => {
|
|||||||
test("patch array", async () => {
|
test("patch array", async () => {
|
||||||
const m = new SchemaObject(
|
const m = new SchemaObject(
|
||||||
Type.Object({
|
Type.Object({
|
||||||
methods: Type.Array(Type.String(), { default: ["GET", "PATCH"] })
|
methods: Type.Array(Type.String(), { default: ["GET", "PATCH"] }),
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
expect(m.get()).toEqual({ methods: ["GET", "PATCH"] });
|
expect(m.get()).toEqual({ methods: ["GET", "PATCH"] });
|
||||||
|
|
||||||
@@ -81,14 +81,14 @@ describe("SchemaObject", async () => {
|
|||||||
a: Type.String({ default: "b" }),
|
a: Type.String({ default: "b" }),
|
||||||
b: Type.Object(
|
b: Type.Object(
|
||||||
{
|
{
|
||||||
c: Type.String({ default: "d" })
|
c: Type.String({ default: "d" }),
|
||||||
},
|
},
|
||||||
{ default: {} }
|
{ default: {} },
|
||||||
)
|
),
|
||||||
},
|
},
|
||||||
{ default: {} }
|
{ default: {} },
|
||||||
)
|
),
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
expect(m.get()).toEqual({ s: { a: "b", b: { c: "d" } } });
|
expect(m.get()).toEqual({ s: { a: "b", b: { c: "d" } } });
|
||||||
|
|
||||||
@@ -108,8 +108,8 @@ describe("SchemaObject", async () => {
|
|||||||
test("set", async () => {
|
test("set", async () => {
|
||||||
const m = new SchemaObject(
|
const m = new SchemaObject(
|
||||||
Type.Object({
|
Type.Object({
|
||||||
methods: Type.Array(Type.String(), { default: ["GET", "PATCH"] })
|
methods: Type.Array(Type.String(), { default: ["GET", "PATCH"] }),
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
expect(m.get()).toEqual({ methods: ["GET", "PATCH"] });
|
expect(m.get()).toEqual({ methods: ["GET", "PATCH"] });
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ describe("SchemaObject", async () => {
|
|||||||
let result: any;
|
let result: any;
|
||||||
const m = new SchemaObject(
|
const m = new SchemaObject(
|
||||||
Type.Object({
|
Type.Object({
|
||||||
methods: Type.Array(Type.String(), { default: ["GET", "PATCH"] })
|
methods: Type.Array(Type.String(), { default: ["GET", "PATCH"] }),
|
||||||
}),
|
}),
|
||||||
undefined,
|
undefined,
|
||||||
{
|
{
|
||||||
@@ -133,8 +133,8 @@ describe("SchemaObject", async () => {
|
|||||||
await new Promise((r) => setTimeout(r, 10));
|
await new Promise((r) => setTimeout(r, 10));
|
||||||
called = true;
|
called = true;
|
||||||
result = config;
|
result = config;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
await m.set({ methods: ["GET", "POST"] });
|
await m.set({ methods: ["GET", "POST"] });
|
||||||
@@ -146,7 +146,7 @@ describe("SchemaObject", async () => {
|
|||||||
let called = false;
|
let called = false;
|
||||||
const m = new SchemaObject(
|
const m = new SchemaObject(
|
||||||
Type.Object({
|
Type.Object({
|
||||||
methods: Type.Array(Type.String(), { default: ["GET", "PATCH"] })
|
methods: Type.Array(Type.String(), { default: ["GET", "PATCH"] }),
|
||||||
}),
|
}),
|
||||||
undefined,
|
undefined,
|
||||||
{
|
{
|
||||||
@@ -155,8 +155,8 @@ describe("SchemaObject", async () => {
|
|||||||
called = true;
|
called = true;
|
||||||
to.methods.push("OPTIONS");
|
to.methods.push("OPTIONS");
|
||||||
return to;
|
return to;
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const result = await m.set({ methods: ["GET", "POST"] });
|
const result = await m.set({ methods: ["GET", "POST"] });
|
||||||
@@ -168,7 +168,7 @@ describe("SchemaObject", async () => {
|
|||||||
|
|
||||||
test("throwIfRestricted", async () => {
|
test("throwIfRestricted", async () => {
|
||||||
const m = new SchemaObject(Type.Object({}), undefined, {
|
const m = new SchemaObject(Type.Object({}), undefined, {
|
||||||
restrictPaths: ["a.b"]
|
restrictPaths: ["a.b"],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(() => m.throwIfRestricted("a.b")).toThrow();
|
expect(() => m.throwIfRestricted("a.b")).toThrow();
|
||||||
@@ -185,18 +185,18 @@ describe("SchemaObject", async () => {
|
|||||||
a: Type.String({ default: "b" }),
|
a: Type.String({ default: "b" }),
|
||||||
b: Type.Object(
|
b: Type.Object(
|
||||||
{
|
{
|
||||||
c: Type.String({ default: "d" })
|
c: Type.String({ default: "d" }),
|
||||||
},
|
},
|
||||||
{ default: {} }
|
{ default: {} },
|
||||||
)
|
),
|
||||||
},
|
},
|
||||||
{ default: {} }
|
{ default: {} },
|
||||||
)
|
),
|
||||||
}),
|
}),
|
||||||
undefined,
|
undefined,
|
||||||
{
|
{
|
||||||
restrictPaths: ["s.b"]
|
restrictPaths: ["s.b"],
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(m.patch("s.b.c", "e")).rejects.toThrow();
|
expect(m.patch("s.b.c", "e")).rejects.toThrow();
|
||||||
@@ -217,33 +217,33 @@ describe("SchemaObject", async () => {
|
|||||||
additionalProperties: Type.Object({
|
additionalProperties: Type.Object({
|
||||||
type: Type.String(),
|
type: Type.String(),
|
||||||
config: Type.Optional(
|
config: Type.Optional(
|
||||||
Type.Object({}, { additionalProperties: Type.String() })
|
Type.Object({}, { additionalProperties: Type.String() }),
|
||||||
)
|
),
|
||||||
})
|
}),
|
||||||
}
|
},
|
||||||
|
),
|
||||||
|
config: Type.Optional(Type.Object({}, { additionalProperties: Type.String() })),
|
||||||
|
}),
|
||||||
|
},
|
||||||
),
|
),
|
||||||
config: Type.Optional(Type.Object({}, { additionalProperties: Type.String() }))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
additionalProperties: false
|
additionalProperties: false,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
test("patch safe object, overwrite", async () => {
|
test("patch safe object, overwrite", async () => {
|
||||||
const data = {
|
const data = {
|
||||||
entities: {
|
entities: {
|
||||||
some: {
|
some: {
|
||||||
fields: {
|
fields: {
|
||||||
a: { type: "string", config: { some: "thing" } }
|
a: { type: "string", config: { some: "thing" } },
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
const m = new SchemaObject(dataEntitiesSchema, data, {
|
const m = new SchemaObject(dataEntitiesSchema, data, {
|
||||||
forceParse: true,
|
forceParse: true,
|
||||||
overwritePaths: [/^entities\..*\.fields\..*\.config/]
|
overwritePaths: [/^entities\..*\.fields\..*\.config/],
|
||||||
});
|
});
|
||||||
|
|
||||||
await m.patch("entities.some.fields.a", { type: "string", config: { another: "one" } });
|
await m.patch("entities.some.fields.a", { type: "string", config: { another: "one" } });
|
||||||
@@ -252,10 +252,10 @@ describe("SchemaObject", async () => {
|
|||||||
entities: {
|
entities: {
|
||||||
some: {
|
some: {
|
||||||
fields: {
|
fields: {
|
||||||
a: { type: "string", config: { another: "one" } }
|
a: { type: "string", config: { another: "one" } },
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -265,22 +265,22 @@ describe("SchemaObject", async () => {
|
|||||||
users: {
|
users: {
|
||||||
fields: {
|
fields: {
|
||||||
email: { type: "string" },
|
email: { type: "string" },
|
||||||
password: { type: "string" }
|
password: { type: "string" },
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
const m = new SchemaObject(dataEntitiesSchema, data, {
|
const m = new SchemaObject(dataEntitiesSchema, data, {
|
||||||
forceParse: true,
|
forceParse: true,
|
||||||
overwritePaths: [/^entities\..*\.fields\..*\.config\.html_config$/]
|
overwritePaths: [/^entities\..*\.fields\..*\.config\.html_config$/],
|
||||||
});
|
});
|
||||||
|
|
||||||
await m.patch("entities.test", {
|
await m.patch("entities.test", {
|
||||||
fields: {
|
fields: {
|
||||||
content: {
|
content: {
|
||||||
type: "text"
|
type: "text",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(m.get()).toEqual({
|
expect(m.get()).toEqual({
|
||||||
@@ -288,17 +288,17 @@ describe("SchemaObject", async () => {
|
|||||||
users: {
|
users: {
|
||||||
fields: {
|
fields: {
|
||||||
email: { type: "string" },
|
email: { type: "string" },
|
||||||
password: { type: "string" }
|
password: { type: "string" },
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
test: {
|
test: {
|
||||||
fields: {
|
fields: {
|
||||||
content: {
|
content: {
|
||||||
type: "text"
|
type: "text",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -308,14 +308,14 @@ describe("SchemaObject", async () => {
|
|||||||
users: {
|
users: {
|
||||||
fields: {
|
fields: {
|
||||||
email: { type: "string" },
|
email: { type: "string" },
|
||||||
password: { type: "string" }
|
password: { type: "string" },
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
const m = new SchemaObject(dataEntitiesSchema, data, {
|
const m = new SchemaObject(dataEntitiesSchema, data, {
|
||||||
forceParse: true,
|
forceParse: true,
|
||||||
overwritePaths: [/^entities\..*\.fields\..*\.config\.html_config$/]
|
overwritePaths: [/^entities\..*\.fields\..*\.config\.html_config$/],
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(m.patch("desc", "entities.users.config.sort_dir")).rejects.toThrow();
|
expect(m.patch("desc", "entities.users.config.sort_dir")).rejects.toThrow();
|
||||||
@@ -323,13 +323,13 @@ describe("SchemaObject", async () => {
|
|||||||
await m.patch("entities.test", {
|
await m.patch("entities.test", {
|
||||||
fields: {
|
fields: {
|
||||||
content: {
|
content: {
|
||||||
type: "text"
|
type: "text",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await m.patch("entities.users.config", {
|
await m.patch("entities.users.config", {
|
||||||
sort_dir: "desc"
|
sort_dir: "desc",
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(m.get()).toEqual({
|
expect(m.get()).toEqual({
|
||||||
@@ -337,20 +337,20 @@ describe("SchemaObject", async () => {
|
|||||||
users: {
|
users: {
|
||||||
fields: {
|
fields: {
|
||||||
email: { type: "string" },
|
email: { type: "string" },
|
||||||
password: { type: "string" }
|
password: { type: "string" },
|
||||||
},
|
},
|
||||||
config: {
|
config: {
|
||||||
sort_dir: "desc"
|
sort_dir: "desc",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
test: {
|
test: {
|
||||||
fields: {
|
fields: {
|
||||||
content: {
|
content: {
|
||||||
type: "text"
|
type: "text",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ describe("diff", () => {
|
|||||||
t: "a",
|
t: "a",
|
||||||
p: ["b"],
|
p: ["b"],
|
||||||
o: undefined,
|
o: undefined,
|
||||||
n: 2
|
n: 2,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const appliedObj = apply(oldObj, diffs);
|
const appliedObj = apply(oldObj, diffs);
|
||||||
@@ -35,8 +35,8 @@ describe("diff", () => {
|
|||||||
t: "r",
|
t: "r",
|
||||||
p: ["b"],
|
p: ["b"],
|
||||||
o: 2,
|
o: 2,
|
||||||
n: undefined
|
n: undefined,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const appliedObj = apply(oldObj, diffs);
|
const appliedObj = apply(oldObj, diffs);
|
||||||
@@ -57,8 +57,8 @@ describe("diff", () => {
|
|||||||
t: "e",
|
t: "e",
|
||||||
p: ["a"],
|
p: ["a"],
|
||||||
o: 1,
|
o: 1,
|
||||||
n: 2
|
n: 2,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const appliedObj = apply(oldObj, diffs);
|
const appliedObj = apply(oldObj, diffs);
|
||||||
@@ -79,8 +79,8 @@ describe("diff", () => {
|
|||||||
t: "e",
|
t: "e",
|
||||||
p: ["a", "b"],
|
p: ["a", "b"],
|
||||||
o: 1,
|
o: 1,
|
||||||
n: 2
|
n: 2,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const appliedObj = apply(oldObj, diffs);
|
const appliedObj = apply(oldObj, diffs);
|
||||||
@@ -101,14 +101,14 @@ describe("diff", () => {
|
|||||||
t: "e",
|
t: "e",
|
||||||
p: ["a", 1],
|
p: ["a", 1],
|
||||||
o: 2,
|
o: 2,
|
||||||
n: 4
|
n: 4,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
t: "a",
|
t: "a",
|
||||||
p: ["a", 3],
|
p: ["a", 3],
|
||||||
o: undefined,
|
o: undefined,
|
||||||
n: 5
|
n: 5,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const appliedObj = apply(oldObj, diffs);
|
const appliedObj = apply(oldObj, diffs);
|
||||||
@@ -129,20 +129,20 @@ describe("diff", () => {
|
|||||||
t: "a",
|
t: "a",
|
||||||
p: ["a", 0],
|
p: ["a", 0],
|
||||||
o: undefined,
|
o: undefined,
|
||||||
n: 1
|
n: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
t: "a",
|
t: "a",
|
||||||
p: ["a", 1],
|
p: ["a", 1],
|
||||||
o: undefined,
|
o: undefined,
|
||||||
n: 2
|
n: 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
t: "a",
|
t: "a",
|
||||||
p: ["a", 2],
|
p: ["a", 2],
|
||||||
o: undefined,
|
o: undefined,
|
||||||
n: 3
|
n: 3,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const appliedObj = apply(oldObj, diffs);
|
const appliedObj = apply(oldObj, diffs);
|
||||||
@@ -163,14 +163,14 @@ describe("diff", () => {
|
|||||||
t: "e",
|
t: "e",
|
||||||
p: ["a", 1],
|
p: ["a", 1],
|
||||||
o: 2,
|
o: 2,
|
||||||
n: 3
|
n: 3,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
t: "r",
|
t: "r",
|
||||||
p: ["a", 2],
|
p: ["a", 2],
|
||||||
o: 3,
|
o: 3,
|
||||||
n: undefined
|
n: undefined,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const appliedObj = apply(oldObj, diffs);
|
const appliedObj = apply(oldObj, diffs);
|
||||||
@@ -183,14 +183,14 @@ describe("diff", () => {
|
|||||||
it("should handle complex nested changes", () => {
|
it("should handle complex nested changes", () => {
|
||||||
const oldObj = {
|
const oldObj = {
|
||||||
a: {
|
a: {
|
||||||
b: [1, 2, { c: 3 }]
|
b: [1, 2, { c: 3 }],
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const newObj = {
|
const newObj = {
|
||||||
a: {
|
a: {
|
||||||
b: [1, 2, { c: 4 }, 5]
|
b: [1, 2, { c: 4 }, 5],
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const diffs = diff(oldObj, newObj);
|
const diffs = diff(oldObj, newObj);
|
||||||
@@ -200,14 +200,14 @@ describe("diff", () => {
|
|||||||
t: "e",
|
t: "e",
|
||||||
p: ["a", "b", 2, "c"],
|
p: ["a", "b", 2, "c"],
|
||||||
o: 3,
|
o: 3,
|
||||||
n: 4
|
n: 4,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
t: "a",
|
t: "a",
|
||||||
p: ["a", "b", 3],
|
p: ["a", "b", 3],
|
||||||
o: undefined,
|
o: undefined,
|
||||||
n: 5
|
n: 5,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const appliedObj = apply(oldObj, diffs);
|
const appliedObj = apply(oldObj, diffs);
|
||||||
@@ -228,14 +228,14 @@ describe("diff", () => {
|
|||||||
t: "e",
|
t: "e",
|
||||||
p: ["a"],
|
p: ["a"],
|
||||||
o: undefined,
|
o: undefined,
|
||||||
n: null
|
n: null,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
t: "e",
|
t: "e",
|
||||||
p: ["b"],
|
p: ["b"],
|
||||||
o: null,
|
o: null,
|
||||||
n: undefined
|
n: undefined,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const appliedObj = apply(oldObj, diffs);
|
const appliedObj = apply(oldObj, diffs);
|
||||||
@@ -256,8 +256,8 @@ describe("diff", () => {
|
|||||||
t: "e",
|
t: "e",
|
||||||
p: ["a"],
|
p: ["a"],
|
||||||
o: 1,
|
o: 1,
|
||||||
n: "1"
|
n: "1",
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const appliedObj = apply(oldObj, diffs);
|
const appliedObj = apply(oldObj, diffs);
|
||||||
@@ -278,14 +278,14 @@ describe("diff", () => {
|
|||||||
t: "r",
|
t: "r",
|
||||||
p: ["b"],
|
p: ["b"],
|
||||||
o: 2,
|
o: 2,
|
||||||
n: undefined
|
n: undefined,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
t: "a",
|
t: "a",
|
||||||
p: ["c"],
|
p: ["c"],
|
||||||
o: undefined,
|
o: undefined,
|
||||||
n: 3
|
n: 3,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const appliedObj = apply(oldObj, diffs);
|
const appliedObj = apply(oldObj, diffs);
|
||||||
@@ -306,8 +306,8 @@ describe("diff", () => {
|
|||||||
t: "e",
|
t: "e",
|
||||||
p: ["a"],
|
p: ["a"],
|
||||||
o: [1, 2, 3],
|
o: [1, 2, 3],
|
||||||
n: { b: 4 }
|
n: { b: 4 },
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const appliedObj = apply(oldObj, diffs);
|
const appliedObj = apply(oldObj, diffs);
|
||||||
@@ -328,8 +328,8 @@ describe("diff", () => {
|
|||||||
t: "e",
|
t: "e",
|
||||||
p: ["a"],
|
p: ["a"],
|
||||||
o: { b: 1 },
|
o: { b: 1 },
|
||||||
n: 2
|
n: 2,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const appliedObj = apply(oldObj, diffs);
|
const appliedObj = apply(oldObj, diffs);
|
||||||
@@ -350,14 +350,14 @@ describe("diff", () => {
|
|||||||
t: "r",
|
t: "r",
|
||||||
p: ["a"],
|
p: ["a"],
|
||||||
o: 1,
|
o: 1,
|
||||||
n: undefined
|
n: undefined,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
t: "a",
|
t: "a",
|
||||||
p: ["b"],
|
p: ["b"],
|
||||||
o: undefined,
|
o: undefined,
|
||||||
n: 2
|
n: 2,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const appliedObj = apply(oldObj, diffs);
|
const appliedObj = apply(oldObj, diffs);
|
||||||
@@ -408,8 +408,8 @@ describe("diff", () => {
|
|||||||
t: "a",
|
t: "a",
|
||||||
p: ["a"],
|
p: ["a"],
|
||||||
o: undefined,
|
o: undefined,
|
||||||
n: 1
|
n: 1,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const appliedObj = apply(oldObj, diffs);
|
const appliedObj = apply(oldObj, diffs);
|
||||||
@@ -430,8 +430,8 @@ describe("diff", () => {
|
|||||||
t: "r",
|
t: "r",
|
||||||
p: ["a"],
|
p: ["a"],
|
||||||
o: 1,
|
o: 1,
|
||||||
n: undefined
|
n: undefined,
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const appliedObj = apply(oldObj, diffs);
|
const appliedObj = apply(oldObj, diffs);
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ describe("object-query", () => {
|
|||||||
|
|
||||||
test("validates", async () => {
|
test("validates", async () => {
|
||||||
const converted = convert({
|
const converted = convert({
|
||||||
name: { $eq: "ch" }
|
name: { $eq: "ch" },
|
||||||
});
|
});
|
||||||
validate(converted, { name: "Michael" });
|
validate(converted, { name: "Michael" });
|
||||||
});
|
});
|
||||||
@@ -31,7 +31,7 @@ describe("object-query", () => {
|
|||||||
[{ val: { $notnull: 1 } }, { val: null }, false],
|
[{ val: { $notnull: 1 } }, { val: null }, false],
|
||||||
[{ val: { $regex: ".*" } }, { val: "test" }, true],
|
[{ val: { $regex: ".*" } }, { val: "test" }, true],
|
||||||
[{ val: { $regex: /^t.*/ } }, { val: "test" }, true],
|
[{ val: { $regex: /^t.*/ } }, { val: "test" }, true],
|
||||||
[{ val: { $regex: /^b.*/ } }, { val: "test" }, false]
|
[{ val: { $regex: /^b.*/ } }, { val: "test" }, false],
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const [query, object, expected] of tests) {
|
for (const [query, object, expected] of tests) {
|
||||||
@@ -55,10 +55,10 @@ describe("object-query", () => {
|
|||||||
[
|
[
|
||||||
{ $or: { val1: { $eq: "foo" }, val2: { $eq: "bar" } } },
|
{ $or: { val1: { $eq: "foo" }, val2: { $eq: "bar" } } },
|
||||||
{ val1: "foo", val2: "bar" },
|
{ val1: "foo", val2: "bar" },
|
||||||
true
|
true,
|
||||||
],
|
],
|
||||||
[{ val1: { $eq: 1 }, $or: { val1: { $eq: 2 } } }, { val1: 1 }, true],
|
[{ val1: { $eq: 1 }, $or: { val1: { $eq: 2 } } }, { val1: 1 }, true],
|
||||||
[{ val1: { $eq: 1 }, $or: { val1: { $eq: 2 } } }, { val1: 3 }, false]
|
[{ val1: { $eq: 1 }, $or: { val1: { $eq: 2 } } }, { val1: 3 }, false],
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const [query, object, expected] of tests) {
|
for (const [query, object, expected] of tests) {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ describe("Core Utils", async () => {
|
|||||||
expect(result).toEqual([
|
expect(result).toEqual([
|
||||||
{ key: "a", value: 1 },
|
{ key: "a", value: 1 },
|
||||||
{ key: "b", value: 2 },
|
{ key: "b", value: 2 },
|
||||||
{ key: "c", value: 3 }
|
{ key: "c", value: 3 },
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ describe("Core Utils", async () => {
|
|||||||
const obj = utils.headersToObject(headers);
|
const obj = utils.headersToObject(headers);
|
||||||
expect(obj).toEqual({
|
expect(obj).toEqual({
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
authorization: "Bearer 123"
|
authorization: "Bearer 123",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ describe("Core Utils", async () => {
|
|||||||
file: new File([""], "file.txt"),
|
file: new File([""], "file.txt"),
|
||||||
stream: new ReadableStream(),
|
stream: new ReadableStream(),
|
||||||
arrayBuffer: new ArrayBuffer(10),
|
arrayBuffer: new ArrayBuffer(10),
|
||||||
arrayBufferView: new Uint8Array(new ArrayBuffer(10))
|
arrayBufferView: new Uint8Array(new ArrayBuffer(10)),
|
||||||
};
|
};
|
||||||
|
|
||||||
const fns = [
|
const fns = [
|
||||||
@@ -90,7 +90,7 @@ describe("Core Utils", async () => {
|
|||||||
[utils.isBlob, "blob", ["stream", "arrayBuffer", "arrayBufferView"]],
|
[utils.isBlob, "blob", ["stream", "arrayBuffer", "arrayBufferView"]],
|
||||||
[utils.isFile, "file", ["stream", "arrayBuffer", "arrayBufferView"]],
|
[utils.isFile, "file", ["stream", "arrayBuffer", "arrayBufferView"]],
|
||||||
[utils.isArrayBuffer, "arrayBuffer"],
|
[utils.isArrayBuffer, "arrayBuffer"],
|
||||||
[utils.isArrayBufferView, "arrayBufferView"]
|
[utils.isArrayBufferView, "arrayBufferView"],
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
const additional = [0, 0.0, "", null, undefined, {}, []];
|
const additional = [0, 0.0, "", null, undefined, {}, []];
|
||||||
@@ -116,10 +116,10 @@ describe("Core Utils", async () => {
|
|||||||
const name = "test.json";
|
const name = "test.json";
|
||||||
const text = "attachment; filename=" + name;
|
const text = "attachment; filename=" + name;
|
||||||
const headers = new Headers({
|
const headers = new Headers({
|
||||||
"Content-Disposition": text
|
"Content-Disposition": text,
|
||||||
});
|
});
|
||||||
const request = new Request("http://example.com", {
|
const request = new Request("http://example.com", {
|
||||||
headers
|
headers,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(utils.getContentName(text)).toBe(name);
|
expect(utils.getContentName(text)).toBe(name);
|
||||||
@@ -166,7 +166,7 @@ describe("Core Utils", async () => {
|
|||||||
[{ a: 1, b: 2, c: 3 }, ["b"], { a: 1, c: 3 }],
|
[{ a: 1, b: 2, c: 3 }, ["b"], { a: 1, c: 3 }],
|
||||||
[{ a: 1, b: 2, c: 3 }, ["c"], { a: 1, b: 2 }],
|
[{ a: 1, b: 2, c: 3 }, ["c"], { a: 1, b: 2 }],
|
||||||
[{ a: 1, b: 2, c: 3 }, ["a", "b"], { c: 3 }],
|
[{ a: 1, b: 2, c: 3 }, ["a", "b"], { c: 3 }],
|
||||||
[{ a: 1, b: 2, c: 3 }, ["a", "b", "c"], {}]
|
[{ a: 1, b: 2, c: 3 }, ["a", "b", "c"], {}],
|
||||||
] as [object, string[], object][];
|
] as [object, string[], object][];
|
||||||
|
|
||||||
for (const [obj, keys, expected] of objects) {
|
for (const [obj, keys, expected] of objects) {
|
||||||
@@ -197,9 +197,9 @@ describe("Core Utils", async () => {
|
|||||||
new Map([["a", 1]]),
|
new Map([["a", 1]]),
|
||||||
new Map([
|
new Map([
|
||||||
["a", 1],
|
["a", 1],
|
||||||
["b", 2]
|
["b", 2],
|
||||||
]),
|
]),
|
||||||
false
|
false,
|
||||||
],
|
],
|
||||||
[{ a: 1 }, { a: 1 }, true],
|
[{ a: 1 }, { a: 1 }, true],
|
||||||
[{ a: 1 }, { a: 2 }, false],
|
[{ a: 1 }, { a: 2 }, false],
|
||||||
@@ -220,7 +220,7 @@ describe("Core Utils", async () => {
|
|||||||
[[1, 2, 3], [1, 2, 3, 4], false],
|
[[1, 2, 3], [1, 2, 3, 4], false],
|
||||||
[[{ a: 1 }], [{ a: 1 }], true],
|
[[{ a: 1 }], [{ a: 1 }], true],
|
||||||
[[{ a: 1 }], [{ a: 2 }], false],
|
[[{ a: 1 }], [{ a: 2 }], false],
|
||||||
[[{ a: 1 }], [{ b: 1 }], false]
|
[[{ a: 1 }], [{ b: 1 }], false],
|
||||||
] as [any, any, boolean][];
|
] as [any, any, boolean][];
|
||||||
|
|
||||||
for (const [a, b, expected] of objects) {
|
for (const [a, b, expected] of objects) {
|
||||||
@@ -236,7 +236,7 @@ describe("Core Utils", async () => {
|
|||||||
[{ a: { b: 1 } }, "a.b", 1],
|
[{ a: { b: 1 } }, "a.b", 1],
|
||||||
[{ a: { b: 1 } }, "a.b.c", null, null],
|
[{ a: { b: 1 } }, "a.b.c", null, null],
|
||||||
[{ a: { b: 1 } }, "a.b.c", 1, 1],
|
[{ a: { b: 1 } }, "a.b.c", 1, 1],
|
||||||
[[[1]], "0.0", 1]
|
[[[1]], "0.0", 1],
|
||||||
] as [object, string, any, any][];
|
] as [object, string, any, any][];
|
||||||
|
|
||||||
for (const [obj, path, expected, defaultValue] of tests) {
|
for (const [obj, path, expected, defaultValue] of tests) {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
ManyToOneRelation,
|
ManyToOneRelation,
|
||||||
type MutatorResponse,
|
type MutatorResponse,
|
||||||
type RepositoryResponse,
|
type RepositoryResponse,
|
||||||
TextField
|
TextField,
|
||||||
} from "../../src/data";
|
} from "../../src/data";
|
||||||
import { DataController } from "../../src/data/api/DataController";
|
import { DataController } from "../../src/data/api/DataController";
|
||||||
import { dataConfigSchema } from "../../src/data/data-schema";
|
import { dataConfigSchema } from "../../src/data/data-schema";
|
||||||
@@ -35,17 +35,17 @@ describe("[data] DataController", async () => {
|
|||||||
meta: {
|
meta: {
|
||||||
total: 0,
|
total: 0,
|
||||||
count: 0,
|
count: 0,
|
||||||
items: 0
|
items: 0,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(res).toEqual({
|
expect(res).toEqual({
|
||||||
meta: {
|
meta: {
|
||||||
total: 0,
|
total: 0,
|
||||||
count: 0,
|
count: 0,
|
||||||
items: 0
|
items: 0,
|
||||||
},
|
},
|
||||||
data: []
|
data: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -59,22 +59,22 @@ describe("[data] DataController", async () => {
|
|||||||
data: [] as any,
|
data: [] as any,
|
||||||
sql: "",
|
sql: "",
|
||||||
parameters: [] as any,
|
parameters: [] as any,
|
||||||
result: [] as any
|
result: [] as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(res).toEqual({
|
expect(res).toEqual({
|
||||||
data: []
|
data: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("getController", async () => {
|
describe("getController", async () => {
|
||||||
const users = new Entity("users", [
|
const users = new Entity("users", [
|
||||||
new TextField("name", { required: true }),
|
new TextField("name", { required: true }),
|
||||||
new TextField("bio")
|
new TextField("bio"),
|
||||||
]);
|
]);
|
||||||
const posts = new Entity("posts", [new TextField("content")]);
|
const posts = new Entity("posts", [new TextField("content")]);
|
||||||
const em = new EntityManager([users, posts], dummyConnection, [
|
const em = new EntityManager([users, posts], dummyConnection, [
|
||||||
new ManyToOneRelation(posts, users)
|
new ManyToOneRelation(posts, users),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await em.schema().sync({ force: true });
|
await em.schema().sync({ force: true });
|
||||||
@@ -83,12 +83,12 @@ describe("[data] DataController", async () => {
|
|||||||
users: [
|
users: [
|
||||||
{ name: "foo", bio: "bar" },
|
{ name: "foo", bio: "bar" },
|
||||||
{ name: "bar", bio: null },
|
{ name: "bar", bio: null },
|
||||||
{ name: "baz", bio: "!!!" }
|
{ name: "baz", bio: "!!!" },
|
||||||
],
|
],
|
||||||
posts: [
|
posts: [
|
||||||
{ content: "post 1", users_id: 1 },
|
{ content: "post 1", users_id: 1 },
|
||||||
{ content: "post 2", users_id: 2 }
|
{ content: "post 2", users_id: 2 },
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const ctx: any = { em, guard: new Guard() };
|
const ctx: any = { em, guard: new Guard() };
|
||||||
@@ -118,7 +118,7 @@ describe("[data] DataController", async () => {
|
|||||||
for await (const _user of fixtures.users) {
|
for await (const _user of fixtures.users) {
|
||||||
const res = await app.request("/entity/users", {
|
const res = await app.request("/entity/users", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify(_user)
|
body: JSON.stringify(_user),
|
||||||
});
|
});
|
||||||
//console.log("res", { _user }, res);
|
//console.log("res", { _user }, res);
|
||||||
const result = (await res.json()) as MutatorResponse;
|
const result = (await res.json()) as MutatorResponse;
|
||||||
@@ -133,7 +133,7 @@ describe("[data] DataController", async () => {
|
|||||||
for await (const _post of fixtures.posts) {
|
for await (const _post of fixtures.posts) {
|
||||||
const res = await app.request("/entity/posts", {
|
const res = await app.request("/entity/posts", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: JSON.stringify(_post)
|
body: JSON.stringify(_post),
|
||||||
});
|
});
|
||||||
const result = (await res.json()) as MutatorResponse;
|
const result = (await res.json()) as MutatorResponse;
|
||||||
const { id, ...data } = result.data as any;
|
const { id, ...data } = result.data as any;
|
||||||
@@ -159,11 +159,11 @@ describe("[data] DataController", async () => {
|
|||||||
const res = await app.request("/entity/users/query", {
|
const res = await app.request("/entity/users/query", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
where: { bio: { $isnull: 1 } }
|
where: { bio: { $isnull: 1 } },
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
const data = (await res.json()) as RepositoryResponse;
|
const data = (await res.json()) as RepositoryResponse;
|
||||||
|
|
||||||
@@ -199,7 +199,7 @@ describe("[data] DataController", async () => {
|
|||||||
test("/:entity (update one)", async () => {
|
test("/:entity (update one)", async () => {
|
||||||
const res = await app.request("/entity/users/3", {
|
const res = await app.request("/entity/users/3", {
|
||||||
method: "PATCH",
|
method: "PATCH",
|
||||||
body: JSON.stringify({ name: "new name" })
|
body: JSON.stringify({ name: "new name" }),
|
||||||
});
|
});
|
||||||
const { data } = (await res.json()) as MutatorResponse;
|
const { data } = (await res.json()) as MutatorResponse;
|
||||||
|
|
||||||
@@ -221,7 +221,7 @@ describe("[data] DataController", async () => {
|
|||||||
|
|
||||||
test("/:entity/:id (delete one)", async () => {
|
test("/:entity/:id (delete one)", async () => {
|
||||||
const res = await app.request("/entity/posts/2", {
|
const res = await app.request("/entity/posts/2", {
|
||||||
method: "DELETE"
|
method: "DELETE",
|
||||||
});
|
});
|
||||||
const { data } = (await res.json()) as RepositoryResponse<EntityData>;
|
const { data } = (await res.json()) as RepositoryResponse<EntityData>;
|
||||||
expect(data).toEqual({ id: 2, ...fixtures.posts[1] });
|
expect(data).toEqual({ id: 2, ...fixtures.posts[1] });
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ describe("data-query-impl", () => {
|
|||||||
[{ val: { $isnull: 0 } }, '"val" is not null', []],
|
[{ val: { $isnull: 0 } }, '"val" is not null', []],
|
||||||
[{ val: { $isnull: false } }, '"val" is not null', []],
|
[{ val: { $isnull: false } }, '"val" is not null', []],
|
||||||
[{ val: { $like: "what" } }, '"val" like ?', ["what"]],
|
[{ val: { $like: "what" } }, '"val" like ?', ["what"]],
|
||||||
[{ val: { $like: "w*t" } }, '"val" like ?', ["w%t"]]
|
[{ val: { $like: "w*t" } }, '"val" like ?', ["w%t"]],
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const [query, expectedSql, expectedParams] of tests) {
|
for (const [query, expectedSql, expectedParams] of tests) {
|
||||||
@@ -51,22 +51,22 @@ describe("data-query-impl", () => {
|
|||||||
[
|
[
|
||||||
{ val1: { $eq: "foo" }, val2: { $eq: "bar" } },
|
{ val1: { $eq: "foo" }, val2: { $eq: "bar" } },
|
||||||
'("val1" = ? and "val2" = ?)',
|
'("val1" = ? and "val2" = ?)',
|
||||||
["foo", "bar"]
|
["foo", "bar"],
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{ val1: { $eq: "foo" }, val2: { $eq: "bar" } },
|
{ val1: { $eq: "foo" }, val2: { $eq: "bar" } },
|
||||||
'("val1" = ? and "val2" = ?)',
|
'("val1" = ? and "val2" = ?)',
|
||||||
["foo", "bar"]
|
["foo", "bar"],
|
||||||
],
|
],
|
||||||
|
|
||||||
// or constructs
|
// or constructs
|
||||||
[
|
[
|
||||||
{ $or: { val1: { $eq: "foo" }, val2: { $eq: "bar" } } },
|
{ $or: { val1: { $eq: "foo" }, val2: { $eq: "bar" } } },
|
||||||
'("val1" = ? or "val2" = ?)',
|
'("val1" = ? or "val2" = ?)',
|
||||||
["foo", "bar"]
|
["foo", "bar"],
|
||||||
],
|
],
|
||||||
[{ val1: { $eq: 1 }, $or: { val1: { $eq: 2 } } }, '("val1" = ? or "val1" = ?)', [1, 2]],
|
[{ val1: { $eq: 1 }, $or: { val1: { $eq: 2 } } }, '("val1" = ? or "val1" = ?)', [1, 2]],
|
||||||
[{ val1: { $eq: 1 }, $or: { val1: { $eq: 2 } } }, '("val1" = ? or "val1" = ?)', [1, 2]]
|
[{ val1: { $eq: 1 }, $or: { val1: { $eq: 2 } } }, '("val1" = ? or "val1" = ?)', [1, 2]],
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const [query, expectedSql, expectedParams] of tests) {
|
for (const [query, expectedSql, expectedParams] of tests) {
|
||||||
@@ -86,7 +86,7 @@ describe("data-query-impl", () => {
|
|||||||
|
|
||||||
// or constructs
|
// or constructs
|
||||||
[{ $or: { val1: { $eq: "foo" }, val2: { $eq: "bar" } } }, ["val1", "val2"]],
|
[{ $or: { val1: { $eq: "foo" }, val2: { $eq: "bar" } } }, ["val1", "val2"]],
|
||||||
[{ val1: { $eq: 1 }, $or: { val1: { $eq: 2 } } }, ["val1"]]
|
[{ val1: { $eq: 1 }, $or: { val1: { $eq: 2 } } }, ["val1"]],
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const [query, expectedKeys] of tests) {
|
for (const [query, expectedKeys] of tests) {
|
||||||
@@ -105,23 +105,23 @@ describe("data-query-impl", () => {
|
|||||||
posts: {
|
posts: {
|
||||||
with: {
|
with: {
|
||||||
images: {
|
images: {
|
||||||
select: ["id"]
|
select: ["id"],
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
with: {
|
with: {
|
||||||
posts: {
|
posts: {
|
||||||
with: {
|
with: {
|
||||||
images: {
|
images: {
|
||||||
select: ["id"]
|
select: ["id"],
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// over http
|
// over http
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
NumberField,
|
NumberField,
|
||||||
PrimaryField,
|
PrimaryField,
|
||||||
Repository,
|
Repository,
|
||||||
TextField
|
TextField,
|
||||||
} from "../../src/data";
|
} from "../../src/data";
|
||||||
import { getDummyConnection } from "./helper";
|
import { getDummyConnection } from "./helper";
|
||||||
|
|
||||||
@@ -18,14 +18,14 @@ describe("some tests", async () => {
|
|||||||
|
|
||||||
const users = new Entity("users", [
|
const users = new Entity("users", [
|
||||||
new TextField("username", { required: true, default_value: "nobody" }),
|
new TextField("username", { required: true, default_value: "nobody" }),
|
||||||
new TextField("email", { maxLength: 3 })
|
new TextField("email", { maxLength: 3 }),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const posts = new Entity("posts", [
|
const posts = new Entity("posts", [
|
||||||
new TextField("title"),
|
new TextField("title"),
|
||||||
new TextField("content"),
|
new TextField("content"),
|
||||||
new TextField("created_at"),
|
new TextField("created_at"),
|
||||||
new NumberField("likes", { default_value: 0 })
|
new NumberField("likes", { default_value: 0 }),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const em = new EntityManager([users, posts], connection);
|
const em = new EntityManager([users, posts], connection);
|
||||||
@@ -43,7 +43,7 @@ describe("some tests", async () => {
|
|||||||
});*/
|
});*/
|
||||||
|
|
||||||
expect(query.sql).toBe(
|
expect(query.sql).toBe(
|
||||||
'select "users"."id" as "id", "users"."username" as "username", "users"."email" as "email" from "users" where "id" = ? limit ?'
|
'select "users"."id" as "id", "users"."username" as "username", "users"."email" as "email" from "users" where "id" = ? limit ?',
|
||||||
);
|
);
|
||||||
expect(query.parameters).toEqual([1, 1]);
|
expect(query.parameters).toEqual([1, 1]);
|
||||||
expect(query.result).toEqual([]);
|
expect(query.result).toEqual([]);
|
||||||
@@ -53,7 +53,7 @@ describe("some tests", async () => {
|
|||||||
const query = await em.repository(users).findMany();
|
const query = await em.repository(users).findMany();
|
||||||
|
|
||||||
expect(query.sql).toBe(
|
expect(query.sql).toBe(
|
||||||
'select "users"."id" as "id", "users"."username" as "username", "users"."email" as "email" from "users" order by "users"."id" asc limit ? offset ?'
|
'select "users"."id" as "id", "users"."username" as "username", "users"."email" as "email" from "users" order by "users"."id" asc limit ? offset ?',
|
||||||
);
|
);
|
||||||
expect(query.parameters).toEqual([10, 0]);
|
expect(query.parameters).toEqual([10, 0]);
|
||||||
expect(query.result).toEqual([]);
|
expect(query.result).toEqual([]);
|
||||||
@@ -63,7 +63,7 @@ describe("some tests", async () => {
|
|||||||
const query = await em.repository(posts).findMany();
|
const query = await em.repository(posts).findMany();
|
||||||
|
|
||||||
expect(query.sql).toBe(
|
expect(query.sql).toBe(
|
||||||
'select "posts"."id" as "id", "posts"."title" as "title", "posts"."content" as "content", "posts"."created_at" as "created_at", "posts"."likes" as "likes" from "posts" order by "posts"."id" asc limit ? offset ?'
|
'select "posts"."id" as "id", "posts"."title" as "title", "posts"."content" as "content", "posts"."created_at" as "created_at", "posts"."likes" as "likes" from "posts" order by "posts"."id" asc limit ? offset ?',
|
||||||
);
|
);
|
||||||
expect(query.parameters).toEqual([10, 0]);
|
expect(query.parameters).toEqual([10, 0]);
|
||||||
expect(query.result).toEqual([]);
|
expect(query.result).toEqual([]);
|
||||||
@@ -74,7 +74,7 @@ describe("some tests", async () => {
|
|||||||
new Entity("users", [
|
new Entity("users", [
|
||||||
new TextField("username"),
|
new TextField("username"),
|
||||||
new TextField("email"),
|
new TextField("email"),
|
||||||
new TextField("email") // not throwing, it's just being ignored
|
new TextField("email"), // not throwing, it's just being ignored
|
||||||
]);
|
]);
|
||||||
}).toBeDefined();
|
}).toBeDefined();
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ describe("some tests", async () => {
|
|||||||
new TextField("username"),
|
new TextField("username"),
|
||||||
new TextField("email"),
|
new TextField("email"),
|
||||||
// field config differs, will throw
|
// field config differs, will throw
|
||||||
new TextField("email", { required: true })
|
new TextField("email", { required: true }),
|
||||||
]);
|
]);
|
||||||
}).toThrow();
|
}).toThrow();
|
||||||
|
|
||||||
@@ -91,7 +91,7 @@ describe("some tests", async () => {
|
|||||||
new Entity("users", [
|
new Entity("users", [
|
||||||
new PrimaryField(),
|
new PrimaryField(),
|
||||||
new TextField("username"),
|
new TextField("username"),
|
||||||
new TextField("email")
|
new TextField("email"),
|
||||||
]);
|
]);
|
||||||
}).toBeDefined();
|
}).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ export function getDummyDatabase(memory: boolean = true): {
|
|||||||
afterAllCleanup: async () => {
|
afterAllCleanup: async () => {
|
||||||
if (!memory) await unlink(DB_NAME);
|
if (!memory) await unlink(DB_NAME);
|
||||||
return true;
|
return true;
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ export function getDummyConnection(memory: boolean = true) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
dummyConnection,
|
dummyConnection,
|
||||||
afterAllCleanup
|
afterAllCleanup,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
ManyToOneRelation,
|
ManyToOneRelation,
|
||||||
NumberField,
|
NumberField,
|
||||||
SchemaManager,
|
SchemaManager,
|
||||||
TextField
|
TextField,
|
||||||
} from "../../src/data";
|
} from "../../src/data";
|
||||||
import { getDummyConnection } from "./helper";
|
import { getDummyConnection } from "./helper";
|
||||||
|
|
||||||
@@ -21,7 +21,7 @@ describe("Mutator relation", async () => {
|
|||||||
const posts = new Entity("posts", [
|
const posts = new Entity("posts", [
|
||||||
new TextField("title"),
|
new TextField("title"),
|
||||||
new TextField("content", { default_value: "..." }),
|
new TextField("content", { default_value: "..." }),
|
||||||
new NumberField("count", { default_value: 0 })
|
new NumberField("count", { default_value: 0 }),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const users = new Entity("users", [new TextField("username")]);
|
const users = new Entity("users", [new TextField("username")]);
|
||||||
@@ -44,7 +44,7 @@ describe("Mutator relation", async () => {
|
|||||||
expect(em.mutator(posts).insertOne({ title: "post2", users_id: 10 })).rejects.toThrow();
|
expect(em.mutator(posts).insertOne({ title: "post2", users_id: 10 })).rejects.toThrow();
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
em.mutator(posts).insertOne({ title: "post2", users_id: data.id })
|
em.mutator(posts).insertOne({ title: "post2", users_id: data.id }),
|
||||||
).resolves.toBeDefined();
|
).resolves.toBeDefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ describe("Mutator simple", async () => {
|
|||||||
|
|
||||||
const items = new Entity("items", [
|
const items = new Entity("items", [
|
||||||
new TextField("label", { required: true, minLength: 1 }),
|
new TextField("label", { required: true, minLength: 1 }),
|
||||||
new NumberField("count", { default_value: 0 })
|
new NumberField("count", { default_value: 0 }),
|
||||||
]);
|
]);
|
||||||
const em = new EntityManager<any>([items], connection);
|
const em = new EntityManager<any>([items], connection);
|
||||||
|
|
||||||
@@ -29,11 +29,11 @@ describe("Mutator simple", async () => {
|
|||||||
test("insert single row", async () => {
|
test("insert single row", async () => {
|
||||||
const mutation = await em.mutator(items).insertOne({
|
const mutation = await em.mutator(items).insertOne({
|
||||||
label: "test",
|
label: "test",
|
||||||
count: 1
|
count: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(mutation.sql).toBe(
|
expect(mutation.sql).toBe(
|
||||||
'insert into "items" ("count", "label") values (?, ?) returning "id", "label", "count"'
|
'insert into "items" ("count", "label") values (?, ?) returning "id", "label", "count"',
|
||||||
);
|
);
|
||||||
expect(mutation.data).toEqual({ id: 1, label: "test", count: 1 });
|
expect(mutation.data).toEqual({ id: 1, label: "test", count: 1 });
|
||||||
|
|
||||||
@@ -41,8 +41,8 @@ describe("Mutator simple", async () => {
|
|||||||
limit: 1,
|
limit: 1,
|
||||||
sort: {
|
sort: {
|
||||||
by: "id",
|
by: "id",
|
||||||
dir: "desc"
|
dir: "desc",
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(query.result).toEqual([{ id: 1, label: "test", count: 1 }]);
|
expect(query.result).toEqual([{ id: 1, label: "test", count: 1 }]);
|
||||||
@@ -53,18 +53,18 @@ describe("Mutator simple", async () => {
|
|||||||
limit: 1,
|
limit: 1,
|
||||||
sort: {
|
sort: {
|
||||||
by: "id",
|
by: "id",
|
||||||
dir: "desc"
|
dir: "desc",
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
const id = query.data![0].id as number;
|
const id = query.data![0].id as number;
|
||||||
|
|
||||||
const mutation = await em.mutator(items).updateOne(id, {
|
const mutation = await em.mutator(items).updateOne(id, {
|
||||||
label: "new label",
|
label: "new label",
|
||||||
count: 100
|
count: 100,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(mutation.sql).toBe(
|
expect(mutation.sql).toBe(
|
||||||
'update "items" set "label" = ?, "count" = ? where "id" = ? returning "id", "label", "count"'
|
'update "items" set "label" = ?, "count" = ? where "id" = ? returning "id", "label", "count"',
|
||||||
);
|
);
|
||||||
expect(mutation.data).toEqual({ id, label: "new label", count: 100 });
|
expect(mutation.data).toEqual({ id, label: "new label", count: 100 });
|
||||||
});
|
});
|
||||||
@@ -74,15 +74,15 @@ describe("Mutator simple", async () => {
|
|||||||
limit: 1,
|
limit: 1,
|
||||||
sort: {
|
sort: {
|
||||||
by: "id",
|
by: "id",
|
||||||
dir: "desc"
|
dir: "desc",
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const id = query.data![0].id as number;
|
const id = query.data![0].id as number;
|
||||||
const mutation = await em.mutator(items).deleteOne(id);
|
const mutation = await em.mutator(items).deleteOne(id);
|
||||||
|
|
||||||
expect(mutation.sql).toBe(
|
expect(mutation.sql).toBe(
|
||||||
'delete from "items" where "id" = ? returning "id", "label", "count"'
|
'delete from "items" where "id" = ? returning "id", "label", "count"',
|
||||||
);
|
);
|
||||||
expect(mutation.data).toEqual({ id, label: "new label", count: 100 });
|
expect(mutation.data).toEqual({ id, label: "new label", count: 100 });
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ describe("Mutator simple", async () => {
|
|||||||
const incompleteCreate = async () =>
|
const incompleteCreate = async () =>
|
||||||
await em.mutator(items).insertOne({
|
await em.mutator(items).insertOne({
|
||||||
//label: "test",
|
//label: "test",
|
||||||
count: 1
|
count: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(incompleteCreate()).rejects.toThrow();
|
expect(incompleteCreate()).rejects.toThrow();
|
||||||
@@ -104,7 +104,7 @@ describe("Mutator simple", async () => {
|
|||||||
const invalidCreate1 = async () =>
|
const invalidCreate1 = async () =>
|
||||||
await em.mutator(items).insertOne({
|
await em.mutator(items).insertOne({
|
||||||
label: 111, // this should work
|
label: 111, // this should work
|
||||||
count: "1" // this should fail
|
count: "1", // this should fail
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(invalidCreate1()).rejects.toThrow(TransformPersistFailedException);
|
expect(invalidCreate1()).rejects.toThrow(TransformPersistFailedException);
|
||||||
@@ -112,7 +112,7 @@ describe("Mutator simple", async () => {
|
|||||||
const invalidCreate2 = async () =>
|
const invalidCreate2 = async () =>
|
||||||
await em.mutator(items).insertOne({
|
await em.mutator(items).insertOne({
|
||||||
label: "", // this should fail
|
label: "", // this should fail
|
||||||
count: 1
|
count: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(invalidCreate2()).rejects.toThrow(TransformPersistFailedException);
|
expect(invalidCreate2()).rejects.toThrow(TransformPersistFailedException);
|
||||||
@@ -152,27 +152,27 @@ describe("Mutator simple", async () => {
|
|||||||
await em.mutator(items).updateWhere(
|
await em.mutator(items).updateWhere(
|
||||||
{ count: 2 },
|
{ count: 2 },
|
||||||
{
|
{
|
||||||
count: 10
|
count: 10,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
expect((await em.repository(items).findMany()).data).toEqual([
|
expect((await em.repository(items).findMany()).data).toEqual([
|
||||||
{ id: 6, label: "update", count: 1 },
|
{ id: 6, label: "update", count: 1 },
|
||||||
{ id: 7, label: "update too", count: 1 },
|
{ id: 7, label: "update too", count: 1 },
|
||||||
{ id: 8, label: "keep", count: 0 }
|
{ id: 8, label: "keep", count: 0 },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// expect 2 to be updated
|
// expect 2 to be updated
|
||||||
await em.mutator(items).updateWhere(
|
await em.mutator(items).updateWhere(
|
||||||
{ count: 2 },
|
{ count: 2 },
|
||||||
{
|
{
|
||||||
count: 1
|
count: 1,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
expect((await em.repository(items).findMany()).data).toEqual([
|
expect((await em.repository(items).findMany()).data).toEqual([
|
||||||
{ id: 6, label: "update", count: 2 },
|
{ id: 6, label: "update", count: 2 },
|
||||||
{ id: 7, label: "update too", count: 2 },
|
{ id: 7, label: "update too", count: 2 },
|
||||||
{ id: 8, label: "keep", count: 0 }
|
{ id: 8, label: "keep", count: 0 },
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -23,23 +23,23 @@ describe("Polymorphic", async () => {
|
|||||||
source: "categories",
|
source: "categories",
|
||||||
target: "media",
|
target: "media",
|
||||||
config: {
|
config: {
|
||||||
mappedBy: "image"
|
mappedBy: "image",
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
// media should not see categories
|
// media should not see categories
|
||||||
expect(em.relationsOf(media.name).map((r) => r.toJSON())).toEqual([]);
|
expect(em.relationsOf(media.name).map((r) => r.toJSON())).toEqual([]);
|
||||||
|
|
||||||
// it's important that media cannot access categories
|
// it's important that media cannot access categories
|
||||||
expect(em.relations.targetRelationsOf(categories).map((r) => r.source.entity.name)).toEqual(
|
expect(em.relations.targetRelationsOf(categories).map((r) => r.source.entity.name)).toEqual(
|
||||||
[]
|
[],
|
||||||
);
|
);
|
||||||
expect(em.relations.targetRelationsOf(media).map((r) => r.source.entity.name)).toEqual([]);
|
expect(em.relations.targetRelationsOf(media).map((r) => r.source.entity.name)).toEqual([]);
|
||||||
|
|
||||||
expect(em.relations.sourceRelationsOf(categories).map((r) => r.target.entity.name)).toEqual([
|
expect(em.relations.sourceRelationsOf(categories).map((r) => r.target.entity.name)).toEqual([
|
||||||
"media"
|
"media",
|
||||||
]);
|
]);
|
||||||
expect(em.relations.sourceRelationsOf(categories).map((r) => r.target.reference)).toEqual([
|
expect(em.relations.sourceRelationsOf(categories).map((r) => r.target.reference)).toEqual([
|
||||||
"image"
|
"image",
|
||||||
]);
|
]);
|
||||||
expect(em.relations.sourceRelationsOf(media).map((r) => r.target.entity.name)).toEqual([]);
|
expect(em.relations.sourceRelationsOf(media).map((r) => r.target.entity.name)).toEqual([]);
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ describe("Polymorphic", async () => {
|
|||||||
"id",
|
"id",
|
||||||
"path",
|
"path",
|
||||||
"reference",
|
"reference",
|
||||||
"entity_id"
|
"entity_id",
|
||||||
]);
|
]);
|
||||||
expect(media.getSelect()).toEqual(["id", "path"]);
|
expect(media.getSelect()).toEqual(["id", "path"]);
|
||||||
});
|
});
|
||||||
@@ -60,7 +60,7 @@ describe("Polymorphic", async () => {
|
|||||||
const entities = [media, categories];
|
const entities = [media, categories];
|
||||||
const single = new PolymorphicRelation(categories, media, {
|
const single = new PolymorphicRelation(categories, media, {
|
||||||
mappedBy: "single",
|
mappedBy: "single",
|
||||||
targetCardinality: 1
|
targetCardinality: 1,
|
||||||
});
|
});
|
||||||
const multiple = new PolymorphicRelation(categories, media, { mappedBy: "multiple" });
|
const multiple = new PolymorphicRelation(categories, media, { mappedBy: "multiple" });
|
||||||
|
|
||||||
@@ -71,17 +71,17 @@ describe("Polymorphic", async () => {
|
|||||||
|
|
||||||
// it's important that media cannot access categories
|
// it's important that media cannot access categories
|
||||||
expect(em.relations.targetRelationsOf(categories).map((r) => r.source.entity.name)).toEqual(
|
expect(em.relations.targetRelationsOf(categories).map((r) => r.source.entity.name)).toEqual(
|
||||||
[]
|
[],
|
||||||
);
|
);
|
||||||
expect(em.relations.targetRelationsOf(media).map((r) => r.source.entity.name)).toEqual([]);
|
expect(em.relations.targetRelationsOf(media).map((r) => r.source.entity.name)).toEqual([]);
|
||||||
|
|
||||||
expect(em.relations.sourceRelationsOf(categories).map((r) => r.target.entity.name)).toEqual([
|
expect(em.relations.sourceRelationsOf(categories).map((r) => r.target.entity.name)).toEqual([
|
||||||
"media",
|
"media",
|
||||||
"media"
|
"media",
|
||||||
]);
|
]);
|
||||||
expect(em.relations.sourceRelationsOf(categories).map((r) => r.target.reference)).toEqual([
|
expect(em.relations.sourceRelationsOf(categories).map((r) => r.target.reference)).toEqual([
|
||||||
"single",
|
"single",
|
||||||
"multiple"
|
"multiple",
|
||||||
]);
|
]);
|
||||||
expect(em.relations.sourceRelationsOf(media).map((r) => r.target.entity.name)).toEqual([]);
|
expect(em.relations.sourceRelationsOf(media).map((r) => r.target.entity.name)).toEqual([]);
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ describe("Polymorphic", async () => {
|
|||||||
"id",
|
"id",
|
||||||
"path",
|
"path",
|
||||||
"reference",
|
"reference",
|
||||||
"entity_id"
|
"entity_id",
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import {
|
|||||||
NumberField,
|
NumberField,
|
||||||
OneToOneRelation,
|
OneToOneRelation,
|
||||||
PolymorphicRelation,
|
PolymorphicRelation,
|
||||||
TextField
|
TextField,
|
||||||
} from "../../src/data";
|
} from "../../src/data";
|
||||||
import { DummyConnection } from "../../src/data/connection/DummyConnection";
|
import { DummyConnection } from "../../src/data/connection/DummyConnection";
|
||||||
import {
|
import {
|
||||||
@@ -31,7 +31,7 @@ import {
|
|||||||
medium,
|
medium,
|
||||||
number,
|
number,
|
||||||
relation,
|
relation,
|
||||||
text
|
text,
|
||||||
} from "../../src/data/prototype";
|
} from "../../src/data/prototype";
|
||||||
import { MediaField } from "../../src/media/MediaField";
|
import { MediaField } from "../../src/media/MediaField";
|
||||||
|
|
||||||
@@ -54,7 +54,7 @@ describe("prototype", () => {
|
|||||||
name: text(),
|
name: text(),
|
||||||
bio: text(),
|
bio: text(),
|
||||||
age: number(),
|
age: number(),
|
||||||
some: number()
|
some: number(),
|
||||||
});
|
});
|
||||||
type db = {
|
type db = {
|
||||||
users: Schema<typeof users>;
|
users: Schema<typeof users>;
|
||||||
@@ -70,7 +70,7 @@ describe("prototype", () => {
|
|||||||
name: text({ default_value: "hello" }).required(),
|
name: text({ default_value: "hello" }).required(),
|
||||||
bio: text(),
|
bio: text(),
|
||||||
age: number(),
|
age: number(),
|
||||||
some: number().required()
|
some: number().required(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const obj: InsertSchema<typeof user> = { name: "yo", some: 1 };
|
const obj: InsertSchema<typeof user> = { name: "yo", some: 1 };
|
||||||
@@ -83,12 +83,12 @@ describe("prototype", () => {
|
|||||||
new TextField("title", { required: true }),
|
new TextField("title", { required: true }),
|
||||||
new TextField("content"),
|
new TextField("content"),
|
||||||
new DateField("created_at", {
|
new DateField("created_at", {
|
||||||
type: "datetime"
|
type: "datetime",
|
||||||
}),
|
}),
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
new MediaField("images", { entity: "posts" }),
|
new MediaField("images", { entity: "posts" }),
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
new MediaField("cover", { entity: "posts", max_items: 1 })
|
new MediaField("cover", { entity: "posts", max_items: 1 }),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const posts2 = entity("posts", {
|
const posts2 = entity("posts", {
|
||||||
@@ -96,7 +96,7 @@ describe("prototype", () => {
|
|||||||
content: text(),
|
content: text(),
|
||||||
created_at: datetime(),
|
created_at: datetime(),
|
||||||
images: media(),
|
images: media(),
|
||||||
cover: medium()
|
cover: medium(),
|
||||||
});
|
});
|
||||||
|
|
||||||
type Posts = Schema<typeof posts2>;
|
type Posts = Schema<typeof posts2>;
|
||||||
@@ -117,11 +117,11 @@ describe("prototype", () => {
|
|||||||
type: "objects",
|
type: "objects",
|
||||||
values: [
|
values: [
|
||||||
{ value: "active", label: "Active" },
|
{ value: "active", label: "Active" },
|
||||||
{ value: "inactive", label: "Not active" }
|
{ value: "inactive", label: "Not active" },
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
}),
|
}),
|
||||||
new JsonField("json")
|
new JsonField("json"),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const test2 = entity("test", {
|
const test2 = entity("test", {
|
||||||
@@ -134,10 +134,10 @@ describe("prototype", () => {
|
|||||||
status: enumm<"active" | "inactive">({
|
status: enumm<"active" | "inactive">({
|
||||||
enum: [
|
enum: [
|
||||||
{ value: "active", label: "Active" },
|
{ value: "active", label: "Active" },
|
||||||
{ value: "inactive", label: "Not active" }
|
{ value: "inactive", label: "Not active" },
|
||||||
]
|
],
|
||||||
}),
|
}),
|
||||||
json: json<{ some: number }>()
|
json: json<{ some: number }>(),
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(test.toJSON()).toEqual(test2.toJSON());
|
expect(test.toJSON()).toEqual(test2.toJSON());
|
||||||
@@ -161,12 +161,12 @@ describe("prototype", () => {
|
|||||||
// category has single image
|
// category has single image
|
||||||
new PolymorphicRelation(categories, _media, {
|
new PolymorphicRelation(categories, _media, {
|
||||||
mappedBy: "image",
|
mappedBy: "image",
|
||||||
targetCardinality: 1
|
targetCardinality: 1,
|
||||||
}),
|
}),
|
||||||
|
|
||||||
// post has multiple images
|
// post has multiple images
|
||||||
new PolymorphicRelation(posts, _media, { mappedBy: "images" }),
|
new PolymorphicRelation(posts, _media, { mappedBy: "images" }),
|
||||||
new PolymorphicRelation(posts, _media, { mappedBy: "cover", targetCardinality: 1 })
|
new PolymorphicRelation(posts, _media, { mappedBy: "cover", targetCardinality: 1 }),
|
||||||
];
|
];
|
||||||
|
|
||||||
const relations2 = [
|
const relations2 = [
|
||||||
@@ -180,7 +180,7 @@ describe("prototype", () => {
|
|||||||
relation(categories).polyToOne(_media, { mappedBy: "image" }),
|
relation(categories).polyToOne(_media, { mappedBy: "image" }),
|
||||||
|
|
||||||
relation(posts).polyToMany(_media, { mappedBy: "images" }),
|
relation(posts).polyToMany(_media, { mappedBy: "images" }),
|
||||||
relation(posts).polyToOne(_media, { mappedBy: "cover" })
|
relation(posts).polyToOne(_media, { mappedBy: "cover" }),
|
||||||
];
|
];
|
||||||
|
|
||||||
expect(relations.map((r) => r.toJSON())).toEqual(relations2.map((r) => r.toJSON()));
|
expect(relations.map((r) => r.toJSON())).toEqual(relations2.map((r) => r.toJSON()));
|
||||||
@@ -194,21 +194,21 @@ describe("prototype", () => {
|
|||||||
posts,
|
posts,
|
||||||
categories,
|
categories,
|
||||||
{
|
{
|
||||||
connectionTableMappedName: "custom"
|
connectionTableMappedName: "custom",
|
||||||
},
|
},
|
||||||
[new TextField("description")]
|
[new TextField("description")],
|
||||||
);
|
);
|
||||||
|
|
||||||
const fields = {
|
const fields = {
|
||||||
description: text()
|
description: text(),
|
||||||
};
|
};
|
||||||
let o: FieldSchema<typeof fields>;
|
let o: FieldSchema<typeof fields>;
|
||||||
const rel2 = relation(posts).manyToMany(
|
const rel2 = relation(posts).manyToMany(
|
||||||
categories,
|
categories,
|
||||||
{
|
{
|
||||||
connectionTableMappedName: "custom"
|
connectionTableMappedName: "custom",
|
||||||
},
|
},
|
||||||
fields
|
fields,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(rel.toJSON()).toEqual(rel2.toJSON());
|
expect(rel.toJSON()).toEqual(rel2.toJSON());
|
||||||
@@ -216,11 +216,11 @@ describe("prototype", () => {
|
|||||||
|
|
||||||
test("devexample", async () => {
|
test("devexample", async () => {
|
||||||
const users = entity("users", {
|
const users = entity("users", {
|
||||||
username: text()
|
username: text(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const comments = entity("comments", {
|
const comments = entity("comments", {
|
||||||
content: text()
|
content: text(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const posts = entity("posts", {
|
const posts = entity("posts", {
|
||||||
@@ -228,17 +228,17 @@ describe("prototype", () => {
|
|||||||
content: text(),
|
content: text(),
|
||||||
created_at: datetime(),
|
created_at: datetime(),
|
||||||
images: media(),
|
images: media(),
|
||||||
cover: medium()
|
cover: medium(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const categories = entity("categories", {
|
const categories = entity("categories", {
|
||||||
name: text(),
|
name: text(),
|
||||||
description: text(),
|
description: text(),
|
||||||
image: medium()
|
image: medium(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const settings = entity("settings", {
|
const settings = entity("settings", {
|
||||||
theme: text()
|
theme: text(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const test = entity("test", {
|
const test = entity("test", {
|
||||||
@@ -251,10 +251,10 @@ describe("prototype", () => {
|
|||||||
status: enumm<"active" | "inactive">({
|
status: enumm<"active" | "inactive">({
|
||||||
enum: [
|
enum: [
|
||||||
{ value: "active", label: "Active" },
|
{ value: "active", label: "Active" },
|
||||||
{ value: "inactive", label: "Not active" }
|
{ value: "inactive", label: "Not active" },
|
||||||
]
|
],
|
||||||
}),
|
}),
|
||||||
json: json<{ some: number }>()
|
json: json<{ some: number }>(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const _media = entity("media", {});
|
const _media = entity("media", {});
|
||||||
@@ -270,7 +270,7 @@ describe("prototype", () => {
|
|||||||
relation(users).oneToOne(settings),
|
relation(users).oneToOne(settings),
|
||||||
|
|
||||||
relation(comments).manyToOne(users, { required: true }),
|
relation(comments).manyToOne(users, { required: true }),
|
||||||
relation(comments).manyToOne(posts, { required: true })
|
relation(comments).manyToOne(posts, { required: true }),
|
||||||
];
|
];
|
||||||
|
|
||||||
const obj: Schema<typeof test> = {} as any;
|
const obj: Schema<typeof test> = {} as any;
|
||||||
@@ -281,12 +281,12 @@ describe("prototype", () => {
|
|||||||
{
|
{
|
||||||
posts: entity("posts", { name: text(), slug: text().required() }),
|
posts: entity("posts", { name: text(), slug: text().required() }),
|
||||||
comments: entity("comments", { some: text() }),
|
comments: entity("comments", { some: text() }),
|
||||||
users: entity("users", { email: text() })
|
users: entity("users", { email: text() }),
|
||||||
},
|
},
|
||||||
({ relation, index }, { posts, comments, users }) => {
|
({ relation, index }, { posts, comments, users }) => {
|
||||||
relation(posts).manyToOne(comments).manyToOne(users);
|
relation(posts).manyToOne(comments).manyToOne(users);
|
||||||
index(posts).on(["name"]).on(["slug"], true);
|
index(posts).on(["name"]).on(["slug"], true);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
type LocalDb = (typeof _em)["DB"];
|
type LocalDb = (typeof _em)["DB"];
|
||||||
@@ -294,7 +294,7 @@ describe("prototype", () => {
|
|||||||
const es = [
|
const es = [
|
||||||
new Entity("posts", [new TextField("name"), new TextField("slug", { required: true })]),
|
new Entity("posts", [new TextField("name"), new TextField("slug", { required: true })]),
|
||||||
new Entity("comments", [new TextField("some")]),
|
new Entity("comments", [new TextField("some")]),
|
||||||
new Entity("users", [new TextField("email")])
|
new Entity("users", [new TextField("email")]),
|
||||||
];
|
];
|
||||||
const _em2 = new EntityManager(
|
const _em2 = new EntityManager(
|
||||||
es,
|
es,
|
||||||
@@ -302,8 +302,8 @@ describe("prototype", () => {
|
|||||||
[new ManyToOneRelation(es[0], es[1]), new ManyToOneRelation(es[0], es[2])],
|
[new ManyToOneRelation(es[0], es[1]), new ManyToOneRelation(es[0], es[2])],
|
||||||
[
|
[
|
||||||
new EntityIndex(es[0], [es[0].field("name")!]),
|
new EntityIndex(es[0], [es[0].field("name")!]),
|
||||||
new EntityIndex(es[0], [es[0].field("slug")!], true)
|
new EntityIndex(es[0], [es[0].field("slug")!], true),
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
ManyToOneRelation,
|
ManyToOneRelation,
|
||||||
OneToOneRelation,
|
OneToOneRelation,
|
||||||
PolymorphicRelation,
|
PolymorphicRelation,
|
||||||
RelationField
|
RelationField,
|
||||||
} from "../../src/data/relations";
|
} from "../../src/data/relations";
|
||||||
import { getDummyConnection } from "./helper";
|
import { getDummyConnection } from "./helper";
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ describe("Relations", async () => {
|
|||||||
const r1 = new RelationField("users_id", {
|
const r1 = new RelationField("users_id", {
|
||||||
reference: "users",
|
reference: "users",
|
||||||
target: "users",
|
target: "users",
|
||||||
target_field: "id"
|
target_field: "id",
|
||||||
});
|
});
|
||||||
|
|
||||||
const sql1 = schema
|
const sql1 = schema
|
||||||
@@ -31,14 +31,14 @@ describe("Relations", async () => {
|
|||||||
.compile().sql;
|
.compile().sql;
|
||||||
|
|
||||||
expect(sql1).toBe(
|
expect(sql1).toBe(
|
||||||
'create table "posts" ("users_id" integer references "users" ("id") on delete set null)'
|
'create table "posts" ("users_id" integer references "users" ("id") on delete set null)',
|
||||||
);
|
);
|
||||||
|
|
||||||
//const r2 = new RelationField(new Entity("users"), "author");
|
//const r2 = new RelationField(new Entity("users"), "author");
|
||||||
const r2 = new RelationField("author_id", {
|
const r2 = new RelationField("author_id", {
|
||||||
reference: "author",
|
reference: "author",
|
||||||
target: "users",
|
target: "users",
|
||||||
target_field: "id"
|
target_field: "id",
|
||||||
});
|
});
|
||||||
|
|
||||||
const sql2 = schema
|
const sql2 = schema
|
||||||
@@ -47,7 +47,7 @@ describe("Relations", async () => {
|
|||||||
.compile().sql;
|
.compile().sql;
|
||||||
|
|
||||||
expect(sql2).toBe(
|
expect(sql2).toBe(
|
||||||
'create table "posts" ("author_id" integer references "users" ("id") on delete set null)'
|
'create table "posts" ("author_id" integer references "users" ("id") on delete set null)',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ describe("Relations", async () => {
|
|||||||
reference: "users",
|
reference: "users",
|
||||||
target: "users",
|
target: "users",
|
||||||
target_field: "id",
|
target_field: "id",
|
||||||
required: true
|
required: true,
|
||||||
});
|
});
|
||||||
expect(r1.isRequired()).toBeTrue();
|
expect(r1.isRequired()).toBeTrue();
|
||||||
});
|
});
|
||||||
@@ -66,8 +66,8 @@ describe("Relations", async () => {
|
|||||||
const users = new Entity("users", [new TextField("username")]);
|
const users = new Entity("users", [new TextField("username")]);
|
||||||
const posts = new Entity("posts", [
|
const posts = new Entity("posts", [
|
||||||
new TextField("title", {
|
new TextField("title", {
|
||||||
maxLength: 2
|
maxLength: 2,
|
||||||
})
|
}),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const entities = [users, posts];
|
const entities = [users, posts];
|
||||||
@@ -122,7 +122,7 @@ describe("Relations", async () => {
|
|||||||
.selectFrom(users.name)
|
.selectFrom(users.name)
|
||||||
.select((eb) => postAuthorRel.buildWith(users, "posts")(eb).as("posts"));
|
.select((eb) => postAuthorRel.buildWith(users, "posts")(eb).as("posts"));
|
||||||
expect(selectPostsFromUsers.compile().sql).toBe(
|
expect(selectPostsFromUsers.compile().sql).toBe(
|
||||||
'select (select from "posts" as "posts" where "posts"."author_id" = "users"."id") as "posts" from "users"'
|
'select (select from "posts" as "posts" where "posts"."author_id" = "users"."id") as "posts" from "users"',
|
||||||
);
|
);
|
||||||
expect(postAuthorRel!.getField()).toBeInstanceOf(RelationField);
|
expect(postAuthorRel!.getField()).toBeInstanceOf(RelationField);
|
||||||
const userObj = { id: 1, username: "test" };
|
const userObj = { id: 1, username: "test" };
|
||||||
@@ -142,7 +142,7 @@ describe("Relations", async () => {
|
|||||||
.select((eb) => postAuthorRel.buildWith(posts, "author")(eb).as("author"));
|
.select((eb) => postAuthorRel.buildWith(posts, "author")(eb).as("author"));
|
||||||
|
|
||||||
expect(selectUsersFromPosts.compile().sql).toBe(
|
expect(selectUsersFromPosts.compile().sql).toBe(
|
||||||
'select (select from "users" as "author" where "author"."id" = "posts"."author_id" limit ?) as "author" from "posts"'
|
'select (select from "users" as "author" where "author"."id" = "posts"."author_id" limit ?) as "author" from "posts"',
|
||||||
);
|
);
|
||||||
expect(postAuthorRel.getField()).toBeInstanceOf(RelationField);
|
expect(postAuthorRel.getField()).toBeInstanceOf(RelationField);
|
||||||
const postObj = { id: 1, title: "test" };
|
const postObj = { id: 1, title: "test" };
|
||||||
@@ -158,7 +158,7 @@ describe("Relations", async () => {
|
|||||||
$detach: false,
|
$detach: false,
|
||||||
primary: undefined,
|
primary: undefined,
|
||||||
cardinality: undefined,
|
cardinality: undefined,
|
||||||
relation_type: "n:1"
|
relation_type: "n:1",
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(postAuthorRel!.helper(posts.name)!.getMutationInfo()).toEqual({
|
expect(postAuthorRel!.helper(posts.name)!.getMutationInfo()).toEqual({
|
||||||
@@ -170,7 +170,7 @@ describe("Relations", async () => {
|
|||||||
$detach: false,
|
$detach: false,
|
||||||
primary: "id",
|
primary: "id",
|
||||||
cardinality: 1,
|
cardinality: 1,
|
||||||
relation_type: "n:1"
|
relation_type: "n:1",
|
||||||
});
|
});
|
||||||
|
|
||||||
/*console.log("ManyToOne (source=posts, target=users)");
|
/*console.log("ManyToOne (source=posts, target=users)");
|
||||||
@@ -225,7 +225,7 @@ describe("Relations", async () => {
|
|||||||
$detach: false,
|
$detach: false,
|
||||||
primary: "id",
|
primary: "id",
|
||||||
cardinality: 1,
|
cardinality: 1,
|
||||||
relation_type: "1:1"
|
relation_type: "1:1",
|
||||||
});
|
});
|
||||||
expect(userSettingRel!.helper(settings.name)!.getMutationInfo()).toEqual({
|
expect(userSettingRel!.helper(settings.name)!.getMutationInfo()).toEqual({
|
||||||
reference: "users",
|
reference: "users",
|
||||||
@@ -236,7 +236,7 @@ describe("Relations", async () => {
|
|||||||
$detach: false,
|
$detach: false,
|
||||||
primary: undefined,
|
primary: undefined,
|
||||||
cardinality: 1,
|
cardinality: 1,
|
||||||
relation_type: "1:1"
|
relation_type: "1:1",
|
||||||
});
|
});
|
||||||
|
|
||||||
/*console.log("");
|
/*console.log("");
|
||||||
@@ -312,14 +312,14 @@ describe("Relations", async () => {
|
|||||||
.selectFrom(posts.name)
|
.selectFrom(posts.name)
|
||||||
.select((eb) => postCategoriesRel.buildWith(posts)(eb).select("id").as("categories"));
|
.select((eb) => postCategoriesRel.buildWith(posts)(eb).select("id").as("categories"));
|
||||||
expect(selectCategoriesFromPosts.compile().sql).toBe(
|
expect(selectCategoriesFromPosts.compile().sql).toBe(
|
||||||
'select (select "id" from "categories" inner join "posts_categories" on "categories"."id" = "posts_categories"."categories_id" where "posts"."id" = "posts_categories"."posts_id" limit ?) as "categories" from "posts"'
|
'select (select "id" from "categories" inner join "posts_categories" on "categories"."id" = "posts_categories"."categories_id" where "posts"."id" = "posts_categories"."posts_id" limit ?) as "categories" from "posts"',
|
||||||
);
|
);
|
||||||
|
|
||||||
const selectPostsFromCategories = kysely
|
const selectPostsFromCategories = kysely
|
||||||
.selectFrom(categories.name)
|
.selectFrom(categories.name)
|
||||||
.select((eb) => postCategoriesRel.buildWith(categories)(eb).select("id").as("posts"));
|
.select((eb) => postCategoriesRel.buildWith(categories)(eb).select("id").as("posts"));
|
||||||
expect(selectPostsFromCategories.compile().sql).toBe(
|
expect(selectPostsFromCategories.compile().sql).toBe(
|
||||||
'select (select "id" from "posts" inner join "posts_categories" on "posts"."id" = "posts_categories"."posts_id" where "categories"."id" = "posts_categories"."categories_id" limit ?) as "posts" from "categories"'
|
'select (select "id" from "posts" inner join "posts_categories" on "posts"."id" = "posts_categories"."posts_id" where "categories"."id" = "posts_categories"."categories_id" limit ?) as "posts" from "categories"',
|
||||||
);
|
);
|
||||||
|
|
||||||
// mutation info
|
// mutation info
|
||||||
@@ -332,7 +332,7 @@ describe("Relations", async () => {
|
|||||||
$detach: true,
|
$detach: true,
|
||||||
primary: "id",
|
primary: "id",
|
||||||
cardinality: undefined,
|
cardinality: undefined,
|
||||||
relation_type: "m:n"
|
relation_type: "m:n",
|
||||||
});
|
});
|
||||||
expect(relations[0].helper(categories.name)!.getMutationInfo()).toEqual({
|
expect(relations[0].helper(categories.name)!.getMutationInfo()).toEqual({
|
||||||
reference: "posts",
|
reference: "posts",
|
||||||
@@ -343,7 +343,7 @@ describe("Relations", async () => {
|
|||||||
$detach: false,
|
$detach: false,
|
||||||
primary: undefined,
|
primary: undefined,
|
||||||
cardinality: undefined,
|
cardinality: undefined,
|
||||||
relation_type: "m:n"
|
relation_type: "m:n",
|
||||||
});
|
});
|
||||||
|
|
||||||
/*console.log("");
|
/*console.log("");
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ describe("[data] Entity", async () => {
|
|||||||
new TextField("name", { required: true }),
|
new TextField("name", { required: true }),
|
||||||
new TextField("description"),
|
new TextField("description"),
|
||||||
new NumberField("age", { fillable: false, default_value: 18 }),
|
new NumberField("age", { fillable: false, default_value: 18 }),
|
||||||
new TextField("hidden", { hidden: true, default_value: "secret" })
|
new TextField("hidden", { hidden: true, default_value: "secret" }),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
test("getSelect", async () => {
|
test("getSelect", async () => {
|
||||||
@@ -17,7 +17,7 @@ describe("[data] Entity", async () => {
|
|||||||
expect(entity.getFillableFields().map((f) => f.name)).toEqual([
|
expect(entity.getFillableFields().map((f) => f.name)).toEqual([
|
||||||
"name",
|
"name",
|
||||||
"description",
|
"description",
|
||||||
"hidden"
|
"hidden",
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ describe("[data] Entity", async () => {
|
|||||||
test("getDefaultObject", async () => {
|
test("getDefaultObject", async () => {
|
||||||
expect(entity.getDefaultObject()).toEqual({
|
expect(entity.getDefaultObject()).toEqual({
|
||||||
age: 18,
|
age: 18,
|
||||||
hidden: "secret"
|
hidden: "secret",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
EntityManager,
|
EntityManager,
|
||||||
ManyToManyRelation,
|
ManyToManyRelation,
|
||||||
ManyToOneRelation,
|
ManyToOneRelation,
|
||||||
SchemaManager
|
SchemaManager,
|
||||||
} from "../../../src/data";
|
} from "../../../src/data";
|
||||||
import { UnableToConnectException } from "../../../src/data/errors";
|
import { UnableToConnectException } from "../../../src/data/errors";
|
||||||
import { getDummyConnection } from "../helper";
|
import { getDummyConnection } from "../helper";
|
||||||
@@ -25,7 +25,7 @@ describe("[data] EntityManager", async () => {
|
|||||||
expect(await em.ping()).toBe(true);
|
expect(await em.ping()).toBe(true);
|
||||||
expect(() => em.entity("...")).toThrow();
|
expect(() => em.entity("...")).toThrow();
|
||||||
expect(() =>
|
expect(() =>
|
||||||
em.addRelation(new ManyToOneRelation(new Entity("1"), new Entity("2")))
|
em.addRelation(new ManyToOneRelation(new Entity("1"), new Entity("2"))),
|
||||||
).toThrow();
|
).toThrow();
|
||||||
expect(em.schema()).toBeInstanceOf(SchemaManager);
|
expect(em.schema()).toBeInstanceOf(SchemaManager);
|
||||||
|
|
||||||
@@ -98,7 +98,7 @@ describe("[data] EntityManager", async () => {
|
|||||||
expect(userTargetRel.map((r) => r.other(users).entity.name)).toEqual(["posts", "comments"]);
|
expect(userTargetRel.map((r) => r.other(users).entity.name)).toEqual(["posts", "comments"]);
|
||||||
expect(postTargetRel.map((r) => r.other(posts).entity.name)).toEqual([
|
expect(postTargetRel.map((r) => r.other(posts).entity.name)).toEqual([
|
||||||
"comments",
|
"comments",
|
||||||
"categories"
|
"categories",
|
||||||
]);
|
]);
|
||||||
expect(commentTargetRel.map((r) => r.other(comments).entity.name)).toEqual([]);
|
expect(commentTargetRel.map((r) => r.other(comments).entity.name)).toEqual([]);
|
||||||
expect(categoriesTargetRel.map((r) => r.other(categories).entity.name)).toEqual(["posts"]);
|
expect(categoriesTargetRel.map((r) => r.other(categories).entity.name)).toEqual(["posts"]);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ describe("[data] JoinBuilder", async () => {
|
|||||||
const em = new EntityManager([users], dummyConnection);
|
const em = new EntityManager([users], dummyConnection);
|
||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
JoinBuilder.addClause(em, em.connection.kysely.selectFrom("users"), users, ["posts"])
|
JoinBuilder.addClause(em, em.connection.kysely.selectFrom("users"), users, ["posts"]),
|
||||||
).toThrow('Relation "posts" not found');
|
).toThrow('Relation "posts" not found');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -23,7 +23,7 @@ describe("[data] JoinBuilder", async () => {
|
|||||||
const em = new EntityManager([users, posts], dummyConnection, relations);
|
const em = new EntityManager([users, posts], dummyConnection, relations);
|
||||||
|
|
||||||
const qb = JoinBuilder.addClause(em, em.connection.kysely.selectFrom("users"), users, [
|
const qb = JoinBuilder.addClause(em, em.connection.kysely.selectFrom("users"), users, [
|
||||||
"posts"
|
"posts",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const res = qb.compile();
|
const res = qb.compile();
|
||||||
@@ -34,7 +34,7 @@ describe("[data] JoinBuilder", async () => {
|
|||||||
);*/
|
);*/
|
||||||
|
|
||||||
const qb2 = JoinBuilder.addClause(em, em.connection.kysely.selectFrom("posts"), posts, [
|
const qb2 = JoinBuilder.addClause(em, em.connection.kysely.selectFrom("posts"), posts, [
|
||||||
"author"
|
"author",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const res2 = qb2.compile();
|
const res2 = qb2.compile();
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import {
|
|||||||
OneToOneRelation,
|
OneToOneRelation,
|
||||||
type RelationField,
|
type RelationField,
|
||||||
RelationMutator,
|
RelationMutator,
|
||||||
TextField
|
TextField,
|
||||||
} from "../../../src/data";
|
} from "../../../src/data";
|
||||||
import * as proto from "../../../src/data/prototype";
|
import * as proto from "../../../src/data/prototype";
|
||||||
import { getDummyConnection } from "../helper";
|
import { getDummyConnection } from "../helper";
|
||||||
@@ -22,7 +22,7 @@ describe("[data] Mutator (base)", async () => {
|
|||||||
new TextField("label", { required: true }),
|
new TextField("label", { required: true }),
|
||||||
new NumberField("count"),
|
new NumberField("count"),
|
||||||
new TextField("hidden", { hidden: true }),
|
new TextField("hidden", { hidden: true }),
|
||||||
new TextField("not_fillable", { fillable: false })
|
new TextField("not_fillable", { fillable: false }),
|
||||||
]);
|
]);
|
||||||
const em = new EntityManager<any>([entity], dummyConnection);
|
const em = new EntityManager<any>([entity], dummyConnection);
|
||||||
await em.schema().sync({ force: true });
|
await em.schema().sync({ force: true });
|
||||||
@@ -44,7 +44,7 @@ describe("[data] Mutator (base)", async () => {
|
|||||||
test("updateOne", async () => {
|
test("updateOne", async () => {
|
||||||
const { data } = await em.mutator(entity).insertOne(payload);
|
const { data } = await em.mutator(entity).insertOne(payload);
|
||||||
const updated = await em.mutator(entity).updateOne(data.id, {
|
const updated = await em.mutator(entity).updateOne(data.id, {
|
||||||
count: 2
|
count: 2,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(updated.parameters).toEqual([2, data.id]);
|
expect(updated.parameters).toEqual([2, data.id]);
|
||||||
@@ -77,7 +77,7 @@ describe("[data] Mutator (ManyToOne)", async () => {
|
|||||||
|
|
||||||
// persisting relational field should just return key value to be added
|
// persisting relational field should just return key value to be added
|
||||||
expect(
|
expect(
|
||||||
postRelMutator.persistRelationField(postRelField, "users_id", userData.data.id)
|
postRelMutator.persistRelationField(postRelField, "users_id", userData.data.id),
|
||||||
).resolves.toEqual(["users_id", userData.data.id]);
|
).resolves.toEqual(["users_id", userData.data.id]);
|
||||||
|
|
||||||
// persisting invalid value should throw
|
// persisting invalid value should throw
|
||||||
@@ -86,8 +86,8 @@ describe("[data] Mutator (ManyToOne)", async () => {
|
|||||||
// persisting reference should ...
|
// persisting reference should ...
|
||||||
expect(
|
expect(
|
||||||
postRelMutator.persistReference(relations[0]!, "users", {
|
postRelMutator.persistReference(relations[0]!, "users", {
|
||||||
$set: { id: userData.data.id }
|
$set: { id: userData.data.id },
|
||||||
})
|
}),
|
||||||
).resolves.toEqual(["users_id", userData.data.id]);
|
).resolves.toEqual(["users_id", userData.data.id]);
|
||||||
// @todo: add what methods are allowed to relation, like $create should not be allowed for post<>users
|
// @todo: add what methods are allowed to relation, like $create should not be allowed for post<>users
|
||||||
|
|
||||||
@@ -99,8 +99,8 @@ describe("[data] Mutator (ManyToOne)", async () => {
|
|||||||
expect(
|
expect(
|
||||||
em.mutator(posts).insertOne({
|
em.mutator(posts).insertOne({
|
||||||
title: "post1",
|
title: "post1",
|
||||||
users_id: 100 // user does not exist yet
|
users_id: 100, // user does not exist yet
|
||||||
})
|
}),
|
||||||
).rejects.toThrow();
|
).rejects.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ describe("[data] Mutator (ManyToOne)", async () => {
|
|||||||
const em = new EntityManager([items, cats], dummyConnection, relations);
|
const em = new EntityManager([items, cats], dummyConnection, relations);
|
||||||
|
|
||||||
expect(em.mutator(items).insertOne({ label: "test" })).rejects.toThrow(
|
expect(em.mutator(items).insertOne({ label: "test" })).rejects.toThrow(
|
||||||
'Field "cats_id" is required'
|
'Field "cats_id" is required',
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -119,14 +119,14 @@ describe("[data] Mutator (ManyToOne)", async () => {
|
|||||||
const { data } = await em.mutator(users).insertOne({ username: "user1" });
|
const { data } = await em.mutator(users).insertOne({ username: "user1" });
|
||||||
const res = await em.mutator(posts).insertOne({
|
const res = await em.mutator(posts).insertOne({
|
||||||
title: "post1",
|
title: "post1",
|
||||||
users_id: data.id
|
users_id: data.id,
|
||||||
});
|
});
|
||||||
expect(res.data.users_id).toBe(data.id);
|
expect(res.data.users_id).toBe(data.id);
|
||||||
|
|
||||||
// setting "null" should be allowed
|
// setting "null" should be allowed
|
||||||
const res2 = await em.mutator(posts).insertOne({
|
const res2 = await em.mutator(posts).insertOne({
|
||||||
title: "post1",
|
title: "post1",
|
||||||
users_id: null
|
users_id: null,
|
||||||
});
|
});
|
||||||
expect(res2.data.users_id).toBe(null);
|
expect(res2.data.users_id).toBe(null);
|
||||||
});
|
});
|
||||||
@@ -135,14 +135,14 @@ describe("[data] Mutator (ManyToOne)", async () => {
|
|||||||
const { data } = await em.mutator(users).insertOne({ username: "user1" });
|
const { data } = await em.mutator(users).insertOne({ username: "user1" });
|
||||||
const res = await em.mutator(posts).insertOne({
|
const res = await em.mutator(posts).insertOne({
|
||||||
title: "post1",
|
title: "post1",
|
||||||
users: { $set: { id: data.id } }
|
users: { $set: { id: data.id } },
|
||||||
});
|
});
|
||||||
expect(res.data.users_id).toBe(data.id);
|
expect(res.data.users_id).toBe(data.id);
|
||||||
|
|
||||||
// setting "null" should be allowed
|
// setting "null" should be allowed
|
||||||
const res2 = await em.mutator(posts).insertOne({
|
const res2 = await em.mutator(posts).insertOne({
|
||||||
title: "post1",
|
title: "post1",
|
||||||
users: { $set: { id: null } }
|
users: { $set: { id: null } },
|
||||||
});
|
});
|
||||||
expect(res2.data.users_id).toBe(null);
|
expect(res2.data.users_id).toBe(null);
|
||||||
});
|
});
|
||||||
@@ -151,8 +151,8 @@ describe("[data] Mutator (ManyToOne)", async () => {
|
|||||||
expect(
|
expect(
|
||||||
em.mutator(posts).insertOne({
|
em.mutator(posts).insertOne({
|
||||||
title: "test",
|
title: "test",
|
||||||
users: { $create: { username: "test" } }
|
users: { $create: { username: "test" } },
|
||||||
})
|
}),
|
||||||
).rejects.toThrow();
|
).rejects.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -162,27 +162,27 @@ describe("[data] Mutator (ManyToOne)", async () => {
|
|||||||
const res2 = await em.mutator(posts).insertOne({ title: "post1" });
|
const res2 = await em.mutator(posts).insertOne({ title: "post1" });
|
||||||
|
|
||||||
const up1 = await em.mutator(posts).updateOne(res2.data.id, {
|
const up1 = await em.mutator(posts).updateOne(res2.data.id, {
|
||||||
users: { $set: { id: res1.data.id } }
|
users: { $set: { id: res1.data.id } },
|
||||||
});
|
});
|
||||||
expect(up1.data.users_id).toBe(res1.data.id);
|
expect(up1.data.users_id).toBe(res1.data.id);
|
||||||
|
|
||||||
const up2 = await em.mutator(posts).updateOne(res2.data.id, {
|
const up2 = await em.mutator(posts).updateOne(res2.data.id, {
|
||||||
users: { $set: { id: res1_1.data.id } }
|
users: { $set: { id: res1_1.data.id } },
|
||||||
});
|
});
|
||||||
expect(up2.data.users_id).toBe(res1_1.data.id);
|
expect(up2.data.users_id).toBe(res1_1.data.id);
|
||||||
|
|
||||||
const up3_1 = await em.mutator(posts).updateOne(res2.data.id, {
|
const up3_1 = await em.mutator(posts).updateOne(res2.data.id, {
|
||||||
users_id: res1.data.id
|
users_id: res1.data.id,
|
||||||
});
|
});
|
||||||
expect(up3_1.data.users_id).toBe(res1.data.id);
|
expect(up3_1.data.users_id).toBe(res1.data.id);
|
||||||
|
|
||||||
const up3_2 = await em.mutator(posts).updateOne(res2.data.id, {
|
const up3_2 = await em.mutator(posts).updateOne(res2.data.id, {
|
||||||
users_id: res1_1.data.id
|
users_id: res1_1.data.id,
|
||||||
});
|
});
|
||||||
expect(up3_2.data.users_id).toBe(res1_1.data.id);
|
expect(up3_2.data.users_id).toBe(res1_1.data.id);
|
||||||
|
|
||||||
const up4 = await em.mutator(posts).updateOne(res2.data.id, {
|
const up4 = await em.mutator(posts).updateOne(res2.data.id, {
|
||||||
users_id: null
|
users_id: null,
|
||||||
});
|
});
|
||||||
expect(up4.data.users_id).toBe(null);
|
expect(up4.data.users_id).toBe(null);
|
||||||
});
|
});
|
||||||
@@ -199,8 +199,8 @@ describe("[data] Mutator (OneToOne)", async () => {
|
|||||||
expect(
|
expect(
|
||||||
em.mutator(users).insertOne({
|
em.mutator(users).insertOne({
|
||||||
username: "test",
|
username: "test",
|
||||||
settings_id: 1 // todo: throws because it doesn't exist, but it shouldn't be allowed
|
settings_id: 1, // todo: throws because it doesn't exist, but it shouldn't be allowed
|
||||||
})
|
}),
|
||||||
).rejects.toThrow();
|
).rejects.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -210,15 +210,15 @@ describe("[data] Mutator (OneToOne)", async () => {
|
|||||||
expect(
|
expect(
|
||||||
em.mutator(users).insertOne({
|
em.mutator(users).insertOne({
|
||||||
username: "test",
|
username: "test",
|
||||||
settings: { $set: { id: data.id } }
|
settings: { $set: { id: data.id } },
|
||||||
})
|
}),
|
||||||
).rejects.toThrow();
|
).rejects.toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("insertOne: using $create", async () => {
|
test("insertOne: using $create", async () => {
|
||||||
const res = await em.mutator(users).insertOne({
|
const res = await em.mutator(users).insertOne({
|
||||||
username: "test",
|
username: "test",
|
||||||
settings: { $create: { theme: "dark" } }
|
settings: { $create: { theme: "dark" } },
|
||||||
});
|
});
|
||||||
expect(res.data.settings_id).toBeDefined();
|
expect(res.data.settings_id).toBeDefined();
|
||||||
});
|
});
|
||||||
@@ -303,7 +303,7 @@ describe("[data] Mutator (Events)", async () => {
|
|||||||
test("insertOne event return is respected", async () => {
|
test("insertOne event return is respected", async () => {
|
||||||
const posts = proto.entity("posts", {
|
const posts = proto.entity("posts", {
|
||||||
title: proto.text(),
|
title: proto.text(),
|
||||||
views: proto.number()
|
views: proto.number(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const conn = getDummyConnection();
|
const conn = getDummyConnection();
|
||||||
@@ -318,10 +318,10 @@ describe("[data] Mutator (Events)", async () => {
|
|||||||
async (event) => {
|
async (event) => {
|
||||||
return {
|
return {
|
||||||
...event.params.data,
|
...event.params.data,
|
||||||
views: 2
|
views: 2,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
"sync"
|
"sync",
|
||||||
);
|
);
|
||||||
|
|
||||||
const mutator = em.mutator("posts");
|
const mutator = em.mutator("posts");
|
||||||
@@ -329,14 +329,14 @@ describe("[data] Mutator (Events)", async () => {
|
|||||||
expect(result.data).toEqual({
|
expect(result.data).toEqual({
|
||||||
id: 1,
|
id: 1,
|
||||||
title: "test",
|
title: "test",
|
||||||
views: 2
|
views: 2,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("updateOne event return is respected", async () => {
|
test("updateOne event return is respected", async () => {
|
||||||
const posts = proto.entity("posts", {
|
const posts = proto.entity("posts", {
|
||||||
title: proto.text(),
|
title: proto.text(),
|
||||||
views: proto.number()
|
views: proto.number(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const conn = getDummyConnection();
|
const conn = getDummyConnection();
|
||||||
@@ -351,10 +351,10 @@ describe("[data] Mutator (Events)", async () => {
|
|||||||
async (event) => {
|
async (event) => {
|
||||||
return {
|
return {
|
||||||
...event.params.data,
|
...event.params.data,
|
||||||
views: event.params.data.views + 1
|
views: event.params.data.views + 1,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
"sync"
|
"sync",
|
||||||
);
|
);
|
||||||
|
|
||||||
const mutator = em.mutator("posts");
|
const mutator = em.mutator("posts");
|
||||||
@@ -363,7 +363,7 @@ describe("[data] Mutator (Events)", async () => {
|
|||||||
expect(result.data).toEqual({
|
expect(result.data).toEqual({
|
||||||
id: 1,
|
id: 1,
|
||||||
title: "test",
|
title: "test",
|
||||||
views: 3
|
views: 3,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
LibsqlConnection,
|
LibsqlConnection,
|
||||||
ManyToOneRelation,
|
ManyToOneRelation,
|
||||||
RepositoryEvents,
|
RepositoryEvents,
|
||||||
TextField
|
TextField,
|
||||||
} from "../../../src/data";
|
} from "../../../src/data";
|
||||||
import { getDummyConnection } from "../helper";
|
import { getDummyConnection } from "../helper";
|
||||||
|
|
||||||
@@ -70,13 +70,13 @@ describe("[Repository]", async () => {
|
|||||||
const q1 = selectQ(conn).compile();
|
const q1 = selectQ(conn).compile();
|
||||||
const res = await client.execute({
|
const res = await client.execute({
|
||||||
sql: q1.sql,
|
sql: q1.sql,
|
||||||
args: q1.parameters as any
|
args: q1.parameters as any,
|
||||||
});
|
});
|
||||||
|
|
||||||
const q2 = countQ(conn).compile();
|
const q2 = countQ(conn).compile();
|
||||||
const count = await client.execute({
|
const count = await client.execute({
|
||||||
sql: q2.sql,
|
sql: q2.sql,
|
||||||
args: q2.parameters as any
|
args: q2.parameters as any,
|
||||||
});
|
});
|
||||||
return [res, count];
|
return [res, count];
|
||||||
}
|
}
|
||||||
@@ -93,7 +93,7 @@ describe("[Repository]", async () => {
|
|||||||
const exec = async (
|
const exec = async (
|
||||||
name: string,
|
name: string,
|
||||||
fn: (em: EntityManager<any>) => Promise<any>,
|
fn: (em: EntityManager<any>) => Promise<any>,
|
||||||
em: EntityManager<any>
|
em: EntityManager<any>,
|
||||||
) => {
|
) => {
|
||||||
const res = await Perf.execute(() => fn(em), times);
|
const res = await Perf.execute(() => fn(em), times);
|
||||||
await sleep(1000);
|
await sleep(1000);
|
||||||
@@ -102,7 +102,7 @@ describe("[Repository]", async () => {
|
|||||||
total: res.total.toFixed(2),
|
total: res.total.toFixed(2),
|
||||||
avg: (res.total / times).toFixed(2),
|
avg: (res.total / times).toFixed(2),
|
||||||
first: res.marks[0].time.toFixed(2),
|
first: res.marks[0].time.toFixed(2),
|
||||||
last: res.marks[res.marks.length - 1].time.toFixed(2)
|
last: res.marks[res.marks.length - 1].time.toFixed(2),
|
||||||
};
|
};
|
||||||
console.log(info.name, info, res.marks);
|
console.log(info.name, info, res.marks);
|
||||||
return info;
|
return info;
|
||||||
@@ -183,7 +183,7 @@ describe("[data] Repository (Events)", async () => {
|
|||||||
const items = new Entity("items", [new TextField("label")]);
|
const items = new Entity("items", [new TextField("label")]);
|
||||||
const categories = new Entity("categories", [new TextField("label")]);
|
const categories = new Entity("categories", [new TextField("label")]);
|
||||||
const em = new EntityManager([items, categories], dummyConnection, [
|
const em = new EntityManager([items, categories], dummyConnection, [
|
||||||
new ManyToOneRelation(categories, items)
|
new ManyToOneRelation(categories, items),
|
||||||
]);
|
]);
|
||||||
await em.schema().sync({ force: true });
|
await em.schema().sync({ force: true });
|
||||||
const events = new Map<string, any>();
|
const events = new Map<string, any>();
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ describe("SchemaManager tests", async () => {
|
|||||||
isNullable: true,
|
isNullable: true,
|
||||||
isAutoIncrementing: true,
|
isAutoIncrementing: true,
|
||||||
hasDefaultValue: false,
|
hasDefaultValue: false,
|
||||||
comment: undefined
|
comment: undefined,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "username",
|
name: "username",
|
||||||
@@ -34,7 +34,7 @@ describe("SchemaManager tests", async () => {
|
|||||||
isNullable: true,
|
isNullable: true,
|
||||||
isAutoIncrementing: false,
|
isAutoIncrementing: false,
|
||||||
hasDefaultValue: false,
|
hasDefaultValue: false,
|
||||||
comment: undefined
|
comment: undefined,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "email",
|
name: "email",
|
||||||
@@ -42,7 +42,7 @@ describe("SchemaManager tests", async () => {
|
|||||||
isNullable: true,
|
isNullable: true,
|
||||||
isAutoIncrementing: false,
|
isAutoIncrementing: false,
|
||||||
hasDefaultValue: false,
|
hasDefaultValue: false,
|
||||||
comment: undefined
|
comment: undefined,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "bio",
|
name: "bio",
|
||||||
@@ -50,8 +50,8 @@ describe("SchemaManager tests", async () => {
|
|||||||
isNullable: true,
|
isNullable: true,
|
||||||
isAutoIncrementing: false,
|
isAutoIncrementing: false,
|
||||||
hasDefaultValue: false,
|
hasDefaultValue: false,
|
||||||
comment: undefined
|
comment: undefined,
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
indices: [
|
indices: [
|
||||||
{
|
{
|
||||||
@@ -61,11 +61,11 @@ describe("SchemaManager tests", async () => {
|
|||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
name: "email",
|
name: "email",
|
||||||
order: 0
|
order: 0,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -77,10 +77,10 @@ describe("SchemaManager tests", async () => {
|
|||||||
new Entity(table, [
|
new Entity(table, [
|
||||||
new TextField("username"),
|
new TextField("username"),
|
||||||
new TextField("email"),
|
new TextField("email"),
|
||||||
new TextField("bio")
|
new TextField("bio"),
|
||||||
])
|
]),
|
||||||
],
|
],
|
||||||
dummyConnection
|
dummyConnection,
|
||||||
);
|
);
|
||||||
const kysely = em.connection.kysely;
|
const kysely = em.connection.kysely;
|
||||||
|
|
||||||
@@ -101,8 +101,8 @@ describe("SchemaManager tests", async () => {
|
|||||||
name: table,
|
name: table,
|
||||||
isNew: false,
|
isNew: false,
|
||||||
columns: { add: ["bio"], drop: [], change: [] },
|
columns: { add: ["bio"], drop: [], change: [] },
|
||||||
indices: { add: [], drop: [index] }
|
indices: { add: [], drop: [index] },
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// now sync
|
// now sync
|
||||||
@@ -119,7 +119,7 @@ describe("SchemaManager tests", async () => {
|
|||||||
const table = "drop_column";
|
const table = "drop_column";
|
||||||
const em = new EntityManager(
|
const em = new EntityManager(
|
||||||
[new Entity(table, [new TextField("username")])],
|
[new Entity(table, [new TextField("username")])],
|
||||||
dummyConnection
|
dummyConnection,
|
||||||
);
|
);
|
||||||
const kysely = em.connection.kysely;
|
const kysely = em.connection.kysely;
|
||||||
|
|
||||||
@@ -141,10 +141,10 @@ describe("SchemaManager tests", async () => {
|
|||||||
columns: {
|
columns: {
|
||||||
add: [],
|
add: [],
|
||||||
drop: ["email"],
|
drop: ["email"],
|
||||||
change: []
|
change: [],
|
||||||
|
},
|
||||||
|
indices: { add: [], drop: [] },
|
||||||
},
|
},
|
||||||
indices: { add: [], drop: [] }
|
|
||||||
}
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// now sync
|
// now sync
|
||||||
@@ -165,15 +165,15 @@ describe("SchemaManager tests", async () => {
|
|||||||
new Entity(usersTable, [
|
new Entity(usersTable, [
|
||||||
new TextField("username"),
|
new TextField("username"),
|
||||||
new TextField("email"),
|
new TextField("email"),
|
||||||
new TextField("bio")
|
new TextField("bio"),
|
||||||
]),
|
]),
|
||||||
new Entity(postsTable, [
|
new Entity(postsTable, [
|
||||||
new TextField("title"),
|
new TextField("title"),
|
||||||
new TextField("content"),
|
new TextField("content"),
|
||||||
new TextField("created_at")
|
new TextField("created_at"),
|
||||||
])
|
]),
|
||||||
],
|
],
|
||||||
dummyConnection
|
dummyConnection,
|
||||||
);
|
);
|
||||||
const kysely = em.connection.kysely;
|
const kysely = em.connection.kysely;
|
||||||
|
|
||||||
@@ -192,7 +192,7 @@ describe("SchemaManager tests", async () => {
|
|||||||
name: usersTable,
|
name: usersTable,
|
||||||
isNew: false,
|
isNew: false,
|
||||||
columns: { add: ["bio"], drop: [], change: [] },
|
columns: { add: ["bio"], drop: [], change: [] },
|
||||||
indices: { add: [], drop: [] }
|
indices: { add: [], drop: [] },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: postsTable,
|
name: postsTable,
|
||||||
@@ -200,10 +200,10 @@ describe("SchemaManager tests", async () => {
|
|||||||
columns: {
|
columns: {
|
||||||
add: ["id", "title", "content", "created_at"],
|
add: ["id", "title", "content", "created_at"],
|
||||||
drop: [],
|
drop: [],
|
||||||
change: []
|
change: [],
|
||||||
|
},
|
||||||
|
indices: { add: [], drop: [] },
|
||||||
},
|
},
|
||||||
indices: { add: [], drop: [] }
|
|
||||||
}
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// now sync
|
// now sync
|
||||||
@@ -228,8 +228,8 @@ describe("SchemaManager tests", async () => {
|
|||||||
name: entity.name,
|
name: entity.name,
|
||||||
isNew: true,
|
isNew: true,
|
||||||
columns: { add: ["id", "email"], drop: [], change: [] },
|
columns: { add: ["id", "email"], drop: [], change: [] },
|
||||||
indices: { add: [index.name!], drop: [] }
|
indices: { add: [index.name!], drop: [] },
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// sync and then check again
|
// sync and then check again
|
||||||
@@ -256,8 +256,8 @@ describe("SchemaManager tests", async () => {
|
|||||||
name: entity.name,
|
name: entity.name,
|
||||||
isNew: false,
|
isNew: false,
|
||||||
columns: { add: [], drop: [], change: [] },
|
columns: { add: [], drop: [], change: [] },
|
||||||
indices: { add: [index.name!], drop: [] }
|
indices: { add: [index.name!], drop: [] },
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// sync and then check again
|
// sync and then check again
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
ManyToOneRelation,
|
ManyToOneRelation,
|
||||||
PolymorphicRelation,
|
PolymorphicRelation,
|
||||||
TextField,
|
TextField,
|
||||||
WithBuilder
|
WithBuilder,
|
||||||
} from "../../../src/data";
|
} from "../../../src/data";
|
||||||
import * as proto from "../../../src/data/prototype";
|
import * as proto from "../../../src/data/prototype";
|
||||||
import { compileQb, prettyPrintQb, schemaToEm } from "../../helper";
|
import { compileQb, prettyPrintQb, schemaToEm } from "../../helper";
|
||||||
@@ -21,12 +21,12 @@ describe("[data] WithBuilder", async () => {
|
|||||||
{
|
{
|
||||||
posts: proto.entity("posts", {}),
|
posts: proto.entity("posts", {}),
|
||||||
users: proto.entity("users", {}),
|
users: proto.entity("users", {}),
|
||||||
media: proto.entity("media", {})
|
media: proto.entity("media", {}),
|
||||||
},
|
},
|
||||||
({ relation }, { posts, users, media }) => {
|
({ relation }, { posts, users, media }) => {
|
||||||
relation(posts).manyToOne(users);
|
relation(posts).manyToOne(users);
|
||||||
relation(users).polyToOne(media, { mappedBy: "avatar" });
|
relation(users).polyToOne(media, { mappedBy: "avatar" });
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
const em = schemaToEm(schema);
|
const em = schemaToEm(schema);
|
||||||
|
|
||||||
@@ -36,17 +36,17 @@ describe("[data] WithBuilder", async () => {
|
|||||||
expect(
|
expect(
|
||||||
WithBuilder.validateWiths(em, "posts", {
|
WithBuilder.validateWiths(em, "posts", {
|
||||||
users: {
|
users: {
|
||||||
with: { avatar: {} }
|
with: { avatar: {} },
|
||||||
}
|
},
|
||||||
})
|
}),
|
||||||
).toBe(2);
|
).toBe(2);
|
||||||
expect(() => WithBuilder.validateWiths(em, "posts", { author: {} })).toThrow();
|
expect(() => WithBuilder.validateWiths(em, "posts", { author: {} })).toThrow();
|
||||||
expect(() =>
|
expect(() =>
|
||||||
WithBuilder.validateWiths(em, "posts", {
|
WithBuilder.validateWiths(em, "posts", {
|
||||||
users: {
|
users: {
|
||||||
with: { glibberish: {} }
|
with: { glibberish: {} },
|
||||||
}
|
},
|
||||||
})
|
}),
|
||||||
).toThrow();
|
).toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -56,8 +56,8 @@ describe("[data] WithBuilder", async () => {
|
|||||||
|
|
||||||
expect(() =>
|
expect(() =>
|
||||||
WithBuilder.addClause(em, em.connection.kysely.selectFrom("users"), users, {
|
WithBuilder.addClause(em, em.connection.kysely.selectFrom("users"), users, {
|
||||||
posts: {}
|
posts: {},
|
||||||
})
|
}),
|
||||||
).toThrow('Relation "users<>posts" not found');
|
).toThrow('Relation "users<>posts" not found');
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -68,13 +68,13 @@ describe("[data] WithBuilder", async () => {
|
|||||||
const em = new EntityManager([users, posts], dummyConnection, relations);
|
const em = new EntityManager([users, posts], dummyConnection, relations);
|
||||||
|
|
||||||
const qb = WithBuilder.addClause(em, em.connection.kysely.selectFrom("users"), users, {
|
const qb = WithBuilder.addClause(em, em.connection.kysely.selectFrom("users"), users, {
|
||||||
posts: {}
|
posts: {},
|
||||||
});
|
});
|
||||||
|
|
||||||
const res = qb.compile();
|
const res = qb.compile();
|
||||||
|
|
||||||
expect(res.sql).toBe(
|
expect(res.sql).toBe(
|
||||||
'select (select coalesce(json_group_array(json_object(\'id\', "agg"."id", \'content\', "agg"."content", \'author_id\', "agg"."author_id")), \'[]\') from (select "posts"."id" as "id", "posts"."content" as "content", "posts"."author_id" as "author_id" from "posts" as "posts" where "posts"."author_id" = "users"."id" order by "posts"."id" asc limit ? offset ?) as agg) as "posts" from "users"'
|
'select (select coalesce(json_group_array(json_object(\'id\', "agg"."id", \'content\', "agg"."content", \'author_id\', "agg"."author_id")), \'[]\') from (select "posts"."id" as "id", "posts"."content" as "content", "posts"."author_id" as "author_id" from "posts" as "posts" where "posts"."author_id" = "users"."id" order by "posts"."id" asc limit ? offset ?) as agg) as "posts" from "users"',
|
||||||
);
|
);
|
||||||
expect(res.parameters).toEqual([10, 0]);
|
expect(res.parameters).toEqual([10, 0]);
|
||||||
|
|
||||||
@@ -83,14 +83,14 @@ describe("[data] WithBuilder", async () => {
|
|||||||
em.connection.kysely.selectFrom("posts"),
|
em.connection.kysely.selectFrom("posts"),
|
||||||
posts, // @todo: try with "users", it gives output!
|
posts, // @todo: try with "users", it gives output!
|
||||||
{
|
{
|
||||||
author: {}
|
author: {},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const res2 = qb2.compile();
|
const res2 = qb2.compile();
|
||||||
|
|
||||||
expect(res2.sql).toBe(
|
expect(res2.sql).toBe(
|
||||||
'select (select json_object(\'id\', "obj"."id", \'username\', "obj"."username") from (select "users"."id" as "id", "users"."username" as "username" from "users" as "author" where "author"."id" = "posts"."author_id" order by "users"."id" asc limit ? offset ?) as obj) as "author" from "posts"'
|
'select (select json_object(\'id\', "obj"."id", \'username\', "obj"."username") from (select "users"."id" as "id", "users"."username" as "username" from "users" as "author" where "author"."id" = "posts"."author_id" order by "users"."id" asc limit ? offset ?) as obj) as "author" from "posts"',
|
||||||
);
|
);
|
||||||
expect(res2.parameters).toEqual([1, 0]);
|
expect(res2.parameters).toEqual([1, 0]);
|
||||||
});
|
});
|
||||||
@@ -124,7 +124,7 @@ describe("[data] WithBuilder", async () => {
|
|||||||
.values([
|
.values([
|
||||||
{ posts_id: 1, categories_id: 1 },
|
{ posts_id: 1, categories_id: 1 },
|
||||||
{ posts_id: 2, categories_id: 2 },
|
{ posts_id: 2, categories_id: 2 },
|
||||||
{ posts_id: 1, categories_id: 2 }
|
{ posts_id: 1, categories_id: 2 },
|
||||||
])
|
])
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
@@ -138,14 +138,14 @@ describe("[data] WithBuilder", async () => {
|
|||||||
title: "fashion post",
|
title: "fashion post",
|
||||||
categories: [
|
categories: [
|
||||||
{ id: 1, label: "fashion" },
|
{ id: 1, label: "fashion" },
|
||||||
{ id: 2, label: "beauty" }
|
{ id: 2, label: "beauty" },
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
title: "beauty post",
|
title: "beauty post",
|
||||||
categories: [{ id: 2, label: "beauty" }]
|
categories: [{ id: 2, label: "beauty" }],
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const res2 = await em.repository(categories).findMany({ with: { posts: {} } });
|
const res2 = await em.repository(categories).findMany({ with: { posts: {} } });
|
||||||
@@ -156,21 +156,21 @@ describe("[data] WithBuilder", async () => {
|
|||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
label: "fashion",
|
label: "fashion",
|
||||||
posts: [{ id: 1, title: "fashion post" }]
|
posts: [{ id: 1, title: "fashion post" }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
label: "beauty",
|
label: "beauty",
|
||||||
posts: [
|
posts: [
|
||||||
{ id: 1, title: "fashion post" },
|
{ id: 1, title: "fashion post" },
|
||||||
{ id: 2, title: "beauty post" }
|
{ id: 2, title: "beauty post" },
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
label: "tech",
|
label: "tech",
|
||||||
posts: []
|
posts: [],
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -181,7 +181,7 @@ describe("[data] WithBuilder", async () => {
|
|||||||
const entities = [media, categories];
|
const entities = [media, categories];
|
||||||
const single = new PolymorphicRelation(categories, media, {
|
const single = new PolymorphicRelation(categories, media, {
|
||||||
mappedBy: "single",
|
mappedBy: "single",
|
||||||
targetCardinality: 1
|
targetCardinality: 1,
|
||||||
});
|
});
|
||||||
const multiple = new PolymorphicRelation(categories, media, { mappedBy: "multiple" });
|
const multiple = new PolymorphicRelation(categories, media, { mappedBy: "multiple" });
|
||||||
|
|
||||||
@@ -191,11 +191,11 @@ describe("[data] WithBuilder", async () => {
|
|||||||
em,
|
em,
|
||||||
em.connection.kysely.selectFrom("categories"),
|
em.connection.kysely.selectFrom("categories"),
|
||||||
categories,
|
categories,
|
||||||
{ single: {} }
|
{ single: {} },
|
||||||
);
|
);
|
||||||
const res = qb.compile();
|
const res = qb.compile();
|
||||||
expect(res.sql).toBe(
|
expect(res.sql).toBe(
|
||||||
'select (select json_object(\'id\', "obj"."id", \'path\', "obj"."path") from (select "media"."id" as "id", "media"."path" as "path" from "media" where "media"."reference" = ? and "categories"."id" = "media"."entity_id" order by "media"."id" asc limit ? offset ?) as obj) as "single" from "categories"'
|
'select (select json_object(\'id\', "obj"."id", \'path\', "obj"."path") from (select "media"."id" as "id", "media"."path" as "path" from "media" where "media"."reference" = ? and "categories"."id" = "media"."entity_id" order by "media"."id" asc limit ? offset ?) as obj) as "single" from "categories"',
|
||||||
);
|
);
|
||||||
expect(res.parameters).toEqual(["categories.single", 1, 0]);
|
expect(res.parameters).toEqual(["categories.single", 1, 0]);
|
||||||
|
|
||||||
@@ -203,11 +203,11 @@ describe("[data] WithBuilder", async () => {
|
|||||||
em,
|
em,
|
||||||
em.connection.kysely.selectFrom("categories"),
|
em.connection.kysely.selectFrom("categories"),
|
||||||
categories,
|
categories,
|
||||||
{ multiple: {} }
|
{ multiple: {} },
|
||||||
);
|
);
|
||||||
const res2 = qb2.compile();
|
const res2 = qb2.compile();
|
||||||
expect(res2.sql).toBe(
|
expect(res2.sql).toBe(
|
||||||
'select (select coalesce(json_group_array(json_object(\'id\', "agg"."id", \'path\', "agg"."path")), \'[]\') from (select "media"."id" as "id", "media"."path" as "path" from "media" where "media"."reference" = ? and "categories"."id" = "media"."entity_id" order by "media"."id" asc limit ? offset ?) as agg) as "multiple" from "categories"'
|
'select (select coalesce(json_group_array(json_object(\'id\', "agg"."id", \'path\', "agg"."path")), \'[]\') from (select "media"."id" as "id", "media"."path" as "path" from "media" where "media"."reference" = ? and "categories"."id" = "media"."entity_id" order by "media"."id" asc limit ? offset ?) as agg) as "multiple" from "categories"',
|
||||||
);
|
);
|
||||||
expect(res2.parameters).toEqual(["categories.multiple", 10, 0]);
|
expect(res2.parameters).toEqual(["categories.multiple", 10, 0]);
|
||||||
});
|
});
|
||||||
@@ -240,16 +240,16 @@ describe("[data] WithBuilder", async () => {
|
|||||||
{
|
{
|
||||||
posts: proto.entity("posts", {}),
|
posts: proto.entity("posts", {}),
|
||||||
users: proto.entity("users", {
|
users: proto.entity("users", {
|
||||||
username: proto.text()
|
username: proto.text(),
|
||||||
}),
|
}),
|
||||||
media: proto.entity("media", {
|
media: proto.entity("media", {
|
||||||
path: proto.text()
|
path: proto.text(),
|
||||||
})
|
}),
|
||||||
},
|
},
|
||||||
({ relation }, { posts, users, media }) => {
|
({ relation }, { posts, users, media }) => {
|
||||||
relation(posts).manyToOne(users);
|
relation(posts).manyToOne(users);
|
||||||
relation(users).polyToOne(media, { mappedBy: "avatar" });
|
relation(users).polyToOne(media, { mappedBy: "avatar" });
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
const em = schemaToEm(schema);
|
const em = schemaToEm(schema);
|
||||||
|
|
||||||
@@ -265,16 +265,16 @@ describe("[data] WithBuilder", async () => {
|
|||||||
with: {
|
with: {
|
||||||
avatar: {
|
avatar: {
|
||||||
select: ["id", "path"],
|
select: ["id", "path"],
|
||||||
limit: 2 // ignored
|
limit: 2, // ignored
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
//prettyPrintQb(qb);
|
//prettyPrintQb(qb);
|
||||||
expect(qb.compile().sql).toBe(
|
expect(qb.compile().sql).toBe(
|
||||||
'select (select json_object(\'id\', "obj"."id", \'username\', "obj"."username", \'avatar\', "obj"."avatar") from (select "users"."id" as "id", "users"."username" as "username", (select json_object(\'id\', "obj"."id", \'path\', "obj"."path") from (select "media"."id" as "id", "media"."path" as "path" from "media" where "media"."reference" = ? and "users"."id" = "media"."entity_id" order by "media"."id" asc limit ? offset ?) as obj) as "avatar" from "users" as "users" where "users"."id" = "posts"."users_id" order by "users"."username" asc limit ? offset ?) as obj) as "users" from "posts"'
|
'select (select json_object(\'id\', "obj"."id", \'username\', "obj"."username", \'avatar\', "obj"."avatar") from (select "users"."id" as "id", "users"."username" as "username", (select json_object(\'id\', "obj"."id", \'path\', "obj"."path") from (select "media"."id" as "id", "media"."path" as "path" from "media" where "media"."reference" = ? and "users"."id" = "media"."entity_id" order by "media"."id" asc limit ? offset ?) as obj) as "avatar" from "users" as "users" where "users"."id" = "posts"."users_id" order by "users"."username" asc limit ? offset ?) as obj) as "users" from "posts"',
|
||||||
);
|
);
|
||||||
expect(qb.compile().parameters).toEqual(["users.avatar", 1, 0, 1, 0]);
|
expect(qb.compile().parameters).toEqual(["users.avatar", 1, 0, 1, 0]);
|
||||||
});
|
});
|
||||||
@@ -285,17 +285,17 @@ describe("[data] WithBuilder", async () => {
|
|||||||
posts: proto.entity("posts", {}),
|
posts: proto.entity("posts", {}),
|
||||||
comments: proto.entity("comments", {}),
|
comments: proto.entity("comments", {}),
|
||||||
users: proto.entity("users", {
|
users: proto.entity("users", {
|
||||||
username: proto.text()
|
username: proto.text(),
|
||||||
}),
|
}),
|
||||||
media: proto.entity("media", {
|
media: proto.entity("media", {
|
||||||
path: proto.text()
|
path: proto.text(),
|
||||||
})
|
}),
|
||||||
},
|
},
|
||||||
({ relation }, { posts, comments, users, media }) => {
|
({ relation }, { posts, comments, users, media }) => {
|
||||||
relation(posts).manyToOne(users).polyToOne(media, { mappedBy: "images" });
|
relation(posts).manyToOne(users).polyToOne(media, { mappedBy: "images" });
|
||||||
relation(users).polyToOne(media, { mappedBy: "avatar" });
|
relation(users).polyToOne(media, { mappedBy: "avatar" });
|
||||||
relation(comments).manyToOne(posts).manyToOne(users);
|
relation(comments).manyToOne(posts).manyToOne(users);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
const em = schemaToEm(schema);
|
const em = schemaToEm(schema);
|
||||||
|
|
||||||
@@ -308,15 +308,15 @@ describe("[data] WithBuilder", async () => {
|
|||||||
limit: 12,
|
limit: 12,
|
||||||
with: {
|
with: {
|
||||||
users: {
|
users: {
|
||||||
select: ["username"]
|
select: ["username"],
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(qb.compile().sql).toBe(
|
expect(qb.compile().sql).toBe(
|
||||||
'select (select coalesce(json_group_array(json_object(\'id\', "agg"."id", \'posts_id\', "agg"."posts_id", \'users_id\', "agg"."users_id", \'users\', "agg"."users")), \'[]\') from (select "comments"."id" as "id", "comments"."posts_id" as "posts_id", "comments"."users_id" as "users_id", (select json_object(\'username\', "obj"."username") from (select "users"."username" as "username" from "users" as "users" where "users"."id" = "comments"."users_id" order by "users"."id" asc limit ? offset ?) as obj) as "users" from "comments" as "comments" where "comments"."posts_id" = "posts"."id" order by "comments"."id" asc limit ? offset ?) as agg) as "comments" from "posts"'
|
'select (select coalesce(json_group_array(json_object(\'id\', "agg"."id", \'posts_id\', "agg"."posts_id", \'users_id\', "agg"."users_id", \'users\', "agg"."users")), \'[]\') from (select "comments"."id" as "id", "comments"."posts_id" as "posts_id", "comments"."users_id" as "users_id", (select json_object(\'username\', "obj"."username") from (select "users"."username" as "username" from "users" as "users" where "users"."id" = "comments"."users_id" order by "users"."id" asc limit ? offset ?) as obj) as "users" from "comments" as "comments" where "comments"."posts_id" = "posts"."id" order by "comments"."id" asc limit ? offset ?) as agg) as "comments" from "posts"',
|
||||||
);
|
);
|
||||||
expect(qb.compile().parameters).toEqual([1, 0, 12, 0]);
|
expect(qb.compile().parameters).toEqual([1, 0, 12, 0]);
|
||||||
});
|
});
|
||||||
@@ -325,23 +325,23 @@ describe("[data] WithBuilder", async () => {
|
|||||||
const schema = proto.em(
|
const schema = proto.em(
|
||||||
{
|
{
|
||||||
posts: proto.entity("posts", {
|
posts: proto.entity("posts", {
|
||||||
title: proto.text()
|
title: proto.text(),
|
||||||
}),
|
}),
|
||||||
comments: proto.entity("comments", {
|
comments: proto.entity("comments", {
|
||||||
content: proto.text()
|
content: proto.text(),
|
||||||
}),
|
}),
|
||||||
users: proto.entity("users", {
|
users: proto.entity("users", {
|
||||||
username: proto.text()
|
username: proto.text(),
|
||||||
}),
|
}),
|
||||||
media: proto.entity("media", {
|
media: proto.entity("media", {
|
||||||
path: proto.text()
|
path: proto.text(),
|
||||||
})
|
}),
|
||||||
},
|
},
|
||||||
({ relation }, { posts, comments, users, media }) => {
|
({ relation }, { posts, comments, users, media }) => {
|
||||||
relation(posts).manyToOne(users).polyToOne(media, { mappedBy: "images" });
|
relation(posts).manyToOne(users).polyToOne(media, { mappedBy: "images" });
|
||||||
relation(users).polyToOne(media, { mappedBy: "avatar" });
|
relation(users).polyToOne(media, { mappedBy: "avatar" });
|
||||||
relation(comments).manyToOne(posts).manyToOne(users);
|
relation(comments).manyToOne(posts).manyToOne(users);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
const em = schemaToEm(schema);
|
const em = schemaToEm(schema);
|
||||||
await em.schema().sync({ force: true });
|
await em.schema().sync({ force: true });
|
||||||
@@ -351,7 +351,7 @@ describe("[data] WithBuilder", async () => {
|
|||||||
await em.mutator("posts").insertMany([
|
await em.mutator("posts").insertMany([
|
||||||
{ title: "post1", users_id: 1 },
|
{ title: "post1", users_id: 1 },
|
||||||
{ title: "post2", users_id: 1 },
|
{ title: "post2", users_id: 1 },
|
||||||
{ title: "post3", users_id: 2 }
|
{ title: "post3", users_id: 2 },
|
||||||
]);
|
]);
|
||||||
await em.mutator("comments").insertMany([
|
await em.mutator("comments").insertMany([
|
||||||
{ content: "comment1", posts_id: 1, users_id: 1 },
|
{ content: "comment1", posts_id: 1, users_id: 1 },
|
||||||
@@ -360,7 +360,7 @@ describe("[data] WithBuilder", async () => {
|
|||||||
{ content: "comment3", posts_id: 2, users_id: 1 },
|
{ content: "comment3", posts_id: 2, users_id: 1 },
|
||||||
{ content: "comment4", posts_id: 2, users_id: 2 },
|
{ content: "comment4", posts_id: 2, users_id: 2 },
|
||||||
{ content: "comment5", posts_id: 3, users_id: 1 },
|
{ content: "comment5", posts_id: 3, users_id: 1 },
|
||||||
{ content: "comment6", posts_id: 3, users_id: 2 }
|
{ content: "comment6", posts_id: 3, users_id: 2 },
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const result = await em.repo("posts").findMany({
|
const result = await em.repo("posts").findMany({
|
||||||
@@ -371,11 +371,11 @@ describe("[data] WithBuilder", async () => {
|
|||||||
select: ["content"],
|
select: ["content"],
|
||||||
with: {
|
with: {
|
||||||
users: {
|
users: {
|
||||||
select: ["username"]
|
select: ["username"],
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(result.data).toEqual([
|
expect(result.data).toEqual([
|
||||||
@@ -385,16 +385,16 @@ describe("[data] WithBuilder", async () => {
|
|||||||
{
|
{
|
||||||
content: "comment1",
|
content: "comment1",
|
||||||
users: {
|
users: {
|
||||||
username: "user1"
|
username: "user1",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
content: "comment1-1",
|
content: "comment1-1",
|
||||||
users: {
|
users: {
|
||||||
username: "user1"
|
username: "user1",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "post2",
|
title: "post2",
|
||||||
@@ -402,16 +402,16 @@ describe("[data] WithBuilder", async () => {
|
|||||||
{
|
{
|
||||||
content: "comment3",
|
content: "comment3",
|
||||||
users: {
|
users: {
|
||||||
username: "user1"
|
username: "user1",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
content: "comment4",
|
content: "comment4",
|
||||||
users: {
|
users: {
|
||||||
username: "user2"
|
username: "user2",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "post3",
|
title: "post3",
|
||||||
@@ -419,17 +419,17 @@ describe("[data] WithBuilder", async () => {
|
|||||||
{
|
{
|
||||||
content: "comment5",
|
content: "comment5",
|
||||||
users: {
|
users: {
|
||||||
username: "user1"
|
username: "user1",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
content: "comment6",
|
content: "comment6",
|
||||||
users: {
|
users: {
|
||||||
username: "user2"
|
username: "user2",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
//console.log(_jsonp(result.data));
|
//console.log(_jsonp(result.data));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ describe("Connection", async () => {
|
|||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
name: "name",
|
name: "name",
|
||||||
order: 0
|
order: 0,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -54,14 +54,14 @@ describe("Connection", async () => {
|
|||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
name: "name",
|
name: "name",
|
||||||
order: 0
|
order: 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "desc",
|
name: "desc",
|
||||||
order: 1
|
order: 1,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -83,10 +83,10 @@ describe("Connection", async () => {
|
|||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
name: "name",
|
name: "name",
|
||||||
order: 0
|
order: 0,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ describe("[data] EnumField", async () => {
|
|||||||
runBaseFieldTests(
|
runBaseFieldTests(
|
||||||
EnumField,
|
EnumField,
|
||||||
{ defaultValue: "a", schemaType: "text" },
|
{ defaultValue: "a", schemaType: "text" },
|
||||||
{ options: options(["a", "b", "c"]) }
|
{ options: options(["a", "b", "c"]) },
|
||||||
);
|
);
|
||||||
|
|
||||||
test("yields if default value is not a valid option", async () => {
|
test("yields if default value is not a valid option", async () => {
|
||||||
expect(
|
expect(
|
||||||
() => new EnumField("test", { options: options(["a", "b"]), default_value: "c" })
|
() => new EnumField("test", { options: options(["a", "b"]), default_value: "c" }),
|
||||||
).toThrow();
|
).toThrow();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ describe("[data] EnumField", async () => {
|
|||||||
const field = new EnumField("test", {
|
const field = new EnumField("test", {
|
||||||
options: options(["a", "b", "c"]),
|
options: options(["a", "b", "c"]),
|
||||||
default_value: "a",
|
default_value: "a",
|
||||||
required: true
|
required: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(field.transformRetrieve(null)).toBe("a");
|
expect(field.transformRetrieve(null)).toBe("a");
|
||||||
|
|||||||
@@ -24,20 +24,20 @@ describe("[data] Field", async () => {
|
|||||||
const required = new FieldSpec("test", { required: true });
|
const required = new FieldSpec("test", { required: true });
|
||||||
const requiredDefault = new FieldSpec("test", {
|
const requiredDefault = new FieldSpec("test", {
|
||||||
required: true,
|
required: true,
|
||||||
default_value: "test"
|
default_value: "test",
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(required.transformPersist(null, undefined as any, undefined as any)).rejects.toThrow();
|
expect(required.transformPersist(null, undefined as any, undefined as any)).rejects.toThrow();
|
||||||
expect(
|
expect(
|
||||||
required.transformPersist(undefined, undefined as any, undefined as any)
|
required.transformPersist(undefined, undefined as any, undefined as any),
|
||||||
).rejects.toThrow();
|
).rejects.toThrow();
|
||||||
|
|
||||||
// works because it has a default value
|
// works because it has a default value
|
||||||
expect(
|
expect(
|
||||||
requiredDefault.transformPersist(null, undefined as any, undefined as any)
|
requiredDefault.transformPersist(null, undefined as any, undefined as any),
|
||||||
).resolves.toBeDefined();
|
).resolves.toBeDefined();
|
||||||
expect(
|
expect(
|
||||||
requiredDefault.transformPersist(undefined, undefined as any, undefined as any)
|
requiredDefault.transformPersist(undefined, undefined as any, undefined as any),
|
||||||
).resolves.toBeDefined();
|
).resolves.toBeDefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
EntityIndex,
|
EntityIndex,
|
||||||
type EntityManager,
|
type EntityManager,
|
||||||
Field,
|
Field,
|
||||||
type SchemaResponse
|
type SchemaResponse,
|
||||||
} from "../../../../src/data";
|
} from "../../../../src/data";
|
||||||
|
|
||||||
class TestField extends Field {
|
class TestField extends Field {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ describe("[data] JsonField", async () => {
|
|||||||
runBaseFieldTests(JsonField, {
|
runBaseFieldTests(JsonField, {
|
||||||
defaultValue: { a: 1 },
|
defaultValue: { a: 1 },
|
||||||
sampleValues: ["string", { test: 1 }, 1],
|
sampleValues: ["string", { test: 1 }, 1],
|
||||||
schemaType: "text"
|
schemaType: "text",
|
||||||
});
|
});
|
||||||
|
|
||||||
test("transformPersist (no config)", async () => {
|
test("transformPersist (no config)", async () => {
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export function transformPersist(field: Field, value: any, context?: TActionCont
|
|||||||
export function runBaseFieldTests(
|
export function runBaseFieldTests(
|
||||||
fieldClass: ConstructableField,
|
fieldClass: ConstructableField,
|
||||||
config: FieldTestConfig,
|
config: FieldTestConfig,
|
||||||
_requiredConfig: any = {}
|
_requiredConfig: any = {},
|
||||||
) {
|
) {
|
||||||
const noConfigField = new fieldClass("no_config", _requiredConfig);
|
const noConfigField = new fieldClass("no_config", _requiredConfig);
|
||||||
const fillable = new fieldClass("fillable", { ..._requiredConfig, fillable: true });
|
const fillable = new fieldClass("fillable", { ..._requiredConfig, fillable: true });
|
||||||
@@ -29,7 +29,7 @@ export function runBaseFieldTests(
|
|||||||
..._requiredConfig,
|
..._requiredConfig,
|
||||||
fillable: true,
|
fillable: true,
|
||||||
required: true,
|
required: true,
|
||||||
default_value: config.defaultValue
|
default_value: config.defaultValue,
|
||||||
});
|
});
|
||||||
|
|
||||||
test("schema", () => {
|
test("schema", () => {
|
||||||
@@ -37,7 +37,7 @@ export function runBaseFieldTests(
|
|||||||
expect(noConfigField.schema(null as any)).toEqual([
|
expect(noConfigField.schema(null as any)).toEqual([
|
||||||
"no_config",
|
"no_config",
|
||||||
config.schemaType,
|
config.schemaType,
|
||||||
expect.any(Function)
|
expect.any(Function),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -96,7 +96,7 @@ export function runBaseFieldTests(
|
|||||||
//order: 1,
|
//order: 1,
|
||||||
fillable: true,
|
fillable: true,
|
||||||
required: false,
|
required: false,
|
||||||
hidden: false
|
hidden: false,
|
||||||
//virtual: false,
|
//virtual: false,
|
||||||
//default_value: undefined
|
//default_value: undefined
|
||||||
};
|
};
|
||||||
@@ -105,20 +105,20 @@ export function runBaseFieldTests(
|
|||||||
const json = field.toJSON();
|
const json = field.toJSON();
|
||||||
return {
|
return {
|
||||||
...json,
|
...json,
|
||||||
config: omit(json.config, ["html"])
|
config: omit(json.config, ["html"]),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(fieldJson(noConfigField)).toEqual({
|
expect(fieldJson(noConfigField)).toEqual({
|
||||||
//name: "no_config",
|
//name: "no_config",
|
||||||
type: noConfigField.type,
|
type: noConfigField.type,
|
||||||
config: _config
|
config: _config,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(fieldJson(fillable)).toEqual({
|
expect(fieldJson(fillable)).toEqual({
|
||||||
//name: "fillable",
|
//name: "fillable",
|
||||||
type: noConfigField.type,
|
type: noConfigField.type,
|
||||||
config: _config
|
config: _config,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(fieldJson(required)).toEqual({
|
expect(fieldJson(required)).toEqual({
|
||||||
@@ -126,8 +126,8 @@ export function runBaseFieldTests(
|
|||||||
type: required.type,
|
type: required.type,
|
||||||
config: {
|
config: {
|
||||||
..._config,
|
..._config,
|
||||||
required: true
|
required: true,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(fieldJson(hidden)).toEqual({
|
expect(fieldJson(hidden)).toEqual({
|
||||||
@@ -135,8 +135,8 @@ export function runBaseFieldTests(
|
|||||||
type: required.type,
|
type: required.type,
|
||||||
config: {
|
config: {
|
||||||
..._config,
|
..._config,
|
||||||
hidden: true
|
hidden: true,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(fieldJson(dflt)).toEqual({
|
expect(fieldJson(dflt)).toEqual({
|
||||||
@@ -144,8 +144,8 @@ export function runBaseFieldTests(
|
|||||||
type: dflt.type,
|
type: dflt.type,
|
||||||
config: {
|
config: {
|
||||||
..._config,
|
..._config,
|
||||||
default_value: config.defaultValue
|
default_value: config.defaultValue,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(fieldJson(requiredAndDefault)).toEqual({
|
expect(fieldJson(requiredAndDefault)).toEqual({
|
||||||
@@ -155,8 +155,8 @@ export function runBaseFieldTests(
|
|||||||
..._config,
|
..._config,
|
||||||
fillable: true,
|
fillable: true,
|
||||||
required: true,
|
required: true,
|
||||||
default_value: config.defaultValue
|
default_value: config.defaultValue,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
type BaseRelationConfig,
|
type BaseRelationConfig,
|
||||||
EntityRelation,
|
EntityRelation,
|
||||||
EntityRelationAnchor,
|
EntityRelationAnchor,
|
||||||
RelationTypes
|
RelationTypes,
|
||||||
} from "../../../../src/data/relations";
|
} from "../../../../src/data/relations";
|
||||||
|
|
||||||
class TestEntityRelation extends EntityRelation {
|
class TestEntityRelation extends EntityRelation {
|
||||||
@@ -12,7 +12,7 @@ class TestEntityRelation extends EntityRelation {
|
|||||||
super(
|
super(
|
||||||
new EntityRelationAnchor(new Entity("source"), "source"),
|
new EntityRelationAnchor(new Entity("source"), "source"),
|
||||||
new EntityRelationAnchor(new Entity("target"), "target"),
|
new EntityRelationAnchor(new Entity("target"), "target"),
|
||||||
config
|
config,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
initialize(em: EntityManager<any>) {}
|
initialize(em: EntityManager<any>) {}
|
||||||
|
|||||||
@@ -30,14 +30,14 @@ beforeAll(() =>
|
|||||||
method: init?.method ?? "GET",
|
method: init?.method ?? "GET",
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
headers: Object.fromEntries(init?.headers?.entries() ?? []),
|
headers: Object.fromEntries(init?.headers?.entries() ?? []),
|
||||||
body: init?.body
|
body: init?.body,
|
||||||
};
|
};
|
||||||
|
|
||||||
return new Response(JSON.stringify({ todos: [1, 2], request }), {
|
return new Response(JSON.stringify({ todos: [1, 2], request }), {
|
||||||
status: 200,
|
status: 200,
|
||||||
headers: { "Content-Type": "application/json" }
|
headers: { "Content-Type": "application/json" },
|
||||||
});
|
});
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
afterAll(unmockFetch);
|
afterAll(unmockFetch);
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ describe("FetchTask", async () => {
|
|||||||
const task = new FetchTask("Fetch Something", {
|
const task = new FetchTask("Fetch Something", {
|
||||||
url: "https://jsonplaceholder.typicode.com/todos/1",
|
url: "https://jsonplaceholder.typicode.com/todos/1",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: [{ key: "Content-Type", value: "application/json" }]
|
headers: [{ key: "Content-Type", value: "application/json" }],
|
||||||
});
|
});
|
||||||
|
|
||||||
const result = await task.run();
|
const result = await task.run();
|
||||||
@@ -62,18 +62,18 @@ describe("FetchTask", async () => {
|
|||||||
|
|
||||||
expect(
|
expect(
|
||||||
// // @ts-expect-error
|
// // @ts-expect-error
|
||||||
() => new FetchTask("", { url: "https://jsonplaceholder.typicode.com", method: 1 })
|
() => new FetchTask("", { url: "https://jsonplaceholder.typicode.com", method: 1 }),
|
||||||
).toThrow();
|
).toThrow();
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
new FetchTask("", {
|
new FetchTask("", {
|
||||||
url: "https://jsonplaceholder.typicode.com",
|
url: "https://jsonplaceholder.typicode.com",
|
||||||
method: "invalid"
|
method: "invalid",
|
||||||
}).execute()
|
}).execute(),
|
||||||
).rejects.toThrow(/^Invalid method/);
|
).rejects.toThrow(/^Invalid method/);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
() => new FetchTask("", { url: "https://jsonplaceholder.typicode.com", method: "GET" })
|
() => new FetchTask("", { url: "https://jsonplaceholder.typicode.com", method: "GET" }),
|
||||||
).toBeDefined();
|
).toBeDefined();
|
||||||
|
|
||||||
expect(() => new FetchTask("", { url: "", method: "Invalid" })).toThrow();
|
expect(() => new FetchTask("", { url: "", method: "Invalid" })).toThrow();
|
||||||
@@ -85,17 +85,17 @@ describe("FetchTask", async () => {
|
|||||||
method: "{{ flow.output.method }}",
|
method: "{{ flow.output.method }}",
|
||||||
headers: [
|
headers: [
|
||||||
{ key: "Content-{{ flow.output.headerKey }}", value: "application/json" },
|
{ key: "Content-{{ flow.output.headerKey }}", value: "application/json" },
|
||||||
{ key: "Authorization", value: "Bearer {{ flow.output.apiKey }}" }
|
{ key: "Authorization", value: "Bearer {{ flow.output.apiKey }}" },
|
||||||
],
|
],
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
email: "{{ flow.output.email }}"
|
email: "{{ flow.output.email }}",
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
const inputs = {
|
const inputs = {
|
||||||
headerKey: "Type",
|
headerKey: "Type",
|
||||||
apiKey: 123,
|
apiKey: 123,
|
||||||
email: "what@else.com",
|
email: "what@else.com",
|
||||||
method: "PATCH"
|
method: "PATCH",
|
||||||
};
|
};
|
||||||
|
|
||||||
const flow = new Flow("", [task]);
|
const flow = new Flow("", [task]);
|
||||||
|
|||||||
@@ -4,16 +4,16 @@ import { Flow, LogTask, RenderTask, SubFlowTask } from "../../src/flows";
|
|||||||
describe("SubFlowTask", async () => {
|
describe("SubFlowTask", async () => {
|
||||||
test("Simple Subflow", async () => {
|
test("Simple Subflow", async () => {
|
||||||
const subTask = new RenderTask("render", {
|
const subTask = new RenderTask("render", {
|
||||||
render: "subflow"
|
render: "subflow",
|
||||||
});
|
});
|
||||||
const subflow = new Flow("subflow", [subTask]);
|
const subflow = new Flow("subflow", [subTask]);
|
||||||
|
|
||||||
const task = new LogTask("log");
|
const task = new LogTask("log");
|
||||||
const task2 = new SubFlowTask("sub", {
|
const task2 = new SubFlowTask("sub", {
|
||||||
flow: subflow
|
flow: subflow,
|
||||||
});
|
});
|
||||||
const task3 = new RenderTask("render2", {
|
const task3 = new RenderTask("render2", {
|
||||||
render: "Subflow output: {{ sub.output }}"
|
render: "Subflow output: {{ sub.output }}",
|
||||||
});
|
});
|
||||||
|
|
||||||
const flow = new Flow("test", [task, task2, task3], []);
|
const flow = new Flow("test", [task, task2, task3], []);
|
||||||
@@ -30,7 +30,7 @@ describe("SubFlowTask", async () => {
|
|||||||
|
|
||||||
test("Simple loop", async () => {
|
test("Simple loop", async () => {
|
||||||
const subTask = new RenderTask("render", {
|
const subTask = new RenderTask("render", {
|
||||||
render: "run {{ flow.output }}"
|
render: "run {{ flow.output }}",
|
||||||
});
|
});
|
||||||
const subflow = new Flow("subflow", [subTask]);
|
const subflow = new Flow("subflow", [subTask]);
|
||||||
|
|
||||||
@@ -38,10 +38,10 @@ describe("SubFlowTask", async () => {
|
|||||||
const task2 = new SubFlowTask("sub", {
|
const task2 = new SubFlowTask("sub", {
|
||||||
flow: subflow,
|
flow: subflow,
|
||||||
loop: true,
|
loop: true,
|
||||||
input: [1, 2, 3]
|
input: [1, 2, 3],
|
||||||
});
|
});
|
||||||
const task3 = new RenderTask("render2", {
|
const task3 = new RenderTask("render2", {
|
||||||
render: `Subflow output: {{ sub.output | join: ", " }}`
|
render: `Subflow output: {{ sub.output | join: ", " }}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
const flow = new Flow("test", [task, task2, task3], []);
|
const flow = new Flow("test", [task, task2, task3], []);
|
||||||
@@ -61,7 +61,7 @@ describe("SubFlowTask", async () => {
|
|||||||
|
|
||||||
test("Simple loop from flow input", async () => {
|
test("Simple loop from flow input", async () => {
|
||||||
const subTask = new RenderTask("render", {
|
const subTask = new RenderTask("render", {
|
||||||
render: "run {{ flow.output }}"
|
render: "run {{ flow.output }}",
|
||||||
});
|
});
|
||||||
|
|
||||||
const subflow = new Flow("subflow", [subTask]);
|
const subflow = new Flow("subflow", [subTask]);
|
||||||
@@ -70,10 +70,10 @@ describe("SubFlowTask", async () => {
|
|||||||
const task2 = new SubFlowTask("sub", {
|
const task2 = new SubFlowTask("sub", {
|
||||||
flow: subflow,
|
flow: subflow,
|
||||||
loop: true,
|
loop: true,
|
||||||
input: "{{ flow.output | json }}"
|
input: "{{ flow.output | json }}",
|
||||||
});
|
});
|
||||||
const task3 = new RenderTask("render2", {
|
const task3 = new RenderTask("render2", {
|
||||||
render: `Subflow output: {{ sub.output | join: ", " }}`
|
render: `Subflow output: {{ sub.output | join: ", " }}`,
|
||||||
});
|
});
|
||||||
|
|
||||||
const flow = new Flow("test", [task, task2, task3], []);
|
const flow = new Flow("test", [task, task2, task3], []);
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ describe("Task", async () => {
|
|||||||
const result = await Task.resolveParams(
|
const result = await Task.resolveParams(
|
||||||
Type.Object({ test: dynamic(Type.Number()) }),
|
Type.Object({ test: dynamic(Type.Number()) }),
|
||||||
{
|
{
|
||||||
test: "{{ some.path }}"
|
test: "{{ some.path }}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
some: {
|
some: {
|
||||||
path: 1
|
path: 1,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result.test).toBe(1);
|
expect(result.test).toBe(1);
|
||||||
@@ -24,13 +24,13 @@ describe("Task", async () => {
|
|||||||
const result = await Task.resolveParams(
|
const result = await Task.resolveParams(
|
||||||
Type.Object({ test: Type.String() }),
|
Type.Object({ test: Type.String() }),
|
||||||
{
|
{
|
||||||
test: "{{ some.path }}"
|
test: "{{ some.path }}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
some: {
|
some: {
|
||||||
path: "1/1"
|
path: "1/1",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result.test).toBe("1/1");
|
expect(result.test).toBe("1/1");
|
||||||
@@ -40,13 +40,13 @@ describe("Task", async () => {
|
|||||||
const result = await Task.resolveParams(
|
const result = await Task.resolveParams(
|
||||||
Type.Object({ test: dynamic(Type.Object({ key: Type.String(), value: Type.String() })) }),
|
Type.Object({ test: dynamic(Type.Object({ key: Type.String(), value: Type.String() })) }),
|
||||||
{
|
{
|
||||||
test: { key: "path", value: "{{ some.path }}" }
|
test: { key: "path", value: "{{ some.path }}" },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
some: {
|
some: {
|
||||||
path: "1/1"
|
path: "1/1",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result.test).toEqual({ key: "path", value: "1/1" });
|
expect(result.test).toEqual({ key: "path", value: "1/1" });
|
||||||
@@ -55,17 +55,17 @@ describe("Task", async () => {
|
|||||||
test("resolveParams: with json", async () => {
|
test("resolveParams: with json", async () => {
|
||||||
const result = await Task.resolveParams(
|
const result = await Task.resolveParams(
|
||||||
Type.Object({
|
Type.Object({
|
||||||
test: dynamic(Type.Object({ key: Type.String(), value: Type.String() }))
|
test: dynamic(Type.Object({ key: Type.String(), value: Type.String() })),
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
test: "{{ some | json }}"
|
test: "{{ some | json }}",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
some: {
|
some: {
|
||||||
key: "path",
|
key: "path",
|
||||||
value: "1/1"
|
value: "1/1",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result.test).toEqual({ key: "path", value: "1/1" });
|
expect(result.test).toEqual({ key: "path", value: "1/1" });
|
||||||
@@ -74,11 +74,11 @@ describe("Task", async () => {
|
|||||||
test("resolveParams: with array", async () => {
|
test("resolveParams: with array", async () => {
|
||||||
const result = await Task.resolveParams(
|
const result = await Task.resolveParams(
|
||||||
Type.Object({
|
Type.Object({
|
||||||
test: dynamic(Type.Array(Type.String()))
|
test: dynamic(Type.Array(Type.String())),
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
test: '{{ "1,2,3" | split: "," | json }}'
|
test: '{{ "1,2,3" | split: "," | json }}',
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result.test).toEqual(["1", "2", "3"]);
|
expect(result.test).toEqual(["1", "2", "3"]);
|
||||||
@@ -87,11 +87,11 @@ describe("Task", async () => {
|
|||||||
test("resolveParams: boolean", async () => {
|
test("resolveParams: boolean", async () => {
|
||||||
const result = await Task.resolveParams(
|
const result = await Task.resolveParams(
|
||||||
Type.Object({
|
Type.Object({
|
||||||
test: dynamic(Type.Boolean())
|
test: dynamic(Type.Boolean()),
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
test: "{{ true }}"
|
test: "{{ true }}",
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result.test).toEqual(true);
|
expect(result.test).toEqual(true);
|
||||||
@@ -100,11 +100,11 @@ describe("Task", async () => {
|
|||||||
test("resolveParams: float", async () => {
|
test("resolveParams: float", async () => {
|
||||||
const result = await Task.resolveParams(
|
const result = await Task.resolveParams(
|
||||||
Type.Object({
|
Type.Object({
|
||||||
test: dynamic(Type.Number(), Number.parseFloat)
|
test: dynamic(Type.Number(), Number.parseFloat),
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
test: "{{ 3.14 }}"
|
test: "{{ 3.14 }}",
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(result.test).toEqual(3.14);
|
expect(result.test).toEqual(3.14);
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ const first = getNamedTask(
|
|||||||
//throw new Error("Error");
|
//throw new Error("Error");
|
||||||
return {
|
return {
|
||||||
inner: {
|
inner: {
|
||||||
result: 2
|
result: 2,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
1000
|
1000,
|
||||||
);
|
);
|
||||||
const second = getNamedTask("second (if match)");
|
const second = getNamedTask("second (if match)");
|
||||||
const third = getNamedTask("third (if error)");
|
const third = getNamedTask("third (if error)");
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class ExecTask extends Task {
|
|||||||
constructor(
|
constructor(
|
||||||
name: string,
|
name: string,
|
||||||
params: any,
|
params: any,
|
||||||
private fn: () => any
|
private fn: () => any,
|
||||||
) {
|
) {
|
||||||
super(name, params);
|
super(name, params);
|
||||||
}
|
}
|
||||||
@@ -54,8 +54,8 @@ export function getNamedTask(name: string, _func?: () => Promise<any>, delay?: n
|
|||||||
return new ExecTask(
|
return new ExecTask(
|
||||||
name,
|
name,
|
||||||
{
|
{
|
||||||
delay
|
delay,
|
||||||
},
|
},
|
||||||
func
|
func,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ const first = new LogTask("First", { delay: 1000 });
|
|||||||
const second = new LogTask("Second", { delay: 1000 });
|
const second = new LogTask("Second", { delay: 1000 });
|
||||||
const third = new LogTask("Long Third", { delay: 2500 });
|
const third = new LogTask("Long Third", { delay: 2500 });
|
||||||
const fourth = new FetchTask("Fetch Something", {
|
const fourth = new FetchTask("Fetch Something", {
|
||||||
url: "https://jsonplaceholder.typicode.com/todos/1"
|
url: "https://jsonplaceholder.typicode.com/todos/1",
|
||||||
});
|
});
|
||||||
const fifth = new LogTask("Task 4", { delay: 500 }); // without connection
|
const fifth = new LogTask("Task 4", { delay: 500 }); // without connection
|
||||||
|
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ class OutputParamTask extends Task<typeof OutputParamTask.schema> {
|
|||||||
static override schema = Type.Object({
|
static override schema = Type.Object({
|
||||||
number: dynamic(
|
number: dynamic(
|
||||||
Type.Number({
|
Type.Number({
|
||||||
title: "Output number"
|
title: "Output number",
|
||||||
}),
|
}),
|
||||||
Number.parseInt
|
Number.parseInt,
|
||||||
)
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
async execute(inputs: InputsMap) {
|
async execute(inputs: InputsMap) {
|
||||||
@@ -75,7 +75,7 @@ describe("Flow task inputs", async () => {
|
|||||||
test("output/input", async () => {
|
test("output/input", async () => {
|
||||||
const task = new OutputParamTask("task1", { number: 111 });
|
const task = new OutputParamTask("task1", { number: 111 });
|
||||||
const task2 = new OutputParamTask("task2", {
|
const task2 = new OutputParamTask("task2", {
|
||||||
number: "{{ task1.output }}"
|
number: "{{ task1.output }}",
|
||||||
});
|
});
|
||||||
|
|
||||||
const flow = new Flow("test", [task, task2]);
|
const flow = new Flow("test", [task, task2]);
|
||||||
@@ -94,10 +94,10 @@ describe("Flow task inputs", async () => {
|
|||||||
|
|
||||||
test("input from flow", async () => {
|
test("input from flow", async () => {
|
||||||
const task = new OutputParamTask("task1", {
|
const task = new OutputParamTask("task1", {
|
||||||
number: "{{flow.output.someFancyParam}}"
|
number: "{{flow.output.someFancyParam}}",
|
||||||
});
|
});
|
||||||
const task2 = new OutputParamTask("task2", {
|
const task2 = new OutputParamTask("task2", {
|
||||||
number: "{{task1.output}}"
|
number: "{{task1.output}}",
|
||||||
});
|
});
|
||||||
|
|
||||||
const flow = new Flow("test", [task, task2]);
|
const flow = new Flow("test", [task, task2]);
|
||||||
@@ -126,7 +126,7 @@ describe("Flow task inputs", async () => {
|
|||||||
const emgr = new EventManager({ EventTriggerClass });
|
const emgr = new EventManager({ EventTriggerClass });
|
||||||
|
|
||||||
const task = new OutputParamTask("event", {
|
const task = new OutputParamTask("event", {
|
||||||
number: "{{flow.output.number}}"
|
number: "{{flow.output.number}}",
|
||||||
});
|
});
|
||||||
const flow = new Flow(
|
const flow = new Flow(
|
||||||
"test",
|
"test",
|
||||||
@@ -134,8 +134,8 @@ describe("Flow task inputs", async () => {
|
|||||||
[],
|
[],
|
||||||
new EventTrigger({
|
new EventTrigger({
|
||||||
event: "test-event",
|
event: "test-event",
|
||||||
mode: "sync"
|
mode: "sync",
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
flow.setRespondingTask(task);
|
flow.setRespondingTask(task);
|
||||||
flow.trigger.register(flow, emgr);
|
flow.trigger.register(flow, emgr);
|
||||||
@@ -155,8 +155,8 @@ describe("Flow task inputs", async () => {
|
|||||||
new HttpTrigger({
|
new HttpTrigger({
|
||||||
path: "/test",
|
path: "/test",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
mode: "sync"
|
mode: "sync",
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
flow.setRespondingTask(task);
|
flow.setRespondingTask(task);
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const flows = {
|
|||||||
back,
|
back,
|
||||||
fanout,
|
fanout,
|
||||||
parallel,
|
parallel,
|
||||||
simpleFetch
|
simpleFetch,
|
||||||
};
|
};
|
||||||
|
|
||||||
const arg = process.argv[2];
|
const arg = process.argv[2];
|
||||||
@@ -32,7 +32,7 @@ const colors = [
|
|||||||
"#F78F1E", // Saffron
|
"#F78F1E", // Saffron
|
||||||
"#BD10E0", // Vivid Purple
|
"#BD10E0", // Vivid Purple
|
||||||
"#50E3C2", // Turquoise
|
"#50E3C2", // Turquoise
|
||||||
"#9013FE" // Grape
|
"#9013FE", // Grape
|
||||||
];
|
];
|
||||||
|
|
||||||
const colorsCache: Record<string, string> = {};
|
const colorsCache: Record<string, string> = {};
|
||||||
@@ -82,7 +82,7 @@ function TerminalFlow({ flow }: { flow: Flow }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return t;
|
return t;
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -92,7 +92,7 @@ function TerminalFlow({ flow }: { flow: Flow }) {
|
|||||||
console.log("done", response ? response : "(no response)");
|
console.log("done", response ? response : "(no response)");
|
||||||
console.log(
|
console.log(
|
||||||
"Executed tasks:",
|
"Executed tasks:",
|
||||||
execution.logs.map((l) => l.task.name)
|
execution.logs.map((l) => l.task.name),
|
||||||
);
|
);
|
||||||
console.log("Executed count:", execution.logs.length);
|
console.log("Executed count:", execution.logs.length);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class ExecTask extends Task {
|
|||||||
constructor(
|
constructor(
|
||||||
name: string,
|
name: string,
|
||||||
params: any,
|
params: any,
|
||||||
private fn: () => any
|
private fn: () => any,
|
||||||
) {
|
) {
|
||||||
super(name, params);
|
super(name, params);
|
||||||
}
|
}
|
||||||
@@ -60,7 +60,7 @@ describe("Flow trigger", async () => {
|
|||||||
"test",
|
"test",
|
||||||
[task],
|
[task],
|
||||||
[],
|
[],
|
||||||
new EventTrigger({ event: "test-event", mode: "sync" })
|
new EventTrigger({ event: "test-event", mode: "sync" }),
|
||||||
);
|
);
|
||||||
|
|
||||||
flow.trigger.register(flow, emgr);
|
flow.trigger.register(flow, emgr);
|
||||||
@@ -107,8 +107,8 @@ describe("Flow trigger", async () => {
|
|||||||
new HttpTrigger({
|
new HttpTrigger({
|
||||||
path: "/test",
|
path: "/test",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
mode: "sync"
|
mode: "sync",
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
const hono = new Hono();
|
const hono = new Hono();
|
||||||
@@ -123,7 +123,7 @@ describe("Flow trigger", async () => {
|
|||||||
|
|
||||||
test("http trigger with response", async () => {
|
test("http trigger with response", async () => {
|
||||||
const task = ExecTask.create("http", () => ({
|
const task = ExecTask.create("http", () => ({
|
||||||
called: true
|
called: true,
|
||||||
}));
|
}));
|
||||||
const flow = new Flow(
|
const flow = new Flow(
|
||||||
"test",
|
"test",
|
||||||
@@ -132,8 +132,8 @@ describe("Flow trigger", async () => {
|
|||||||
new HttpTrigger({
|
new HttpTrigger({
|
||||||
path: "/test",
|
path: "/test",
|
||||||
method: "GET",
|
method: "GET",
|
||||||
mode: "sync"
|
mode: "sync",
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
flow.setRespondingTask(task);
|
flow.setRespondingTask(task);
|
||||||
|
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ class ExecTask extends Task<typeof ExecTask.schema> {
|
|||||||
type = "exec";
|
type = "exec";
|
||||||
|
|
||||||
static override schema = Type.Object({
|
static override schema = Type.Object({
|
||||||
delay: Type.Number({ default: 10 })
|
delay: Type.Number({ default: 10 }),
|
||||||
});
|
});
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
name: string,
|
name: string,
|
||||||
params: Static<typeof ExecTask.schema>,
|
params: Static<typeof ExecTask.schema>,
|
||||||
private func: () => Promise<any>
|
private func: () => Promise<any>,
|
||||||
) {
|
) {
|
||||||
super(name, params);
|
super(name, params);
|
||||||
}
|
}
|
||||||
@@ -36,12 +36,12 @@ function getTask(num: number = 0, delay: number = 5) {
|
|||||||
return new ExecTask(
|
return new ExecTask(
|
||||||
`Task ${num}`,
|
`Task ${num}`,
|
||||||
{
|
{
|
||||||
delay
|
delay,
|
||||||
},
|
},
|
||||||
async () => {
|
async () => {
|
||||||
//console.log(`[DONE] Task: ${num}`);
|
//console.log(`[DONE] Task: ${num}`);
|
||||||
return true;
|
return true;
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
//return new LogTask(`Log ${num}`, { delay });
|
//return new LogTask(`Log ${num}`, { delay });
|
||||||
}
|
}
|
||||||
@@ -56,9 +56,9 @@ function getNamedTask(name: string, _func?: () => Promise<any>, delay?: number)
|
|||||||
return new ExecTask(
|
return new ExecTask(
|
||||||
name,
|
name,
|
||||||
{
|
{
|
||||||
delay: delay ?? 0
|
delay: delay ?? 0,
|
||||||
},
|
},
|
||||||
func
|
func,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +228,7 @@ describe("Flow tests", async () => {
|
|||||||
back
|
back
|
||||||
.task(third)
|
.task(third)
|
||||||
.getOutTasks()
|
.getOutTasks()
|
||||||
.map((t) => t.name)
|
.map((t) => t.name),
|
||||||
).toEqual(["second", "fourth"]);
|
).toEqual(["second", "fourth"]);
|
||||||
|
|
||||||
const execution = back.createExecution();
|
const execution = back.createExecution();
|
||||||
@@ -263,7 +263,7 @@ describe("Flow tests", async () => {
|
|||||||
back
|
back
|
||||||
.task(third)
|
.task(third)
|
||||||
.getOutTasks()
|
.getOutTasks()
|
||||||
.map((t) => t.name)
|
.map((t) => t.name),
|
||||||
).toEqual(["second", "fourth"]);
|
).toEqual(["second", "fourth"]);
|
||||||
|
|
||||||
const execution = back.createExecution();
|
const execution = back.createExecution();
|
||||||
@@ -324,8 +324,8 @@ describe("Flow tests", async () => {
|
|||||||
const first = getNamedTask("first", async () => {
|
const first = getNamedTask("first", async () => {
|
||||||
return {
|
return {
|
||||||
inner: {
|
inner: {
|
||||||
result: 2
|
result: 2,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
const second = getNamedTask("second");
|
const second = getNamedTask("second");
|
||||||
@@ -361,7 +361,7 @@ describe("Flow tests", async () => {
|
|||||||
"[event]",
|
"[event]",
|
||||||
event.isStart() ? "start" : "end",
|
event.isStart() ? "start" : "end",
|
||||||
event.task().name,
|
event.task().name,
|
||||||
event.isStart() ? undefined : event.succeeded()
|
event.isStart() ? undefined : event.succeeded(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -389,7 +389,7 @@ describe("Flow tests", async () => {
|
|||||||
const second = new LogTask("Task 1");
|
const second = new LogTask("Task 1");
|
||||||
const third = new LogTask("Task 2", { delay: 50 });
|
const third = new LogTask("Task 2", { delay: 50 });
|
||||||
const fourth = new FetchTask("Fetch Something", {
|
const fourth = new FetchTask("Fetch Something", {
|
||||||
url: "https://jsonplaceholder.typicode.com/todos/1"
|
url: "https://jsonplaceholder.typicode.com/todos/1",
|
||||||
});
|
});
|
||||||
const fifth = new LogTask("Task 4"); // without connection
|
const fifth = new LogTask("Task 4"); // without connection
|
||||||
|
|
||||||
@@ -405,7 +405,7 @@ describe("Flow tests", async () => {
|
|||||||
// @todo: fix
|
// @todo: fix
|
||||||
const deserialized = Flow.fromObject("", original, {
|
const deserialized = Flow.fromObject("", original, {
|
||||||
fetch: { cls: FetchTask },
|
fetch: { cls: FetchTask },
|
||||||
log: { cls: LogTask }
|
log: { cls: LogTask },
|
||||||
} as any);
|
} as any);
|
||||||
|
|
||||||
const diffdeep = getObjectDiff(original, deserialized.toJSON());
|
const diffdeep = getObjectDiff(original, deserialized.toJSON());
|
||||||
@@ -414,7 +414,7 @@ describe("Flow tests", async () => {
|
|||||||
expect(flow.startTask.name).toEqual(deserialized.startTask.name);
|
expect(flow.startTask.name).toEqual(deserialized.startTask.name);
|
||||||
expect(flow.respondingTask?.name).toEqual(
|
expect(flow.respondingTask?.name).toEqual(
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
deserialized.respondingTask?.name
|
deserialized.respondingTask?.name,
|
||||||
);
|
);
|
||||||
|
|
||||||
//console.log("--- creating original sequence");
|
//console.log("--- creating original sequence");
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export function getDummyDatabase(memory: boolean = true): {
|
|||||||
afterAllCleanup: async () => {
|
afterAllCleanup: async () => {
|
||||||
if (!memory) await unlink(DB_NAME);
|
if (!memory) await unlink(DB_NAME);
|
||||||
return true;
|
return true;
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,7 +27,7 @@ export function getDummyConnection(memory: boolean = true) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
dummyConnection,
|
dummyConnection,
|
||||||
afterAllCleanup
|
afterAllCleanup,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ type ConsoleSeverity = "log" | "warn" | "error";
|
|||||||
const _oldConsoles = {
|
const _oldConsoles = {
|
||||||
log: console.log,
|
log: console.log,
|
||||||
warn: console.warn,
|
warn: console.warn,
|
||||||
error: console.error
|
error: console.error,
|
||||||
};
|
};
|
||||||
|
|
||||||
export function disableConsoleLog(severities: ConsoleSeverity[] = ["log", "warn"]) {
|
export function disableConsoleLog(severities: ConsoleSeverity[] = ["log", "warn"]) {
|
||||||
|
|||||||
@@ -16,25 +16,25 @@ const roles = {
|
|||||||
"system.schema.read",
|
"system.schema.read",
|
||||||
"system.access.api",
|
"system.access.api",
|
||||||
"system.config.read",
|
"system.config.read",
|
||||||
"data.entity.read"
|
"data.entity.read",
|
||||||
],
|
],
|
||||||
is_default: true
|
is_default: true,
|
||||||
},
|
},
|
||||||
admin: {
|
admin: {
|
||||||
is_default: true,
|
is_default: true,
|
||||||
implicit_allow: true
|
implicit_allow: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
strict: {
|
strict: {
|
||||||
guest: {
|
guest: {
|
||||||
permissions: ["system.access.api", "system.config.read", "data.entity.read"],
|
permissions: ["system.access.api", "system.config.read", "data.entity.read"],
|
||||||
is_default: true
|
is_default: true,
|
||||||
},
|
},
|
||||||
admin: {
|
admin: {
|
||||||
is_default: true,
|
is_default: true,
|
||||||
implicit_allow: true
|
implicit_allow: true,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
const configs = {
|
const configs = {
|
||||||
auth: {
|
auth: {
|
||||||
@@ -42,31 +42,31 @@ const configs = {
|
|||||||
entity_name: "users",
|
entity_name: "users",
|
||||||
jwt: {
|
jwt: {
|
||||||
secret: secureRandomString(20),
|
secret: secureRandomString(20),
|
||||||
issuer: randomString(10)
|
issuer: randomString(10),
|
||||||
},
|
},
|
||||||
roles: roles.strict,
|
roles: roles.strict,
|
||||||
guard: {
|
guard: {
|
||||||
enabled: true
|
enabled: true,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
users: {
|
users: {
|
||||||
normal: {
|
normal: {
|
||||||
email: "normal@bknd.io",
|
email: "normal@bknd.io",
|
||||||
password: "12345678"
|
password: "12345678",
|
||||||
},
|
},
|
||||||
admin: {
|
admin: {
|
||||||
email: "admin@bknd.io",
|
email: "admin@bknd.io",
|
||||||
password: "12345678",
|
password: "12345678",
|
||||||
role: "admin"
|
role: "admin",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function createAuthApp() {
|
function createAuthApp() {
|
||||||
const app = createApp({
|
const app = createApp({
|
||||||
initialConfig: {
|
initialConfig: {
|
||||||
auth: configs.auth
|
auth: configs.auth,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
app.emgr.onEvent(
|
app.emgr.onEvent(
|
||||||
@@ -75,7 +75,7 @@ function createAuthApp() {
|
|||||||
await app.createUser(configs.users.normal);
|
await app.createUser(configs.users.normal);
|
||||||
await app.createUser(configs.users.admin);
|
await app.createUser(configs.users.admin);
|
||||||
},
|
},
|
||||||
"sync"
|
"sync",
|
||||||
);
|
);
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
@@ -94,14 +94,14 @@ const fns = <Mode extends "cookie" | "token" = "token">(app: App, mode?: Mode) =
|
|||||||
if (mode === "cookie") {
|
if (mode === "cookie") {
|
||||||
return {
|
return {
|
||||||
cookie: `auth=${token};`,
|
cookie: `auth=${token};`,
|
||||||
...additional
|
...additional,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
Authorization: token ? `Bearer ${token}` : "",
|
Authorization: token ? `Bearer ${token}` : "",
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
...additional
|
...additional,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
function body(obj?: Record<string, any>) {
|
function body(obj?: Record<string, any>) {
|
||||||
@@ -118,12 +118,12 @@ const fns = <Mode extends "cookie" | "token" = "token">(app: App, mode?: Mode) =
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
login: async (
|
login: async (
|
||||||
user: any
|
user: any,
|
||||||
): Promise<{ res: Response; data: Mode extends "token" ? AuthResponse : string }> => {
|
): Promise<{ res: Response; data: Mode extends "token" ? AuthResponse : string }> => {
|
||||||
const res = (await app.server.request("/api/auth/password/login", {
|
const res = (await app.server.request("/api/auth/password/login", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: headers(),
|
headers: headers(),
|
||||||
body: body(user)
|
body: body(user),
|
||||||
})) as Response;
|
})) as Response;
|
||||||
|
|
||||||
const data = mode === "cookie" ? getCookie(res, "auth") : await res.json();
|
const data = mode === "cookie" ? getCookie(res, "auth") : await res.json();
|
||||||
@@ -133,10 +133,10 @@ const fns = <Mode extends "cookie" | "token" = "token">(app: App, mode?: Mode) =
|
|||||||
me: async (token?: string): Promise<Pick<AuthResponse, "user">> => {
|
me: async (token?: string): Promise<Pick<AuthResponse, "user">> => {
|
||||||
const res = (await app.server.request("/api/auth/me", {
|
const res = (await app.server.request("/api/auth/me", {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: headers(token)
|
headers: headers(token),
|
||||||
})) as Response;
|
})) as Response;
|
||||||
return await res.json();
|
return await res.json();
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -219,7 +219,7 @@ describe("integration auth", () => {
|
|||||||
|
|
||||||
app.server.get("/get", auth(), async (c) => {
|
app.server.get("/get", auth(), async (c) => {
|
||||||
return c.json({
|
return c.json({
|
||||||
user: c.get("auth").user ?? null
|
user: c.get("auth").user ?? null,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
app.server.get("/wait", auth(), async (c) => {
|
app.server.get("/wait", auth(), async (c) => {
|
||||||
@@ -232,7 +232,7 @@ describe("integration auth", () => {
|
|||||||
expect(me.user.email).toBe(configs.users.normal.email);
|
expect(me.user.email).toBe(configs.users.normal.email);
|
||||||
|
|
||||||
app.server.request("/wait", {
|
app.server.request("/wait", {
|
||||||
headers: { Authorization: `Bearer ${data.token}` }
|
headers: { Authorization: `Bearer ${data.token}` },
|
||||||
});
|
});
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ describe("integration config", () => {
|
|||||||
await app.build();
|
await app.build();
|
||||||
const api = new Api({
|
const api = new Api({
|
||||||
host: "http://localhost",
|
host: "http://localhost",
|
||||||
fetcher: app.server.request as typeof fetch
|
fetcher: app.server.request as typeof fetch,
|
||||||
});
|
});
|
||||||
|
|
||||||
// create entity
|
// create entity
|
||||||
@@ -16,7 +16,7 @@ describe("integration config", () => {
|
|||||||
name: "posts",
|
name: "posts",
|
||||||
config: { sort_field: "id", sort_dir: "asc" },
|
config: { sort_field: "id", sort_dir: "asc" },
|
||||||
fields: { id: { type: "primary", name: "id" }, asdf: { type: "text" } },
|
fields: { id: { type: "primary", name: "id" }, asdf: { type: "text" } },
|
||||||
type: "regular"
|
type: "regular",
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(app.em.entities.map((e) => e.name)).toContain("posts");
|
expect(app.em.entities.map((e) => e.name)).toContain("posts");
|
||||||
|
|||||||
@@ -22,13 +22,13 @@ async function makeApp(mediaOverride: Partial<TAppMediaConfig> = {}) {
|
|||||||
adapter: {
|
adapter: {
|
||||||
type: "local",
|
type: "local",
|
||||||
config: {
|
config: {
|
||||||
path: assetsTmpPath
|
path: assetsTmpPath,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
mediaOverride,
|
||||||
|
),
|
||||||
},
|
},
|
||||||
mediaOverride
|
|
||||||
)
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
await app.build();
|
await app.build();
|
||||||
@@ -50,7 +50,7 @@ describe("MediaController", () => {
|
|||||||
const name = makeName("png");
|
const name = makeName("png");
|
||||||
const res = await app.server.request("/api/media/upload/" + name, {
|
const res = await app.server.request("/api/media/upload/" + name, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: file
|
body: file,
|
||||||
});
|
});
|
||||||
const result = (await res.json()) as any;
|
const result = (await res.json()) as any;
|
||||||
console.log(result);
|
console.log(result);
|
||||||
@@ -71,7 +71,7 @@ describe("MediaController", () => {
|
|||||||
|
|
||||||
const res = await app.server.request("/api/media/upload/" + name, {
|
const res = await app.server.request("/api/media/upload/" + name, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: form
|
body: form,
|
||||||
});
|
});
|
||||||
const result = (await res.json()) as any;
|
const result = (await res.json()) as any;
|
||||||
expect(result.name).toBe(name);
|
expect(result.name).toBe(name);
|
||||||
@@ -88,7 +88,7 @@ describe("MediaController", () => {
|
|||||||
const name = makeName("png");
|
const name = makeName("png");
|
||||||
const res = await app.server.request("/api/media/upload/" + name, {
|
const res = await app.server.request("/api/media/upload/" + name, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: file
|
body: file,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(res.status).toBe(413);
|
expect(res.status).toBe(413);
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ describe("Storage", async () => {
|
|||||||
|
|
||||||
test("uploads a file", async () => {
|
test("uploads a file", async () => {
|
||||||
const {
|
const {
|
||||||
meta: { type, size }
|
meta: { type, size },
|
||||||
} = await storage.uploadFile("hello", "world.txt");
|
} = await storage.uploadFile("hello", "world.txt");
|
||||||
expect({ type, size }).toEqual({ type: "text/plain", size: 0 });
|
expect({ type, size }).toEqual({ type: "text/plain", size: 0 });
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ test("what", async () => {
|
|||||||
const mf = new Miniflare({
|
const mf = new Miniflare({
|
||||||
modules: true,
|
modules: true,
|
||||||
script: "export default { async fetch() { return new Response(null); } }",
|
script: "export default { async fetch() { return new Response(null); } }",
|
||||||
r2Buckets: ["BUCKET"]
|
r2Buckets: ["BUCKET"],
|
||||||
});
|
});
|
||||||
|
|
||||||
const bucket = await mf.getR2Bucket("BUCKET");
|
const bucket = await mf.getR2Bucket("BUCKET");
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const {
|
|||||||
CLOUDINARY_CLOUD_NAME,
|
CLOUDINARY_CLOUD_NAME,
|
||||||
CLOUDINARY_API_KEY,
|
CLOUDINARY_API_KEY,
|
||||||
CLOUDINARY_API_SECRET,
|
CLOUDINARY_API_SECRET,
|
||||||
CLOUDINARY_UPLOAD_PRESET
|
CLOUDINARY_UPLOAD_PRESET,
|
||||||
} = dotenvOutput.parsed!;
|
} = dotenvOutput.parsed!;
|
||||||
|
|
||||||
const ALL_TESTS = !!process.env.ALL_TESTS;
|
const ALL_TESTS = !!process.env.ALL_TESTS;
|
||||||
@@ -20,7 +20,7 @@ describe.skipIf(ALL_TESTS)("StorageCloudinaryAdapter", () => {
|
|||||||
cloud_name: CLOUDINARY_CLOUD_NAME as string,
|
cloud_name: CLOUDINARY_CLOUD_NAME as string,
|
||||||
api_key: CLOUDINARY_API_KEY as string,
|
api_key: CLOUDINARY_API_KEY as string,
|
||||||
api_secret: CLOUDINARY_API_SECRET as string,
|
api_secret: CLOUDINARY_API_SECRET as string,
|
||||||
upload_preset: CLOUDINARY_UPLOAD_PRESET as string
|
upload_preset: CLOUDINARY_UPLOAD_PRESET as string,
|
||||||
});
|
});
|
||||||
|
|
||||||
const file = Bun.file(`${import.meta.dir}/icon.png`);
|
const file = Bun.file(`${import.meta.dir}/icon.png`);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { assetsPath, assetsTmpPath } from "../../helper";
|
|||||||
|
|
||||||
describe("StorageLocalAdapter", () => {
|
describe("StorageLocalAdapter", () => {
|
||||||
const adapter = new StorageLocalAdapter({
|
const adapter = new StorageLocalAdapter({
|
||||||
path: assetsTmpPath
|
path: assetsTmpPath,
|
||||||
});
|
});
|
||||||
|
|
||||||
const file = Bun.file(`${assetsPath}/image.png`);
|
const file = Bun.file(`${assetsPath}/image.png`);
|
||||||
@@ -36,7 +36,7 @@ describe("StorageLocalAdapter", () => {
|
|||||||
test("gets object meta", async () => {
|
test("gets object meta", async () => {
|
||||||
expect(await adapter.getObjectMeta(filename)).toEqual({
|
expect(await adapter.getObjectMeta(filename)).toEqual({
|
||||||
type: file.type, // image/png
|
type: file.type, // image/png
|
||||||
size: file.size
|
size: file.size,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -20,17 +20,17 @@ describe.skipIf(true)("StorageS3Adapter", async () => {
|
|||||||
new StorageS3Adapter({
|
new StorageS3Adapter({
|
||||||
access_key: R2_ACCESS_KEY as string,
|
access_key: R2_ACCESS_KEY as string,
|
||||||
secret_access_key: R2_SECRET_ACCESS_KEY as string,
|
secret_access_key: R2_SECRET_ACCESS_KEY as string,
|
||||||
url: R2_URL as string
|
url: R2_URL as string,
|
||||||
})
|
}),
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"s3",
|
"s3",
|
||||||
new StorageS3Adapter({
|
new StorageS3Adapter({
|
||||||
access_key: AWS_ACCESS_KEY as string,
|
access_key: AWS_ACCESS_KEY as string,
|
||||||
secret_access_key: AWS_SECRET_KEY as string,
|
secret_access_key: AWS_SECRET_KEY as string,
|
||||||
url: AWS_S3_URL as string
|
url: AWS_S3_URL as string,
|
||||||
})
|
}),
|
||||||
]
|
],
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
const _conf = {
|
const _conf = {
|
||||||
@@ -41,8 +41,8 @@ describe.skipIf(true)("StorageS3Adapter", async () => {
|
|||||||
"objectExists",
|
"objectExists",
|
||||||
"getObject",
|
"getObject",
|
||||||
"deleteObject",
|
"deleteObject",
|
||||||
"getObjectMeta"
|
"getObjectMeta",
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
const file = Bun.file(`${import.meta.dir}/icon.png`);
|
const file = Bun.file(`${import.meta.dir}/icon.png`);
|
||||||
@@ -86,7 +86,7 @@ describe.skipIf(true)("StorageS3Adapter", async () => {
|
|||||||
test.skipIf(disabled("getObjectMeta"))("gets object meta", async () => {
|
test.skipIf(disabled("getObjectMeta"))("gets object meta", async () => {
|
||||||
expect(await adapter.getObjectMeta(filename)).toEqual({
|
expect(await adapter.getObjectMeta(filename)).toEqual({
|
||||||
type: file.type, // image/png
|
type: file.type, // image/png
|
||||||
size: file.size
|
size: file.size,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ describe("media/mime-types", () => {
|
|||||||
exts,
|
exts,
|
||||||
ext,
|
ext,
|
||||||
expected: ex,
|
expected: ex,
|
||||||
actual: large.guessMimeType("." + ext)
|
actual: large.guessMimeType("." + ext),
|
||||||
});
|
});
|
||||||
throw new Error(`Failed for ${ext}`);
|
throw new Error(`Failed for ${ext}`);
|
||||||
}
|
}
|
||||||
@@ -49,13 +49,13 @@ describe("media/mime-types", () => {
|
|||||||
["image/gif", true],
|
["image/gif", true],
|
||||||
["whatever", false],
|
["whatever", false],
|
||||||
["text/tab-separated-values", true],
|
["text/tab-separated-values", true],
|
||||||
["application/zip", true]
|
["application/zip", true],
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const [mime, expected, exclude] of tests) {
|
for (const [mime, expected, exclude] of tests) {
|
||||||
expect(
|
expect(
|
||||||
tiny.isMimeType(mime, exclude as any),
|
tiny.isMimeType(mime, exclude as any),
|
||||||
`isMimeType(): ${mime} should be ${expected}`
|
`isMimeType(): ${mime} should be ${expected}`,
|
||||||
).toBe(expected as any);
|
).toBe(expected as any);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -68,7 +68,7 @@ describe("media/mime-types", () => {
|
|||||||
["image/jpeg", "jpeg"],
|
["image/jpeg", "jpeg"],
|
||||||
["application/zip", "zip"],
|
["application/zip", "zip"],
|
||||||
["text/tab-separated-values", "tsv"],
|
["text/tab-separated-values", "tsv"],
|
||||||
["application/zip", "zip"]
|
["application/zip", "zip"],
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const [mime, ext] of tests) {
|
for (const [mime, ext] of tests) {
|
||||||
@@ -85,13 +85,13 @@ describe("media/mime-types", () => {
|
|||||||
["image.heic", "heic"],
|
["image.heic", "heic"],
|
||||||
["image.jpeg", "jpeg"],
|
["image.jpeg", "jpeg"],
|
||||||
["-473Wx593H-466453554-black-MODEL.jpg", "jpg"],
|
["-473Wx593H-466453554-black-MODEL.jpg", "jpg"],
|
||||||
["-473Wx593H-466453554-black-MODEL.avif", "avif"]
|
["-473Wx593H-466453554-black-MODEL.avif", "avif"],
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const [filename, ext] of tests) {
|
for (const [filename, ext] of tests) {
|
||||||
expect(
|
expect(
|
||||||
getRandomizedFilename(filename).split(".").pop(),
|
getRandomizedFilename(filename).split(".").pop(),
|
||||||
`getRandomizedFilename(): ${filename} should end with ${ext}`
|
`getRandomizedFilename(): ${filename} should end with ${ext}`,
|
||||||
).toBe(ext);
|
).toBe(ext);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -43,10 +43,10 @@ describe("AppAuth", () => {
|
|||||||
{
|
{
|
||||||
enabled: true,
|
enabled: true,
|
||||||
jwt: {
|
jwt: {
|
||||||
secret: "123456"
|
secret: "123456",
|
||||||
}
|
|
||||||
},
|
},
|
||||||
ctx
|
},
|
||||||
|
ctx,
|
||||||
);
|
);
|
||||||
|
|
||||||
await auth.build();
|
await auth.build();
|
||||||
@@ -63,12 +63,12 @@ describe("AppAuth", () => {
|
|||||||
const res = await app.request("/password/register", {
|
const res = await app.request("/password/register", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json"
|
"Content-Type": "application/json",
|
||||||
},
|
},
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
email: "some@body.com",
|
email: "some@body.com",
|
||||||
password: "123456"
|
password: "123456",
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
enableConsoleLog();
|
enableConsoleLog();
|
||||||
expect(res.status).toBe(200);
|
expect(res.status).toBe(200);
|
||||||
@@ -85,10 +85,10 @@ describe("AppAuth", () => {
|
|||||||
auth: {
|
auth: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
jwt: {
|
jwt: {
|
||||||
secret: "123456"
|
secret: "123456",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await app.build();
|
await app.build();
|
||||||
@@ -109,14 +109,14 @@ describe("AppAuth", () => {
|
|||||||
initialConfig: {
|
initialConfig: {
|
||||||
auth: {
|
auth: {
|
||||||
entity_name: "users",
|
entity_name: "users",
|
||||||
enabled: true
|
enabled: true,
|
||||||
},
|
},
|
||||||
data: em({
|
data: em({
|
||||||
users: entity("users", {
|
users: entity("users", {
|
||||||
additional: text()
|
additional: text(),
|
||||||
})
|
}),
|
||||||
}).toJSON()
|
}).toJSON(),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await app.build();
|
await app.build();
|
||||||
@@ -132,21 +132,21 @@ describe("AppAuth", () => {
|
|||||||
const app = createApp({
|
const app = createApp({
|
||||||
initialConfig: {
|
initialConfig: {
|
||||||
auth: {
|
auth: {
|
||||||
enabled: true
|
enabled: true,
|
||||||
},
|
},
|
||||||
data: em({
|
data: em({
|
||||||
users: entity("users", {
|
users: entity("users", {
|
||||||
strategy: text({
|
strategy: text({
|
||||||
fillable: true,
|
fillable: true,
|
||||||
hidden: false
|
hidden: false,
|
||||||
}),
|
}),
|
||||||
strategy_value: text({
|
strategy_value: text({
|
||||||
fillable: true,
|
fillable: true,
|
||||||
hidden: false
|
hidden: false,
|
||||||
})
|
}),
|
||||||
})
|
}),
|
||||||
}).toJSON()
|
}).toJSON(),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
await app.build();
|
await app.build();
|
||||||
|
|
||||||
|
|||||||
@@ -19,16 +19,16 @@ describe("AppMedia", () => {
|
|||||||
adapter: {
|
adapter: {
|
||||||
type: "local",
|
type: "local",
|
||||||
config: {
|
config: {
|
||||||
path: "./"
|
path: "./",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
data: em({
|
data: em({
|
||||||
media: entity("media", {
|
media: entity("media", {
|
||||||
additional: text()
|
additional: text(),
|
||||||
})
|
}),
|
||||||
}).toJSON()
|
}).toJSON(),
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await app.build();
|
await app.build();
|
||||||
@@ -49,7 +49,7 @@ describe("AppMedia", () => {
|
|||||||
"modified_at",
|
"modified_at",
|
||||||
"reference",
|
"reference",
|
||||||
"entity_id",
|
"entity_id",
|
||||||
"metadata"
|
"metadata",
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ describe("Module", async () => {
|
|||||||
prt = {
|
prt = {
|
||||||
ensureEntity: this.ensureEntity.bind(this),
|
ensureEntity: this.ensureEntity.bind(this),
|
||||||
ensureIndex: this.ensureIndex.bind(this),
|
ensureIndex: this.ensureIndex.bind(this),
|
||||||
ensureSchema: this.ensureSchema.bind(this)
|
ensureSchema: this.ensureSchema.bind(this),
|
||||||
};
|
};
|
||||||
|
|
||||||
get em() {
|
get em() {
|
||||||
@@ -60,7 +60,7 @@ describe("Module", async () => {
|
|||||||
Object.values(_em.entities),
|
Object.values(_em.entities),
|
||||||
new DummyConnection(),
|
new DummyConnection(),
|
||||||
_em.relations,
|
_em.relations,
|
||||||
_em.indices
|
_em.indices,
|
||||||
);
|
);
|
||||||
return new M({} as any, { em, flags: Module.ctx_flags } as any);
|
return new M({} as any, { em, flags: Module.ctx_flags } as any);
|
||||||
}
|
}
|
||||||
@@ -69,14 +69,14 @@ describe("Module", async () => {
|
|||||||
entities: _em.entities.map((e) => ({
|
entities: _em.entities.map((e) => ({
|
||||||
name: e.name,
|
name: e.name,
|
||||||
fields: e.fields.map((f) => f.name),
|
fields: e.fields.map((f) => f.name),
|
||||||
type: e.type
|
type: e.type,
|
||||||
})),
|
})),
|
||||||
indices: _em.indices.map((i) => ({
|
indices: _em.indices.map((i) => ({
|
||||||
name: i.name,
|
name: i.name,
|
||||||
entity: i.entity.name,
|
entity: i.entity.name,
|
||||||
fields: i.fields.map((f) => f.name),
|
fields: i.fields.map((f) => f.name),
|
||||||
unique: i.unique
|
unique: i.unique,
|
||||||
}))
|
})),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,15 +88,15 @@ describe("Module", async () => {
|
|||||||
|
|
||||||
expect(flat(make(initial).em)).toEqual({
|
expect(flat(make(initial).em)).toEqual({
|
||||||
entities: [],
|
entities: [],
|
||||||
indices: []
|
indices: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("init", () => {
|
test("init", () => {
|
||||||
const initial = em({
|
const initial = em({
|
||||||
users: entity("u", {
|
users: entity("u", {
|
||||||
name: text()
|
name: text(),
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const m = make(initial);
|
const m = make(initial);
|
||||||
@@ -107,18 +107,18 @@ describe("Module", async () => {
|
|||||||
{
|
{
|
||||||
name: "u",
|
name: "u",
|
||||||
fields: ["id", "name"],
|
fields: ["id", "name"],
|
||||||
type: "regular"
|
type: "regular",
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
indices: []
|
indices: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("ensure entity", () => {
|
test("ensure entity", () => {
|
||||||
const initial = em({
|
const initial = em({
|
||||||
users: entity("u", {
|
users: entity("u", {
|
||||||
name: text()
|
name: text(),
|
||||||
})
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
const m = make(initial);
|
const m = make(initial);
|
||||||
@@ -127,17 +127,17 @@ describe("Module", async () => {
|
|||||||
{
|
{
|
||||||
name: "u",
|
name: "u",
|
||||||
fields: ["id", "name"],
|
fields: ["id", "name"],
|
||||||
type: "regular"
|
type: "regular",
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
indices: []
|
indices: [],
|
||||||
});
|
});
|
||||||
|
|
||||||
// this should add a new entity
|
// this should add a new entity
|
||||||
m.prt.ensureEntity(
|
m.prt.ensureEntity(
|
||||||
entity("p", {
|
entity("p", {
|
||||||
title: text()
|
title: text(),
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// this should only add the field "important"
|
// this should only add the field "important"
|
||||||
@@ -145,11 +145,11 @@ describe("Module", async () => {
|
|||||||
entity(
|
entity(
|
||||||
"u",
|
"u",
|
||||||
{
|
{
|
||||||
important: text()
|
important: text(),
|
||||||
},
|
},
|
||||||
undefined,
|
undefined,
|
||||||
"system"
|
"system",
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(m.ctx.flags.sync_required).toBe(true);
|
expect(m.ctx.flags.sync_required).toBe(true);
|
||||||
@@ -159,22 +159,22 @@ describe("Module", async () => {
|
|||||||
name: "u",
|
name: "u",
|
||||||
fields: ["id", "name", "important"],
|
fields: ["id", "name", "important"],
|
||||||
// ensured type must be present
|
// ensured type must be present
|
||||||
type: "system"
|
type: "system",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "p",
|
name: "p",
|
||||||
fields: ["id", "title"],
|
fields: ["id", "title"],
|
||||||
type: "regular"
|
type: "regular",
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
indices: []
|
indices: [],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("ensure index", () => {
|
test("ensure index", () => {
|
||||||
const users = entity("u", {
|
const users = entity("u", {
|
||||||
name: text(),
|
name: text(),
|
||||||
title: text()
|
title: text(),
|
||||||
});
|
});
|
||||||
const initial = em({ users }, ({ index }, { users }) => {
|
const initial = em({ users }, ({ index }, { users }) => {
|
||||||
index(users).on(["title"]);
|
index(users).on(["title"]);
|
||||||
@@ -189,23 +189,23 @@ describe("Module", async () => {
|
|||||||
{
|
{
|
||||||
name: "u",
|
name: "u",
|
||||||
fields: ["id", "name", "title"],
|
fields: ["id", "name", "title"],
|
||||||
type: "regular"
|
type: "regular",
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
indices: [
|
indices: [
|
||||||
{
|
{
|
||||||
name: "idx_u_title",
|
name: "idx_u_title",
|
||||||
entity: "u",
|
entity: "u",
|
||||||
fields: ["title"],
|
fields: ["title"],
|
||||||
unique: false
|
unique: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "idx_u_name",
|
name: "idx_u_name",
|
||||||
entity: "u",
|
entity: "u",
|
||||||
fields: ["name"],
|
fields: ["name"],
|
||||||
unique: false
|
unique: false,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -39,10 +39,10 @@ describe("ModuleManager", async () => {
|
|||||||
basepath: "/api/data2",
|
basepath: "/api/data2",
|
||||||
entities: {
|
entities: {
|
||||||
test: entity("test", {
|
test: entity("test", {
|
||||||
content: text()
|
content: text(),
|
||||||
}).toJSON()
|
}).toJSON(),
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
//const { version, ...json } = mm.toJSON() as any;
|
//const { version, ...json } = mm.toJSON() as any;
|
||||||
|
|
||||||
@@ -69,10 +69,10 @@ describe("ModuleManager", async () => {
|
|||||||
basepath: "/api/data2",
|
basepath: "/api/data2",
|
||||||
entities: {
|
entities: {
|
||||||
test: entity("test", {
|
test: entity("test", {
|
||||||
content: text()
|
content: text(),
|
||||||
}).toJSON()
|
}).toJSON(),
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
//const { version, ...json } = mm.toJSON() as any;
|
//const { version, ...json } = mm.toJSON() as any;
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ describe("ModuleManager", async () => {
|
|||||||
const c2 = getDummyConnection();
|
const c2 = getDummyConnection();
|
||||||
const db = c2.dummyConnection.kysely;
|
const db = c2.dummyConnection.kysely;
|
||||||
const mm2 = new ModuleManager(c2.dummyConnection, {
|
const mm2 = new ModuleManager(c2.dummyConnection, {
|
||||||
initial: { version: version - 1, ...json }
|
initial: { version: version - 1, ...json },
|
||||||
});
|
});
|
||||||
await mm2.syncConfigTable();
|
await mm2.syncConfigTable();
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ describe("ModuleManager", async () => {
|
|||||||
const db = c2.dummyConnection.kysely;
|
const db = c2.dummyConnection.kysely;
|
||||||
|
|
||||||
const mm2 = new ModuleManager(c2.dummyConnection, {
|
const mm2 = new ModuleManager(c2.dummyConnection, {
|
||||||
initial: { version: version - 1, ...json }
|
initial: { version: version - 1, ...json },
|
||||||
});
|
});
|
||||||
await mm2.syncConfigTable();
|
await mm2.syncConfigTable();
|
||||||
await db
|
await db
|
||||||
@@ -157,8 +157,8 @@ describe("ModuleManager", async () => {
|
|||||||
...json,
|
...json,
|
||||||
data: {
|
data: {
|
||||||
...json.data,
|
...json.data,
|
||||||
basepath: "/api/data2"
|
basepath: "/api/data2",
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
await db
|
await db
|
||||||
.insertInto(TABLE_NAME)
|
.insertInto(TABLE_NAME)
|
||||||
@@ -190,9 +190,9 @@ describe("ModuleManager", async () => {
|
|||||||
...configs.server,
|
...configs.server,
|
||||||
admin: {
|
admin: {
|
||||||
...configs.server.admin,
|
...configs.server.admin,
|
||||||
color_scheme: "dark"
|
color_scheme: "dark",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -201,11 +201,11 @@ describe("ModuleManager", async () => {
|
|||||||
|
|
||||||
const partial = {
|
const partial = {
|
||||||
auth: {
|
auth: {
|
||||||
enabled: true
|
enabled: true,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
const mm = new ModuleManager(dummyConnection, {
|
const mm = new ModuleManager(dummyConnection, {
|
||||||
initial: partial
|
initial: partial,
|
||||||
});
|
});
|
||||||
await mm.build();
|
await mm.build();
|
||||||
|
|
||||||
@@ -227,9 +227,9 @@ describe("ModuleManager", async () => {
|
|||||||
const mm2 = new ModuleManager(c2.dummyConnection, {
|
const mm2 = new ModuleManager(c2.dummyConnection, {
|
||||||
initial: {
|
initial: {
|
||||||
auth: {
|
auth: {
|
||||||
basepath: "/shouldnt/take/this"
|
basepath: "/shouldnt/take/this",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
await mm2.syncConfigTable();
|
await mm2.syncConfigTable();
|
||||||
const payload = {
|
const payload = {
|
||||||
@@ -237,15 +237,15 @@ describe("ModuleManager", async () => {
|
|||||||
auth: {
|
auth: {
|
||||||
...json.auth,
|
...json.auth,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
basepath: "/api/auth2"
|
basepath: "/api/auth2",
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
await db
|
await db
|
||||||
.insertInto(TABLE_NAME)
|
.insertInto(TABLE_NAME)
|
||||||
.values({
|
.values({
|
||||||
type: "config",
|
type: "config",
|
||||||
json: JSON.stringify(payload),
|
json: JSON.stringify(payload),
|
||||||
version: CURRENT_VERSION
|
version: CURRENT_VERSION,
|
||||||
})
|
})
|
||||||
.execute();
|
.execute();
|
||||||
await mm2.build();
|
await mm2.build();
|
||||||
@@ -256,7 +256,7 @@ describe("ModuleManager", async () => {
|
|||||||
|
|
||||||
describe("revert", async () => {
|
describe("revert", async () => {
|
||||||
const failingModuleSchema = Type.Object({
|
const failingModuleSchema = Type.Object({
|
||||||
value: Type.Optional(Type.Number())
|
value: Type.Optional(Type.Number()),
|
||||||
});
|
});
|
||||||
class FailingModule extends Module<typeof failingModuleSchema> {
|
class FailingModule extends Module<typeof failingModuleSchema> {
|
||||||
getSchema() {
|
getSchema() {
|
||||||
@@ -301,8 +301,8 @@ describe("ModuleManager", async () => {
|
|||||||
const mm = new TestModuleManager(dummyConnection, {
|
const mm = new TestModuleManager(dummyConnection, {
|
||||||
initial: {
|
initial: {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
failing: { value: 2 }
|
failing: { value: 2 },
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
await mm.build();
|
await mm.build();
|
||||||
expect(mm.configs()["failing"].value).toBe(2);
|
expect(mm.configs()["failing"].value).toBe(2);
|
||||||
@@ -313,8 +313,8 @@ describe("ModuleManager", async () => {
|
|||||||
const mm = new TestModuleManager(dummyConnection, {
|
const mm = new TestModuleManager(dummyConnection, {
|
||||||
initial: {
|
initial: {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
failing: { value: -1 }
|
failing: { value: -1 },
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
expect(mm.build()).rejects.toThrow(/value must be positive/);
|
expect(mm.build()).rejects.toThrow(/value must be positive/);
|
||||||
expect(mm.configs()["failing"].value).toBe(-1);
|
expect(mm.configs()["failing"].value).toBe(-1);
|
||||||
@@ -326,7 +326,7 @@ describe("ModuleManager", async () => {
|
|||||||
const mm = new TestModuleManager(dummyConnection, {
|
const mm = new TestModuleManager(dummyConnection, {
|
||||||
onUpdated: async () => {
|
onUpdated: async () => {
|
||||||
mockOnUpdated();
|
mockOnUpdated();
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
await mm.build();
|
await mm.build();
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -342,11 +342,11 @@ describe("ModuleManager", async () => {
|
|||||||
const mm = new TestModuleManager(dummyConnection, {
|
const mm = new TestModuleManager(dummyConnection, {
|
||||||
initial: {
|
initial: {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
failing: { value: 1 }
|
failing: { value: 1 },
|
||||||
},
|
},
|
||||||
onUpdated: async () => {
|
onUpdated: async () => {
|
||||||
mockOnUpdated();
|
mockOnUpdated();
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
await mm.build();
|
await mm.build();
|
||||||
expect(mm.configs()["failing"].value).toBe(1);
|
expect(mm.configs()["failing"].value).toBe(1);
|
||||||
@@ -354,7 +354,7 @@ describe("ModuleManager", async () => {
|
|||||||
// now safe mutate
|
// now safe mutate
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
expect(mm.mutateConfigSafe("failing").set({ value: -2 })).rejects.toThrow(
|
expect(mm.mutateConfigSafe("failing").set({ value: -2 })).rejects.toThrow(
|
||||||
/value must be positive/
|
/value must be positive/,
|
||||||
);
|
);
|
||||||
expect(mm.configs()["failing"].value).toBe(1);
|
expect(mm.configs()["failing"].value).toBe(1);
|
||||||
expect(mockOnUpdated).toHaveBeenCalled();
|
expect(mockOnUpdated).toHaveBeenCalled();
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export function makeCtx(overrides?: Partial<ModuleBuildContext>): ModuleBuildCon
|
|||||||
guard: new Guard(),
|
guard: new Guard(),
|
||||||
flags: Module.ctx_flags,
|
flags: Module.ctx_flags,
|
||||||
logger: new DebugLogger(false),
|
logger: new DebugLogger(false),
|
||||||
...overrides
|
...overrides,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ describe("json form", () => {
|
|||||||
["0", { type: "boolean" }, false],
|
["0", { type: "boolean" }, false],
|
||||||
["on", { type: "boolean" }, true],
|
["on", { type: "boolean" }, true],
|
||||||
["off", { type: "boolean" }, false],
|
["off", { type: "boolean" }, false],
|
||||||
["null", { type: "null" }, null]
|
["null", { type: "null" }, null],
|
||||||
] satisfies [string, Exclude<JSONSchema, boolean>, any][];
|
] satisfies [string, Exclude<JSONSchema, boolean>, any][];
|
||||||
|
|
||||||
for (const [input, schema, output] of examples) {
|
for (const [input, schema, output] of examples) {
|
||||||
@@ -35,7 +35,7 @@ describe("json form", () => {
|
|||||||
["array", "array", true],
|
["array", "array", true],
|
||||||
["object", "array", false],
|
["object", "array", false],
|
||||||
[["string", "number"], "number", true],
|
[["string", "number"], "number", true],
|
||||||
["number", ["string", "number"], true]
|
["number", ["string", "number"], true],
|
||||||
] satisfies [IsTypeType, IsTypeType, boolean][];
|
] satisfies [IsTypeType, IsTypeType, boolean][];
|
||||||
|
|
||||||
for (const [type, schemaType, output] of examples) {
|
for (const [type, schemaType, output] of examples) {
|
||||||
@@ -48,7 +48,7 @@ describe("json form", () => {
|
|||||||
["#/nested/property/0/name", "#/nested/property/0"],
|
["#/nested/property/0/name", "#/nested/property/0"],
|
||||||
["#/nested/property/0", "#/nested/property"],
|
["#/nested/property/0", "#/nested/property"],
|
||||||
["#/nested/property", "#/nested"],
|
["#/nested/property", "#/nested"],
|
||||||
["#/nested", "#"]
|
["#/nested", "#"],
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const [input, output] of examples) {
|
for (const [input, output] of examples) {
|
||||||
@@ -61,16 +61,16 @@ describe("json form", () => {
|
|||||||
[
|
[
|
||||||
"#/description",
|
"#/description",
|
||||||
{ type: "object", properties: { description: { type: "string" } } },
|
{ type: "object", properties: { description: { type: "string" } } },
|
||||||
false
|
false,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"#/description",
|
"#/description",
|
||||||
{
|
{
|
||||||
type: "object",
|
type: "object",
|
||||||
required: ["description"],
|
required: ["description"],
|
||||||
properties: { description: { type: "string" } }
|
properties: { description: { type: "string" } },
|
||||||
},
|
},
|
||||||
true
|
true,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"#/nested/property",
|
"#/nested/property",
|
||||||
@@ -79,11 +79,11 @@ describe("json form", () => {
|
|||||||
properties: {
|
properties: {
|
||||||
nested: {
|
nested: {
|
||||||
type: "object",
|
type: "object",
|
||||||
properties: { property: { type: "string" } }
|
properties: { property: { type: "string" } },
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
false
|
},
|
||||||
|
},
|
||||||
|
false,
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
"#/nested/property",
|
"#/nested/property",
|
||||||
@@ -93,12 +93,12 @@ describe("json form", () => {
|
|||||||
nested: {
|
nested: {
|
||||||
type: "object",
|
type: "object",
|
||||||
required: ["property"],
|
required: ["property"],
|
||||||
properties: { property: { type: "string" } }
|
properties: { property: { type: "string" } },
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
true
|
},
|
||||||
]
|
},
|
||||||
|
true,
|
||||||
|
],
|
||||||
] satisfies [string, Exclude<JSONSchema, boolean>, boolean][];
|
] satisfies [string, Exclude<JSONSchema, boolean>, boolean][];
|
||||||
|
|
||||||
for (const [pointer, schema, output] of examples) {
|
for (const [pointer, schema, output] of examples) {
|
||||||
@@ -113,7 +113,7 @@ describe("json form", () => {
|
|||||||
["tags", "0", "0.tags"],
|
["tags", "0", "0.tags"],
|
||||||
["tags", 0, "0.tags"],
|
["tags", 0, "0.tags"],
|
||||||
["nested.property", "prefix", "prefix.nested.property"],
|
["nested.property", "prefix", "prefix.nested.property"],
|
||||||
["nested.property", "", "nested.property"]
|
["nested.property", "", "nested.property"],
|
||||||
] satisfies [string, any, string][];
|
] satisfies [string, any, string][];
|
||||||
|
|
||||||
for (const [path, prefix, output] of examples) {
|
for (const [path, prefix, output] of examples) {
|
||||||
@@ -128,7 +128,7 @@ describe("json form", () => {
|
|||||||
["tags", "0", "tags.0"],
|
["tags", "0", "tags.0"],
|
||||||
["tags", 0, "tags.0"],
|
["tags", 0, "tags.0"],
|
||||||
["nested.property", "suffix", "nested.property.suffix"],
|
["nested.property", "suffix", "nested.property.suffix"],
|
||||||
["nested.property", "", "nested.property"]
|
["nested.property", "", "nested.property"],
|
||||||
] satisfies [string, any, string][];
|
] satisfies [string, any, string][];
|
||||||
|
|
||||||
for (const [path, suffix, output] of examples) {
|
for (const [path, suffix, output] of examples) {
|
||||||
|
|||||||
@@ -19,11 +19,11 @@ const baseOptions: Partial<Omit<esbuild.BuildOptions, "plugins">> & { plugins?:
|
|||||||
format: "esm",
|
format: "esm",
|
||||||
drop: ["console", "debugger"],
|
drop: ["console", "debugger"],
|
||||||
loader: {
|
loader: {
|
||||||
".svg": "dataurl"
|
".svg": "dataurl",
|
||||||
},
|
},
|
||||||
define: {
|
define: {
|
||||||
__isDev: "0"
|
__isDev: "0",
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@@ -40,7 +40,7 @@ const builds: Record<string, BuildFn> = {
|
|||||||
"src/core/index.ts",
|
"src/core/index.ts",
|
||||||
"src/core/utils/index.ts",
|
"src/core/utils/index.ts",
|
||||||
"src/ui/index.ts",
|
"src/ui/index.ts",
|
||||||
"src/ui/main.css"
|
"src/ui/main.css",
|
||||||
],
|
],
|
||||||
outdir: "dist",
|
outdir: "dist",
|
||||||
outExtension: { ".js": format === "esm" ? ".js" : ".cjs" },
|
outExtension: { ".js": format === "esm" ? ".js" : ".cjs" },
|
||||||
@@ -49,7 +49,7 @@ const builds: Record<string, BuildFn> = {
|
|||||||
bundle: true,
|
bundle: true,
|
||||||
plugins: [postcss()],
|
plugins: [postcss()],
|
||||||
//target: "es2022",
|
//target: "es2022",
|
||||||
format
|
format,
|
||||||
}),
|
}),
|
||||||
/*components: (format = "esm") => ({
|
/*components: (format = "esm") => ({
|
||||||
...baseOptions,
|
...baseOptions,
|
||||||
@@ -84,11 +84,11 @@ const builds: Record<string, BuildFn> = {
|
|||||||
format,
|
format,
|
||||||
loader: {
|
loader: {
|
||||||
".svg": "dataurl",
|
".svg": "dataurl",
|
||||||
".js": "jsx"
|
".js": "jsx",
|
||||||
},
|
},
|
||||||
define: {
|
define: {
|
||||||
__isDev: "0",
|
__isDev: "0",
|
||||||
"process.env.NODE_ENV": '"production"'
|
"process.env.NODE_ENV": '"production"',
|
||||||
},
|
},
|
||||||
chunkNames: "chunks/[name]-[hash]",
|
chunkNames: "chunks/[name]-[hash]",
|
||||||
plugins: [
|
plugins: [
|
||||||
@@ -100,7 +100,7 @@ const builds: Record<string, BuildFn> = {
|
|||||||
return {
|
return {
|
||||||
name,
|
name,
|
||||||
path: output,
|
path: output,
|
||||||
mime: guessMimeType(name)
|
mime: guessMimeType(name),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
for (const { output, meta } of info) {
|
for (const { output, meta } of info) {
|
||||||
@@ -113,9 +113,9 @@ const builds: Record<string, BuildFn> = {
|
|||||||
const manifest_file = "dist/static/manifest.json";
|
const manifest_file = "dist/static/manifest.json";
|
||||||
await Bun.write(manifest_file, JSON.stringify(manifest, null, 2));
|
await Bun.write(manifest_file, JSON.stringify(manifest, null, 2));
|
||||||
console.log(`Manifest written to ${manifest_file}`, manifest);
|
console.log(`Manifest written to ${manifest_file}`, manifest);
|
||||||
})
|
}),
|
||||||
]
|
],
|
||||||
})
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
function adapter(adapter: string, overrides: Partial<esbuild.BuildOptions> = {}): BuildOptions {
|
function adapter(adapter: string, overrides: Partial<esbuild.BuildOptions> = {}): BuildOptions {
|
||||||
@@ -135,12 +135,12 @@ function adapter(adapter: string, overrides: Partial<esbuild.BuildOptions> = {})
|
|||||||
"react*",
|
"react*",
|
||||||
"next*",
|
"next*",
|
||||||
"libsql",
|
"libsql",
|
||||||
"@libsql*"
|
"@libsql*",
|
||||||
],
|
],
|
||||||
splitting: false,
|
splitting: false,
|
||||||
treeShaking: true,
|
treeShaking: true,
|
||||||
bundle: true,
|
bundle: true,
|
||||||
...overrides
|
...overrides,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const adapters = [
|
const adapters = [
|
||||||
@@ -152,7 +152,7 @@ const adapters = [
|
|||||||
adapter("remix", { format: "cjs" }),
|
adapter("remix", { format: "cjs" }),
|
||||||
adapter("bun"),
|
adapter("bun"),
|
||||||
adapter("node", { platform: "node", format: "esm" }),
|
adapter("node", { platform: "node", format: "esm" }),
|
||||||
adapter("node", { platform: "node", format: "cjs" })
|
adapter("node", { platform: "node", format: "cjs" }),
|
||||||
];
|
];
|
||||||
|
|
||||||
const collect = [
|
const collect = [
|
||||||
@@ -161,7 +161,7 @@ const collect = [
|
|||||||
//builds.components(),
|
//builds.components(),
|
||||||
builds.backend("cjs"),
|
builds.backend("cjs"),
|
||||||
//builds.components("cjs"),
|
//builds.components("cjs"),
|
||||||
...adapters
|
...adapters,
|
||||||
];
|
];
|
||||||
|
|
||||||
if (watch) {
|
if (watch) {
|
||||||
@@ -172,7 +172,7 @@ if (watch) {
|
|||||||
} = {
|
} = {
|
||||||
timeout: undefined,
|
timeout: undefined,
|
||||||
cleanup: undefined,
|
cleanup: undefined,
|
||||||
building: undefined
|
building: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
async function rebuildTypes() {
|
async function rebuildTypes() {
|
||||||
@@ -190,9 +190,9 @@ if (watch) {
|
|||||||
onExit: () => {
|
onExit: () => {
|
||||||
_state.building = undefined;
|
_state.building = undefined;
|
||||||
console.log("Types rebuilt");
|
console.log("Types rebuilt");
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
@@ -209,9 +209,9 @@ if (watch) {
|
|||||||
console.log(`rebuilt ${name} with ${result.errors.length} errors`);
|
console.log(`rebuilt ${name} with ${result.errors.length} errors`);
|
||||||
rebuildTypes();
|
rebuildTypes();
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
});
|
});
|
||||||
ctx.watch();
|
ctx.watch();
|
||||||
}
|
}
|
||||||
@@ -235,9 +235,9 @@ if (watch) {
|
|||||||
const from = String(i).padStart(String(count).length);
|
const from = String(i).padStart(String(count).length);
|
||||||
console.log(`[${from}/${count}] built ${name} with ${errors} errors`);
|
console.log(`[${from}/${count}] built ${name} with ${errors} errors`);
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,7 +249,7 @@ if (watch) {
|
|||||||
Bun.spawn(["bun", "build:types"], {
|
Bun.spawn(["bun", "build:types"], {
|
||||||
onExit: () => {
|
onExit: () => {
|
||||||
console.log("Types rebuilt");
|
console.log("Types rebuilt");
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
40
app/build.ts
40
app/build.ts
@@ -27,9 +27,9 @@ function buildTypes() {
|
|||||||
onExit: () => {
|
onExit: () => {
|
||||||
console.log("Types aliased");
|
console.log("Types aliased");
|
||||||
types_running = false;
|
types_running = false;
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,11 +63,11 @@ async function buildApi() {
|
|||||||
splitting: false,
|
splitting: false,
|
||||||
treeshake: true,
|
treeshake: true,
|
||||||
loader: {
|
loader: {
|
||||||
".svg": "dataurl"
|
".svg": "dataurl",
|
||||||
},
|
},
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
delayTypes();
|
delayTypes();
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ async function buildUi() {
|
|||||||
"use-sync-external-store",
|
"use-sync-external-store",
|
||||||
/codemirror/,
|
/codemirror/,
|
||||||
"@xyflow/react",
|
"@xyflow/react",
|
||||||
"@mantine/core"
|
"@mantine/core",
|
||||||
],
|
],
|
||||||
metafile: true,
|
metafile: true,
|
||||||
platform: "browser",
|
platform: "browser",
|
||||||
@@ -99,14 +99,14 @@ async function buildUi() {
|
|||||||
bundle: true,
|
bundle: true,
|
||||||
treeshake: true,
|
treeshake: true,
|
||||||
loader: {
|
loader: {
|
||||||
".svg": "dataurl"
|
".svg": "dataurl",
|
||||||
},
|
},
|
||||||
esbuildOptions: (options) => {
|
esbuildOptions: (options) => {
|
||||||
options.logLevel = "silent";
|
options.logLevel = "silent";
|
||||||
},
|
},
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
delayTypes();
|
delayTypes();
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +128,7 @@ async function buildUiElements() {
|
|||||||
"react-dom",
|
"react-dom",
|
||||||
"react/jsx-runtime",
|
"react/jsx-runtime",
|
||||||
"react/jsx-dev-runtime",
|
"react/jsx-dev-runtime",
|
||||||
"use-sync-external-store"
|
"use-sync-external-store",
|
||||||
],
|
],
|
||||||
metafile: true,
|
metafile: true,
|
||||||
platform: "browser",
|
platform: "browser",
|
||||||
@@ -137,12 +137,12 @@ async function buildUiElements() {
|
|||||||
bundle: true,
|
bundle: true,
|
||||||
treeshake: true,
|
treeshake: true,
|
||||||
loader: {
|
loader: {
|
||||||
".svg": "dataurl"
|
".svg": "dataurl",
|
||||||
},
|
},
|
||||||
esbuildOptions: (options) => {
|
esbuildOptions: (options) => {
|
||||||
options.alias = {
|
options.alias = {
|
||||||
// not important for elements, mock to reduce bundle
|
// not important for elements, mock to reduce bundle
|
||||||
"tailwind-merge": "./src/ui/elements/mocks/tailwind-merge.ts"
|
"tailwind-merge": "./src/ui/elements/mocks/tailwind-merge.ts",
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
onSuccess: async () => {
|
onSuccess: async () => {
|
||||||
@@ -152,7 +152,7 @@ async function buildUiElements() {
|
|||||||
await Bun.write(path, bundle.replaceAll("ui/client", "bknd/client"));
|
await Bun.write(path, bundle.replaceAll("ui/client", "bknd/client"));
|
||||||
|
|
||||||
delayTypes();
|
delayTypes();
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,15 +176,15 @@ function baseConfig(adapter: string, overrides: Partial<tsup.Options> = {}): tsu
|
|||||||
...overrides,
|
...overrides,
|
||||||
define: {
|
define: {
|
||||||
__isDev: "0",
|
__isDev: "0",
|
||||||
...overrides.define
|
...overrides.define,
|
||||||
},
|
},
|
||||||
external: [
|
external: [
|
||||||
/^cloudflare*/,
|
/^cloudflare*/,
|
||||||
/^@?(hono|libsql).*?/,
|
/^@?(hono|libsql).*?/,
|
||||||
/^(bknd|react|next|node).*?/,
|
/^(bknd|react|next|node).*?/,
|
||||||
/.*\.(html)$/,
|
/.*\.(html)$/,
|
||||||
...(Array.isArray(overrides.external) ? overrides.external : [])
|
...(Array.isArray(overrides.external) ? overrides.external : []),
|
||||||
]
|
],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +193,7 @@ async function buildAdapters() {
|
|||||||
await tsup.build({
|
await tsup.build({
|
||||||
...baseConfig(""),
|
...baseConfig(""),
|
||||||
entry: ["src/adapter/index.ts"],
|
entry: ["src/adapter/index.ts"],
|
||||||
outDir: "dist/adapter"
|
outDir: "dist/adapter",
|
||||||
});
|
});
|
||||||
|
|
||||||
// specific adatpers
|
// specific adatpers
|
||||||
@@ -202,23 +202,23 @@ async function buildAdapters() {
|
|||||||
await tsup.build(baseConfig("astro"));
|
await tsup.build(baseConfig("astro"));
|
||||||
await tsup.build(
|
await tsup.build(
|
||||||
baseConfig("cloudflare", {
|
baseConfig("cloudflare", {
|
||||||
external: [/^kysely/]
|
external: [/^kysely/],
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
await tsup.build({
|
await tsup.build({
|
||||||
...baseConfig("vite"),
|
...baseConfig("vite"),
|
||||||
platform: "node"
|
platform: "node",
|
||||||
});
|
});
|
||||||
|
|
||||||
await tsup.build({
|
await tsup.build({
|
||||||
...baseConfig("nextjs"),
|
...baseConfig("nextjs"),
|
||||||
platform: "node"
|
platform: "node",
|
||||||
});
|
});
|
||||||
|
|
||||||
await tsup.build({
|
await tsup.build({
|
||||||
...baseConfig("node"),
|
...baseConfig("node"),
|
||||||
platform: "node"
|
platform: "node",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ export const entryOutputMeta = (
|
|||||||
outputs: {
|
outputs: {
|
||||||
output: string;
|
output: string;
|
||||||
meta: Metafile["outputs"][string];
|
meta: Metafile["outputs"][string];
|
||||||
}[]
|
}[],
|
||||||
) => void | Promise<void>
|
) => void | Promise<void>,
|
||||||
): Plugin => ({
|
): Plugin => ({
|
||||||
name: "report-entry-output-plugin",
|
name: "report-entry-output-plugin",
|
||||||
setup(build) {
|
setup(build) {
|
||||||
@@ -29,5 +29,5 @@ export const entryOutputMeta = (
|
|||||||
await onComplete?.(outputs);
|
await onComplete?.(outputs);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ export default {
|
|||||||
"mantine-breakpoint-sm": "48em",
|
"mantine-breakpoint-sm": "48em",
|
||||||
"mantine-breakpoint-md": "62em",
|
"mantine-breakpoint-md": "62em",
|
||||||
"mantine-breakpoint-lg": "75em",
|
"mantine-breakpoint-lg": "75em",
|
||||||
"mantine-breakpoint-xl": "88em"
|
"mantine-breakpoint-xl": "88em",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ export class Api {
|
|||||||
return {
|
return {
|
||||||
token: this.token,
|
token: this.token,
|
||||||
user: this.user,
|
user: this.user,
|
||||||
verified: this.verified
|
verified: this.verified,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +198,7 @@ export class Api {
|
|||||||
token: this.token,
|
token: this.token,
|
||||||
headers: this.options.headers,
|
headers: this.options.headers,
|
||||||
token_transport: this.token_transport,
|
token_transport: this.token_transport,
|
||||||
verbose: this.options.verbose
|
verbose: this.options.verbose,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -211,9 +211,9 @@ export class Api {
|
|||||||
this.auth = new AuthApi(
|
this.auth = new AuthApi(
|
||||||
{
|
{
|
||||||
...baseParams,
|
...baseParams,
|
||||||
onTokenUpdate: (token) => this.updateToken(token, true)
|
onTokenUpdate: (token) => this.updateToken(token, true),
|
||||||
},
|
},
|
||||||
fetcher
|
fetcher,
|
||||||
);
|
);
|
||||||
this.media = new MediaApi(baseParams, fetcher);
|
this.media = new MediaApi(baseParams, fetcher);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
type ModuleBuildContext,
|
type ModuleBuildContext,
|
||||||
ModuleManager,
|
ModuleManager,
|
||||||
type ModuleManagerOptions,
|
type ModuleManagerOptions,
|
||||||
type Modules
|
type Modules,
|
||||||
} from "modules/ModuleManager";
|
} from "modules/ModuleManager";
|
||||||
import * as SystemPermissions from "modules/permissions";
|
import * as SystemPermissions from "modules/permissions";
|
||||||
import { AdminController, type AdminControllerOptions } from "modules/server/AdminController";
|
import { AdminController, type AdminControllerOptions } from "modules/server/AdminController";
|
||||||
@@ -61,7 +61,7 @@ export class App {
|
|||||||
constructor(
|
constructor(
|
||||||
private connection: Connection,
|
private connection: Connection,
|
||||||
_initialConfig?: InitialModuleConfigs,
|
_initialConfig?: InitialModuleConfigs,
|
||||||
private options?: AppOptions
|
private options?: AppOptions,
|
||||||
) {
|
) {
|
||||||
this.plugins = options?.plugins ?? [];
|
this.plugins = options?.plugins ?? [];
|
||||||
this.modules = new ModuleManager(connection, {
|
this.modules = new ModuleManager(connection, {
|
||||||
@@ -91,7 +91,7 @@ export class App {
|
|||||||
c.set("app", this);
|
c.set("app", this);
|
||||||
await next();
|
await next();
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
this.modules.ctx().emgr.registerEvents(AppEvents);
|
this.modules.ctx().emgr.registerEvents(AppEvents);
|
||||||
}
|
}
|
||||||
@@ -148,8 +148,8 @@ export class App {
|
|||||||
{
|
{
|
||||||
get: (_, module: keyof Modules) => {
|
get: (_, module: keyof Modules) => {
|
||||||
return this.modules.get(module);
|
return this.modules.get(module);
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
) as Modules;
|
) as Modules;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +203,7 @@ export function createApp(config: CreateAppConfig = {}) {
|
|||||||
} else if (typeof config.connection === "object") {
|
} else if (typeof config.connection === "object") {
|
||||||
if ("type" in config.connection) {
|
if ("type" in config.connection) {
|
||||||
$console.warn(
|
$console.warn(
|
||||||
"Using deprecated connection type 'libsql', use the 'config' object directly."
|
"Using deprecated connection type 'libsql', use the 'config' object directly.",
|
||||||
);
|
);
|
||||||
connection = new LibsqlConnection(config.connection.config);
|
connection = new LibsqlConnection(config.connection.config);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export type Options = {
|
|||||||
export async function getApi(Astro: TAstro, options: Options = { mode: "static" }) {
|
export async function getApi(Astro: TAstro, options: Options = { mode: "static" }) {
|
||||||
const api = new Api({
|
const api = new Api({
|
||||||
host: new URL(Astro.request.url).origin,
|
host: new URL(Astro.request.url).origin,
|
||||||
headers: options.mode === "dynamic" ? Astro.request.headers : undefined
|
headers: options.mode === "dynamic" ? Astro.request.headers : undefined,
|
||||||
});
|
});
|
||||||
await api.verifyAuth();
|
await api.verifyAuth();
|
||||||
return api;
|
return api;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export async function createApp({ distPath, ...config }: RuntimeBkndConfig = {})
|
|||||||
registerLocalMediaAdapter();
|
registerLocalMediaAdapter();
|
||||||
app = await createRuntimeApp({
|
app = await createRuntimeApp({
|
||||||
...config,
|
...config,
|
||||||
serveStatic: serveStatic({ root })
|
serveStatic: serveStatic({ root }),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,10 +46,10 @@ export function serve({
|
|||||||
options,
|
options,
|
||||||
onBuilt,
|
onBuilt,
|
||||||
buildConfig,
|
buildConfig,
|
||||||
distPath
|
distPath,
|
||||||
});
|
});
|
||||||
return app.fetch(request);
|
return app.fetch(request);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`Server is running on http://localhost:${port}`);
|
console.log(`Server is running on http://localhost:${port}`);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export type D1ConnectionConfig = {
|
|||||||
class CustomD1Dialect extends D1Dialect {
|
class CustomD1Dialect extends D1Dialect {
|
||||||
override createIntrospector(db: Kysely<any>): DatabaseIntrospector {
|
override createIntrospector(db: Kysely<any>): DatabaseIntrospector {
|
||||||
return new SqliteIntrospector(db, {
|
return new SqliteIntrospector(db, {
|
||||||
excludeTables: ["_cf_KV"]
|
excludeTables: ["_cf_KV"],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -23,7 +23,7 @@ export class D1Connection extends SqliteConnection {
|
|||||||
|
|
||||||
const kysely = new Kysely({
|
const kysely = new Kysely({
|
||||||
dialect: new CustomD1Dialect({ database: config.binding }),
|
dialect: new CustomD1Dialect({ database: config.binding }),
|
||||||
plugins
|
plugins,
|
||||||
});
|
});
|
||||||
super(kysely, {}, plugins);
|
super(kysely, {}, plugins);
|
||||||
}
|
}
|
||||||
@@ -37,7 +37,7 @@ export class D1Connection extends SqliteConnection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override async batch<Queries extends QB[]>(
|
protected override async batch<Queries extends QB[]>(
|
||||||
queries: [...Queries]
|
queries: [...Queries],
|
||||||
): Promise<{
|
): Promise<{
|
||||||
[K in keyof Queries]: Awaited<ReturnType<Queries[K]["execute"]>>;
|
[K in keyof Queries]: Awaited<ReturnType<Queries[K]["execute"]>>;
|
||||||
}> {
|
}> {
|
||||||
@@ -47,7 +47,7 @@ export class D1Connection extends SqliteConnection {
|
|||||||
queries.map((q) => {
|
queries.map((q) => {
|
||||||
const { sql, parameters } = q.compile();
|
const { sql, parameters } = q.compile();
|
||||||
return db.prepare(sql).bind(...parameters);
|
return db.prepare(sql).bind(...parameters);
|
||||||
})
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
// let it run through plugins
|
// let it run through plugins
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import { getBindings } from "./bindings";
|
|||||||
export function makeSchema(bindings: string[] = []) {
|
export function makeSchema(bindings: string[] = []) {
|
||||||
return Type.Object(
|
return Type.Object(
|
||||||
{
|
{
|
||||||
binding: bindings.length > 0 ? StringEnum(bindings) : Type.Optional(Type.String())
|
binding: bindings.length > 0 ? StringEnum(bindings) : Type.Optional(Type.String()),
|
||||||
},
|
},
|
||||||
{ title: "R2", description: "Cloudflare R2 storage" }
|
{ title: "R2", description: "Cloudflare R2 storage" },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,10 +36,10 @@ export function registerMedia(env: Record<string, any>) {
|
|||||||
override toJSON() {
|
override toJSON() {
|
||||||
return {
|
return {
|
||||||
...super.toJSON(),
|
...super.toJSON(),
|
||||||
config: this.config
|
config: this.config,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,13 +67,13 @@ export class StorageR2Adapter implements StorageAdapter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
async listObjects(
|
async listObjects(
|
||||||
prefix?: string
|
prefix?: string,
|
||||||
): Promise<{ key: string; last_modified: Date; size: number }[]> {
|
): Promise<{ key: string; last_modified: Date; size: number }[]> {
|
||||||
const list = await this.bucket.list({ limit: 50 });
|
const list = await this.bucket.list({ limit: 50 });
|
||||||
return list.objects.map((item) => ({
|
return list.objects.map((item) => ({
|
||||||
key: item.key,
|
key: item.key,
|
||||||
size: item.size,
|
size: item.size,
|
||||||
last_modified: item.uploaded
|
last_modified: item.uploaded,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +89,7 @@ export class StorageR2Adapter implements StorageAdapter {
|
|||||||
let object: R2ObjectBody | null;
|
let object: R2ObjectBody | null;
|
||||||
const responseHeaders = new Headers({
|
const responseHeaders = new Headers({
|
||||||
"Accept-Ranges": "bytes",
|
"Accept-Ranges": "bytes",
|
||||||
"Content-Type": guess(key)
|
"Content-Type": guess(key),
|
||||||
});
|
});
|
||||||
|
|
||||||
//console.log("getObject:headers", headersToObject(headers));
|
//console.log("getObject:headers", headersToObject(headers));
|
||||||
@@ -98,7 +98,7 @@ export class StorageR2Adapter implements StorageAdapter {
|
|||||||
? {} // miniflare doesn't support range requests
|
? {} // miniflare doesn't support range requests
|
||||||
: {
|
: {
|
||||||
range: headers,
|
range: headers,
|
||||||
onlyIf: headers
|
onlyIf: headers,
|
||||||
};
|
};
|
||||||
object = (await this.bucket.get(key, options)) as R2ObjectBody;
|
object = (await this.bucket.get(key, options)) as R2ObjectBody;
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ export class StorageR2Adapter implements StorageAdapter {
|
|||||||
|
|
||||||
return new Response(object.body, {
|
return new Response(object.body, {
|
||||||
status: object.range ? 206 : 200,
|
status: object.range ? 206 : 200,
|
||||||
headers: responseHeaders
|
headers: responseHeaders,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,7 +139,7 @@ export class StorageR2Adapter implements StorageAdapter {
|
|||||||
if (!metadata || Object.keys(metadata).length === 0) {
|
if (!metadata || Object.keys(metadata).length === 0) {
|
||||||
// guessing is especially required for dev environment (miniflare)
|
// guessing is especially required for dev environment (miniflare)
|
||||||
metadata = {
|
metadata = {
|
||||||
contentType: guess(object.key)
|
contentType: guess(object.key),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +157,7 @@ export class StorageR2Adapter implements StorageAdapter {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
type: String(head.httpMetadata?.contentType ?? guess(key)),
|
type: String(head.httpMetadata?.contentType ?? guess(key)),
|
||||||
size: head.size
|
size: head.size,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,7 +172,7 @@ export class StorageR2Adapter implements StorageAdapter {
|
|||||||
toJSON(secrets?: boolean) {
|
toJSON(secrets?: boolean) {
|
||||||
return {
|
return {
|
||||||
type: this.getName(),
|
type: this.getName(),
|
||||||
config: {}
|
config: {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export function getBindings<T extends GetBindingType>(env: any, type: T): Bindin
|
|||||||
if (env[key] && (env[key] as any).constructor.name === type) {
|
if (env[key] && (env[key] as any).constructor.name === type) {
|
||||||
bindings.push({
|
bindings.push({
|
||||||
key,
|
key,
|
||||||
value: env[key] as BindingTypeMap[T]
|
value: env[key] as BindingTypeMap[T],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export function serve<Env = any>(config: CloudflareBkndConfig<Env> = {}) {
|
|||||||
hono.all("*", async (c, next) => {
|
hono.all("*", async (c, next) => {
|
||||||
const res = await serveStatic({
|
const res = await serveStatic({
|
||||||
path: `./${pathname}`,
|
path: `./${pathname}`,
|
||||||
manifest: config.manifest!
|
manifest: config.manifest!,
|
||||||
})(c as any, next);
|
})(c as any, next);
|
||||||
if (res instanceof Response) {
|
if (res instanceof Response) {
|
||||||
const ttl = 60 * 60 * 24 * 365;
|
const ttl = 60 * 60 * 24 * 365;
|
||||||
@@ -114,6 +114,6 @@ export function serve<Env = any>(config: CloudflareBkndConfig<Env> = {}) {
|
|||||||
default:
|
default:
|
||||||
throw new Error(`Unknown mode ${mode}`);
|
throw new Error(`Unknown mode ${mode}`);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export {
|
|||||||
getBindings,
|
getBindings,
|
||||||
type BindingTypeMap,
|
type BindingTypeMap,
|
||||||
type GetBindingType,
|
type GetBindingType,
|
||||||
type BindingMap
|
type BindingMap,
|
||||||
} from "./bindings";
|
} from "./bindings";
|
||||||
|
|
||||||
export function d1(config: D1ConnectionConfig) {
|
export function d1(config: D1ConnectionConfig) {
|
||||||
|
|||||||
@@ -31,13 +31,13 @@ export async function getCached(config: CloudflareBkndConfig, { env, ctx, ...arg
|
|||||||
async ({ params: { app } }) => {
|
async ({ params: { app } }) => {
|
||||||
saveConfig(app.toJSON(true));
|
saveConfig(app.toJSON(true));
|
||||||
},
|
},
|
||||||
"sync"
|
"sync",
|
||||||
);
|
);
|
||||||
await config.beforeBuild?.(app);
|
await config.beforeBuild?.(app);
|
||||||
},
|
},
|
||||||
adminOptions: { html: config.html }
|
adminOptions: { html: config.html },
|
||||||
},
|
},
|
||||||
{ env, ctx, ...args }
|
{ env, ctx, ...args },
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!cachedConfig) {
|
if (!cachedConfig) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export async function getDurable(config: CloudflareBkndConfig, ctx: Context) {
|
|||||||
config: create_config,
|
config: create_config,
|
||||||
html: config.html,
|
html: config.html,
|
||||||
keepAliveSeconds: config.keepAliveSeconds,
|
keepAliveSeconds: config.keepAliveSeconds,
|
||||||
setAdminHtml: config.setAdminHtml
|
setAdminHtml: config.setAdminHtml,
|
||||||
});
|
});
|
||||||
|
|
||||||
const headers = new Headers(res.headers);
|
const headers = new Headers(res.headers);
|
||||||
@@ -32,7 +32,7 @@ export async function getDurable(config: CloudflareBkndConfig, ctx: Context) {
|
|||||||
return new Response(res.body, {
|
return new Response(res.body, {
|
||||||
status: res.status,
|
status: res.status,
|
||||||
statusText: res.statusText,
|
statusText: res.statusText,
|
||||||
headers
|
headers,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,7 +48,7 @@ export class DurableBkndApp extends DurableObject {
|
|||||||
html?: string;
|
html?: string;
|
||||||
keepAliveSeconds?: number;
|
keepAliveSeconds?: number;
|
||||||
setAdminHtml?: boolean;
|
setAdminHtml?: boolean;
|
||||||
}
|
},
|
||||||
) {
|
) {
|
||||||
let buildtime = 0;
|
let buildtime = 0;
|
||||||
if (!this.app) {
|
if (!this.app) {
|
||||||
@@ -73,7 +73,7 @@ export class DurableBkndApp extends DurableObject {
|
|||||||
return c.json({
|
return c.json({
|
||||||
id: this.id,
|
id: this.id,
|
||||||
keepAliveSeconds: options?.keepAliveSeconds ?? 0,
|
keepAliveSeconds: options?.keepAliveSeconds ?? 0,
|
||||||
colo: context.colo
|
colo: context.colo,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ export class DurableBkndApp extends DurableObject {
|
|||||||
adminOptions: { html: options.html },
|
adminOptions: { html: options.html },
|
||||||
beforeBuild: async (app) => {
|
beforeBuild: async (app) => {
|
||||||
await this.beforeBuild(app);
|
await this.beforeBuild(app);
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
buildtime = performance.now() - start;
|
buildtime = performance.now() - start;
|
||||||
@@ -101,7 +101,7 @@ export class DurableBkndApp extends DurableObject {
|
|||||||
return new Response(res.body, {
|
return new Response(res.body, {
|
||||||
status: res.status,
|
status: res.status,
|
||||||
statusText: res.statusText,
|
statusText: res.statusText,
|
||||||
headers
|
headers,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ export async function makeApp(config: CloudflareBkndConfig, ctx: Context) {
|
|||||||
return await createRuntimeApp(
|
return await createRuntimeApp(
|
||||||
{
|
{
|
||||||
...makeCfConfig(config, ctx),
|
...makeCfConfig(config, ctx),
|
||||||
adminOptions: config.html ? { html: config.html } : undefined
|
adminOptions: config.html ? { html: config.html } : undefined,
|
||||||
},
|
},
|
||||||
ctx
|
ctx,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export function makeConfig<Args = any>(config: BkndConfig<Args>, args?: Args): C
|
|||||||
|
|
||||||
export async function createFrameworkApp<Args = any>(
|
export async function createFrameworkApp<Args = any>(
|
||||||
config: FrameworkBkndConfig,
|
config: FrameworkBkndConfig,
|
||||||
args?: Args
|
args?: Args,
|
||||||
): Promise<App> {
|
): Promise<App> {
|
||||||
const app = App.create(makeConfig(config, args));
|
const app = App.create(makeConfig(config, args));
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@ export async function createFrameworkApp<Args = any>(
|
|||||||
async () => {
|
async () => {
|
||||||
await config.onBuilt?.(app);
|
await config.onBuilt?.(app);
|
||||||
},
|
},
|
||||||
"sync"
|
"sync",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +63,7 @@ export async function createRuntimeApp<Env = any>(
|
|||||||
serveStatic?: MiddlewareHandler | [string, MiddlewareHandler];
|
serveStatic?: MiddlewareHandler | [string, MiddlewareHandler];
|
||||||
adminOptions?: AdminControllerOptions | false;
|
adminOptions?: AdminControllerOptions | false;
|
||||||
},
|
},
|
||||||
env?: Env
|
env?: Env,
|
||||||
): Promise<App> {
|
): Promise<App> {
|
||||||
const app = App.create(makeConfig(config, env));
|
const app = App.create(makeConfig(config, env));
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ export async function createRuntimeApp<Env = any>(
|
|||||||
app.registerAdminController(adminOptions);
|
app.registerAdminController(adminOptions);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sync"
|
"sync",
|
||||||
);
|
);
|
||||||
|
|
||||||
await config.beforeBuild?.(app);
|
await config.beforeBuild?.(app);
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export function createApi({ req }: GetServerSidePropsContext) {
|
|||||||
const request = nodeRequestToRequest(req);
|
const request = nodeRequestToRequest(req);
|
||||||
return new Api({
|
return new Api({
|
||||||
host: new URL(request.url).origin,
|
host: new URL(request.url).origin,
|
||||||
headers: request.headers
|
headers: request.headers,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,7 +40,7 @@ export function withApi<T>(handler: (ctx: GetServerSidePropsContext & { api: Api
|
|||||||
|
|
||||||
function getCleanRequest(
|
function getCleanRequest(
|
||||||
req: Request,
|
req: Request,
|
||||||
{ cleanSearch = ["route"] }: Pick<NextjsBkndConfig, "cleanSearch">
|
{ cleanSearch = ["route"] }: Pick<NextjsBkndConfig, "cleanSearch">,
|
||||||
) {
|
) {
|
||||||
const url = new URL(req.url);
|
const url = new URL(req.url);
|
||||||
cleanSearch?.forEach((k) => url.searchParams.delete(k));
|
cleanSearch?.forEach((k) => url.searchParams.delete(k));
|
||||||
@@ -48,7 +48,7 @@ function getCleanRequest(
|
|||||||
return new Request(url.toString(), {
|
return new Request(url.toString(), {
|
||||||
method: req.method,
|
method: req.method,
|
||||||
headers: req.headers,
|
headers: req.headers,
|
||||||
body: req.body
|
body: req.body,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { registries } from "bknd";
|
import { registries } from "bknd";
|
||||||
import {
|
import {
|
||||||
type LocalAdapterConfig,
|
type LocalAdapterConfig,
|
||||||
StorageLocalAdapter
|
StorageLocalAdapter,
|
||||||
} from "../../media/storage/adapters/StorageLocalAdapter";
|
} from "../../media/storage/adapters/StorageLocalAdapter";
|
||||||
|
|
||||||
export * from "./node.adapter";
|
export * from "./node.adapter";
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export function serve({
|
|||||||
}: NodeBkndConfig = {}) {
|
}: NodeBkndConfig = {}) {
|
||||||
const root = path.relative(
|
const root = path.relative(
|
||||||
process.cwd(),
|
process.cwd(),
|
||||||
path.resolve(distPath ?? relativeDistPath ?? "./node_modules/bknd/dist", "static")
|
path.resolve(distPath ?? relativeDistPath ?? "./node_modules/bknd/dist", "static"),
|
||||||
);
|
);
|
||||||
if (relativeDistPath) {
|
if (relativeDistPath) {
|
||||||
console.warn("relativeDistPath is deprecated, please use distPath instead");
|
console.warn("relativeDistPath is deprecated, please use distPath instead");
|
||||||
@@ -41,16 +41,16 @@ export function serve({
|
|||||||
registerLocalMediaAdapter();
|
registerLocalMediaAdapter();
|
||||||
app = await createRuntimeApp({
|
app = await createRuntimeApp({
|
||||||
...config,
|
...config,
|
||||||
serveStatic: serveStatic({ root })
|
serveStatic: serveStatic({ root }),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return app.fetch(req);
|
return app.fetch(req);
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
(connInfo) => {
|
(connInfo) => {
|
||||||
console.log(`Server is running on http://localhost:${connInfo.port}`);
|
console.log(`Server is running on http://localhost:${connInfo.port}`);
|
||||||
listener?.(connInfo);
|
listener?.(connInfo);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export async function getApp(config: RemixBkndConfig, args?: RemixContext) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function serve<Args extends RemixContext = RemixContext>(
|
export function serve<Args extends RemixContext = RemixContext>(
|
||||||
config: RemixBkndConfig<Args> = {}
|
config: RemixBkndConfig<Args> = {},
|
||||||
) {
|
) {
|
||||||
return async (args: Args) => {
|
return async (args: Args) => {
|
||||||
app = await createFrameworkApp(config, args);
|
app = await createFrameworkApp(config, args);
|
||||||
|
|||||||
@@ -20,6 +20,6 @@ export function nodeRequestToRequest(req: IncomingMessage): Request {
|
|||||||
const method = req.method || "GET";
|
const method = req.method || "GET";
|
||||||
return new Request(url, {
|
return new Request(url, {
|
||||||
method,
|
method,
|
||||||
headers
|
headers,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export const devServerConfig = {
|
|||||||
/^\/@.+$/,
|
/^\/@.+$/,
|
||||||
/\/components.*?\.json.*/, // @todo: improve
|
/\/components.*?\.json.*/, // @todo: improve
|
||||||
/^\/(public|assets|static)\/.+/,
|
/^\/(public|assets|static)\/.+/,
|
||||||
/^\/node_modules\/.*/
|
/^\/node_modules\/.*/,
|
||||||
] as any,
|
] as any,
|
||||||
injectClientScript: false
|
injectClientScript: false,
|
||||||
} as const;
|
} as const;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ window.__vite_plugin_react_preamble_installed__ = true
|
|||||||
</script>
|
</script>
|
||||||
<script type="module" src="/@vite/client"></script>
|
<script type="module" src="/@vite/client"></script>
|
||||||
${addBkndContext ? "<!-- BKND_CONTEXT -->" : ""}
|
${addBkndContext ? "<!-- BKND_CONTEXT -->" : ""}
|
||||||
</head>`
|
</head>`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,12 +39,12 @@ async function createApp(config: ViteBkndConfig = {}, env?: any) {
|
|||||||
: {
|
: {
|
||||||
html: config.html,
|
html: config.html,
|
||||||
forceDev: config.forceDev ?? {
|
forceDev: config.forceDev ?? {
|
||||||
mainPath: "/src/main.tsx"
|
mainPath: "/src/main.tsx",
|
||||||
}
|
|
||||||
},
|
},
|
||||||
serveStatic: ["/assets/*", serveStatic({ root: config.distPath ?? "./" })]
|
|
||||||
},
|
},
|
||||||
env
|
serveStatic: ["/assets/*", serveStatic({ root: config.distPath ?? "./" })],
|
||||||
|
},
|
||||||
|
env,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +53,7 @@ export function serveFresh(config: Omit<ViteBkndConfig, "mode"> = {}) {
|
|||||||
async fetch(request: Request, env: any, ctx: ExecutionContext) {
|
async fetch(request: Request, env: any, ctx: ExecutionContext) {
|
||||||
const app = await createApp(config, env);
|
const app = await createApp(config, env);
|
||||||
return app.fetch(request, env, ctx);
|
return app.fetch(request, env, ctx);
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ export function serveCached(config: Omit<ViteBkndConfig, "mode"> = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return app.fetch(request, env, ctx);
|
return app.fetch(request, env, ctx);
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,6 +77,6 @@ export function serve({ mode, ...config }: ViteBkndConfig = {}) {
|
|||||||
export function devServer(options: DevServerOptions) {
|
export function devServer(options: DevServerOptions) {
|
||||||
return honoViteDevServer({
|
return honoViteDevServer({
|
||||||
...devServerConfig,
|
...devServerConfig,
|
||||||
...options
|
...options,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
Authenticator,
|
Authenticator,
|
||||||
type ProfileExchange,
|
type ProfileExchange,
|
||||||
Role,
|
Role,
|
||||||
type Strategy
|
type Strategy,
|
||||||
} from "auth";
|
} from "auth";
|
||||||
import type { PasswordStrategy } from "auth/authenticate/strategies";
|
import type { PasswordStrategy } from "auth/authenticate/strategies";
|
||||||
import { type DB, Exception, type PrimaryFieldType } from "core";
|
import { type DB, Exception, type PrimaryFieldType } from "core";
|
||||||
@@ -68,15 +68,15 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Could not build strategy ${String(
|
`Could not build strategy ${String(
|
||||||
name
|
name,
|
||||||
)} with config ${JSON.stringify(strategy.config)}`
|
)} with config ${JSON.stringify(strategy.config)}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this._authenticator = new Authenticator(strategies, this.resolveUser.bind(this), {
|
this._authenticator = new Authenticator(strategies, this.resolveUser.bind(this), {
|
||||||
jwt: this.config.jwt,
|
jwt: this.config.jwt,
|
||||||
cookie: this.config.cookie
|
cookie: this.config.cookie,
|
||||||
});
|
});
|
||||||
|
|
||||||
this.registerEntities();
|
this.registerEntities();
|
||||||
@@ -117,7 +117,7 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
|||||||
action: AuthAction,
|
action: AuthAction,
|
||||||
strategy: Strategy,
|
strategy: Strategy,
|
||||||
identifier: string,
|
identifier: string,
|
||||||
profile: ProfileExchange
|
profile: ProfileExchange,
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
if (!this.config.allow_register && action === "register") {
|
if (!this.config.allow_register && action === "register") {
|
||||||
throw new Exception("Registration is not allowed", 403);
|
throw new Exception("Registration is not allowed", 403);
|
||||||
@@ -127,7 +127,7 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
|||||||
.getFillableFields("create")
|
.getFillableFields("create")
|
||||||
.map((f) => f.name);
|
.map((f) => f.name);
|
||||||
const filteredProfile = Object.fromEntries(
|
const filteredProfile = Object.fromEntries(
|
||||||
Object.entries(profile).filter(([key]) => fields.includes(key))
|
Object.entries(profile).filter(([key]) => fields.includes(key)),
|
||||||
);
|
);
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
@@ -190,7 +190,7 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
|||||||
const payload: any = {
|
const payload: any = {
|
||||||
...profile,
|
...profile,
|
||||||
strategy: strategy.getName(),
|
strategy: strategy.getName(),
|
||||||
strategy_value: identifier
|
strategy_value: identifier,
|
||||||
};
|
};
|
||||||
|
|
||||||
const mutator = this.em.mutator(users);
|
const mutator = this.em.mutator(users);
|
||||||
@@ -240,13 +240,13 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
|||||||
email: text().required(),
|
email: text().required(),
|
||||||
strategy: text({
|
strategy: text({
|
||||||
fillable: ["create"],
|
fillable: ["create"],
|
||||||
hidden: ["update", "form"]
|
hidden: ["update", "form"],
|
||||||
}).required(),
|
}).required(),
|
||||||
strategy_value: text({
|
strategy_value: text({
|
||||||
fillable: ["create"],
|
fillable: ["create"],
|
||||||
hidden: ["read", "table", "update", "form"]
|
hidden: ["read", "table", "update", "form"],
|
||||||
}).required(),
|
}).required(),
|
||||||
role: text()
|
role: text(),
|
||||||
};
|
};
|
||||||
|
|
||||||
registerEntities() {
|
registerEntities() {
|
||||||
@@ -254,12 +254,12 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
|||||||
this.ensureSchema(
|
this.ensureSchema(
|
||||||
em(
|
em(
|
||||||
{
|
{
|
||||||
[users.name as "users"]: users
|
[users.name as "users"]: users,
|
||||||
},
|
},
|
||||||
({ index }, { users }) => {
|
({ index }, { users }) => {
|
||||||
index(users).on(["email"], true).on(["strategy"]).on(["strategy_value"]);
|
index(users).on(["email"], true).on(["strategy"]).on(["strategy_value"]);
|
||||||
}
|
},
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -288,7 +288,7 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
|||||||
...(additional as any),
|
...(additional as any),
|
||||||
email,
|
email,
|
||||||
strategy,
|
strategy,
|
||||||
strategy_value
|
strategy_value,
|
||||||
});
|
});
|
||||||
mutator.__unstable_toggleSystemEntityCreation(true);
|
mutator.__unstable_toggleSystemEntityCreation(true);
|
||||||
return created;
|
return created;
|
||||||
@@ -307,8 +307,8 @@ export class AppAuth extends Module<typeof authConfigSchema> {
|
|||||||
strategies: transformObject(strategies, (strategy) => ({
|
strategies: transformObject(strategies, (strategy) => ({
|
||||||
enabled: this.isStrategyEnabled(strategy),
|
enabled: this.isStrategyEnabled(strategy),
|
||||||
type: strategy.getType(),
|
type: strategy.getType(),
|
||||||
config: strategy.toJSON(secrets)
|
config: strategy.toJSON(secrets),
|
||||||
}))
|
})),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,13 +10,13 @@ export type AuthApiOptions = BaseModuleApiOptions & {
|
|||||||
export class AuthApi extends ModuleApi<AuthApiOptions> {
|
export class AuthApi extends ModuleApi<AuthApiOptions> {
|
||||||
protected override getDefaultOptions(): Partial<AuthApiOptions> {
|
protected override getDefaultOptions(): Partial<AuthApiOptions> {
|
||||||
return {
|
return {
|
||||||
basepath: "/api/auth"
|
basepath: "/api/auth",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async login(strategy: string, input: any) {
|
async login(strategy: string, input: any) {
|
||||||
const res = await this.post<AuthResponse>([strategy, "login"], input, {
|
const res = await this.post<AuthResponse>([strategy, "login"], input, {
|
||||||
credentials: "include"
|
credentials: "include",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.ok && res.body.token) {
|
if (res.ok && res.body.token) {
|
||||||
@@ -27,7 +27,7 @@ export class AuthApi extends ModuleApi<AuthApiOptions> {
|
|||||||
|
|
||||||
async register(strategy: string, input: any) {
|
async register(strategy: string, input: any) {
|
||||||
const res = await this.post<AuthResponse>([strategy, "register"], input, {
|
const res = await this.post<AuthResponse>([strategy, "register"], input, {
|
||||||
credentials: "include"
|
credentials: "include",
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.ok && res.body.token) {
|
if (res.ok && res.body.token) {
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export class AuthController extends Controller {
|
|||||||
try {
|
try {
|
||||||
const body = await this.auth.authenticator.getBody(c);
|
const body = await this.auth.authenticator.getBody(c);
|
||||||
const valid = parse(create.schema, body, {
|
const valid = parse(create.schema, body, {
|
||||||
skipMark: true
|
skipMark: true,
|
||||||
});
|
});
|
||||||
const processed = (await create.preprocess?.(valid)) ?? valid;
|
const processed = (await create.preprocess?.(valid)) ?? valid;
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ export class AuthController extends Controller {
|
|||||||
mutator.__unstable_toggleSystemEntityCreation(false);
|
mutator.__unstable_toggleSystemEntityCreation(false);
|
||||||
const { data: created } = await mutator.insertOne({
|
const { data: created } = await mutator.insertOne({
|
||||||
...processed,
|
...processed,
|
||||||
strategy: name
|
strategy: name,
|
||||||
});
|
});
|
||||||
mutator.__unstable_toggleSystemEntityCreation(true);
|
mutator.__unstable_toggleSystemEntityCreation(true);
|
||||||
|
|
||||||
@@ -75,21 +75,21 @@ export class AuthController extends Controller {
|
|||||||
success: true,
|
success: true,
|
||||||
action: "create",
|
action: "create",
|
||||||
strategy: name,
|
strategy: name,
|
||||||
data: created as unknown as SafeUser
|
data: created as unknown as SafeUser,
|
||||||
} as AuthActionResponse);
|
} as AuthActionResponse);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof TypeInvalidError) {
|
if (e instanceof TypeInvalidError) {
|
||||||
return c.json(
|
return c.json(
|
||||||
{
|
{
|
||||||
success: false,
|
success: false,
|
||||||
errors: e.errors
|
errors: e.errors,
|
||||||
},
|
},
|
||||||
400
|
400,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
hono.get("create/schema.json", async (c) => {
|
hono.get("create/schema.json", async (c) => {
|
||||||
return c.json(create.schema);
|
return c.json(create.schema);
|
||||||
@@ -147,12 +147,12 @@ export class AuthController extends Controller {
|
|||||||
strategies: transformObject(strategies ?? {}, (strategy, name) => {
|
strategies: transformObject(strategies ?? {}, (strategy, name) => {
|
||||||
return this.auth.isStrategyEnabled(name) ? strategy : undefined;
|
return this.auth.isStrategyEnabled(name) ? strategy : undefined;
|
||||||
}),
|
}),
|
||||||
basepath
|
basepath,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.json({ strategies, basepath });
|
return c.json({ strategies, basepath });
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
return hono.all("*", (c) => c.notFound());
|
return hono.all("*", (c) => c.notFound());
|
||||||
|
|||||||
@@ -5,16 +5,16 @@ import { type Static, StringRecord, Type, objectTransform } from "core/utils";
|
|||||||
export const Strategies = {
|
export const Strategies = {
|
||||||
password: {
|
password: {
|
||||||
cls: PasswordStrategy,
|
cls: PasswordStrategy,
|
||||||
schema: PasswordStrategy.prototype.getSchema()
|
schema: PasswordStrategy.prototype.getSchema(),
|
||||||
},
|
},
|
||||||
oauth: {
|
oauth: {
|
||||||
cls: OAuthStrategy,
|
cls: OAuthStrategy,
|
||||||
schema: OAuthStrategy.prototype.getSchema()
|
schema: OAuthStrategy.prototype.getSchema(),
|
||||||
},
|
},
|
||||||
custom_oauth: {
|
custom_oauth: {
|
||||||
cls: CustomOAuthStrategy,
|
cls: CustomOAuthStrategy,
|
||||||
schema: CustomOAuthStrategy.prototype.getSchema()
|
schema: CustomOAuthStrategy.prototype.getSchema(),
|
||||||
}
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export const STRATEGIES = Strategies;
|
export const STRATEGIES = Strategies;
|
||||||
@@ -23,12 +23,12 @@ const strategiesSchemaObject = objectTransform(STRATEGIES, (strategy, name) => {
|
|||||||
{
|
{
|
||||||
enabled: Type.Optional(Type.Boolean({ default: true })),
|
enabled: Type.Optional(Type.Boolean({ default: true })),
|
||||||
type: Type.Const(name, { default: name, readOnly: true }),
|
type: Type.Const(name, { default: name, readOnly: true }),
|
||||||
config: strategy.schema
|
config: strategy.schema,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: name,
|
title: name,
|
||||||
additionalProperties: false
|
additionalProperties: false,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
const strategiesSchema = Type.Union(Object.values(strategiesSchemaObject));
|
const strategiesSchema = Type.Union(Object.values(strategiesSchemaObject));
|
||||||
@@ -37,15 +37,15 @@ export type AppAuthOAuthStrategy = Static<typeof STRATEGIES.oauth.schema>;
|
|||||||
export type AppAuthCustomOAuthStrategy = Static<typeof STRATEGIES.custom_oauth.schema>;
|
export type AppAuthCustomOAuthStrategy = Static<typeof STRATEGIES.custom_oauth.schema>;
|
||||||
|
|
||||||
const guardConfigSchema = Type.Object({
|
const guardConfigSchema = Type.Object({
|
||||||
enabled: Type.Optional(Type.Boolean({ default: false }))
|
enabled: Type.Optional(Type.Boolean({ default: false })),
|
||||||
});
|
});
|
||||||
export const guardRoleSchema = Type.Object(
|
export const guardRoleSchema = Type.Object(
|
||||||
{
|
{
|
||||||
permissions: Type.Optional(Type.Array(Type.String())),
|
permissions: Type.Optional(Type.Array(Type.String())),
|
||||||
is_default: Type.Optional(Type.Boolean()),
|
is_default: Type.Optional(Type.Boolean()),
|
||||||
implicit_allow: Type.Optional(Type.Boolean())
|
implicit_allow: Type.Optional(Type.Boolean()),
|
||||||
},
|
},
|
||||||
{ additionalProperties: false }
|
{ additionalProperties: false },
|
||||||
);
|
);
|
||||||
|
|
||||||
export const authConfigSchema = Type.Object(
|
export const authConfigSchema = Type.Object(
|
||||||
@@ -64,19 +64,19 @@ export const authConfigSchema = Type.Object(
|
|||||||
type: "password",
|
type: "password",
|
||||||
enabled: true,
|
enabled: true,
|
||||||
config: {
|
config: {
|
||||||
hashing: "sha256"
|
hashing: "sha256",
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
})
|
}),
|
||||||
),
|
),
|
||||||
guard: Type.Optional(guardConfigSchema),
|
guard: Type.Optional(guardConfigSchema),
|
||||||
roles: Type.Optional(StringRecord(guardRoleSchema, { default: {} }))
|
roles: Type.Optional(StringRecord(guardRoleSchema, { default: {} })),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "Authentication",
|
title: "Authentication",
|
||||||
additionalProperties: false
|
additionalProperties: false,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export type AppAuthSchema = Static<typeof authConfigSchema>;
|
export type AppAuthSchema = Static<typeof authConfigSchema>;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
Type,
|
Type,
|
||||||
parse,
|
parse,
|
||||||
runtimeSupports,
|
runtimeSupports,
|
||||||
transformObject
|
transformObject,
|
||||||
} from "core/utils";
|
} from "core/utils";
|
||||||
import type { Context, Hono } from "hono";
|
import type { Context, Hono } from "hono";
|
||||||
import { deleteCookie, getSignedCookie, setSignedCookie } from "hono/cookie";
|
import { deleteCookie, getSignedCookie, setSignedCookie } from "hono/cookie";
|
||||||
@@ -71,9 +71,9 @@ export const cookieConfig = Type.Partial(
|
|||||||
expires: Type.Number({ default: defaultCookieExpires }), // seconds
|
expires: Type.Number({ default: defaultCookieExpires }), // seconds
|
||||||
renew: Type.Boolean({ default: true }),
|
renew: Type.Boolean({ default: true }),
|
||||||
pathSuccess: Type.String({ default: "/" }),
|
pathSuccess: Type.String({ default: "/" }),
|
||||||
pathLoggedOut: Type.String({ default: "/" })
|
pathLoggedOut: Type.String({ default: "/" }),
|
||||||
}),
|
}),
|
||||||
{ default: {}, additionalProperties: false }
|
{ default: {}, additionalProperties: false },
|
||||||
);
|
);
|
||||||
|
|
||||||
// @todo: maybe add a config to not allow cookie/api tokens to be used interchangably?
|
// @todo: maybe add a config to not allow cookie/api tokens to be used interchangably?
|
||||||
@@ -86,16 +86,16 @@ export const jwtConfig = Type.Object(
|
|||||||
alg: Type.Optional(StringEnum(["HS256", "HS384", "HS512"], { default: "HS256" })),
|
alg: Type.Optional(StringEnum(["HS256", "HS384", "HS512"], { default: "HS256" })),
|
||||||
expires: Type.Optional(Type.Number()), // seconds
|
expires: Type.Optional(Type.Number()), // seconds
|
||||||
issuer: Type.Optional(Type.String()),
|
issuer: Type.Optional(Type.String()),
|
||||||
fields: Type.Array(Type.String(), { default: ["id", "email", "role"] })
|
fields: Type.Array(Type.String(), { default: ["id", "email", "role"] }),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
default: {},
|
default: {},
|
||||||
additionalProperties: false
|
additionalProperties: false,
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
export const authenticatorConfig = Type.Object({
|
export const authenticatorConfig = Type.Object({
|
||||||
jwt: jwtConfig,
|
jwt: jwtConfig,
|
||||||
cookie: cookieConfig
|
cookie: cookieConfig,
|
||||||
});
|
});
|
||||||
|
|
||||||
type AuthConfig = Static<typeof authenticatorConfig>;
|
type AuthConfig = Static<typeof authenticatorConfig>;
|
||||||
@@ -104,7 +104,7 @@ export type AuthUserResolver = (
|
|||||||
action: AuthAction,
|
action: AuthAction,
|
||||||
strategy: Strategy,
|
strategy: Strategy,
|
||||||
identifier: string,
|
identifier: string,
|
||||||
profile: ProfileExchange
|
profile: ProfileExchange,
|
||||||
) => Promise<SafeUser | undefined>;
|
) => Promise<SafeUser | undefined>;
|
||||||
type AuthClaims = SafeUser & {
|
type AuthClaims = SafeUser & {
|
||||||
iat: number;
|
iat: number;
|
||||||
@@ -127,7 +127,7 @@ export class Authenticator<Strategies extends Record<string, Strategy> = Record<
|
|||||||
action: AuthAction,
|
action: AuthAction,
|
||||||
strategy: Strategy,
|
strategy: Strategy,
|
||||||
identifier: string,
|
identifier: string,
|
||||||
profile: ProfileExchange
|
profile: ProfileExchange,
|
||||||
): Promise<AuthResponse> {
|
): Promise<AuthResponse> {
|
||||||
//console.log("resolve", { action, strategy: strategy.getName(), profile });
|
//console.log("resolve", { action, strategy: strategy.getName(), profile });
|
||||||
const user = await this.userResolver(action, strategy, identifier, profile);
|
const user = await this.userResolver(action, strategy, identifier, profile);
|
||||||
@@ -135,7 +135,7 @@ export class Authenticator<Strategies extends Record<string, Strategy> = Record<
|
|||||||
if (user) {
|
if (user) {
|
||||||
return {
|
return {
|
||||||
user,
|
user,
|
||||||
token: await this.jwt(user)
|
token: await this.jwt(user),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ export class Authenticator<Strategies extends Record<string, Strategy> = Record<
|
|||||||
|
|
||||||
strategy<
|
strategy<
|
||||||
StrategyName extends keyof Strategies,
|
StrategyName extends keyof Strategies,
|
||||||
Strat extends Strategy = Strategies[StrategyName]
|
Strat extends Strategy = Strategies[StrategyName],
|
||||||
>(strategy: StrategyName): Strat {
|
>(strategy: StrategyName): Strat {
|
||||||
try {
|
try {
|
||||||
return this.strategies[strategy] as unknown as Strat;
|
return this.strategies[strategy] as unknown as Strat;
|
||||||
@@ -168,7 +168,7 @@ export class Authenticator<Strategies extends Record<string, Strategy> = Record<
|
|||||||
|
|
||||||
const payload: JWTPayload = {
|
const payload: JWTPayload = {
|
||||||
...user,
|
...user,
|
||||||
iat: Math.floor(Date.now() / 1000)
|
iat: Math.floor(Date.now() / 1000),
|
||||||
};
|
};
|
||||||
|
|
||||||
// issuer
|
// issuer
|
||||||
@@ -194,7 +194,7 @@ export class Authenticator<Strategies extends Record<string, Strategy> = Record<
|
|||||||
const payload = await verify(
|
const payload = await verify(
|
||||||
jwt,
|
jwt,
|
||||||
this.config.jwt?.secret ?? "",
|
this.config.jwt?.secret ?? "",
|
||||||
this.config.jwt?.alg ?? "HS256"
|
this.config.jwt?.alg ?? "HS256",
|
||||||
);
|
);
|
||||||
|
|
||||||
// manually verify issuer (hono doesn't support it)
|
// manually verify issuer (hono doesn't support it)
|
||||||
@@ -215,7 +215,7 @@ export class Authenticator<Strategies extends Record<string, Strategy> = Record<
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...cookieConfig,
|
...cookieConfig,
|
||||||
expires: new Date(Date.now() + expires * 1000)
|
expires: new Date(Date.now() + expires * 1000),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,17 +342,17 @@ export class Authenticator<Strategies extends Record<string, Strategy> = Record<
|
|||||||
toJSON(secrets?: boolean) {
|
toJSON(secrets?: boolean) {
|
||||||
return {
|
return {
|
||||||
...this.config,
|
...this.config,
|
||||||
jwt: secrets ? this.config.jwt : undefined
|
jwt: secrets ? this.config.jwt : undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createStrategyAction<S extends TObject>(
|
export function createStrategyAction<S extends TObject>(
|
||||||
schema: S,
|
schema: S,
|
||||||
preprocess: (input: Static<S>) => Promise<Partial<DB["users"]>>
|
preprocess: (input: Static<S>) => Promise<Partial<DB["users"]>>,
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
schema,
|
schema,
|
||||||
preprocess
|
preprocess,
|
||||||
} as StrategyAction<S>;
|
} as StrategyAction<S>;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ type LoginSchema = { username: string; password: string } | { email: string; pas
|
|||||||
type RegisterSchema = { email: string; password: string; [key: string]: any };
|
type RegisterSchema = { email: string; password: string; [key: string]: any };
|
||||||
|
|
||||||
const schema = Type.Object({
|
const schema = Type.Object({
|
||||||
hashing: StringEnum(["plain", "sha256" /*, "bcrypt"*/] as const, { default: "sha256" })
|
hashing: StringEnum(["plain", "sha256" /*, "bcrypt"*/] as const, { default: "sha256" }),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type PasswordStrategyOptions = Static<typeof schema>;
|
export type PasswordStrategyOptions = Static<typeof schema>;
|
||||||
@@ -49,7 +49,7 @@ export class PasswordStrategy implements Strategy {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...input,
|
...input,
|
||||||
password: await this.hash(input.password)
|
password: await this.hash(input.password),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,8 +62,8 @@ export class PasswordStrategy implements Strategy {
|
|||||||
tb(
|
tb(
|
||||||
"query",
|
"query",
|
||||||
Type.Object({
|
Type.Object({
|
||||||
redirect: Type.Optional(Type.String())
|
redirect: Type.Optional(Type.String()),
|
||||||
})
|
}),
|
||||||
),
|
),
|
||||||
async (c) => {
|
async (c) => {
|
||||||
const body = await authenticator.getBody(c);
|
const body = await authenticator.getBody(c);
|
||||||
@@ -75,22 +75,22 @@ export class PasswordStrategy implements Strategy {
|
|||||||
"login",
|
"login",
|
||||||
this,
|
this,
|
||||||
payload.password,
|
payload.password,
|
||||||
payload
|
payload,
|
||||||
);
|
);
|
||||||
|
|
||||||
return await authenticator.respond(c, data, redirect);
|
return await authenticator.respond(c, data, redirect);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return await authenticator.respond(c, e);
|
return await authenticator.respond(c, e);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
)
|
)
|
||||||
.post(
|
.post(
|
||||||
"/register",
|
"/register",
|
||||||
tb(
|
tb(
|
||||||
"query",
|
"query",
|
||||||
Type.Object({
|
Type.Object({
|
||||||
redirect: Type.Optional(Type.String())
|
redirect: Type.Optional(Type.String()),
|
||||||
})
|
}),
|
||||||
),
|
),
|
||||||
async (c) => {
|
async (c) => {
|
||||||
const body = await authenticator.getBody(c);
|
const body = await authenticator.getBody(c);
|
||||||
@@ -101,11 +101,11 @@ export class PasswordStrategy implements Strategy {
|
|||||||
"register",
|
"register",
|
||||||
this,
|
this,
|
||||||
payload.password,
|
payload.password,
|
||||||
payload
|
payload,
|
||||||
);
|
);
|
||||||
|
|
||||||
return await authenticator.respond(c, data, redirect);
|
return await authenticator.respond(c, data, redirect);
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,19 +114,19 @@ export class PasswordStrategy implements Strategy {
|
|||||||
create: createStrategyAction(
|
create: createStrategyAction(
|
||||||
Type.Object({
|
Type.Object({
|
||||||
email: Type.String({
|
email: Type.String({
|
||||||
pattern: "^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$"
|
pattern: "^[\\w-\\.]+@([\\w-]+\\.)+[\\w-]{2,4}$",
|
||||||
}),
|
}),
|
||||||
password: Type.String({
|
password: Type.String({
|
||||||
minLength: 8 // @todo: this should be configurable
|
minLength: 8, // @todo: this should be configurable
|
||||||
})
|
}),
|
||||||
}),
|
}),
|
||||||
async ({ password, ...input }) => {
|
async ({ password, ...input }) => {
|
||||||
return {
|
return {
|
||||||
...input,
|
...input,
|
||||||
strategy_value: await this.hash(password)
|
strategy_value: await this.hash(password),
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
)
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,5 +9,5 @@ export {
|
|||||||
type PasswordStrategyOptions,
|
type PasswordStrategyOptions,
|
||||||
OAuthStrategy,
|
OAuthStrategy,
|
||||||
OAuthCallbackException,
|
OAuthCallbackException,
|
||||||
CustomOAuthStrategy
|
CustomOAuthStrategy,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ const oauthSchemaCustom = Type.Object(
|
|||||||
{
|
{
|
||||||
client_id: Type.String(),
|
client_id: Type.String(),
|
||||||
client_secret: Type.String(),
|
client_secret: Type.String(),
|
||||||
token_endpoint_auth_method: StringEnum(["client_secret_basic"])
|
token_endpoint_auth_method: StringEnum(["client_secret_basic"]),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
additionalProperties: false
|
additionalProperties: false,
|
||||||
}
|
},
|
||||||
),
|
),
|
||||||
as: Type.Object(
|
as: Type.Object(
|
||||||
{
|
{
|
||||||
@@ -29,15 +29,15 @@ const oauthSchemaCustom = Type.Object(
|
|||||||
scope_separator: Type.Optional(Type.String({ default: " " })),
|
scope_separator: Type.Optional(Type.String({ default: " " })),
|
||||||
authorization_endpoint: Type.Optional(UrlString),
|
authorization_endpoint: Type.Optional(UrlString),
|
||||||
token_endpoint: Type.Optional(UrlString),
|
token_endpoint: Type.Optional(UrlString),
|
||||||
userinfo_endpoint: Type.Optional(UrlString)
|
userinfo_endpoint: Type.Optional(UrlString),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
additionalProperties: false
|
additionalProperties: false,
|
||||||
}
|
},
|
||||||
)
|
),
|
||||||
// @todo: profile mapping
|
// @todo: profile mapping
|
||||||
},
|
},
|
||||||
{ title: "Custom OAuth", additionalProperties: false }
|
{ title: "Custom OAuth", additionalProperties: false },
|
||||||
);
|
);
|
||||||
|
|
||||||
type OAuthConfigCustom = Static<typeof oauthSchemaCustom>;
|
type OAuthConfigCustom = Static<typeof oauthSchemaCustom>;
|
||||||
@@ -57,7 +57,7 @@ export type IssuerConfig<UserInfo = any> = {
|
|||||||
profile: (
|
profile: (
|
||||||
info: UserInfo,
|
info: UserInfo,
|
||||||
config: Omit<IssuerConfig, "profile">,
|
config: Omit<IssuerConfig, "profile">,
|
||||||
tokenResponse: any
|
tokenResponse: any,
|
||||||
) => Promise<UserProfile>;
|
) => Promise<UserProfile>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -18,14 +18,14 @@ const schemaProvided = Type.Object(
|
|||||||
client: Type.Object(
|
client: Type.Object(
|
||||||
{
|
{
|
||||||
client_id: Type.String(),
|
client_id: Type.String(),
|
||||||
client_secret: Type.String()
|
client_secret: Type.String(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
additionalProperties: false
|
additionalProperties: false,
|
||||||
}
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
{ title: "OAuth" }
|
),
|
||||||
|
},
|
||||||
|
{ title: "OAuth" },
|
||||||
);
|
);
|
||||||
type ProvidedOAuthConfig = Static<typeof schemaProvided>;
|
type ProvidedOAuthConfig = Static<typeof schemaProvided>;
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ export type IssuerConfig<UserInfo = any> = {
|
|||||||
profile: (
|
profile: (
|
||||||
info: UserInfo,
|
info: UserInfo,
|
||||||
config: Omit<IssuerConfig, "profile">,
|
config: Omit<IssuerConfig, "profile">,
|
||||||
tokenResponse: any
|
tokenResponse: any,
|
||||||
) => Promise<UserProfile>;
|
) => Promise<UserProfile>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ export class OAuthCallbackException extends Exception {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public error: any,
|
public error: any,
|
||||||
public step: string
|
public step: string,
|
||||||
) {
|
) {
|
||||||
super("OAuthCallbackException on " + step);
|
super("OAuthCallbackException on " + step);
|
||||||
}
|
}
|
||||||
@@ -103,8 +103,8 @@ export class OAuthStrategy implements Strategy {
|
|||||||
type: info.type,
|
type: info.type,
|
||||||
client: {
|
client: {
|
||||||
...info.client,
|
...info.client,
|
||||||
...this._config.client
|
...this._config.client,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ export class OAuthStrategy implements Strategy {
|
|||||||
|
|
||||||
const { challenge_supported, challenge, challenge_method } = await this.getCodeChallenge(
|
const { challenge_supported, challenge, challenge_method } = await this.getCodeChallenge(
|
||||||
as,
|
as,
|
||||||
options.state
|
options.state,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!as.authorization_endpoint) {
|
if (!as.authorization_endpoint) {
|
||||||
@@ -150,7 +150,7 @@ export class OAuthStrategy implements Strategy {
|
|||||||
client_id: client.client_id,
|
client_id: client.client_id,
|
||||||
redirect_uri: options.redirect_uri,
|
redirect_uri: options.redirect_uri,
|
||||||
response_type: "code",
|
response_type: "code",
|
||||||
scope: scopes.join(as.scope_separator ?? " ")
|
scope: scopes.join(as.scope_separator ?? " "),
|
||||||
};
|
};
|
||||||
if (challenge_supported) {
|
if (challenge_supported) {
|
||||||
params.code_challenge = challenge;
|
params.code_challenge = challenge;
|
||||||
@@ -162,13 +162,13 @@ export class OAuthStrategy implements Strategy {
|
|||||||
return {
|
return {
|
||||||
url: new URL(endpoint) + "?" + new URLSearchParams(params).toString(),
|
url: new URL(endpoint) + "?" + new URLSearchParams(params).toString(),
|
||||||
endpoint,
|
endpoint,
|
||||||
params
|
params,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private async oidc(
|
private async oidc(
|
||||||
callbackParams: URL | URLSearchParams,
|
callbackParams: URL | URLSearchParams,
|
||||||
options: { redirect_uri: string; state: string; scopes?: string[] }
|
options: { redirect_uri: string; state: string; scopes?: string[] },
|
||||||
) {
|
) {
|
||||||
const config = await this.getConfig();
|
const config = await this.getConfig();
|
||||||
const { client, as, type } = config;
|
const { client, as, type } = config;
|
||||||
@@ -178,7 +178,7 @@ export class OAuthStrategy implements Strategy {
|
|||||||
as,
|
as,
|
||||||
client, // no client_secret required
|
client, // no client_secret required
|
||||||
callbackParams,
|
callbackParams,
|
||||||
oauth.expectNoState
|
oauth.expectNoState,
|
||||||
);
|
);
|
||||||
if (oauth.isOAuth2Error(parameters)) {
|
if (oauth.isOAuth2Error(parameters)) {
|
||||||
//console.log("callback.error", parameters);
|
//console.log("callback.error", parameters);
|
||||||
@@ -193,7 +193,7 @@ export class OAuthStrategy implements Strategy {
|
|||||||
client,
|
client,
|
||||||
parameters,
|
parameters,
|
||||||
options.redirect_uri,
|
options.redirect_uri,
|
||||||
options.state
|
options.state,
|
||||||
);
|
);
|
||||||
//console.log("callback.response", response);
|
//console.log("callback.response", response);
|
||||||
|
|
||||||
@@ -213,7 +213,7 @@ export class OAuthStrategy implements Strategy {
|
|||||||
as,
|
as,
|
||||||
client,
|
client,
|
||||||
response,
|
response,
|
||||||
expectedNonce
|
expectedNonce,
|
||||||
);
|
);
|
||||||
if (oauth.isOAuth2Error(result)) {
|
if (oauth.isOAuth2Error(result)) {
|
||||||
console.log("callback.error", result);
|
console.log("callback.error", result);
|
||||||
@@ -236,7 +236,7 @@ export class OAuthStrategy implements Strategy {
|
|||||||
|
|
||||||
private async oauth2(
|
private async oauth2(
|
||||||
callbackParams: URL | URLSearchParams,
|
callbackParams: URL | URLSearchParams,
|
||||||
options: { redirect_uri: string; state: string; scopes?: string[] }
|
options: { redirect_uri: string; state: string; scopes?: string[] },
|
||||||
) {
|
) {
|
||||||
const config = await this.getConfig();
|
const config = await this.getConfig();
|
||||||
const { client, type, as, profile } = config;
|
const { client, type, as, profile } = config;
|
||||||
@@ -246,7 +246,7 @@ export class OAuthStrategy implements Strategy {
|
|||||||
as,
|
as,
|
||||||
client, // no client_secret required
|
client, // no client_secret required
|
||||||
callbackParams,
|
callbackParams,
|
||||||
oauth.expectNoState
|
oauth.expectNoState,
|
||||||
);
|
);
|
||||||
if (oauth.isOAuth2Error(parameters)) {
|
if (oauth.isOAuth2Error(parameters)) {
|
||||||
console.log("callback.error", parameters);
|
console.log("callback.error", parameters);
|
||||||
@@ -254,14 +254,14 @@ export class OAuthStrategy implements Strategy {
|
|||||||
}
|
}
|
||||||
console.log(
|
console.log(
|
||||||
"callback.parameters",
|
"callback.parameters",
|
||||||
JSON.stringify(Object.fromEntries(parameters.entries()), null, 2)
|
JSON.stringify(Object.fromEntries(parameters.entries()), null, 2),
|
||||||
);
|
);
|
||||||
const response = await oauth.authorizationCodeGrantRequest(
|
const response = await oauth.authorizationCodeGrantRequest(
|
||||||
as,
|
as,
|
||||||
client,
|
client,
|
||||||
parameters,
|
parameters,
|
||||||
options.redirect_uri,
|
options.redirect_uri,
|
||||||
options.state
|
options.state,
|
||||||
);
|
);
|
||||||
|
|
||||||
const challenges = oauth.parseWwwAuthenticateChallenges(response);
|
const challenges = oauth.parseWwwAuthenticateChallenges(response);
|
||||||
@@ -297,7 +297,7 @@ export class OAuthStrategy implements Strategy {
|
|||||||
|
|
||||||
async callback(
|
async callback(
|
||||||
callbackParams: URL | URLSearchParams,
|
callbackParams: URL | URLSearchParams,
|
||||||
options: { redirect_uri: string; state: string; scopes?: string[] }
|
options: { redirect_uri: string; state: string; scopes?: string[] },
|
||||||
): Promise<UserProfile> {
|
): Promise<UserProfile> {
|
||||||
const type = this.getIssuerConfig().type;
|
const type = this.getIssuerConfig().type;
|
||||||
|
|
||||||
@@ -330,7 +330,7 @@ export class OAuthStrategy implements Strategy {
|
|||||||
secure: true,
|
secure: true,
|
||||||
httpOnly: true,
|
httpOnly: true,
|
||||||
sameSite: "Lax",
|
sameSite: "Lax",
|
||||||
maxAge: 60 * 5 // 5 minutes
|
maxAge: 60 * 5, // 5 minutes
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -339,7 +339,7 @@ export class OAuthStrategy implements Strategy {
|
|||||||
return {
|
return {
|
||||||
state: c.req.header("X-State-Challenge"),
|
state: c.req.header("X-State-Challenge"),
|
||||||
action: c.req.header("X-State-Action"),
|
action: c.req.header("X-State-Action"),
|
||||||
mode: "token"
|
mode: "token",
|
||||||
} as any;
|
} as any;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -366,7 +366,7 @@ export class OAuthStrategy implements Strategy {
|
|||||||
|
|
||||||
const profile = await this.callback(params, {
|
const profile = await this.callback(params, {
|
||||||
redirect_uri,
|
redirect_uri,
|
||||||
state: state.state
|
state: state.state,
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -392,7 +392,7 @@ export class OAuthStrategy implements Strategy {
|
|||||||
const params = new URLSearchParams(url.search);
|
const params = new URLSearchParams(url.search);
|
||||||
|
|
||||||
return c.json({
|
return c.json({
|
||||||
code: params.get("code") ?? null
|
code: params.get("code") ?? null,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -410,7 +410,7 @@ export class OAuthStrategy implements Strategy {
|
|||||||
const state = oauth.generateRandomCodeVerifier();
|
const state = oauth.generateRandomCodeVerifier();
|
||||||
const response = await this.request({
|
const response = await this.request({
|
||||||
redirect_uri,
|
redirect_uri,
|
||||||
state
|
state,
|
||||||
});
|
});
|
||||||
//console.log("_state", state);
|
//console.log("_state", state);
|
||||||
|
|
||||||
@@ -433,7 +433,7 @@ export class OAuthStrategy implements Strategy {
|
|||||||
const state = oauth.generateRandomCodeVerifier();
|
const state = oauth.generateRandomCodeVerifier();
|
||||||
const response = await this.request({
|
const response = await this.request({
|
||||||
redirect_uri,
|
redirect_uri,
|
||||||
state
|
state,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isDebug()) {
|
if (isDebug()) {
|
||||||
@@ -442,14 +442,14 @@ export class OAuthStrategy implements Strategy {
|
|||||||
redirect_uri,
|
redirect_uri,
|
||||||
challenge: state,
|
challenge: state,
|
||||||
action,
|
action,
|
||||||
params: response.params
|
params: response.params,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return c.json({
|
return c.json({
|
||||||
url: response.url,
|
url: response.url,
|
||||||
challenge: state,
|
challenge: state,
|
||||||
action
|
action,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -477,7 +477,7 @@ export class OAuthStrategy implements Strategy {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
type: this.getIssuerConfig().type,
|
type: this.getIssuerConfig().type,
|
||||||
...config
|
...config,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export class Guard {
|
|||||||
implicit_allow?: boolean;
|
implicit_allow?: boolean;
|
||||||
}
|
}
|
||||||
>,
|
>,
|
||||||
config?: GuardConfig
|
config?: GuardConfig,
|
||||||
) {
|
) {
|
||||||
const _roles = roles
|
const _roles = roles
|
||||||
? objectTransform(roles, ({ permissions = [], is_default, implicit_allow }, name) => {
|
? objectTransform(roles, ({ permissions = [], is_default, implicit_allow }, name) => {
|
||||||
@@ -103,7 +103,7 @@ export class Guard {
|
|||||||
debug &&
|
debug &&
|
||||||
console.log("guard: role not found", {
|
console.log("guard: role not found", {
|
||||||
user: user,
|
user: user,
|
||||||
role: user?.role
|
role: user?.role,
|
||||||
});
|
});
|
||||||
return this.getDefaultRole();
|
return this.getDefaultRole();
|
||||||
}
|
}
|
||||||
@@ -141,14 +141,14 @@ export class Guard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const rolePermission = role.permissions.find(
|
const rolePermission = role.permissions.find(
|
||||||
(rolePermission) => rolePermission.permission.name === name
|
(rolePermission) => rolePermission.permission.name === name,
|
||||||
);
|
);
|
||||||
|
|
||||||
debug &&
|
debug &&
|
||||||
console.log("guard: rolePermission, allowing?", {
|
console.log("guard: rolePermission, allowing?", {
|
||||||
permission: name,
|
permission: name,
|
||||||
role: role.name,
|
role: role.name,
|
||||||
allowing: !!rolePermission
|
allowing: !!rolePermission,
|
||||||
});
|
});
|
||||||
return !!rolePermission;
|
return !!rolePermission;
|
||||||
}
|
}
|
||||||
@@ -162,7 +162,7 @@ export class Guard {
|
|||||||
if (!this.granted(permission, c)) {
|
if (!this.granted(permission, c)) {
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
`Permission "${typeof permission === "string" ? permission : permission.name}" not granted`,
|
`Permission "${typeof permission === "string" ? permission : permission.name}" not granted`,
|
||||||
403
|
403,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { Permission } from "core";
|
|||||||
export class RolePermission {
|
export class RolePermission {
|
||||||
constructor(
|
constructor(
|
||||||
public permission: Permission,
|
public permission: Permission,
|
||||||
public config?: any
|
public config?: any,
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -12,20 +12,20 @@ export class Role {
|
|||||||
public name: string,
|
public name: string,
|
||||||
public permissions: RolePermission[] = [],
|
public permissions: RolePermission[] = [],
|
||||||
public is_default: boolean = false,
|
public is_default: boolean = false,
|
||||||
public implicit_allow: boolean = false
|
public implicit_allow: boolean = false,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
static createWithPermissionNames(
|
static createWithPermissionNames(
|
||||||
name: string,
|
name: string,
|
||||||
permissionNames: string[],
|
permissionNames: string[],
|
||||||
is_default: boolean = false,
|
is_default: boolean = false,
|
||||||
implicit_allow: boolean = false
|
implicit_allow: boolean = false,
|
||||||
) {
|
) {
|
||||||
return new Role(
|
return new Role(
|
||||||
name,
|
name,
|
||||||
permissionNames.map((name) => new RolePermission(new Permission(name))),
|
permissionNames.map((name) => new RolePermission(new Permission(name))),
|
||||||
is_default,
|
is_default,
|
||||||
implicit_allow
|
implicit_allow,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +39,7 @@ export class Role {
|
|||||||
config.name,
|
config.name,
|
||||||
config.permissions?.map((name) => new RolePermission(new Permission(name))) ?? [],
|
config.permissions?.map((name) => new RolePermission(new Permission(name))) ?? [],
|
||||||
config.is_default,
|
config.is_default,
|
||||||
config.implicit_allow
|
config.implicit_allow,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user