@webiny/api-core-sql 0.0.0-unstable.a4f3e4ea8b → 0.0.0-unstable.d0f34a8194
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ApiCoreSqlFeature.d.ts +18 -0
- package/ApiCoreSqlFeature.js +18 -0
- package/ApiCoreSqlFeature.js.map +1 -0
- package/TableManager.d.ts +3 -0
- package/TableManager.js +21 -1
- package/TableManager.js.map +1 -1
- package/adminUsers/index.js +6 -3
- package/adminUsers/index.js.map +1 -1
- package/index.d.ts +2 -0
- package/index.js +1 -0
- package/index.js.map +1 -1
- package/keyValueStore/index.js +152 -15
- package/keyValueStore/index.js.map +1 -1
- package/package.json +8 -9
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Knex } from "knex";
|
|
2
|
+
export interface ApiCoreSqlConfig {
|
|
3
|
+
knex: Knex;
|
|
4
|
+
tableNamePrefix?: string;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Registers the SQL implementation of ApiCoreStorageOperationsFactory. ApiCoreFeature.register
|
|
8
|
+
* resolves + builds it. Mirrors ApiCoreDdbFeature.
|
|
9
|
+
*
|
|
10
|
+
* The storage operations are built once, here, and `create()` hands out the same object. It runs on
|
|
11
|
+
* every request (ApiCoreFeature is per-request), and building per request created a new TableManager
|
|
12
|
+
* each time: every one stayed in the global test registry, so a long-running server leaked one per
|
|
13
|
+
* request, and each started with no verified tables. The operations hold no per-request state.
|
|
14
|
+
*/
|
|
15
|
+
export declare const ApiCoreSqlFeature: {
|
|
16
|
+
name: string;
|
|
17
|
+
register(container: import("@webiny/di").Container, context: ApiCoreSqlConfig): void;
|
|
18
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createFeature } from "@webiny/feature/api";
|
|
2
|
+
import { ApiCoreStorageOperationsFactory } from "@webiny/api-core";
|
|
3
|
+
import { createApiCoreSql } from "./createApiCoreSql.js";
|
|
4
|
+
const ApiCoreSqlFeature = createFeature({
|
|
5
|
+
name: "ApiCoreSql",
|
|
6
|
+
register (container, { knex, tableNamePrefix }) {
|
|
7
|
+
const storageOperations = createApiCoreSql({
|
|
8
|
+
knex,
|
|
9
|
+
tableNamePrefix
|
|
10
|
+
});
|
|
11
|
+
container.registerInstance(ApiCoreStorageOperationsFactory, {
|
|
12
|
+
create: ()=>storageOperations
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
export { ApiCoreSqlFeature };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=ApiCoreSqlFeature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ApiCoreSqlFeature.js","sources":["../src/ApiCoreSqlFeature.ts"],"sourcesContent":["import { createFeature } from \"@webiny/feature/api\";\nimport type { Knex } from \"knex\";\nimport { ApiCoreStorageOperationsFactory } from \"@webiny/api-core\";\nimport { createApiCoreSql } from \"./createApiCoreSql.js\";\n\nexport interface ApiCoreSqlConfig {\n knex: Knex;\n tableNamePrefix?: string;\n}\n\n/**\n * Registers the SQL implementation of ApiCoreStorageOperationsFactory. ApiCoreFeature.register\n * resolves + builds it. Mirrors ApiCoreDdbFeature.\n *\n * The storage operations are built once, here, and `create()` hands out the same object. It runs on\n * every request (ApiCoreFeature is per-request), and building per request created a new TableManager\n * each time: every one stayed in the global test registry, so a long-running server leaked one per\n * request, and each started with no verified tables. The operations hold no per-request state.\n */\nexport const ApiCoreSqlFeature = createFeature<ApiCoreSqlConfig>({\n name: \"ApiCoreSql\",\n register(container, { knex, tableNamePrefix }) {\n const storageOperations = createApiCoreSql({ knex, tableNamePrefix });\n\n container.registerInstance(ApiCoreStorageOperationsFactory, {\n create: () => storageOperations\n });\n }\n});\n"],"names":["ApiCoreSqlFeature","createFeature","container","knex","tableNamePrefix","storageOperations","createApiCoreSql","ApiCoreStorageOperationsFactory"],"mappings":";;;AAmBO,MAAMA,oBAAoBC,cAAgC;IAC7D,MAAM;IACN,UAASC,SAAS,EAAE,EAAEC,IAAI,EAAEC,eAAe,EAAE;QACzC,MAAMC,oBAAoBC,iBAAiB;YAAEH;YAAMC;QAAgB;QAEnEF,UAAU,gBAAgB,CAACK,iCAAiC;YACxD,QAAQ,IAAMF;QAClB;IACJ;AACJ"}
|
package/TableManager.d.ts
CHANGED
|
@@ -8,9 +8,12 @@ export declare class TableManager implements ITableManager {
|
|
|
8
8
|
private readonly knex;
|
|
9
9
|
private readonly prefix;
|
|
10
10
|
private readonly verified;
|
|
11
|
+
private readonly pending;
|
|
11
12
|
constructor(knex: Knex, prefix?: string);
|
|
12
13
|
reset(): void;
|
|
13
14
|
resolve(tableName: string): string;
|
|
14
15
|
ensure(tableName: string, creator: (table: Knex.CreateTableBuilder) => void): Promise<void>;
|
|
16
|
+
private ensureTable;
|
|
17
|
+
private createTable;
|
|
15
18
|
}
|
|
16
19
|
export {};
|
package/TableManager.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
class TableManager {
|
|
2
2
|
constructor(knex, prefix = ""){
|
|
3
3
|
this.verified = new Set();
|
|
4
|
+
this.pending = new Map();
|
|
4
5
|
this.knex = knex;
|
|
5
6
|
this.prefix = prefix ? `${prefix}_` : "";
|
|
6
7
|
const g = globalThis;
|
|
@@ -9,6 +10,7 @@ class TableManager {
|
|
|
9
10
|
}
|
|
10
11
|
reset() {
|
|
11
12
|
this.verified.clear();
|
|
13
|
+
this.pending.clear();
|
|
12
14
|
}
|
|
13
15
|
resolve(tableName) {
|
|
14
16
|
return `${this.prefix}${tableName}`;
|
|
@@ -16,10 +18,28 @@ class TableManager {
|
|
|
16
18
|
async ensure(tableName, creator) {
|
|
17
19
|
const resolved = this.resolve(tableName);
|
|
18
20
|
if (this.verified.has(resolved)) return;
|
|
21
|
+
const pending = this.pending.get(resolved);
|
|
22
|
+
if (pending) return pending;
|
|
23
|
+
const check = this.ensureTable(resolved, creator).finally(()=>{
|
|
24
|
+
if (this.pending.get(resolved) === check) this.pending.delete(resolved);
|
|
25
|
+
});
|
|
26
|
+
this.pending.set(resolved, check);
|
|
27
|
+
return check;
|
|
28
|
+
}
|
|
29
|
+
async ensureTable(resolved, creator) {
|
|
19
30
|
const exists = await this.knex.schema.hasTable(resolved);
|
|
20
|
-
if (!exists) await this.
|
|
31
|
+
if (!exists) await this.createTable(resolved, creator);
|
|
21
32
|
this.verified.add(resolved);
|
|
22
33
|
}
|
|
34
|
+
async createTable(resolved, creator) {
|
|
35
|
+
try {
|
|
36
|
+
await this.knex.schema.createTable(resolved, creator);
|
|
37
|
+
} catch (err) {
|
|
38
|
+
const exists = await this.knex.schema.hasTable(resolved);
|
|
39
|
+
if (exists) return;
|
|
40
|
+
throw err;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
23
43
|
}
|
|
24
44
|
export { TableManager };
|
|
25
45
|
|
package/TableManager.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TableManager.js","sources":["../src/TableManager.ts"],"sourcesContent":["import type { Knex } from \"knex\";\n\ninterface ITableManager {\n reset(): void;\n resolve(tableName: string): string;\n ensure(tableName: string, creator: (table: Knex.CreateTableBuilder) => void): Promise<void>;\n}\n\nexport class TableManager implements ITableManager {\n private readonly knex: Knex;\n private readonly prefix: string;\n private readonly verified = new Set<string>();\n\n constructor(knex: Knex, prefix: string = \"\") {\n this.knex = knex;\n this.prefix = prefix ? `${prefix}_` : \"\";\n\n const g = globalThis as Record<string, unknown>;\n const managers = (g.__sqlTableManagers ??= []) as ITableManager[];\n managers.push(this);\n }\n\n public reset(): void {\n this.verified.clear();\n }\n\n public resolve(tableName: string): string {\n return `${this.prefix}${tableName}`;\n }\n\n public async ensure(\n tableName: string,\n creator: (table: Knex.CreateTableBuilder) => void\n ): Promise<void> {\n const resolved = this.resolve(tableName);\n\n if (this.verified.has(resolved)) {\n return;\n }\n\n const exists = await this.knex.schema.hasTable(resolved);\n\n if (!exists) {\n await this.
|
|
1
|
+
{"version":3,"file":"TableManager.js","sources":["../src/TableManager.ts"],"sourcesContent":["import type { Knex } from \"knex\";\n\ninterface ITableManager {\n reset(): void;\n resolve(tableName: string): string;\n ensure(tableName: string, creator: (table: Knex.CreateTableBuilder) => void): Promise<void>;\n}\n\nexport class TableManager implements ITableManager {\n private readonly knex: Knex;\n private readonly prefix: string;\n private readonly verified = new Set<string>();\n private readonly pending = new Map<string, Promise<void>>();\n\n constructor(knex: Knex, prefix: string = \"\") {\n this.knex = knex;\n this.prefix = prefix ? `${prefix}_` : \"\";\n\n const g = globalThis as Record<string, unknown>;\n const managers = (g.__sqlTableManagers ??= []) as ITableManager[];\n managers.push(this);\n }\n\n public reset(): void {\n this.verified.clear();\n this.pending.clear();\n }\n\n public resolve(tableName: string): string {\n return `${this.prefix}${tableName}`;\n }\n\n public async ensure(\n tableName: string,\n creator: (table: Knex.CreateTableBuilder) => void\n ): Promise<void> {\n const resolved = this.resolve(tableName);\n\n if (this.verified.has(resolved)) {\n return;\n }\n\n // One TableManager serves every request, so concurrent first requests share a single\n // hasTable+createTable instead of racing into \"table already exists\". Cleared on failure so\n // a later call can retry.\n const pending = this.pending.get(resolved);\n if (pending) {\n return pending;\n }\n\n const check = this.ensureTable(resolved, creator).finally(() => {\n // Only remove our own entry: after reset() a newer check may own this table's slot.\n if (this.pending.get(resolved) === check) {\n this.pending.delete(resolved);\n }\n });\n this.pending.set(resolved, check);\n\n return check;\n }\n\n private async ensureTable(\n resolved: string,\n creator: (table: Knex.CreateTableBuilder) => void\n ): Promise<void> {\n const exists = await this.knex.schema.hasTable(resolved);\n\n if (!exists) {\n await this.createTable(resolved, creator);\n }\n\n this.verified.add(resolved);\n }\n\n private async createTable(\n resolved: string,\n creator: (table: Knex.CreateTableBuilder) => void\n ): Promise<void> {\n try {\n await this.knex.schema.createTable(resolved, creator);\n } catch (err) {\n // Another process (or connection) may have created it in the meantime. If it exists now,\n // that's success; otherwise the failure is real.\n const exists = await this.knex.schema.hasTable(resolved);\n if (exists) {\n return;\n }\n throw err;\n }\n }\n}\n"],"names":["TableManager","knex","prefix","Set","Map","g","globalThis","managers","tableName","creator","resolved","pending","check","exists","err"],"mappings":"AAQO,MAAMA;IAMT,YAAYC,IAAU,EAAEC,SAAiB,EAAE,CAAE;aAH5B,QAAQ,GAAG,IAAIC;aACf,OAAO,GAAG,IAAIC;QAG3B,IAAI,CAAC,IAAI,GAAGH;QACZ,IAAI,CAAC,MAAM,GAAGC,SAAS,GAAGA,OAAO,CAAC,CAAC,GAAG;QAEtC,MAAMG,IAAIC;QACV,MAAMC,WAAYF,EAAE,kBAAkB,KAAK,EAAE;QAC7CE,SAAS,IAAI,CAAC,IAAI;IACtB;IAEO,QAAc;QACjB,IAAI,CAAC,QAAQ,CAAC,KAAK;QACnB,IAAI,CAAC,OAAO,CAAC,KAAK;IACtB;IAEO,QAAQC,SAAiB,EAAU;QACtC,OAAO,GAAG,IAAI,CAAC,MAAM,GAAGA,WAAW;IACvC;IAEA,MAAa,OACTA,SAAiB,EACjBC,OAAiD,EACpC;QACb,MAAMC,WAAW,IAAI,CAAC,OAAO,CAACF;QAE9B,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAACE,WAClB;QAMJ,MAAMC,UAAU,IAAI,CAAC,OAAO,CAAC,GAAG,CAACD;QACjC,IAAIC,SACA,OAAOA;QAGX,MAAMC,QAAQ,IAAI,CAAC,WAAW,CAACF,UAAUD,SAAS,OAAO,CAAC;YAEtD,IAAI,IAAI,CAAC,OAAO,CAAC,GAAG,CAACC,cAAcE,OAC/B,IAAI,CAAC,OAAO,CAAC,MAAM,CAACF;QAE5B;QACA,IAAI,CAAC,OAAO,CAAC,GAAG,CAACA,UAAUE;QAE3B,OAAOA;IACX;IAEA,MAAc,YACVF,QAAgB,EAChBD,OAAiD,EACpC;QACb,MAAMI,SAAS,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAACH;QAE/C,IAAI,CAACG,QACD,MAAM,IAAI,CAAC,WAAW,CAACH,UAAUD;QAGrC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAACC;IACtB;IAEA,MAAc,YACVA,QAAgB,EAChBD,OAAiD,EACpC;QACb,IAAI;YACA,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAACC,UAAUD;QACjD,EAAE,OAAOK,KAAK;YAGV,MAAMD,SAAS,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAACH;YAC/C,IAAIG,QACA;YAEJ,MAAMC;QACV;IACJ;AACJ"}
|
package/adminUsers/index.js
CHANGED
|
@@ -54,9 +54,12 @@ const createStorageOperations = (params)=>{
|
|
|
54
54
|
const rows = await query().where("tenant", where.tenant);
|
|
55
55
|
let items = rows.map((row)=>rowToUser(row));
|
|
56
56
|
items = sortItems(items, sort);
|
|
57
|
-
const { id_in } = where;
|
|
58
|
-
|
|
59
|
-
|
|
57
|
+
const { id_in, teams_in } = where;
|
|
58
|
+
return items.filter((item)=>{
|
|
59
|
+
if (Array.isArray(id_in) && !id_in.includes(item.id)) return false;
|
|
60
|
+
if (Array.isArray(teams_in)) return (item.teams || []).some((team)=>teams_in.includes(team));
|
|
61
|
+
return true;
|
|
62
|
+
});
|
|
60
63
|
} catch (err) {
|
|
61
64
|
throw error.from(err, {
|
|
62
65
|
message: "Could not list users.",
|
package/adminUsers/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adminUsers/index.js","sources":["../../src/adminUsers/index.ts"],"sourcesContent":["import type { Knex } from \"knex\";\nimport type {\n AdminUser,\n AdminUsersStorageOperations,\n StorageOperationsGetUserParams,\n StorageOperationsListUsersParams\n} from \"@webiny/api-core/types/users.js\";\nimport WebinyError from \"@webiny/error\";\nimport type { TableManager } from \"~/TableManager.js\";\nimport { sortItems } from \"~/sortItems.js\";\n\nconst TABLE_NAME = \"webiny_core_admin_users\";\n\ninterface IAdminUserRow {\n id: string;\n tenant: string;\n email: string;\n data: string;\n}\n\nconst userToRow = (user: AdminUser): IAdminUserRow => {\n return {\n id: user.id,\n tenant: user.tenant,\n email: user.email,\n data: JSON.stringify(user)\n };\n};\n\nconst rowToUser = <TUser extends AdminUser = AdminUser>(row: IAdminUserRow): TUser => {\n return JSON.parse(row.data) as TUser;\n};\n\ninterface CreateStorageOperationsParams {\n knex: Knex;\n tableManager: TableManager;\n}\n\nexport const createStorageOperations = (\n params: CreateStorageOperationsParams\n): AdminUsersStorageOperations => {\n const { knex, tableManager } = params;\n\n const ensureTable = () => {\n return tableManager.ensure(TABLE_NAME, table => {\n table.text(\"id\").notNullable();\n table.text(\"tenant\").notNullable();\n table.text(\"email\").notNullable();\n table.text(\"data\").notNullable();\n\n table.primary([\"tenant\", \"id\"]);\n table.unique([\"tenant\", \"email\"]);\n });\n };\n\n const query = () => {\n return knex<IAdminUserRow>(tableManager.resolve(TABLE_NAME));\n };\n\n return {\n async getUser<TUser extends AdminUser = AdminUser>(\n params: StorageOperationsGetUserParams\n ): Promise<TUser | null> {\n await ensureTable();\n\n const {\n where: { tenant, id, email }\n } = params;\n\n try {\n if (id) {\n const row = await query().where(\"tenant\", tenant).andWhere(\"id\", id).first();\n\n return row ? rowToUser<TUser>(row) : null;\n }\n\n const row = await query()\n .where(\"tenant\", tenant)\n .andWhere(\"email\", email as string)\n .first();\n\n return row ? rowToUser<TUser>(row) : null;\n } catch (err) {\n throw WebinyError.from(err, {\n message: \"Could not load user.\",\n code: \"GET_ADMIN_USERS_ERROR\",\n data: { id, email }\n });\n }\n },\n\n async listUsers<TUser extends AdminUser = AdminUser>(\n params: StorageOperationsListUsersParams\n ): Promise<TUser[]> {\n await ensureTable();\n\n const { where, sort } = params;\n\n try {\n const rows = await query().where(\"tenant\", where.tenant);\n\n let items = rows.map(row => rowToUser<TUser>(row));\n\n items = sortItems(items, sort);\n\n const { id_in } = where;\n\n if (Array.isArray(id_in)) {\n
|
|
1
|
+
{"version":3,"file":"adminUsers/index.js","sources":["../../src/adminUsers/index.ts"],"sourcesContent":["import type { Knex } from \"knex\";\nimport type {\n AdminUser,\n AdminUsersStorageOperations,\n StorageOperationsGetUserParams,\n StorageOperationsListUsersParams\n} from \"@webiny/api-core/types/users.js\";\nimport WebinyError from \"@webiny/error\";\nimport type { TableManager } from \"~/TableManager.js\";\nimport { sortItems } from \"~/sortItems.js\";\n\nconst TABLE_NAME = \"webiny_core_admin_users\";\n\ninterface IAdminUserRow {\n id: string;\n tenant: string;\n email: string;\n data: string;\n}\n\nconst userToRow = (user: AdminUser): IAdminUserRow => {\n return {\n id: user.id,\n tenant: user.tenant,\n email: user.email,\n data: JSON.stringify(user)\n };\n};\n\nconst rowToUser = <TUser extends AdminUser = AdminUser>(row: IAdminUserRow): TUser => {\n return JSON.parse(row.data) as TUser;\n};\n\ninterface CreateStorageOperationsParams {\n knex: Knex;\n tableManager: TableManager;\n}\n\nexport const createStorageOperations = (\n params: CreateStorageOperationsParams\n): AdminUsersStorageOperations => {\n const { knex, tableManager } = params;\n\n const ensureTable = () => {\n return tableManager.ensure(TABLE_NAME, table => {\n table.text(\"id\").notNullable();\n table.text(\"tenant\").notNullable();\n table.text(\"email\").notNullable();\n table.text(\"data\").notNullable();\n\n table.primary([\"tenant\", \"id\"]);\n table.unique([\"tenant\", \"email\"]);\n });\n };\n\n const query = () => {\n return knex<IAdminUserRow>(tableManager.resolve(TABLE_NAME));\n };\n\n return {\n async getUser<TUser extends AdminUser = AdminUser>(\n params: StorageOperationsGetUserParams\n ): Promise<TUser | null> {\n await ensureTable();\n\n const {\n where: { tenant, id, email }\n } = params;\n\n try {\n if (id) {\n const row = await query().where(\"tenant\", tenant).andWhere(\"id\", id).first();\n\n return row ? rowToUser<TUser>(row) : null;\n }\n\n const row = await query()\n .where(\"tenant\", tenant)\n .andWhere(\"email\", email as string)\n .first();\n\n return row ? rowToUser<TUser>(row) : null;\n } catch (err) {\n throw WebinyError.from(err, {\n message: \"Could not load user.\",\n code: \"GET_ADMIN_USERS_ERROR\",\n data: { id, email }\n });\n }\n },\n\n async listUsers<TUser extends AdminUser = AdminUser>(\n params: StorageOperationsListUsersParams\n ): Promise<TUser[]> {\n await ensureTable();\n\n const { where, sort } = params;\n\n try {\n const rows = await query().where(\"tenant\", where.tenant);\n\n let items = rows.map(row => rowToUser<TUser>(row));\n\n items = sortItems(items, sort);\n\n const { id_in, teams_in } = where;\n\n return items.filter(item => {\n if (Array.isArray(id_in) && !id_in.includes(item.id)) {\n return false;\n }\n if (Array.isArray(teams_in)) {\n return (item.teams || []).some(team => teams_in.includes(team));\n }\n return true;\n });\n } catch (err) {\n throw WebinyError.from(err, {\n message: \"Could not list users.\",\n code: \"LIST_ADMIN_USERS_ERROR\"\n });\n }\n },\n\n async createUser<TUser extends AdminUser = AdminUser>({\n user\n }: {\n user: TUser;\n }): Promise<TUser> {\n await ensureTable();\n\n try {\n const row = userToRow(user);\n await query().insert(row);\n\n return user;\n } catch (err) {\n throw WebinyError.from(err, {\n message: \"Could not create admin user.\",\n code: \"CREATE_ADMIN_USER_ERROR\",\n data: { user }\n });\n }\n },\n\n async updateUser<TUser extends AdminUser = AdminUser>({\n user\n }: {\n user: TUser;\n }): Promise<TUser> {\n await ensureTable();\n\n try {\n const row = userToRow(user);\n await query().where(\"tenant\", user.tenant).andWhere(\"id\", user.id).update(row);\n\n return user;\n } catch (err) {\n throw WebinyError.from(err, {\n message: \"Could not update user.\",\n code: \"UPDATE_ADMIN_USER_ERROR\",\n data: { user }\n });\n }\n },\n\n async deleteUser<TUser extends AdminUser = AdminUser>({\n user\n }: {\n user: TUser;\n }): Promise<void> {\n await ensureTable();\n\n try {\n await query().where(\"tenant\", user.tenant).andWhere(\"id\", user.id).delete();\n } catch (err) {\n throw WebinyError.from(err, {\n message: \"Could not delete user.\",\n code: \"DELETE_ADMIN_USER_ERROR\",\n data: { user }\n });\n }\n }\n };\n};\n"],"names":["TABLE_NAME","userToRow","user","JSON","rowToUser","row","createStorageOperations","params","knex","tableManager","ensureTable","table","query","tenant","id","email","err","WebinyError","where","sort","rows","items","sortItems","id_in","teams_in","item","Array","team"],"mappings":"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"}
|
package/index.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { Knex } from "knex";
|
|
2
2
|
export { createApiCoreSql } from "./createApiCoreSql.js";
|
|
3
|
+
export { ApiCoreSqlFeature } from "./ApiCoreSqlFeature.js";
|
|
4
|
+
export type { ApiCoreSqlConfig } from "./ApiCoreSqlFeature.js";
|
|
3
5
|
export { getSqlTablePrefix } from "./getSqlTablePrefix.js";
|
|
4
6
|
export { SqlServiceManifestLoader } from "./serviceDiscovery/index.js";
|
|
5
7
|
export { KnexClient } from "./feature/KnexClient/index.js";
|
package/index.js
CHANGED
|
@@ -4,6 +4,7 @@ const registerSQLCore = ({ knex })=>createRegisterExtensionPlugin(async (context
|
|
|
4
4
|
KnexClientFeature.register(context.container, knex);
|
|
5
5
|
});
|
|
6
6
|
export { createApiCoreSql } from "./createApiCoreSql.js";
|
|
7
|
+
export { ApiCoreSqlFeature } from "./ApiCoreSqlFeature.js";
|
|
7
8
|
export { getSqlTablePrefix } from "./getSqlTablePrefix.js";
|
|
8
9
|
export { SqlServiceManifestLoader } from "./serviceDiscovery/index.js";
|
|
9
10
|
export { KnexClient, registerSQLCore };
|
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { createRegisterExtensionPlugin } from \"@webiny/handler\";\nimport type { Knex } from \"knex\";\nimport { KnexClientFeature } from \"./feature/KnexClient/index.js\";\n\nexport { createApiCoreSql } from \"./createApiCoreSql.js\";\nexport { getSqlTablePrefix } from \"./getSqlTablePrefix.js\";\nexport { SqlServiceManifestLoader } from \"./serviceDiscovery/index.js\";\n\nexport { KnexClient } from \"./feature/KnexClient/index.js\";\n\ninterface IRegisterApiCoreSqlExtension {\n knex: Knex;\n}\n\nexport const registerSQLCore = ({ knex }: IRegisterApiCoreSqlExtension) => {\n return createRegisterExtensionPlugin(async context => {\n KnexClientFeature.register(context.container, knex);\n });\n};\n"],"names":["registerSQLCore","knex","createRegisterExtensionPlugin","context","KnexClientFeature"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { createRegisterExtensionPlugin } from \"@webiny/handler\";\nimport type { Knex } from \"knex\";\nimport { KnexClientFeature } from \"./feature/KnexClient/index.js\";\n\nexport { createApiCoreSql } from \"./createApiCoreSql.js\";\nexport { ApiCoreSqlFeature } from \"./ApiCoreSqlFeature.js\";\nexport type { ApiCoreSqlConfig } from \"./ApiCoreSqlFeature.js\";\nexport { getSqlTablePrefix } from \"./getSqlTablePrefix.js\";\nexport { SqlServiceManifestLoader } from \"./serviceDiscovery/index.js\";\n\nexport { KnexClient } from \"./feature/KnexClient/index.js\";\n\ninterface IRegisterApiCoreSqlExtension {\n knex: Knex;\n}\n\nexport const registerSQLCore = ({ knex }: IRegisterApiCoreSqlExtension) => {\n return createRegisterExtensionPlugin(async context => {\n KnexClientFeature.register(context.container, knex);\n });\n};\n"],"names":["registerSQLCore","knex","createRegisterExtensionPlugin","context","KnexClientFeature"],"mappings":";;AAgBO,MAAMA,kBAAkB,CAAC,EAAEC,IAAI,EAAgC,GAC3DC,8BAA8B,OAAMC;QACvCC,kBAAkB,QAAQ,CAACD,QAAQ,SAAS,EAAEF;IAClD"}
|
package/keyValueStore/index.js
CHANGED
|
@@ -1,16 +1,71 @@
|
|
|
1
1
|
import { WebinyError } from "@webiny/error";
|
|
2
2
|
const TABLE_NAME = "webiny_core_key_value";
|
|
3
|
+
const COLLECTION_TABLE_NAME = "webiny_core_key_value_collection";
|
|
4
|
+
const isPrimaryKeyViolation = (error)=>{
|
|
5
|
+
const code = error?.code;
|
|
6
|
+
return "23505" === code || "ER_DUP_ENTRY" === code || "SQLITE_CONSTRAINT_PRIMARYKEY" === code || "SQLITE_CONSTRAINT_UNIQUE" === code;
|
|
7
|
+
};
|
|
3
8
|
const createStorageOperations = (params)=>{
|
|
4
9
|
const { knex, tableManager } = params;
|
|
5
|
-
const ensureTable =
|
|
10
|
+
const ensureTable = async ()=>{
|
|
11
|
+
await tableManager.ensure(TABLE_NAME, (table)=>{
|
|
6
12
|
table.text("scopedKey").primary().notNullable();
|
|
7
13
|
table.text("key").notNullable();
|
|
8
14
|
table.text("scope").notNullable();
|
|
9
15
|
table.text("value").notNullable();
|
|
10
16
|
table.datetime("expiresAt");
|
|
11
17
|
});
|
|
12
|
-
|
|
18
|
+
await tableManager.ensure(COLLECTION_TABLE_NAME, (table)=>{
|
|
19
|
+
table.text("scopedKey").primary().notNullable();
|
|
20
|
+
table.text("scope").notNullable();
|
|
21
|
+
table.text("collection").notNullable();
|
|
22
|
+
table.text("key").notNullable();
|
|
23
|
+
table.index([
|
|
24
|
+
"scope",
|
|
25
|
+
"collection"
|
|
26
|
+
]);
|
|
27
|
+
});
|
|
28
|
+
};
|
|
29
|
+
const query = (trx = knex)=>trx(tableManager.resolve(TABLE_NAME));
|
|
30
|
+
const collectionQuery = (trx = knex)=>trx(tableManager.resolve(COLLECTION_TABLE_NAME));
|
|
31
|
+
const binaryKey = (column)=>{
|
|
32
|
+
switch(knex.client.dialect){
|
|
33
|
+
case "postgresql":
|
|
34
|
+
return {
|
|
35
|
+
sql: '?? COLLATE "C"',
|
|
36
|
+
bindings: [
|
|
37
|
+
column
|
|
38
|
+
]
|
|
39
|
+
};
|
|
40
|
+
case "mysql":
|
|
41
|
+
case "mysql2":
|
|
42
|
+
return {
|
|
43
|
+
sql: "BINARY ??",
|
|
44
|
+
bindings: [
|
|
45
|
+
column
|
|
46
|
+
]
|
|
47
|
+
};
|
|
48
|
+
default:
|
|
49
|
+
return {
|
|
50
|
+
sql: "??",
|
|
51
|
+
bindings: [
|
|
52
|
+
column
|
|
53
|
+
]
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
};
|
|
13
57
|
const createScopedKey = (key, scope)=>`${scope}:${key}`;
|
|
58
|
+
const whereLive = (builder, scopedKey, equals)=>{
|
|
59
|
+
const now = new Date();
|
|
60
|
+
builder.where("scopedKey", scopedKey).where((live)=>live.whereNull("expiresAt").orWhere("expiresAt", ">", now));
|
|
61
|
+
if (void 0 === equals) return builder;
|
|
62
|
+
const expectedValue = JSON.stringify(equals);
|
|
63
|
+
const binaryValue = binaryKey("value");
|
|
64
|
+
return builder.whereRaw(`${binaryValue.sql} = ?`, [
|
|
65
|
+
...binaryValue.bindings,
|
|
66
|
+
expectedValue
|
|
67
|
+
]);
|
|
68
|
+
};
|
|
14
69
|
return {
|
|
15
70
|
async get (key, scope) {
|
|
16
71
|
await ensureTable();
|
|
@@ -19,7 +74,10 @@ const createStorageOperations = (params)=>{
|
|
|
19
74
|
const row = await query().where("scopedKey", scopedKey).first();
|
|
20
75
|
if (!row) return null;
|
|
21
76
|
if (row.expiresAt && new Date(row.expiresAt) <= new Date()) {
|
|
22
|
-
await
|
|
77
|
+
await knex.transaction(async (trx)=>{
|
|
78
|
+
await query(trx).where("scopedKey", scopedKey).delete();
|
|
79
|
+
await collectionQuery(trx).where("scopedKey", scopedKey).delete();
|
|
80
|
+
});
|
|
23
81
|
return null;
|
|
24
82
|
}
|
|
25
83
|
return {
|
|
@@ -39,18 +97,53 @@ const createStorageOperations = (params)=>{
|
|
|
39
97
|
},
|
|
40
98
|
async set (key, value, scope, options) {
|
|
41
99
|
await ensureTable();
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
100
|
+
const scopedKey = createScopedKey(key, scope);
|
|
101
|
+
const row = {
|
|
102
|
+
scopedKey,
|
|
103
|
+
key,
|
|
104
|
+
scope,
|
|
105
|
+
value: JSON.stringify(value),
|
|
106
|
+
expiresAt: options?.expiresAt ?? null
|
|
107
|
+
};
|
|
108
|
+
const collection = options?.collection;
|
|
109
|
+
const condition = options?.condition;
|
|
110
|
+
const writeCollection = async (trx)=>{
|
|
111
|
+
if (collection) return void await collectionQuery(trx).insert({
|
|
46
112
|
scopedKey,
|
|
47
|
-
key,
|
|
48
113
|
scope,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
};
|
|
52
|
-
await
|
|
114
|
+
collection,
|
|
115
|
+
key
|
|
116
|
+
}).onConflict("scopedKey").merge();
|
|
117
|
+
await collectionQuery(trx).where("scopedKey", scopedKey).delete();
|
|
118
|
+
};
|
|
119
|
+
try {
|
|
120
|
+
if (condition?.exists === false) {
|
|
121
|
+
await knex.transaction(async (trx)=>{
|
|
122
|
+
const now = new Date();
|
|
123
|
+
const expired = await query(trx).where("scopedKey", scopedKey).whereNotNull("expiresAt").where("expiresAt", "<=", now).first("scopedKey");
|
|
124
|
+
if (expired) await query(trx).where("scopedKey", scopedKey).where("expiresAt", "<=", now).delete();
|
|
125
|
+
await query(trx).insert(row);
|
|
126
|
+
await writeCollection(trx);
|
|
127
|
+
});
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
if (condition) return await knex.transaction(async (trx)=>{
|
|
131
|
+
const records = query(trx);
|
|
132
|
+
const updated = await whereLive(records, scopedKey, condition.equals).update({
|
|
133
|
+
value: row.value,
|
|
134
|
+
expiresAt: row.expiresAt
|
|
135
|
+
});
|
|
136
|
+
if (0 === updated) return false;
|
|
137
|
+
await writeCollection(trx);
|
|
138
|
+
return true;
|
|
139
|
+
});
|
|
140
|
+
await knex.transaction(async (trx)=>{
|
|
141
|
+
await query(trx).insert(row).onConflict("scopedKey").merge();
|
|
142
|
+
await writeCollection(trx);
|
|
143
|
+
});
|
|
144
|
+
return true;
|
|
53
145
|
} catch (err) {
|
|
146
|
+
if (condition?.exists === false && isPrimaryKeyViolation(err)) return false;
|
|
54
147
|
throw WebinyError.from(err, {
|
|
55
148
|
message: "Could not set key-value record.",
|
|
56
149
|
code: "SET_KEY_VALUE_ERROR",
|
|
@@ -61,11 +154,55 @@ const createStorageOperations = (params)=>{
|
|
|
61
154
|
});
|
|
62
155
|
}
|
|
63
156
|
},
|
|
64
|
-
async
|
|
157
|
+
async list ({ collection, scope, limit, reverse, after }) {
|
|
65
158
|
await ensureTable();
|
|
66
159
|
try {
|
|
67
|
-
const
|
|
68
|
-
|
|
160
|
+
const builder = knex.from({
|
|
161
|
+
c: tableManager.resolve(COLLECTION_TABLE_NAME)
|
|
162
|
+
}).join({
|
|
163
|
+
kv: tableManager.resolve(TABLE_NAME)
|
|
164
|
+
}, "kv.scopedKey", "c.scopedKey").where("c.scope", scope).where("c.collection", collection).select("kv.key", "kv.value", "kv.expiresAt");
|
|
165
|
+
const orderedKey = binaryKey("c.key");
|
|
166
|
+
if (void 0 !== after) builder.whereRaw(`${orderedKey.sql} ${reverse ? "<" : ">"} ?`, [
|
|
167
|
+
...orderedKey.bindings,
|
|
168
|
+
after
|
|
169
|
+
]);
|
|
170
|
+
const rows = await builder.orderByRaw(`${orderedKey.sql} ${reverse ? "DESC" : "ASC"}`, orderedKey.bindings).limit(limit + 1);
|
|
171
|
+
const page = rows.slice(0, limit);
|
|
172
|
+
const now = new Date();
|
|
173
|
+
return {
|
|
174
|
+
items: page.filter((row)=>!row.expiresAt || new Date(row.expiresAt) > now).map((row)=>({
|
|
175
|
+
key: row.key,
|
|
176
|
+
value: JSON.parse(row.value)
|
|
177
|
+
})),
|
|
178
|
+
lastKey: rows.length > limit ? page[page.length - 1].key : null
|
|
179
|
+
};
|
|
180
|
+
} catch (err) {
|
|
181
|
+
throw WebinyError.from(err, {
|
|
182
|
+
message: "Could not list key-value records.",
|
|
183
|
+
code: "LIST_KEY_VALUE_ERROR",
|
|
184
|
+
data: {
|
|
185
|
+
collection,
|
|
186
|
+
scope,
|
|
187
|
+
after
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
async delete (key, scope, options) {
|
|
193
|
+
await ensureTable();
|
|
194
|
+
const scopedKey = createScopedKey(key, scope);
|
|
195
|
+
try {
|
|
196
|
+
return await knex.transaction(async (trx)=>{
|
|
197
|
+
const condition = options?.condition;
|
|
198
|
+
if (condition) {
|
|
199
|
+
const records = query(trx);
|
|
200
|
+
const deleted = await whereLive(records, scopedKey, condition.equals).delete();
|
|
201
|
+
if (0 === deleted) return false;
|
|
202
|
+
} else await query(trx).where("scopedKey", scopedKey).delete();
|
|
203
|
+
await collectionQuery(trx).where("scopedKey", scopedKey).delete();
|
|
204
|
+
return true;
|
|
205
|
+
});
|
|
69
206
|
} catch (err) {
|
|
70
207
|
throw WebinyError.from(err, {
|
|
71
208
|
message: "Could not delete key-value record.",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyValueStore/index.js","sources":["../../src/keyValueStore/index.ts"],"sourcesContent":["import type { Knex } from \"knex\";\nimport type {\n IKeyValueStorageOperations,\n IKeyValueStoreSetOptions\n} from \"@webiny/api-core/features/keyValueStore/abstractions.js\";\nimport { WebinyError } from \"@webiny/error\";\nimport type { TableManager } from \"~/TableManager.js\";\n\nconst TABLE_NAME = \"webiny_core_key_value\";\n\ninterface IKeyValueRow {\n scopedKey: string;\n key: string;\n scope: string;\n value: string;\n expiresAt: Date | null;\n}\n\ninterface CreateStorageOperationsParams {\n knex: Knex;\n tableManager: TableManager;\n}\n\nexport const createStorageOperations = (\n params: CreateStorageOperationsParams\n): IKeyValueStorageOperations => {\n const { knex, tableManager } = params;\n\n const ensureTable = () => {\n return tableManager.ensure(TABLE_NAME, table => {\n table.text(\"scopedKey\").primary().notNullable();\n table.text(\"key\").notNullable();\n table.text(\"scope\").notNullable();\n table.text(\"value\").notNullable();\n table.datetime(\"expiresAt\");\n });\n };\n\n const query = () => {\n return knex<IKeyValueRow>(tableManager.resolve(TABLE_NAME));\n };\n\n const createScopedKey = (key: string, scope: string): string => {\n return `${scope}:${key}`;\n };\n\n return {\n async get(key: string, scope: string) {\n await ensureTable();\n\n try {\n const scopedKey = createScopedKey(key, scope);\n const row = await query().where(\"scopedKey\", scopedKey).first();\n\n if (!row) {\n return null;\n }\n\n if (row.expiresAt && new Date(row.expiresAt) <= new Date()) {\n await query().where(\"scopedKey\", scopedKey).delete();\n return null;\n }\n\n return {\n key,\n value: JSON.parse(row.value)\n };\n } catch (err) {\n throw WebinyError.from(err, {\n message: \"Could not get key-value record.\",\n code: \"GET_KEY_VALUE_ERROR\",\n data: { key, scope }\n });\n }\n },\n\n async set(key: string, value: any, scope: string, options?: IKeyValueStoreSetOptions) {\n await ensureTable();\n\n try {\n const scopedKey = createScopedKey(key, scope);\n const expiresAt = options?.expiresAt ?? null;\n\n const row: IKeyValueRow = {\n scopedKey,\n key,\n scope,\n value: JSON.stringify(value),\n expiresAt\n };\n\n await query().insert(row).onConflict(\"scopedKey\").merge();\n } catch (err) {\n throw WebinyError.from(err, {\n message: \"Could not set key-value record.\",\n code: \"SET_KEY_VALUE_ERROR\",\n data: { key, scope }\n });\n }\n },\n\n async delete(key: string, scope: string) {\n await ensureTable();\n\n try {\n const scopedKey = createScopedKey(key, scope);\n await query().where(\"scopedKey\", scopedKey).delete();\n } catch (err) {\n throw WebinyError.from(err, {\n message: \"Could not delete key-value record.\",\n code: \"DELETE_KEY_VALUE_ERROR\",\n data: { key, scope }\n });\n }\n }\n };\n};\n"],"names":["TABLE_NAME","createStorageOperations","params","knex","tableManager","ensureTable","table","query","createScopedKey","key","scope","scopedKey","row","Date","JSON","err","WebinyError","value","options","expiresAt"],"mappings":";AAQA,MAAMA,aAAa;AAeZ,MAAMC,0BAA0B,CACnCC;IAEA,MAAM,EAAEC,IAAI,EAAEC,YAAY,EAAE,GAAGF;IAE/B,MAAMG,cAAc,IACTD,aAAa,MAAM,CAACJ,YAAYM,CAAAA;YACnCA,MAAM,IAAI,CAAC,aAAa,OAAO,GAAG,WAAW;YAC7CA,MAAM,IAAI,CAAC,OAAO,WAAW;YAC7BA,MAAM,IAAI,CAAC,SAAS,WAAW;YAC/BA,MAAM,IAAI,CAAC,SAAS,WAAW;YAC/BA,MAAM,QAAQ,CAAC;QACnB;IAGJ,MAAMC,QAAQ,IACHJ,KAAmBC,aAAa,OAAO,CAACJ;IAGnD,MAAMQ,kBAAkB,CAACC,KAAaC,QAC3B,GAAGA,MAAM,CAAC,EAAED,KAAK;IAG5B,OAAO;QACH,MAAM,KAAIA,GAAW,EAAEC,KAAa;YAChC,MAAML;YAEN,IAAI;gBACA,MAAMM,YAAYH,gBAAgBC,KAAKC;gBACvC,MAAME,MAAM,MAAML,QAAQ,KAAK,CAAC,aAAaI,WAAW,KAAK;gBAE7D,IAAI,CAACC,KACD,OAAO;gBAGX,IAAIA,IAAI,SAAS,IAAI,IAAIC,KAAKD,IAAI,SAAS,KAAK,IAAIC,QAAQ;oBACxD,MAAMN,QAAQ,KAAK,CAAC,aAAaI,WAAW,MAAM;oBAClD,OAAO;gBACX;gBAEA,OAAO;oBACHF;oBACA,OAAOK,KAAK,KAAK,CAACF,IAAI,KAAK;gBAC/B;YACJ,EAAE,OAAOG,KAAK;gBACV,MAAMC,YAAY,IAAI,CAACD,KAAK;oBACxB,SAAS;oBACT,MAAM;oBACN,MAAM;wBAAEN;wBAAKC;oBAAM;gBACvB;YACJ;QACJ;QAEA,MAAM,KAAID,GAAW,EAAEQ,KAAU,EAAEP,KAAa,EAAEQ,OAAkC;YAChF,MAAMb;YAEN,IAAI;gBACA,MAAMM,YAAYH,gBAAgBC,KAAKC;gBACvC,MAAMS,YAAYD,SAAS,aAAa;gBAExC,MAAMN,MAAoB;oBACtBD;oBACAF;oBACAC;oBACA,OAAOI,KAAK,SAAS,CAACG;oBACtBE;gBACJ;gBAEA,MAAMZ,QAAQ,MAAM,CAACK,KAAK,UAAU,CAAC,aAAa,KAAK;YAC3D,EAAE,OAAOG,KAAK;gBACV,MAAMC,YAAY,IAAI,CAACD,KAAK;oBACxB,SAAS;oBACT,MAAM;oBACN,MAAM;wBAAEN;wBAAKC;oBAAM;gBACvB;YACJ;QACJ;QAEA,MAAM,QAAOD,GAAW,EAAEC,KAAa;YACnC,MAAML;YAEN,IAAI;gBACA,MAAMM,YAAYH,gBAAgBC,KAAKC;gBACvC,MAAMH,QAAQ,KAAK,CAAC,aAAaI,WAAW,MAAM;YACtD,EAAE,OAAOI,KAAK;gBACV,MAAMC,YAAY,IAAI,CAACD,KAAK;oBACxB,SAAS;oBACT,MAAM;oBACN,MAAM;wBAAEN;wBAAKC;oBAAM;gBACvB;YACJ;QACJ;IACJ;AACJ"}
|
|
1
|
+
{"version":3,"file":"keyValueStore/index.js","sources":["../../src/keyValueStore/index.ts"],"sourcesContent":["import type { Knex } from \"knex\";\nimport type { IKeyValueStorageOperations } from \"@webiny/api-core/features/keyValueStore/abstractions.js\";\nimport type { IKeyValueStoreSetOptions } from \"@webiny/api-core/features/keyValueStore/abstractions.js\";\nimport type { IKeyValueDeleteOptions } from \"@webiny/api-core/features/keyValueStore/abstractions.js\";\nimport type { KeyValueComparable } from \"@webiny/api-core/features/keyValueStore/abstractions.js\";\nimport { WebinyError } from \"@webiny/error\";\nimport type { TableManager } from \"~/TableManager.js\";\n\nconst TABLE_NAME = \"webiny_core_key_value\";\n/*\n * Which collection each listable record belongs to. A table of its own because `ensure` only creates\n * tables, so an existing key-value table cannot gain a column, and because a record in no collection,\n * like most of them, then costs nothing here.\n */\nconst COLLECTION_TABLE_NAME = \"webiny_core_key_value_collection\";\n\ninterface IKeyValueRow {\n scopedKey: string;\n key: string;\n scope: string;\n value: string;\n expiresAt: Date | null;\n}\n\ninterface IKeyValueCollectionRow {\n scopedKey: string;\n scope: string;\n collection: string;\n key: string;\n}\n\n/*\n * An `exists: false` insert fails on the primary key when a live record holds the key. The code names\n * that violation per driver: Postgres, MySQL, and SQLite (better-sqlite3).\n */\nconst isPrimaryKeyViolation = (error: unknown): boolean => {\n const code = (error as { code?: unknown })?.code;\n return (\n code === \"23505\" ||\n code === \"ER_DUP_ENTRY\" ||\n code === \"SQLITE_CONSTRAINT_PRIMARYKEY\" ||\n code === \"SQLITE_CONSTRAINT_UNIQUE\"\n );\n};\n\ninterface CreateStorageOperationsParams {\n knex: Knex;\n tableManager: TableManager;\n}\n\nexport const createStorageOperations = (\n params: CreateStorageOperationsParams\n): IKeyValueStorageOperations => {\n const { knex, tableManager } = params;\n\n const ensureTable = async () => {\n await tableManager.ensure(TABLE_NAME, table => {\n table.text(\"scopedKey\").primary().notNullable();\n table.text(\"key\").notNullable();\n table.text(\"scope\").notNullable();\n table.text(\"value\").notNullable();\n table.datetime(\"expiresAt\");\n });\n await tableManager.ensure(COLLECTION_TABLE_NAME, table => {\n table.text(\"scopedKey\").primary().notNullable();\n table.text(\"scope\").notNullable();\n table.text(\"collection\").notNullable();\n table.text(\"key\").notNullable();\n table.index([\"scope\", \"collection\"]);\n });\n };\n\n const query = (trx: Knex = knex) => {\n return trx<IKeyValueRow>(tableManager.resolve(TABLE_NAME));\n };\n\n const collectionQuery = (trx: Knex = knex) => {\n return trx<IKeyValueCollectionRow>(tableManager.resolve(COLLECTION_TABLE_NAME));\n };\n\n /*\n * The key compared byte by byte, as DynamoDB compares sort keys, so both stores page in the same\n * order. SQLite compares text that way already. Postgres and MySQL use the column's collation,\n * which can be a locale that ignores case and punctuation, unless told otherwise. `??` leaves\n * quoting the column to the dialect.\n */\n const binaryKey = (column: string): { sql: string; bindings: string[] } => {\n switch (knex.client.dialect) {\n case \"postgresql\":\n return { sql: `?? COLLATE \"C\"`, bindings: [column] };\n case \"mysql\":\n case \"mysql2\":\n return { sql: \"BINARY ??\", bindings: [column] };\n default:\n return { sql: \"??\", bindings: [column] };\n }\n };\n\n const createScopedKey = (key: string, scope: string): string => {\n return `${scope}:${key}`;\n };\n\n /*\n * Narrows a query to the live record, and with `equals` to one holding that value. The value is\n * compared as stored, JSON text, byte for byte: a case-insensitive collation would let \"P1\"\n * match \"p1\".\n */\n const whereLive = (\n builder: Knex.QueryBuilder<IKeyValueRow>,\n scopedKey: string,\n equals: KeyValueComparable | undefined\n ) => {\n const now = new Date();\n builder\n .where(\"scopedKey\", scopedKey)\n .where(live => live.whereNull(\"expiresAt\").orWhere(\"expiresAt\", \">\", now));\n if (equals === undefined) {\n return builder;\n }\n const expectedValue = JSON.stringify(equals);\n const binaryValue = binaryKey(\"value\");\n return builder.whereRaw(`${binaryValue.sql} = ?`, [...binaryValue.bindings, expectedValue]);\n };\n\n return {\n async get(key: string, scope: string) {\n await ensureTable();\n\n try {\n const scopedKey = createScopedKey(key, scope);\n const row = await query().where(\"scopedKey\", scopedKey).first();\n\n if (!row) {\n return null;\n }\n\n if (row.expiresAt && new Date(row.expiresAt) <= new Date()) {\n await knex.transaction(async trx => {\n await query(trx).where(\"scopedKey\", scopedKey).delete();\n await collectionQuery(trx).where(\"scopedKey\", scopedKey).delete();\n });\n return null;\n }\n\n return {\n key,\n value: JSON.parse(row.value)\n };\n } catch (err) {\n throw WebinyError.from(err, {\n message: \"Could not get key-value record.\",\n code: \"GET_KEY_VALUE_ERROR\",\n data: { key, scope }\n });\n }\n },\n\n async set(key: string, value: any, scope: string, options?: IKeyValueStoreSetOptions) {\n await ensureTable();\n\n const scopedKey = createScopedKey(key, scope);\n const row: IKeyValueRow = {\n scopedKey,\n key,\n scope,\n value: JSON.stringify(value),\n expiresAt: options?.expiresAt ?? null\n };\n const collection = options?.collection;\n const condition = options?.condition;\n\n /*\n * Like DynamoDB's put, a write without a collection takes the record out of the one it\n * was in, so both stores agree on what `list` returns.\n */\n const writeCollection = async (trx: Knex) => {\n if (collection) {\n await collectionQuery(trx)\n .insert({ scopedKey, scope, collection, key })\n .onConflict(\"scopedKey\")\n .merge();\n return;\n }\n await collectionQuery(trx).where(\"scopedKey\", scopedKey).delete();\n };\n\n try {\n if (condition?.exists === false) {\n /*\n * An expired record counts as absent, so it is cleared first. The insert then\n * fails on the primary key exactly when a live record holds the key, and the\n * transaction rolls back with it. Of two callers racing, the database lets one\n * insert through.\n *\n * The delete runs only when an expired record is there: on MySQL a delete that\n * matches nothing locks the gap, and two racing callers holding that lock would\n * deadlock on the insert instead of one losing on the primary key.\n */\n await knex.transaction(async trx => {\n const now = new Date();\n const expired = await query(trx)\n .where(\"scopedKey\", scopedKey)\n .whereNotNull(\"expiresAt\")\n .where(\"expiresAt\", \"<=\", now)\n .first(\"scopedKey\");\n if (expired) {\n await query(trx)\n .where(\"scopedKey\", scopedKey)\n .where(\"expiresAt\", \"<=\", now)\n .delete();\n }\n await query(trx).insert(row);\n await writeCollection(trx);\n });\n return true;\n }\n\n // `exists: true` or `equals`: only a live record, and the right one, is replaced.\n if (condition) {\n return await knex.transaction(async trx => {\n const records = query(trx);\n const updated = await whereLive(\n records,\n scopedKey,\n condition.equals\n ).update({\n value: row.value,\n expiresAt: row.expiresAt\n });\n if (updated === 0) {\n return false;\n }\n await writeCollection(trx);\n return true;\n });\n }\n\n await knex.transaction(async trx => {\n await query(trx).insert(row).onConflict(\"scopedKey\").merge();\n await writeCollection(trx);\n });\n return true;\n } catch (err) {\n if (condition?.exists === false && isPrimaryKeyViolation(err)) {\n return false;\n }\n throw WebinyError.from(err, {\n message: \"Could not set key-value record.\",\n code: \"SET_KEY_VALUE_ERROR\",\n data: { key, scope }\n });\n }\n },\n\n async list({ collection, scope, limit, reverse, after }) {\n await ensureTable();\n\n try {\n const builder = knex\n .from({ c: tableManager.resolve(COLLECTION_TABLE_NAME) })\n .join({ kv: tableManager.resolve(TABLE_NAME) }, \"kv.scopedKey\", \"c.scopedKey\")\n .where(\"c.scope\", scope)\n .where(\"c.collection\", collection)\n .select(\"kv.key\", \"kv.value\", \"kv.expiresAt\");\n\n const orderedKey = binaryKey(\"c.key\");\n if (after !== undefined) {\n builder.whereRaw(`${orderedKey.sql} ${reverse ? \"<\" : \">\"} ?`, [\n ...orderedKey.bindings,\n after\n ]);\n }\n\n // One extra row tells whether another page exists without a second, empty read.\n const rows: Pick<IKeyValueRow, \"key\" | \"value\" | \"expiresAt\">[] = await builder\n .orderByRaw(\n `${orderedKey.sql} ${reverse ? \"DESC\" : \"ASC\"}`,\n orderedKey.bindings\n )\n .limit(limit + 1);\n const page = rows.slice(0, limit);\n const now = new Date();\n\n return {\n items: page\n .filter(row => !row.expiresAt || new Date(row.expiresAt) > now)\n .map(row => ({ key: row.key, value: JSON.parse(row.value) })),\n lastKey: rows.length > limit ? page[page.length - 1].key : null\n };\n } catch (err) {\n throw WebinyError.from(err, {\n message: \"Could not list key-value records.\",\n code: \"LIST_KEY_VALUE_ERROR\",\n data: { collection, scope, after }\n });\n }\n },\n\n async delete(key: string, scope: string, options?: IKeyValueDeleteOptions) {\n await ensureTable();\n\n const scopedKey = createScopedKey(key, scope);\n\n try {\n return await knex.transaction(async trx => {\n const condition = options?.condition;\n if (condition) {\n const records = query(trx);\n const deleted = await whereLive(\n records,\n scopedKey,\n condition.equals\n ).delete();\n if (deleted === 0) {\n return false;\n }\n } else {\n await query(trx).where(\"scopedKey\", scopedKey).delete();\n }\n await collectionQuery(trx).where(\"scopedKey\", scopedKey).delete();\n return true;\n });\n } catch (err) {\n throw WebinyError.from(err, {\n message: \"Could not delete key-value record.\",\n code: \"DELETE_KEY_VALUE_ERROR\",\n data: { key, scope }\n });\n }\n }\n };\n};\n"],"names":["TABLE_NAME","COLLECTION_TABLE_NAME","isPrimaryKeyViolation","error","code","createStorageOperations","params","knex","tableManager","ensureTable","table","query","trx","collectionQuery","binaryKey","column","createScopedKey","key","scope","whereLive","builder","scopedKey","equals","now","Date","live","undefined","expectedValue","JSON","binaryValue","row","err","WebinyError","value","options","collection","condition","writeCollection","expired","records","updated","limit","reverse","after","orderedKey","rows","page","deleted"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webiny/api-core-sql",
|
|
3
|
-
"version": "0.0.0-unstable.
|
|
3
|
+
"version": "0.0.0-unstable.d0f34a8194",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./index.js",
|
|
@@ -21,18 +21,17 @@
|
|
|
21
21
|
"author": "Webiny Ltd.",
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@webiny/api-core": "0.0.0-unstable.
|
|
25
|
-
"@webiny/error": "0.0.0-unstable.
|
|
26
|
-
"@webiny/feature": "0.0.0-unstable.
|
|
27
|
-
"@webiny/handler": "0.0.0-unstable.
|
|
24
|
+
"@webiny/api-core": "0.0.0-unstable.d0f34a8194",
|
|
25
|
+
"@webiny/error": "0.0.0-unstable.d0f34a8194",
|
|
26
|
+
"@webiny/feature": "0.0.0-unstable.d0f34a8194",
|
|
27
|
+
"@webiny/handler": "0.0.0-unstable.d0f34a8194",
|
|
28
28
|
"knex": "3.3.0"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@webiny/build-tools": "0.0.0-unstable.
|
|
32
|
-
"
|
|
33
|
-
"better-sqlite3": "13.0.1",
|
|
31
|
+
"@webiny/build-tools": "0.0.0-unstable.d0f34a8194",
|
|
32
|
+
"better-sqlite3": "13.0.3",
|
|
34
33
|
"typescript": "7.0.2",
|
|
35
|
-
"vitest": "4.1.
|
|
34
|
+
"vitest": "4.1.11"
|
|
36
35
|
},
|
|
37
36
|
"publishConfig": {
|
|
38
37
|
"access": "public"
|