velocious 1.0.481 → 1.0.483
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/README.md +2 -0
- package/build/cli/commands/db/tenants/drop.js +34 -0
- package/build/cli/tenant-database-command-helper.js +8 -85
- package/build/database/tenants/data-copier.js +269 -0
- package/build/database/tenants/schema-cloner.js +390 -0
- package/build/database/tenants/tenant-table-plan.js +20 -0
- package/build/src/cli/commands/db/tenants/drop.d.ts +13 -0
- package/build/src/cli/commands/db/tenants/drop.d.ts.map +1 -0
- package/build/src/cli/commands/db/tenants/drop.js +31 -0
- package/build/src/cli/tenant-database-command-helper.d.ts +0 -20
- package/build/src/cli/tenant-database-command-helper.d.ts.map +1 -1
- package/build/src/cli/tenant-database-command-helper.js +8 -73
- package/build/src/database/tenants/data-copier.d.ts +125 -0
- package/build/src/database/tenants/data-copier.d.ts.map +1 -0
- package/build/src/database/tenants/data-copier.js +232 -0
- package/build/src/database/tenants/schema-cloner.d.ts +147 -0
- package/build/src/database/tenants/schema-cloner.d.ts.map +1 -0
- package/build/src/database/tenants/schema-cloner.js +326 -0
- package/build/src/database/tenants/tenant-table-plan.d.ts +30 -0
- package/build/src/database/tenants/tenant-table-plan.d.ts.map +1 -0
- package/build/src/database/tenants/tenant-table-plan.js +3 -0
- package/build/src/tenants/tenant-iterator.d.ts +52 -0
- package/build/src/tenants/tenant-iterator.d.ts.map +1 -0
- package/build/src/tenants/tenant-iterator.js +97 -0
- package/build/src/tenants/tenant.d.ts +51 -0
- package/build/src/tenants/tenant.d.ts.map +1 -0
- package/build/src/tenants/tenant.js +76 -0
- package/build/tenants/tenant-iterator.js +111 -0
- package/build/tenants/tenant.js +86 -0
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/cli/commands/db/tenants/drop.js +34 -0
- package/src/cli/tenant-database-command-helper.js +8 -85
- package/src/database/tenants/data-copier.js +269 -0
- package/src/database/tenants/schema-cloner.js +390 -0
- package/src/database/tenants/tenant-table-plan.js +20 -0
- package/src/tenants/tenant-iterator.js +111 -0
- package/src/tenants/tenant.js +86 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apartment-style runtime façade for multi-tenant apps. A "tenant" is whatever descriptor
|
|
3
|
+
* object the app's `tenantDatabaseResolver` understands (an account, a project, …); this
|
|
4
|
+
* class is the single discoverable home for switching into a tenant's context, reading the
|
|
5
|
+
* current one, iterating every tenant of a database identifier, and dropping a tenant's
|
|
6
|
+
* database. Switching/reading delegate to {@link Current} (which owns the async-context
|
|
7
|
+
* tenant state), so they compose with the existing connection pools and request lifecycle;
|
|
8
|
+
* iteration and drop drive the app's tenant database provider hooks.
|
|
9
|
+
*/
|
|
10
|
+
export default class Tenant {
|
|
11
|
+
/**
|
|
12
|
+
* Runs `callback` with `tenant` as the current tenant, restoring the previous tenant after.
|
|
13
|
+
* @param {object} tenant Descriptor understood by the app's tenantDatabaseResolver.
|
|
14
|
+
* @param {() => Promise<?>} callback
|
|
15
|
+
* @returns {Promise<?>}
|
|
16
|
+
*/
|
|
17
|
+
static with(tenant: object, callback: () => Promise<unknown>): Promise<unknown>;
|
|
18
|
+
/**
|
|
19
|
+
* The current tenant descriptor, or undefined when running outside any tenant context.
|
|
20
|
+
* @returns {Record<string, unknown> | undefined}
|
|
21
|
+
*/
|
|
22
|
+
static current(): Record<string, unknown> | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Lists the tenants for a database identifier through the provider and runs `callback`
|
|
25
|
+
* within each tenant's context, optionally filtered and several at a time. Returns how
|
|
26
|
+
* many tenants the callback ran for (after filtering).
|
|
27
|
+
* @param {{identifier: string, callback: function({databaseConfiguration: import("../configuration-types.js").DatabaseConfigurationType, tenant: ?}) : Promise<void>, parallel?: number, filter?: (tenant: ?) => boolean, configuration?: import("../configuration.js").default}} args
|
|
28
|
+
* @returns {Promise<number>}
|
|
29
|
+
*/
|
|
30
|
+
static each({ identifier, callback, parallel, filter, configuration }: {
|
|
31
|
+
identifier: string;
|
|
32
|
+
callback: (arg0: {
|
|
33
|
+
databaseConfiguration: import("../configuration-types.js").DatabaseConfigurationType;
|
|
34
|
+
tenant: unknown;
|
|
35
|
+
}) => Promise<void>;
|
|
36
|
+
parallel?: number;
|
|
37
|
+
filter?: (tenant: unknown) => boolean;
|
|
38
|
+
configuration?: import("../configuration.js").default;
|
|
39
|
+
}): Promise<number>;
|
|
40
|
+
/**
|
|
41
|
+
* Drops one tenant's database/schema through the provider's `dropDatabase` hook.
|
|
42
|
+
* @param {{identifier: string, tenant: object, configuration?: import("../configuration.js").default}} args
|
|
43
|
+
* @returns {Promise<void>}
|
|
44
|
+
*/
|
|
45
|
+
static drop({ identifier, tenant, configuration }: {
|
|
46
|
+
identifier: string;
|
|
47
|
+
tenant: object;
|
|
48
|
+
configuration?: import("../configuration.js").default;
|
|
49
|
+
}): Promise<void>;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=tenant.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenant.d.ts","sourceRoot":"","sources":["../../../src/tenants/tenant.js"],"names":[],"mappings":"AAKA;;;;;;;;GAQG;AACH;IACE;;;;;OAKG;IACH,oBAJW,MAAM,YACN,MAAM,OAAO,CAAC,OAAC,CAAC,GACd,OAAO,CAAC,OAAC,CAAC,CAItB;IAED;;;OAGG;IACH,kBAFa,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAI/C;IAED;;;;;;OAMG;IACH,uEAHW;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,CAAS,IAAiG,EAAjG;YAAC,qBAAqB,EAAE,OAAO,2BAA2B,EAAE,yBAAyB,CAAC;YAAC,MAAM,EAAE,OAAC,CAAA;SAAC,KAAI,OAAO,CAAC,IAAI,CAAC,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,OAAC,KAAK,OAAO,CAAC;QAAC,aAAa,CAAC,EAAE,OAAO,qBAAqB,EAAE,OAAO,CAAA;KAAC,GACpQ,OAAO,CAAC,MAAM,CAAC,CAgB3B;IAED;;;;OAIG;IACH,mDAHW;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,aAAa,CAAC,EAAE,OAAO,qBAAqB,EAAE,OAAO,CAAA;KAAC,GACzF,OAAO,CAAC,IAAI,CAAC,CAyBzB;CACF"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import Current from "../current.js";
|
|
3
|
+
import TenantIterator from "./tenant-iterator.js";
|
|
4
|
+
/**
|
|
5
|
+
* Apartment-style runtime façade for multi-tenant apps. A "tenant" is whatever descriptor
|
|
6
|
+
* object the app's `tenantDatabaseResolver` understands (an account, a project, …); this
|
|
7
|
+
* class is the single discoverable home for switching into a tenant's context, reading the
|
|
8
|
+
* current one, iterating every tenant of a database identifier, and dropping a tenant's
|
|
9
|
+
* database. Switching/reading delegate to {@link Current} (which owns the async-context
|
|
10
|
+
* tenant state), so they compose with the existing connection pools and request lifecycle;
|
|
11
|
+
* iteration and drop drive the app's tenant database provider hooks.
|
|
12
|
+
*/
|
|
13
|
+
export default class Tenant {
|
|
14
|
+
/**
|
|
15
|
+
* Runs `callback` with `tenant` as the current tenant, restoring the previous tenant after.
|
|
16
|
+
* @param {object} tenant Descriptor understood by the app's tenantDatabaseResolver.
|
|
17
|
+
* @param {() => Promise<?>} callback
|
|
18
|
+
* @returns {Promise<?>}
|
|
19
|
+
*/
|
|
20
|
+
static async with(tenant, callback) {
|
|
21
|
+
return await Current.withTenant(tenant, callback);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The current tenant descriptor, or undefined when running outside any tenant context.
|
|
25
|
+
* @returns {Record<string, unknown> | undefined}
|
|
26
|
+
*/
|
|
27
|
+
static current() {
|
|
28
|
+
return Current.tenant();
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Lists the tenants for a database identifier through the provider and runs `callback`
|
|
32
|
+
* within each tenant's context, optionally filtered and several at a time. Returns how
|
|
33
|
+
* many tenants the callback ran for (after filtering).
|
|
34
|
+
* @param {{identifier: string, callback: function({databaseConfiguration: import("../configuration-types.js").DatabaseConfigurationType, tenant: ?}) : Promise<void>, parallel?: number, filter?: (tenant: ?) => boolean, configuration?: import("../configuration.js").default}} args
|
|
35
|
+
* @returns {Promise<number>}
|
|
36
|
+
*/
|
|
37
|
+
static async each({ identifier, callback, parallel = 1, filter, configuration = Current.configuration() }) {
|
|
38
|
+
const provider = configuration.getTenantDatabaseProvider(identifier);
|
|
39
|
+
const listedTenants = await configuration.ensureConnections({ name: `Tenant.each: ${identifier}` }, async () => {
|
|
40
|
+
return await provider.listTenants({ configuration, identifier });
|
|
41
|
+
});
|
|
42
|
+
if (!Array.isArray(listedTenants)) {
|
|
43
|
+
throw new Error(`Tenant database provider for ${identifier} must return an array from listTenants`);
|
|
44
|
+
}
|
|
45
|
+
const tenants = filter ? listedTenants.filter(filter) : listedTenants;
|
|
46
|
+
const iterator = new TenantIterator({ configuration, identifier, parallelCount: parallel });
|
|
47
|
+
return await iterator.run(tenants, callback);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Drops one tenant's database/schema through the provider's `dropDatabase` hook.
|
|
51
|
+
* @param {{identifier: string, tenant: object, configuration?: import("../configuration.js").default}} args
|
|
52
|
+
* @returns {Promise<void>}
|
|
53
|
+
*/
|
|
54
|
+
static async drop({ identifier, tenant, configuration = Current.configuration() }) {
|
|
55
|
+
const provider = configuration.getTenantDatabaseProvider(identifier);
|
|
56
|
+
if (typeof provider.dropDatabase !== "function") {
|
|
57
|
+
throw new Error(`Tenant database provider for ${identifier} must define dropDatabase to drop a tenant`);
|
|
58
|
+
}
|
|
59
|
+
await configuration.runWithTenant(tenant, async () => {
|
|
60
|
+
// Guard against an unresolved tenant. resolveDatabaseConfiguration falls back to the
|
|
61
|
+
// base (template/default) tenant database when the resolver returns nothing for this
|
|
62
|
+
// descriptor, so without this check a provider that drops by databaseConfiguration.name
|
|
63
|
+
// would drop the template database instead of rejecting the bad tenant.
|
|
64
|
+
if (!configuration.isDatabaseIdentifierActive(identifier)) {
|
|
65
|
+
throw new Error(`Tenant database identifier ${identifier} is inactive for tenant: ${TenantIterator.tenantLabel(tenant)}`);
|
|
66
|
+
}
|
|
67
|
+
await provider.dropDatabase?.({
|
|
68
|
+
configuration,
|
|
69
|
+
databaseConfiguration: configuration.resolveDatabaseConfiguration(identifier),
|
|
70
|
+
identifier,
|
|
71
|
+
tenant
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVuYW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3RlbmFudHMvdGVuYW50LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVk7QUFFWixPQUFPLE9BQU8sTUFBTSxlQUFlLENBQUE7QUFDbkMsT0FBTyxjQUFjLE1BQU0sc0JBQXNCLENBQUE7QUFFakQ7Ozs7Ozs7O0dBUUc7QUFDSCxNQUFNLENBQUMsT0FBTyxPQUFPLE1BQU07SUFDekI7Ozs7O09BS0c7SUFDSCxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsUUFBUTtRQUNoQyxPQUFPLE1BQU0sT0FBTyxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsUUFBUSxDQUFDLENBQUE7SUFDbkQsQ0FBQztJQUVEOzs7T0FHRztJQUNILE1BQU0sQ0FBQyxPQUFPO1FBQ1osT0FBTyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUE7SUFDekIsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNILE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUMsVUFBVSxFQUFFLFFBQVEsRUFBRSxRQUFRLEdBQUcsQ0FBQyxFQUFFLE1BQU0sRUFBRSxhQUFhLEdBQUcsT0FBTyxDQUFDLGFBQWEsRUFBRSxFQUFDO1FBQ3JHLE1BQU0sUUFBUSxHQUFHLGFBQWEsQ0FBQyx5QkFBeUIsQ0FBQyxVQUFVLENBQUMsQ0FBQTtRQUNwRSxNQUFNLGFBQWEsR0FBRyxNQUFNLGFBQWEsQ0FBQyxpQkFBaUIsQ0FBQyxFQUFDLElBQUksRUFBRSxnQkFBZ0IsVUFBVSxFQUFFLEVBQUMsRUFBRSxLQUFLLElBQUksRUFBRTtZQUMzRyxPQUFPLE1BQU0sUUFBUSxDQUFDLFdBQVcsQ0FBQyxFQUFDLGFBQWEsRUFBRSxVQUFVLEVBQUMsQ0FBQyxDQUFBO1FBQ2hFLENBQUMsQ0FBQyxDQUFBO1FBRUYsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQztZQUNsQyxNQUFNLElBQUksS0FBSyxDQUFDLGdDQUFnQyxVQUFVLHdDQUF3QyxDQUFDLENBQUE7UUFDckcsQ0FBQztRQUVELE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFBO1FBQ3JFLE1BQU0sUUFBUSxHQUFHLElBQUksY0FBYyxDQUFDLEVBQUMsYUFBYSxFQUFFLFVBQVUsRUFBRSxhQUFhLEVBQUUsUUFBUSxFQUFDLENBQUMsQ0FBQTtRQUV6RixPQUFPLE1BQU0sUUFBUSxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDLENBQUE7SUFDOUMsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFDLFVBQVUsRUFBRSxNQUFNLEVBQUUsYUFBYSxHQUFHLE9BQU8sQ0FBQyxhQUFhLEVBQUUsRUFBQztRQUM3RSxNQUFNLFFBQVEsR0FBRyxhQUFhLENBQUMseUJBQXlCLENBQUMsVUFBVSxDQUFDLENBQUE7UUFFcEUsSUFBSSxPQUFPLFFBQVEsQ0FBQyxZQUFZLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDaEQsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsVUFBVSw0Q0FBNEMsQ0FBQyxDQUFBO1FBQ3pHLENBQUM7UUFFRCxNQUFNLGFBQWEsQ0FBQyxhQUFhLENBQUMsTUFBTSxFQUFFLEtBQUssSUFBSSxFQUFFO1lBQ25ELHFGQUFxRjtZQUNyRixxRkFBcUY7WUFDckYsd0ZBQXdGO1lBQ3hGLHdFQUF3RTtZQUN4RSxJQUFJLENBQUMsYUFBYSxDQUFDLDBCQUEwQixDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7Z0JBQzFELE1BQU0sSUFBSSxLQUFLLENBQUMsOEJBQThCLFVBQVUsNEJBQTRCLGNBQWMsQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFBO1lBQzNILENBQUM7WUFFRCxNQUFNLFFBQVEsQ0FBQyxZQUFZLEVBQUUsQ0FBQztnQkFDNUIsYUFBYTtnQkFDYixxQkFBcUIsRUFBRSxhQUFhLENBQUMsNEJBQTRCLENBQUMsVUFBVSxDQUFDO2dCQUM3RSxVQUFVO2dCQUNWLE1BQU07YUFDUCxDQUFDLENBQUE7UUFDSixDQUFDLENBQUMsQ0FBQTtJQUNKLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5pbXBvcnQgQ3VycmVudCBmcm9tIFwiLi4vY3VycmVudC5qc1wiXG5pbXBvcnQgVGVuYW50SXRlcmF0b3IgZnJvbSBcIi4vdGVuYW50LWl0ZXJhdG9yLmpzXCJcblxuLyoqXG4gKiBBcGFydG1lbnQtc3R5bGUgcnVudGltZSBmYcOnYWRlIGZvciBtdWx0aS10ZW5hbnQgYXBwcy4gQSBcInRlbmFudFwiIGlzIHdoYXRldmVyIGRlc2NyaXB0b3JcbiAqIG9iamVjdCB0aGUgYXBwJ3MgYHRlbmFudERhdGFiYXNlUmVzb2x2ZXJgIHVuZGVyc3RhbmRzIChhbiBhY2NvdW50LCBhIHByb2plY3QsIOKApik7IHRoaXNcbiAqIGNsYXNzIGlzIHRoZSBzaW5nbGUgZGlzY292ZXJhYmxlIGhvbWUgZm9yIHN3aXRjaGluZyBpbnRvIGEgdGVuYW50J3MgY29udGV4dCwgcmVhZGluZyB0aGVcbiAqIGN1cnJlbnQgb25lLCBpdGVyYXRpbmcgZXZlcnkgdGVuYW50IG9mIGEgZGF0YWJhc2UgaWRlbnRpZmllciwgYW5kIGRyb3BwaW5nIGEgdGVuYW50J3NcbiAqIGRhdGFiYXNlLiBTd2l0Y2hpbmcvcmVhZGluZyBkZWxlZ2F0ZSB0byB7QGxpbmsgQ3VycmVudH0gKHdoaWNoIG93bnMgdGhlIGFzeW5jLWNvbnRleHRcbiAqIHRlbmFudCBzdGF0ZSksIHNvIHRoZXkgY29tcG9zZSB3aXRoIHRoZSBleGlzdGluZyBjb25uZWN0aW9uIHBvb2xzIGFuZCByZXF1ZXN0IGxpZmVjeWNsZTtcbiAqIGl0ZXJhdGlvbiBhbmQgZHJvcCBkcml2ZSB0aGUgYXBwJ3MgdGVuYW50IGRhdGFiYXNlIHByb3ZpZGVyIGhvb2tzLlxuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBUZW5hbnQge1xuICAvKipcbiAgICogUnVucyBgY2FsbGJhY2tgIHdpdGggYHRlbmFudGAgYXMgdGhlIGN1cnJlbnQgdGVuYW50LCByZXN0b3JpbmcgdGhlIHByZXZpb3VzIHRlbmFudCBhZnRlci5cbiAgICogQHBhcmFtIHtvYmplY3R9IHRlbmFudCBEZXNjcmlwdG9yIHVuZGVyc3Rvb2QgYnkgdGhlIGFwcCdzIHRlbmFudERhdGFiYXNlUmVzb2x2ZXIuXG4gICAqIEBwYXJhbSB7KCkgPT4gUHJvbWlzZTw/Pn0gY2FsbGJhY2tcbiAgICogQHJldHVybnMge1Byb21pc2U8Pz59XG4gICAqL1xuICBzdGF0aWMgYXN5bmMgd2l0aCh0ZW5hbnQsIGNhbGxiYWNrKSB7XG4gICAgcmV0dXJuIGF3YWl0IEN1cnJlbnQud2l0aFRlbmFudCh0ZW5hbnQsIGNhbGxiYWNrKVxuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBjdXJyZW50IHRlbmFudCBkZXNjcmlwdG9yLCBvciB1bmRlZmluZWQgd2hlbiBydW5uaW5nIG91dHNpZGUgYW55IHRlbmFudCBjb250ZXh0LlxuICAgKiBAcmV0dXJucyB7UmVjb3JkPHN0cmluZywgdW5rbm93bj4gfCB1bmRlZmluZWR9XG4gICAqL1xuICBzdGF0aWMgY3VycmVudCgpIHtcbiAgICByZXR1cm4gQ3VycmVudC50ZW5hbnQoKVxuICB9XG5cbiAgLyoqXG4gICAqIExpc3RzIHRoZSB0ZW5hbnRzIGZvciBhIGRhdGFiYXNlIGlkZW50aWZpZXIgdGhyb3VnaCB0aGUgcHJvdmlkZXIgYW5kIHJ1bnMgYGNhbGxiYWNrYFxuICAgKiB3aXRoaW4gZWFjaCB0ZW5hbnQncyBjb250ZXh0LCBvcHRpb25hbGx5IGZpbHRlcmVkIGFuZCBzZXZlcmFsIGF0IGEgdGltZS4gUmV0dXJucyBob3dcbiAgICogbWFueSB0ZW5hbnRzIHRoZSBjYWxsYmFjayByYW4gZm9yIChhZnRlciBmaWx0ZXJpbmcpLlxuICAgKiBAcGFyYW0ge3tpZGVudGlmaWVyOiBzdHJpbmcsIGNhbGxiYWNrOiBmdW5jdGlvbih7ZGF0YWJhc2VDb25maWd1cmF0aW9uOiBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLkRhdGFiYXNlQ29uZmlndXJhdGlvblR5cGUsIHRlbmFudDogP30pIDogUHJvbWlzZTx2b2lkPiwgcGFyYWxsZWw/OiBudW1iZXIsIGZpbHRlcj86ICh0ZW5hbnQ6ID8pID0+IGJvb2xlYW4sIGNvbmZpZ3VyYXRpb24/OiBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLmpzXCIpLmRlZmF1bHR9fSBhcmdzXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPG51bWJlcj59XG4gICAqL1xuICBzdGF0aWMgYXN5bmMgZWFjaCh7aWRlbnRpZmllciwgY2FsbGJhY2ssIHBhcmFsbGVsID0gMSwgZmlsdGVyLCBjb25maWd1cmF0aW9uID0gQ3VycmVudC5jb25maWd1cmF0aW9uKCl9KSB7XG4gICAgY29uc3QgcHJvdmlkZXIgPSBjb25maWd1cmF0aW9uLmdldFRlbmFudERhdGFiYXNlUHJvdmlkZXIoaWRlbnRpZmllcilcbiAgICBjb25zdCBsaXN0ZWRUZW5hbnRzID0gYXdhaXQgY29uZmlndXJhdGlvbi5lbnN1cmVDb25uZWN0aW9ucyh7bmFtZTogYFRlbmFudC5lYWNoOiAke2lkZW50aWZpZXJ9YH0sIGFzeW5jICgpID0+IHtcbiAgICAgIHJldHVybiBhd2FpdCBwcm92aWRlci5saXN0VGVuYW50cyh7Y29uZmlndXJhdGlvbiwgaWRlbnRpZmllcn0pXG4gICAgfSlcblxuICAgIGlmICghQXJyYXkuaXNBcnJheShsaXN0ZWRUZW5hbnRzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBUZW5hbnQgZGF0YWJhc2UgcHJvdmlkZXIgZm9yICR7aWRlbnRpZmllcn0gbXVzdCByZXR1cm4gYW4gYXJyYXkgZnJvbSBsaXN0VGVuYW50c2ApXG4gICAgfVxuXG4gICAgY29uc3QgdGVuYW50cyA9IGZpbHRlciA/IGxpc3RlZFRlbmFudHMuZmlsdGVyKGZpbHRlcikgOiBsaXN0ZWRUZW5hbnRzXG4gICAgY29uc3QgaXRlcmF0b3IgPSBuZXcgVGVuYW50SXRlcmF0b3Ioe2NvbmZpZ3VyYXRpb24sIGlkZW50aWZpZXIsIHBhcmFsbGVsQ291bnQ6IHBhcmFsbGVsfSlcblxuICAgIHJldHVybiBhd2FpdCBpdGVyYXRvci5ydW4odGVuYW50cywgY2FsbGJhY2spXG4gIH1cblxuICAvKipcbiAgICogRHJvcHMgb25lIHRlbmFudCdzIGRhdGFiYXNlL3NjaGVtYSB0aHJvdWdoIHRoZSBwcm92aWRlcidzIGBkcm9wRGF0YWJhc2VgIGhvb2suXG4gICAqIEBwYXJhbSB7e2lkZW50aWZpZXI6IHN0cmluZywgdGVuYW50OiBvYmplY3QsIGNvbmZpZ3VyYXRpb24/OiBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLmpzXCIpLmRlZmF1bHR9fSBhcmdzXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgc3RhdGljIGFzeW5jIGRyb3Aoe2lkZW50aWZpZXIsIHRlbmFudCwgY29uZmlndXJhdGlvbiA9IEN1cnJlbnQuY29uZmlndXJhdGlvbigpfSkge1xuICAgIGNvbnN0IHByb3ZpZGVyID0gY29uZmlndXJhdGlvbi5nZXRUZW5hbnREYXRhYmFzZVByb3ZpZGVyKGlkZW50aWZpZXIpXG5cbiAgICBpZiAodHlwZW9mIHByb3ZpZGVyLmRyb3BEYXRhYmFzZSAhPT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFRlbmFudCBkYXRhYmFzZSBwcm92aWRlciBmb3IgJHtpZGVudGlmaWVyfSBtdXN0IGRlZmluZSBkcm9wRGF0YWJhc2UgdG8gZHJvcCBhIHRlbmFudGApXG4gICAgfVxuXG4gICAgYXdhaXQgY29uZmlndXJhdGlvbi5ydW5XaXRoVGVuYW50KHRlbmFudCwgYXN5bmMgKCkgPT4ge1xuICAgICAgLy8gR3VhcmQgYWdhaW5zdCBhbiB1bnJlc29sdmVkIHRlbmFudC4gcmVzb2x2ZURhdGFiYXNlQ29uZmlndXJhdGlvbiBmYWxscyBiYWNrIHRvIHRoZVxuICAgICAgLy8gYmFzZSAodGVtcGxhdGUvZGVmYXVsdCkgdGVuYW50IGRhdGFiYXNlIHdoZW4gdGhlIHJlc29sdmVyIHJldHVybnMgbm90aGluZyBmb3IgdGhpc1xuICAgICAgLy8gZGVzY3JpcHRvciwgc28gd2l0aG91dCB0aGlzIGNoZWNrIGEgcHJvdmlkZXIgdGhhdCBkcm9wcyBieSBkYXRhYmFzZUNvbmZpZ3VyYXRpb24ubmFtZVxuICAgICAgLy8gd291bGQgZHJvcCB0aGUgdGVtcGxhdGUgZGF0YWJhc2UgaW5zdGVhZCBvZiByZWplY3RpbmcgdGhlIGJhZCB0ZW5hbnQuXG4gICAgICBpZiAoIWNvbmZpZ3VyYXRpb24uaXNEYXRhYmFzZUlkZW50aWZpZXJBY3RpdmUoaWRlbnRpZmllcikpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBUZW5hbnQgZGF0YWJhc2UgaWRlbnRpZmllciAke2lkZW50aWZpZXJ9IGlzIGluYWN0aXZlIGZvciB0ZW5hbnQ6ICR7VGVuYW50SXRlcmF0b3IudGVuYW50TGFiZWwodGVuYW50KX1gKVxuICAgICAgfVxuXG4gICAgICBhd2FpdCBwcm92aWRlci5kcm9wRGF0YWJhc2U/Lih7XG4gICAgICAgIGNvbmZpZ3VyYXRpb24sXG4gICAgICAgIGRhdGFiYXNlQ29uZmlndXJhdGlvbjogY29uZmlndXJhdGlvbi5yZXNvbHZlRGF0YWJhc2VDb25maWd1cmF0aW9uKGlkZW50aWZpZXIpLFxuICAgICAgICBpZGVudGlmaWVyLFxuICAgICAgICB0ZW5hbnRcbiAgICAgIH0pXG4gICAgfSlcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Runs a callback once within each tenant's context for a tenant database identifier,
|
|
5
|
+
* optionally several tenants at a time. Each tenant is entered with `runWithTenant`, and a
|
|
6
|
+
* tenant whose database identifier is inactive throws rather than running the callback
|
|
7
|
+
* against the wrong connection. When iterating in parallel the per-tenant failures are
|
|
8
|
+
* collected and rethrown together as an `AggregateError` so one bad tenant does not hide the
|
|
9
|
+
* others. This is the iteration engine shared by the `db:tenants:*` CLI commands and the
|
|
10
|
+
* runtime {@link Tenant} façade; the caller is responsible for producing the tenant list.
|
|
11
|
+
*/
|
|
12
|
+
export default class TenantIterator {
|
|
13
|
+
/**
|
|
14
|
+
* Creates an iterator bound to a configuration and tenant database identifier.
|
|
15
|
+
* @param {{configuration: import("../configuration.js").default, identifier: string, parallelCount?: number}} args
|
|
16
|
+
*/
|
|
17
|
+
constructor({configuration, identifier, parallelCount = 1}) {
|
|
18
|
+
this.configuration = configuration
|
|
19
|
+
this.identifier = identifier
|
|
20
|
+
this.parallelCount = parallelCount
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Runs `callback` within each tenant's context and returns how many tenants were processed.
|
|
25
|
+
* @param {Array<?>} tenants
|
|
26
|
+
* @param {function({databaseConfiguration: import("../configuration-types.js").DatabaseConfigurationType, tenant: ?}) : Promise<void>} callback
|
|
27
|
+
* @returns {Promise<number>}
|
|
28
|
+
*/
|
|
29
|
+
async run(tenants, callback) {
|
|
30
|
+
if (this.parallelCount <= 1) {
|
|
31
|
+
for (const tenant of tenants) {
|
|
32
|
+
await this.runTenantCallback({callback, tenant})
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return tenants.length
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** @type {Array<{error: Error, tenant: ?}>} */
|
|
39
|
+
const failures = []
|
|
40
|
+
const workers = []
|
|
41
|
+
let tenantIndex = 0
|
|
42
|
+
const workerCount = Math.min(this.parallelCount, tenants.length)
|
|
43
|
+
|
|
44
|
+
for (let workerIndex = 0; workerIndex < workerCount; workerIndex++) {
|
|
45
|
+
workers.push((async () => {
|
|
46
|
+
while (tenantIndex < tenants.length) {
|
|
47
|
+
const tenant = tenants[tenantIndex]
|
|
48
|
+
|
|
49
|
+
tenantIndex++
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
await this.runTenantCallback({callback, tenant})
|
|
53
|
+
} catch (error) {
|
|
54
|
+
failures.push({
|
|
55
|
+
error: error instanceof Error ? error : new Error(String(error)),
|
|
56
|
+
tenant
|
|
57
|
+
})
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
})())
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
await Promise.all(workers)
|
|
64
|
+
|
|
65
|
+
if (failures.length > 0) {
|
|
66
|
+
const failedTenantLabels = failures.map((failure) => TenantIterator.tenantLabel(failure.tenant)).join(", ")
|
|
67
|
+
|
|
68
|
+
throw new AggregateError(
|
|
69
|
+
failures.map((failure) => failure.error),
|
|
70
|
+
`Failed tenant database command for tenant(s): ${failedTenantLabels}`
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return tenants.length
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Enters one tenant's context and runs the callback, asserting the database is active first.
|
|
79
|
+
* @param {{callback: function({databaseConfiguration: import("../configuration-types.js").DatabaseConfigurationType, tenant: ?}) : Promise<void>, tenant: ?}} args
|
|
80
|
+
* @returns {Promise<void>}
|
|
81
|
+
*/
|
|
82
|
+
async runTenantCallback({callback, tenant}) {
|
|
83
|
+
await this.configuration.runWithTenant(tenant, async () => {
|
|
84
|
+
if (!this.configuration.isDatabaseIdentifierActive(this.identifier)) {
|
|
85
|
+
throw new Error(`Tenant database identifier ${this.identifier} is inactive for tenant: ${TenantIterator.tenantLabel(tenant)}`)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
await callback({
|
|
89
|
+
databaseConfiguration: this.configuration.resolveDatabaseConfiguration(this.identifier),
|
|
90
|
+
tenant
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Builds a human-readable label for a tenant for use in error messages.
|
|
97
|
+
* @param {?} tenant
|
|
98
|
+
* @returns {string}
|
|
99
|
+
*/
|
|
100
|
+
static tenantLabel(tenant) {
|
|
101
|
+
if (tenant && typeof tenant === "object") {
|
|
102
|
+
const tenantObject = /** @type {{id?: ?, name?: ?, slug?: ?}} */ (tenant)
|
|
103
|
+
|
|
104
|
+
if (tenantObject.slug) return String(tenantObject.slug)
|
|
105
|
+
if (tenantObject.name) return String(tenantObject.name)
|
|
106
|
+
if (tenantObject.id) return String(tenantObject.id)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return JSON.stringify(tenant)
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import Current from "../current.js"
|
|
4
|
+
import TenantIterator from "./tenant-iterator.js"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Apartment-style runtime façade for multi-tenant apps. A "tenant" is whatever descriptor
|
|
8
|
+
* object the app's `tenantDatabaseResolver` understands (an account, a project, …); this
|
|
9
|
+
* class is the single discoverable home for switching into a tenant's context, reading the
|
|
10
|
+
* current one, iterating every tenant of a database identifier, and dropping a tenant's
|
|
11
|
+
* database. Switching/reading delegate to {@link Current} (which owns the async-context
|
|
12
|
+
* tenant state), so they compose with the existing connection pools and request lifecycle;
|
|
13
|
+
* iteration and drop drive the app's tenant database provider hooks.
|
|
14
|
+
*/
|
|
15
|
+
export default class Tenant {
|
|
16
|
+
/**
|
|
17
|
+
* Runs `callback` with `tenant` as the current tenant, restoring the previous tenant after.
|
|
18
|
+
* @param {object} tenant Descriptor understood by the app's tenantDatabaseResolver.
|
|
19
|
+
* @param {() => Promise<?>} callback
|
|
20
|
+
* @returns {Promise<?>}
|
|
21
|
+
*/
|
|
22
|
+
static async with(tenant, callback) {
|
|
23
|
+
return await Current.withTenant(tenant, callback)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* The current tenant descriptor, or undefined when running outside any tenant context.
|
|
28
|
+
* @returns {Record<string, unknown> | undefined}
|
|
29
|
+
*/
|
|
30
|
+
static current() {
|
|
31
|
+
return Current.tenant()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Lists the tenants for a database identifier through the provider and runs `callback`
|
|
36
|
+
* within each tenant's context, optionally filtered and several at a time. Returns how
|
|
37
|
+
* many tenants the callback ran for (after filtering).
|
|
38
|
+
* @param {{identifier: string, callback: function({databaseConfiguration: import("../configuration-types.js").DatabaseConfigurationType, tenant: ?}) : Promise<void>, parallel?: number, filter?: (tenant: ?) => boolean, configuration?: import("../configuration.js").default}} args
|
|
39
|
+
* @returns {Promise<number>}
|
|
40
|
+
*/
|
|
41
|
+
static async each({identifier, callback, parallel = 1, filter, configuration = Current.configuration()}) {
|
|
42
|
+
const provider = configuration.getTenantDatabaseProvider(identifier)
|
|
43
|
+
const listedTenants = await configuration.ensureConnections({name: `Tenant.each: ${identifier}`}, async () => {
|
|
44
|
+
return await provider.listTenants({configuration, identifier})
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
if (!Array.isArray(listedTenants)) {
|
|
48
|
+
throw new Error(`Tenant database provider for ${identifier} must return an array from listTenants`)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const tenants = filter ? listedTenants.filter(filter) : listedTenants
|
|
52
|
+
const iterator = new TenantIterator({configuration, identifier, parallelCount: parallel})
|
|
53
|
+
|
|
54
|
+
return await iterator.run(tenants, callback)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Drops one tenant's database/schema through the provider's `dropDatabase` hook.
|
|
59
|
+
* @param {{identifier: string, tenant: object, configuration?: import("../configuration.js").default}} args
|
|
60
|
+
* @returns {Promise<void>}
|
|
61
|
+
*/
|
|
62
|
+
static async drop({identifier, tenant, configuration = Current.configuration()}) {
|
|
63
|
+
const provider = configuration.getTenantDatabaseProvider(identifier)
|
|
64
|
+
|
|
65
|
+
if (typeof provider.dropDatabase !== "function") {
|
|
66
|
+
throw new Error(`Tenant database provider for ${identifier} must define dropDatabase to drop a tenant`)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
await configuration.runWithTenant(tenant, async () => {
|
|
70
|
+
// Guard against an unresolved tenant. resolveDatabaseConfiguration falls back to the
|
|
71
|
+
// base (template/default) tenant database when the resolver returns nothing for this
|
|
72
|
+
// descriptor, so without this check a provider that drops by databaseConfiguration.name
|
|
73
|
+
// would drop the template database instead of rejecting the bad tenant.
|
|
74
|
+
if (!configuration.isDatabaseIdentifierActive(identifier)) {
|
|
75
|
+
throw new Error(`Tenant database identifier ${identifier} is inactive for tenant: ${TenantIterator.tenantLabel(tenant)}`)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
await provider.dropDatabase?.({
|
|
79
|
+
configuration,
|
|
80
|
+
databaseConfiguration: configuration.resolveDatabaseConfiguration(identifier),
|
|
81
|
+
identifier,
|
|
82
|
+
tenant
|
|
83
|
+
})
|
|
84
|
+
})
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../index.js","../bin/velocious.js","../src/application.js","../src/configuration-resolver.js","../src/configuration-types.js","../src/configuration.js","../src/controller.js","../src/current-configuration.js","../src/current.js","../src/error-logger.js","../src/frontend-model-controller.js","../src/initializer.js","../src/logger.js","../src/mailer.js","../src/record-payload-values.js","../src/time-zone.js","../src/velocious-error.js","../src/authorization/ability.js","../src/authorization/base-resource.js","../src/background-jobs/client.js","../src/background-jobs/cron-expression.js","../src/background-jobs/forked-runner-child.js","../src/background-jobs/job-record.js","../src/background-jobs/job-registry.js","../src/background-jobs/job-runner.js","../src/background-jobs/job.js","../src/background-jobs/json-socket.js","../src/background-jobs/main.js","../src/background-jobs/normalize-error.js","../src/background-jobs/scheduler.js","../src/background-jobs/socket-request.js","../src/background-jobs/status-reporter.js","../src/background-jobs/store.js","../src/background-jobs/types.js","../src/background-jobs/worker.js","../src/background-jobs/web/authorization.js","../src/background-jobs/web/controller.js","../src/background-jobs/web/index.js","../src/background-jobs/web/path-matcher.js","../src/background-jobs/web/registry.js","../src/beacon/client.js","../src/beacon/in-process-broker.js","../src/beacon/in-process-client.js","../src/beacon/server.js","../src/beacon/types.js","../src/cli/base-command.js","../src/cli/browser-cli.js","../src/cli/index.js","../src/cli/tenant-database-command-helper.js","../src/cli/use-browser-cli.js","../src/cli/commands/background-jobs-main.js","../src/cli/commands/background-jobs-runner.js","../src/cli/commands/background-jobs-worker.js","../src/cli/commands/beacon.js","../src/cli/commands/console.js","../src/cli/commands/init.js","../src/cli/commands/routes.js","../src/cli/commands/run-script.js","../src/cli/commands/runner.js","../src/cli/commands/server.js","../src/cli/commands/test.js","../src/cli/commands/db/base-command.js","../src/cli/commands/db/create.js","../src/cli/commands/db/drop.js","../src/cli/commands/db/migrate.js","../src/cli/commands/db/reset.js","../src/cli/commands/db/rollback.js","../src/cli/commands/db/seed.js","../src/cli/commands/db/schema/dump.js","../src/cli/commands/db/schema/load.js","../src/cli/commands/db/tenants/check.js","../src/cli/commands/db/tenants/create.js","../src/cli/commands/db/tenants/migrate.js","../src/cli/commands/destroy/migration.js","../src/cli/commands/generate/base-models.js","../src/cli/commands/generate/frontend-models.js","../src/cli/commands/generate/migration.js","../src/cli/commands/generate/model.js","../src/cli/commands/lint/relationships.js","../src/database/annotations-async-hooks.js","../src/database/annotations.js","../src/database/datetime-storage.js","../src/database/handler.js","../src/database/initializer-from-require-context.js","../src/database/migrations-ledger.js","../src/database/migrator.js","../src/database/use-database.js","../src/database/drivers/base-column.js","../src/database/drivers/base-columns-index.js","../src/database/drivers/base-foreign-key.js","../src/database/drivers/base-table.js","../src/database/drivers/base.js","../src/database/drivers/mssql/column.js","../src/database/drivers/mssql/columns-index.js","../src/database/drivers/mssql/connect-connection.js","../src/database/drivers/mssql/foreign-key.js","../src/database/drivers/mssql/index.js","../src/database/drivers/mssql/options.js","../src/database/drivers/mssql/query-parser.js","../src/database/drivers/mssql/structure-sql.js","../src/database/drivers/mssql/table.js","../src/database/drivers/mssql/sql/alter-table.js","../src/database/drivers/mssql/sql/create-database.js","../src/database/drivers/mssql/sql/create-index.js","../src/database/drivers/mssql/sql/create-table.js","../src/database/drivers/mssql/sql/delete.js","../src/database/drivers/mssql/sql/drop-database.js","../src/database/drivers/mssql/sql/drop-table.js","../src/database/drivers/mssql/sql/insert.js","../src/database/drivers/mssql/sql/remove-index.js","../src/database/drivers/mssql/sql/update.js","../src/database/drivers/mssql/sql/upsert.js","../src/database/drivers/mysql/column.js","../src/database/drivers/mysql/columns-index.js","../src/database/drivers/mysql/foreign-key.js","../src/database/drivers/mysql/index.js","../src/database/drivers/mysql/options.js","../src/database/drivers/mysql/query-parser.js","../src/database/drivers/mysql/query.js","../src/database/drivers/mysql/structure-sql.js","../src/database/drivers/mysql/table.js","../src/database/drivers/mysql/sql/alter-table.js","../src/database/drivers/mysql/sql/create-database.js","../src/database/drivers/mysql/sql/create-index.js","../src/database/drivers/mysql/sql/create-table.js","../src/database/drivers/mysql/sql/delete.js","../src/database/drivers/mysql/sql/drop-database.js","../src/database/drivers/mysql/sql/drop-table.js","../src/database/drivers/mysql/sql/insert.js","../src/database/drivers/mysql/sql/remove-index.js","../src/database/drivers/mysql/sql/update.js","../src/database/drivers/mysql/sql/upsert.js","../src/database/drivers/pgsql/column.js","../src/database/drivers/pgsql/columns-index.js","../src/database/drivers/pgsql/foreign-key.js","../src/database/drivers/pgsql/index.js","../src/database/drivers/pgsql/options.js","../src/database/drivers/pgsql/query-parser.js","../src/database/drivers/pgsql/structure-sql.js","../src/database/drivers/pgsql/table.js","../src/database/drivers/pgsql/sql/alter-table.js","../src/database/drivers/pgsql/sql/create-database.js","../src/database/drivers/pgsql/sql/create-index.js","../src/database/drivers/pgsql/sql/create-table.js","../src/database/drivers/pgsql/sql/delete.js","../src/database/drivers/pgsql/sql/drop-database.js","../src/database/drivers/pgsql/sql/drop-table.js","../src/database/drivers/pgsql/sql/insert.js","../src/database/drivers/pgsql/sql/remove-index.js","../src/database/drivers/pgsql/sql/update.js","../src/database/drivers/pgsql/sql/upsert.js","../src/database/drivers/sqlite/base.js","../src/database/drivers/sqlite/column.js","../src/database/drivers/sqlite/columns-index.js","../src/database/drivers/sqlite/connection-sql-js.js","../src/database/drivers/sqlite/foreign-key.js","../src/database/drivers/sqlite/index.js","../src/database/drivers/sqlite/index.native.js","../src/database/drivers/sqlite/index.web.js","../src/database/drivers/sqlite/options.js","../src/database/drivers/sqlite/query-parser.js","../src/database/drivers/sqlite/query.js","../src/database/drivers/sqlite/query.native.js","../src/database/drivers/sqlite/query.web.js","../src/database/drivers/sqlite/structure-sql.js","../src/database/drivers/sqlite/table-rebuilder.js","../src/database/drivers/sqlite/table.js","../src/database/drivers/sqlite/web-persistence.js","../src/database/drivers/sqlite/sql/alter-table.js","../src/database/drivers/sqlite/sql/create-index.js","../src/database/drivers/sqlite/sql/create-table.js","../src/database/drivers/sqlite/sql/delete.js","../src/database/drivers/sqlite/sql/drop-table.js","../src/database/drivers/sqlite/sql/insert.js","../src/database/drivers/sqlite/sql/remove-index.js","../src/database/drivers/sqlite/sql/update.js","../src/database/drivers/sqlite/sql/upsert.js","../src/database/drivers/structure-sql/utils.js","../src/database/migration/index.js","../src/database/migrator/files-finder.js","../src/database/migrator/types.js","../src/database/pool/async-tracked-multi-connection.js","../src/database/pool/base-methods-forward.js","../src/database/pool/base.js","../src/database/pool/single-multi-use.js","../src/database/query/alter-table-base.js","../src/database/query/base.js","../src/database/query/create-database-base.js","../src/database/query/create-index-base.js","../src/database/query/create-table-base.js","../src/database/query/delete-base.js","../src/database/query/drop-database-base.js","../src/database/query/drop-table-base.js","../src/database/query/from-base.js","../src/database/query/from-plain.js","../src/database/query/from-table.js","../src/database/query/index.js","../src/database/query/insert-base.js","../src/database/query/join-base.js","../src/database/query/join-object.js","../src/database/query/join-plain.js","../src/database/query/join-tracker.js","../src/database/query/model-class-query.js","../src/database/query/order-base.js","../src/database/query/order-column.js","../src/database/query/order-plain.js","../src/database/query/preloader.js","../src/database/query/query-data.js","../src/database/query/remove-index-base.js","../src/database/query/select-base.js","../src/database/query/select-plain.js","../src/database/query/select-table-and-column.js","../src/database/query/update-base.js","../src/database/query/upsert-base.js","../src/database/query/where-base.js","../src/database/query/where-combinator.js","../src/database/query/where-hash.js","../src/database/query/where-model-class-hash.js","../src/database/query/where-not.js","../src/database/query/where-plain.js","../src/database/query/with-count.js","../src/database/query/preloader/belongs-to.js","../src/database/query/preloader/ensure-model-class-initialized.js","../src/database/query/preloader/has-many.js","../src/database/query/preloader/has-one.js","../src/database/query/preloader/selection.js","../src/database/query-parser/base-query-parser.js","../src/database/query-parser/from-parser.js","../src/database/query-parser/group-parser.js","../src/database/query-parser/joins-parser.js","../src/database/query-parser/limit-parser.js","../src/database/query-parser/options.js","../src/database/query-parser/order-parser.js","../src/database/query-parser/select-parser.js","../src/database/query-parser/where-parser.js","../src/database/record/acts-as-list.js","../src/database/record/index.js","../src/database/record/record-not-found-error.js","../src/database/record/state-machine.js","../src/database/record/user-module.js","../src/database/record/attachments/attachment-record.js","../src/database/record/attachments/download.js","../src/database/record/attachments/handle.js","../src/database/record/attachments/normalize-input.js","../src/database/record/attachments/store.js","../src/database/record/attachments/storage-drivers/filesystem.js","../src/database/record/attachments/storage-drivers/native.js","../src/database/record/attachments/storage-drivers/s3.js","../src/database/record/instance-relationships/base.js","../src/database/record/instance-relationships/belongs-to.js","../src/database/record/instance-relationships/has-many.js","../src/database/record/instance-relationships/has-one.js","../src/database/record/relationships/base.js","../src/database/record/relationships/belongs-to.js","../src/database/record/relationships/has-many.js","../src/database/record/relationships/has-one.js","../src/database/record/validators/base.js","../src/database/record/validators/format.js","../src/database/record/validators/presence.js","../src/database/record/validators/uniqueness.js","../src/database/table-data/index.js","../src/database/table-data/table-column.js","../src/database/table-data/table-foreign-key.js","../src/database/table-data/table-index.js","../src/database/table-data/table-reference.js","../src/environment-handlers/base.js","../src/environment-handlers/browser.js","../src/environment-handlers/node.js","../src/environment-handlers/node/cli/commands/background-jobs-main.js","../src/environment-handlers/node/cli/commands/background-jobs-runner.js","../src/environment-handlers/node/cli/commands/background-jobs-worker.js","../src/environment-handlers/node/cli/commands/beacon.js","../src/environment-handlers/node/cli/commands/cli-command-context.js","../src/environment-handlers/node/cli/commands/console.js","../src/environment-handlers/node/cli/commands/init.js","../src/environment-handlers/node/cli/commands/routes.js","../src/environment-handlers/node/cli/commands/run-script.js","../src/environment-handlers/node/cli/commands/runner.js","../src/environment-handlers/node/cli/commands/server.js","../src/environment-handlers/node/cli/commands/test.js","../src/environment-handlers/node/cli/commands/db/seed.js","../src/environment-handlers/node/cli/commands/db/schema/dump.js","../src/environment-handlers/node/cli/commands/db/schema/load.js","../src/environment-handlers/node/cli/commands/destroy/migration.js","../src/environment-handlers/node/cli/commands/generate/base-models.js","../src/environment-handlers/node/cli/commands/generate/frontend-models.js","../src/environment-handlers/node/cli/commands/generate/generated-file-banner.js","../src/environment-handlers/node/cli/commands/generate/migration.js","../src/environment-handlers/node/cli/commands/generate/model.js","../src/environment-handlers/node/cli/commands/lint/relationships.js","../src/error-reporting/request-details.js","../src/frontend-model-resource/base-resource.js","../src/frontend-model-resource/velocious-attachment-resource.js","../src/frontend-models/base.js","../src/frontend-models/built-in-resources.js","../src/frontend-models/clear-pending-debounced-callback.js","../src/frontend-models/event-hook-models.js","../src/frontend-models/model-registry.js","../src/frontend-models/outgoing-event-buffer.js","../src/frontend-models/preloader.js","../src/frontend-models/query.js","../src/frontend-models/resource-config-validation.js","../src/frontend-models/resource-definition.js","../src/frontend-models/transport-serialization.js","../src/frontend-models/use-created-event.js","../src/frontend-models/use-destroyed-event.js","../src/frontend-models/use-model-class-event.js","../src/frontend-models/use-updated-event.js","../src/frontend-models/websocket-channel.js","../src/frontend-models/websocket-publishers.js","../src/http-client/header.js","../src/http-client/index.js","../src/http-client/request.js","../src/http-client/response.js","../src/http-client/websocket-client.js","../src/http-server/cookie.js","../src/http-server/development-reloader.js","../src/http-server/index.js","../src/http-server/remote-address.js","../src/http-server/server-client.js","../src/http-server/server-lock.js","../src/http-server/websocket-channel-subscribers.js","../src/http-server/websocket-channel.js","../src/http-server/websocket-connection.js","../src/http-server/websocket-event-log-store.js","../src/http-server/websocket-events-host.js","../src/http-server/websocket-events.js","../src/http-server/client/index.js","../src/http-server/client/params-to-object.js","../src/http-server/client/request-parser.js","../src/http-server/client/request-runner.js","../src/http-server/client/request-timing.js","../src/http-server/client/request.js","../src/http-server/client/response.js","../src/http-server/client/websocket-request.js","../src/http-server/client/websocket-session.js","../src/http-server/client/request-buffer/form-data-part.js","../src/http-server/client/request-buffer/header.js","../src/http-server/client/request-buffer/index.js","../src/http-server/client/uploaded-file/memory-uploaded-file.js","../src/http-server/client/uploaded-file/temporary-uploaded-file.js","../src/http-server/client/uploaded-file/uploaded-file.js","../src/http-server/worker-handler/channel-subscriber-dispatch.js","../src/http-server/worker-handler/in-process.js","../src/http-server/worker-handler/index.js","../src/http-server/worker-handler/worker-script.js","../src/http-server/worker-handler/worker-thread.js","../src/jobs/mail-delivery.js","../src/logger/base-logger.js","../src/logger/console-logger.js","../src/logger/file-logger.js","../src/logger/outputs/array-output.js","../src/logger/outputs/console-output.js","../src/logger/outputs/file-output.js","../src/logger/outputs/stdout-output.js","../src/mailer/base.js","../src/mailer/delivery.js","../src/mailer/index.js","../src/mailer/backends/smtp.js","../src/plugins/sqljs-wasm-route-controller.js","../src/plugins/sqljs-wasm-route.js","../src/routes/app-routes.js","../src/routes/base-route.js","../src/routes/basic-route.js","../src/routes/get-route.js","../src/routes/index.js","../src/routes/namespace-route.js","../src/routes/plugin-routes.js","../src/routes/post-route.js","../src/routes/resolver.js","../src/routes/resource-route.js","../src/routes/root-route.js","../src/routes/built-in/debug/controller.js","../src/routes/built-in/errors/controller.js","../src/routes/hooks/frontend-model-command-route-hook.js","../src/sync/conflict-strategy.js","../src/sync/device-identity.js","../src/sync/local-mutation-log.js","../src/sync/offline-grant.js","../src/sync/peer-mutation-bundle.js","../src/sync/server-change-feed.js","../src/sync/sync-envelope-replay-service.js","../src/testing/base-expect.js","../src/testing/browser-frontend-model-event-hook-scenarios.js","../src/testing/browser-test-app.js","../src/testing/expect-to-change.js","../src/testing/expect-utils.js","../src/testing/expect.js","../src/testing/request-client.js","../src/testing/test-files-finder.js","../src/testing/test-filter-parser.js","../src/testing/test-runner.js","../src/testing/test-suite-splitter.js","../src/testing/test.js","../src/types/external-modules.d.ts","../src/utils/backtrace-cleaner-node.js","../src/utils/backtrace-cleaner.js","../src/utils/deburr-column-name.js","../src/utils/event-emitter.js","../src/utils/file-exists.js","../src/utils/format-value.js","../src/utils/is-date.js","../src/utils/model-scope.js","../src/utils/nest-callbacks.js","../src/utils/plain-object.js","../src/utils/ransack.js","../src/utils/rest-args-error.js","../src/utils/singularize-model-name.js","../src/utils/split-sql-statements.js","../src/utils/to-import-specifier.js","../src/utils/with-tracked-stack-async-hooks.js","../src/utils/with-tracked-stack.js"],"version":"6.0.3"}
|
|
1
|
+
{"root":["../index.js","../bin/velocious.js","../src/application.js","../src/configuration-resolver.js","../src/configuration-types.js","../src/configuration.js","../src/controller.js","../src/current-configuration.js","../src/current.js","../src/error-logger.js","../src/frontend-model-controller.js","../src/initializer.js","../src/logger.js","../src/mailer.js","../src/record-payload-values.js","../src/time-zone.js","../src/velocious-error.js","../src/authorization/ability.js","../src/authorization/base-resource.js","../src/background-jobs/client.js","../src/background-jobs/cron-expression.js","../src/background-jobs/forked-runner-child.js","../src/background-jobs/job-record.js","../src/background-jobs/job-registry.js","../src/background-jobs/job-runner.js","../src/background-jobs/job.js","../src/background-jobs/json-socket.js","../src/background-jobs/main.js","../src/background-jobs/normalize-error.js","../src/background-jobs/scheduler.js","../src/background-jobs/socket-request.js","../src/background-jobs/status-reporter.js","../src/background-jobs/store.js","../src/background-jobs/types.js","../src/background-jobs/worker.js","../src/background-jobs/web/authorization.js","../src/background-jobs/web/controller.js","../src/background-jobs/web/index.js","../src/background-jobs/web/path-matcher.js","../src/background-jobs/web/registry.js","../src/beacon/client.js","../src/beacon/in-process-broker.js","../src/beacon/in-process-client.js","../src/beacon/server.js","../src/beacon/types.js","../src/cli/base-command.js","../src/cli/browser-cli.js","../src/cli/index.js","../src/cli/tenant-database-command-helper.js","../src/cli/use-browser-cli.js","../src/cli/commands/background-jobs-main.js","../src/cli/commands/background-jobs-runner.js","../src/cli/commands/background-jobs-worker.js","../src/cli/commands/beacon.js","../src/cli/commands/console.js","../src/cli/commands/init.js","../src/cli/commands/routes.js","../src/cli/commands/run-script.js","../src/cli/commands/runner.js","../src/cli/commands/server.js","../src/cli/commands/test.js","../src/cli/commands/db/base-command.js","../src/cli/commands/db/create.js","../src/cli/commands/db/drop.js","../src/cli/commands/db/migrate.js","../src/cli/commands/db/reset.js","../src/cli/commands/db/rollback.js","../src/cli/commands/db/seed.js","../src/cli/commands/db/schema/dump.js","../src/cli/commands/db/schema/load.js","../src/cli/commands/db/tenants/check.js","../src/cli/commands/db/tenants/create.js","../src/cli/commands/db/tenants/drop.js","../src/cli/commands/db/tenants/migrate.js","../src/cli/commands/destroy/migration.js","../src/cli/commands/generate/base-models.js","../src/cli/commands/generate/frontend-models.js","../src/cli/commands/generate/migration.js","../src/cli/commands/generate/model.js","../src/cli/commands/lint/relationships.js","../src/database/annotations-async-hooks.js","../src/database/annotations.js","../src/database/datetime-storage.js","../src/database/handler.js","../src/database/initializer-from-require-context.js","../src/database/migrations-ledger.js","../src/database/migrator.js","../src/database/use-database.js","../src/database/drivers/base-column.js","../src/database/drivers/base-columns-index.js","../src/database/drivers/base-foreign-key.js","../src/database/drivers/base-table.js","../src/database/drivers/base.js","../src/database/drivers/mssql/column.js","../src/database/drivers/mssql/columns-index.js","../src/database/drivers/mssql/connect-connection.js","../src/database/drivers/mssql/foreign-key.js","../src/database/drivers/mssql/index.js","../src/database/drivers/mssql/options.js","../src/database/drivers/mssql/query-parser.js","../src/database/drivers/mssql/structure-sql.js","../src/database/drivers/mssql/table.js","../src/database/drivers/mssql/sql/alter-table.js","../src/database/drivers/mssql/sql/create-database.js","../src/database/drivers/mssql/sql/create-index.js","../src/database/drivers/mssql/sql/create-table.js","../src/database/drivers/mssql/sql/delete.js","../src/database/drivers/mssql/sql/drop-database.js","../src/database/drivers/mssql/sql/drop-table.js","../src/database/drivers/mssql/sql/insert.js","../src/database/drivers/mssql/sql/remove-index.js","../src/database/drivers/mssql/sql/update.js","../src/database/drivers/mssql/sql/upsert.js","../src/database/drivers/mysql/column.js","../src/database/drivers/mysql/columns-index.js","../src/database/drivers/mysql/foreign-key.js","../src/database/drivers/mysql/index.js","../src/database/drivers/mysql/options.js","../src/database/drivers/mysql/query-parser.js","../src/database/drivers/mysql/query.js","../src/database/drivers/mysql/structure-sql.js","../src/database/drivers/mysql/table.js","../src/database/drivers/mysql/sql/alter-table.js","../src/database/drivers/mysql/sql/create-database.js","../src/database/drivers/mysql/sql/create-index.js","../src/database/drivers/mysql/sql/create-table.js","../src/database/drivers/mysql/sql/delete.js","../src/database/drivers/mysql/sql/drop-database.js","../src/database/drivers/mysql/sql/drop-table.js","../src/database/drivers/mysql/sql/insert.js","../src/database/drivers/mysql/sql/remove-index.js","../src/database/drivers/mysql/sql/update.js","../src/database/drivers/mysql/sql/upsert.js","../src/database/drivers/pgsql/column.js","../src/database/drivers/pgsql/columns-index.js","../src/database/drivers/pgsql/foreign-key.js","../src/database/drivers/pgsql/index.js","../src/database/drivers/pgsql/options.js","../src/database/drivers/pgsql/query-parser.js","../src/database/drivers/pgsql/structure-sql.js","../src/database/drivers/pgsql/table.js","../src/database/drivers/pgsql/sql/alter-table.js","../src/database/drivers/pgsql/sql/create-database.js","../src/database/drivers/pgsql/sql/create-index.js","../src/database/drivers/pgsql/sql/create-table.js","../src/database/drivers/pgsql/sql/delete.js","../src/database/drivers/pgsql/sql/drop-database.js","../src/database/drivers/pgsql/sql/drop-table.js","../src/database/drivers/pgsql/sql/insert.js","../src/database/drivers/pgsql/sql/remove-index.js","../src/database/drivers/pgsql/sql/update.js","../src/database/drivers/pgsql/sql/upsert.js","../src/database/drivers/sqlite/base.js","../src/database/drivers/sqlite/column.js","../src/database/drivers/sqlite/columns-index.js","../src/database/drivers/sqlite/connection-sql-js.js","../src/database/drivers/sqlite/foreign-key.js","../src/database/drivers/sqlite/index.js","../src/database/drivers/sqlite/index.native.js","../src/database/drivers/sqlite/index.web.js","../src/database/drivers/sqlite/options.js","../src/database/drivers/sqlite/query-parser.js","../src/database/drivers/sqlite/query.js","../src/database/drivers/sqlite/query.native.js","../src/database/drivers/sqlite/query.web.js","../src/database/drivers/sqlite/structure-sql.js","../src/database/drivers/sqlite/table-rebuilder.js","../src/database/drivers/sqlite/table.js","../src/database/drivers/sqlite/web-persistence.js","../src/database/drivers/sqlite/sql/alter-table.js","../src/database/drivers/sqlite/sql/create-index.js","../src/database/drivers/sqlite/sql/create-table.js","../src/database/drivers/sqlite/sql/delete.js","../src/database/drivers/sqlite/sql/drop-table.js","../src/database/drivers/sqlite/sql/insert.js","../src/database/drivers/sqlite/sql/remove-index.js","../src/database/drivers/sqlite/sql/update.js","../src/database/drivers/sqlite/sql/upsert.js","../src/database/drivers/structure-sql/utils.js","../src/database/migration/index.js","../src/database/migrator/files-finder.js","../src/database/migrator/types.js","../src/database/pool/async-tracked-multi-connection.js","../src/database/pool/base-methods-forward.js","../src/database/pool/base.js","../src/database/pool/single-multi-use.js","../src/database/query/alter-table-base.js","../src/database/query/base.js","../src/database/query/create-database-base.js","../src/database/query/create-index-base.js","../src/database/query/create-table-base.js","../src/database/query/delete-base.js","../src/database/query/drop-database-base.js","../src/database/query/drop-table-base.js","../src/database/query/from-base.js","../src/database/query/from-plain.js","../src/database/query/from-table.js","../src/database/query/index.js","../src/database/query/insert-base.js","../src/database/query/join-base.js","../src/database/query/join-object.js","../src/database/query/join-plain.js","../src/database/query/join-tracker.js","../src/database/query/model-class-query.js","../src/database/query/order-base.js","../src/database/query/order-column.js","../src/database/query/order-plain.js","../src/database/query/preloader.js","../src/database/query/query-data.js","../src/database/query/remove-index-base.js","../src/database/query/select-base.js","../src/database/query/select-plain.js","../src/database/query/select-table-and-column.js","../src/database/query/update-base.js","../src/database/query/upsert-base.js","../src/database/query/where-base.js","../src/database/query/where-combinator.js","../src/database/query/where-hash.js","../src/database/query/where-model-class-hash.js","../src/database/query/where-not.js","../src/database/query/where-plain.js","../src/database/query/with-count.js","../src/database/query/preloader/belongs-to.js","../src/database/query/preloader/ensure-model-class-initialized.js","../src/database/query/preloader/has-many.js","../src/database/query/preloader/has-one.js","../src/database/query/preloader/selection.js","../src/database/query-parser/base-query-parser.js","../src/database/query-parser/from-parser.js","../src/database/query-parser/group-parser.js","../src/database/query-parser/joins-parser.js","../src/database/query-parser/limit-parser.js","../src/database/query-parser/options.js","../src/database/query-parser/order-parser.js","../src/database/query-parser/select-parser.js","../src/database/query-parser/where-parser.js","../src/database/record/acts-as-list.js","../src/database/record/index.js","../src/database/record/record-not-found-error.js","../src/database/record/state-machine.js","../src/database/record/user-module.js","../src/database/record/attachments/attachment-record.js","../src/database/record/attachments/download.js","../src/database/record/attachments/handle.js","../src/database/record/attachments/normalize-input.js","../src/database/record/attachments/store.js","../src/database/record/attachments/storage-drivers/filesystem.js","../src/database/record/attachments/storage-drivers/native.js","../src/database/record/attachments/storage-drivers/s3.js","../src/database/record/instance-relationships/base.js","../src/database/record/instance-relationships/belongs-to.js","../src/database/record/instance-relationships/has-many.js","../src/database/record/instance-relationships/has-one.js","../src/database/record/relationships/base.js","../src/database/record/relationships/belongs-to.js","../src/database/record/relationships/has-many.js","../src/database/record/relationships/has-one.js","../src/database/record/validators/base.js","../src/database/record/validators/format.js","../src/database/record/validators/presence.js","../src/database/record/validators/uniqueness.js","../src/database/table-data/index.js","../src/database/table-data/table-column.js","../src/database/table-data/table-foreign-key.js","../src/database/table-data/table-index.js","../src/database/table-data/table-reference.js","../src/database/tenants/data-copier.js","../src/database/tenants/schema-cloner.js","../src/database/tenants/tenant-table-plan.js","../src/environment-handlers/base.js","../src/environment-handlers/browser.js","../src/environment-handlers/node.js","../src/environment-handlers/node/cli/commands/background-jobs-main.js","../src/environment-handlers/node/cli/commands/background-jobs-runner.js","../src/environment-handlers/node/cli/commands/background-jobs-worker.js","../src/environment-handlers/node/cli/commands/beacon.js","../src/environment-handlers/node/cli/commands/cli-command-context.js","../src/environment-handlers/node/cli/commands/console.js","../src/environment-handlers/node/cli/commands/init.js","../src/environment-handlers/node/cli/commands/routes.js","../src/environment-handlers/node/cli/commands/run-script.js","../src/environment-handlers/node/cli/commands/runner.js","../src/environment-handlers/node/cli/commands/server.js","../src/environment-handlers/node/cli/commands/test.js","../src/environment-handlers/node/cli/commands/db/seed.js","../src/environment-handlers/node/cli/commands/db/schema/dump.js","../src/environment-handlers/node/cli/commands/db/schema/load.js","../src/environment-handlers/node/cli/commands/destroy/migration.js","../src/environment-handlers/node/cli/commands/generate/base-models.js","../src/environment-handlers/node/cli/commands/generate/frontend-models.js","../src/environment-handlers/node/cli/commands/generate/generated-file-banner.js","../src/environment-handlers/node/cli/commands/generate/migration.js","../src/environment-handlers/node/cli/commands/generate/model.js","../src/environment-handlers/node/cli/commands/lint/relationships.js","../src/error-reporting/request-details.js","../src/frontend-model-resource/base-resource.js","../src/frontend-model-resource/velocious-attachment-resource.js","../src/frontend-models/base.js","../src/frontend-models/built-in-resources.js","../src/frontend-models/clear-pending-debounced-callback.js","../src/frontend-models/event-hook-models.js","../src/frontend-models/model-registry.js","../src/frontend-models/outgoing-event-buffer.js","../src/frontend-models/preloader.js","../src/frontend-models/query.js","../src/frontend-models/resource-config-validation.js","../src/frontend-models/resource-definition.js","../src/frontend-models/transport-serialization.js","../src/frontend-models/use-created-event.js","../src/frontend-models/use-destroyed-event.js","../src/frontend-models/use-model-class-event.js","../src/frontend-models/use-updated-event.js","../src/frontend-models/websocket-channel.js","../src/frontend-models/websocket-publishers.js","../src/http-client/header.js","../src/http-client/index.js","../src/http-client/request.js","../src/http-client/response.js","../src/http-client/websocket-client.js","../src/http-server/cookie.js","../src/http-server/development-reloader.js","../src/http-server/index.js","../src/http-server/remote-address.js","../src/http-server/server-client.js","../src/http-server/server-lock.js","../src/http-server/websocket-channel-subscribers.js","../src/http-server/websocket-channel.js","../src/http-server/websocket-connection.js","../src/http-server/websocket-event-log-store.js","../src/http-server/websocket-events-host.js","../src/http-server/websocket-events.js","../src/http-server/client/index.js","../src/http-server/client/params-to-object.js","../src/http-server/client/request-parser.js","../src/http-server/client/request-runner.js","../src/http-server/client/request-timing.js","../src/http-server/client/request.js","../src/http-server/client/response.js","../src/http-server/client/websocket-request.js","../src/http-server/client/websocket-session.js","../src/http-server/client/request-buffer/form-data-part.js","../src/http-server/client/request-buffer/header.js","../src/http-server/client/request-buffer/index.js","../src/http-server/client/uploaded-file/memory-uploaded-file.js","../src/http-server/client/uploaded-file/temporary-uploaded-file.js","../src/http-server/client/uploaded-file/uploaded-file.js","../src/http-server/worker-handler/channel-subscriber-dispatch.js","../src/http-server/worker-handler/in-process.js","../src/http-server/worker-handler/index.js","../src/http-server/worker-handler/worker-script.js","../src/http-server/worker-handler/worker-thread.js","../src/jobs/mail-delivery.js","../src/logger/base-logger.js","../src/logger/console-logger.js","../src/logger/file-logger.js","../src/logger/outputs/array-output.js","../src/logger/outputs/console-output.js","../src/logger/outputs/file-output.js","../src/logger/outputs/stdout-output.js","../src/mailer/base.js","../src/mailer/delivery.js","../src/mailer/index.js","../src/mailer/backends/smtp.js","../src/plugins/sqljs-wasm-route-controller.js","../src/plugins/sqljs-wasm-route.js","../src/routes/app-routes.js","../src/routes/base-route.js","../src/routes/basic-route.js","../src/routes/get-route.js","../src/routes/index.js","../src/routes/namespace-route.js","../src/routes/plugin-routes.js","../src/routes/post-route.js","../src/routes/resolver.js","../src/routes/resource-route.js","../src/routes/root-route.js","../src/routes/built-in/debug/controller.js","../src/routes/built-in/errors/controller.js","../src/routes/hooks/frontend-model-command-route-hook.js","../src/sync/conflict-strategy.js","../src/sync/device-identity.js","../src/sync/local-mutation-log.js","../src/sync/offline-grant.js","../src/sync/peer-mutation-bundle.js","../src/sync/server-change-feed.js","../src/sync/sync-envelope-replay-service.js","../src/tenants/tenant-iterator.js","../src/tenants/tenant.js","../src/testing/base-expect.js","../src/testing/browser-frontend-model-event-hook-scenarios.js","../src/testing/browser-test-app.js","../src/testing/expect-to-change.js","../src/testing/expect-utils.js","../src/testing/expect.js","../src/testing/request-client.js","../src/testing/test-files-finder.js","../src/testing/test-filter-parser.js","../src/testing/test-runner.js","../src/testing/test-suite-splitter.js","../src/testing/test.js","../src/types/external-modules.d.ts","../src/utils/backtrace-cleaner-node.js","../src/utils/backtrace-cleaner.js","../src/utils/deburr-column-name.js","../src/utils/event-emitter.js","../src/utils/file-exists.js","../src/utils/format-value.js","../src/utils/is-date.js","../src/utils/model-scope.js","../src/utils/nest-callbacks.js","../src/utils/plain-object.js","../src/utils/ransack.js","../src/utils/rest-args-error.js","../src/utils/singularize-model-name.js","../src/utils/split-sql-statements.js","../src/utils/to-import-specifier.js","../src/utils/with-tracked-stack-async-hooks.js","../src/utils/with-tracked-stack.js"],"version":"6.0.3"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
import BaseCommand from "../../../base-command.js"
|
|
4
|
+
import TenantDatabaseCommandHelper from "../../../tenant-database-command-helper.js"
|
|
5
|
+
|
|
6
|
+
export default class DbTenantsDrop extends BaseCommand {
|
|
7
|
+
/**
|
|
8
|
+
* Drops the tenant database/schema for every listed tenant through the provider's
|
|
9
|
+
* `dropDatabase` hook.
|
|
10
|
+
* @returns {Promise<{identifier: string, tenantCount: number} | void>} - Result in test mode.
|
|
11
|
+
*/
|
|
12
|
+
async execute() {
|
|
13
|
+
const helper = new TenantDatabaseCommandHelper({
|
|
14
|
+
command: this,
|
|
15
|
+
identifier: this.processArgs?.[1]
|
|
16
|
+
})
|
|
17
|
+
const provider = helper.provider
|
|
18
|
+
|
|
19
|
+
if (typeof provider.dropDatabase !== "function") {
|
|
20
|
+
throw new Error(`Tenant database provider for ${helper.identifier} must define dropDatabase to use db:tenants:drop`)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const tenantCount = await helper.eachTenant(async ({databaseConfiguration, tenant}) => {
|
|
24
|
+
await provider.dropDatabase?.({
|
|
25
|
+
configuration: this.getConfiguration(),
|
|
26
|
+
databaseConfiguration,
|
|
27
|
+
identifier: helper.identifier,
|
|
28
|
+
tenant
|
|
29
|
+
})
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
if (this.args.testing) return {identifier: helper.identifier, tenantCount}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
|
|
3
|
+
import TenantIterator from "../tenants/tenant-iterator.js"
|
|
4
|
+
|
|
3
5
|
export default class TenantDatabaseCommandHelper {
|
|
4
6
|
/**
|
|
5
7
|
* Runs constructor.
|
|
@@ -76,55 +78,13 @@ export default class TenantDatabaseCommandHelper {
|
|
|
76
78
|
*/
|
|
77
79
|
async eachTenant(callback) {
|
|
78
80
|
const tenants = await this.listTenants()
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return tenants.length
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
/**
|
|
90
|
-
* Failures.
|
|
91
|
-
* @type {Array<{error: Error, tenant: ?}>} */
|
|
92
|
-
const failures = []
|
|
93
|
-
const workers = []
|
|
94
|
-
let tenantIndex = 0
|
|
95
|
-
const workerCount = Math.min(parallelCount, tenants.length)
|
|
96
|
-
|
|
97
|
-
for (let workerIndex = 0; workerIndex < workerCount; workerIndex++) {
|
|
98
|
-
workers.push((async () => {
|
|
99
|
-
while (tenantIndex < tenants.length) {
|
|
100
|
-
const tenant = tenants[tenantIndex]
|
|
101
|
-
|
|
102
|
-
tenantIndex++
|
|
103
|
-
|
|
104
|
-
try {
|
|
105
|
-
await this.runTenantCallback({callback, tenant})
|
|
106
|
-
} catch (error) {
|
|
107
|
-
failures.push({
|
|
108
|
-
error: error instanceof Error ? error : new Error(String(error)),
|
|
109
|
-
tenant
|
|
110
|
-
})
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
})())
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
await Promise.all(workers)
|
|
117
|
-
|
|
118
|
-
if (failures.length > 0) {
|
|
119
|
-
const failedTenantLabels = failures.map((failure) => this.tenantLabel(failure.tenant)).join(", ")
|
|
120
|
-
|
|
121
|
-
throw new AggregateError(
|
|
122
|
-
failures.map((failure) => failure.error),
|
|
123
|
-
`Failed tenant database command for tenant(s): ${failedTenantLabels}`
|
|
124
|
-
)
|
|
125
|
-
}
|
|
81
|
+
const iterator = new TenantIterator({
|
|
82
|
+
configuration: this.configuration,
|
|
83
|
+
identifier: this.identifier,
|
|
84
|
+
parallelCount: this.parallelCount()
|
|
85
|
+
})
|
|
126
86
|
|
|
127
|
-
return tenants
|
|
87
|
+
return await iterator.run(tenants, callback)
|
|
128
88
|
}
|
|
129
89
|
|
|
130
90
|
/**
|
|
@@ -156,41 +116,4 @@ export default class TenantDatabaseCommandHelper {
|
|
|
156
116
|
|
|
157
117
|
return parallelCount
|
|
158
118
|
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Runs run tenant callback.
|
|
162
|
-
* @param {object} args - Tenant callback args.
|
|
163
|
-
* @param {function({databaseConfiguration: import("../configuration-types.js").DatabaseConfigurationType, tenant: ?}) : Promise<void>} args.callback - Callback.
|
|
164
|
-
* @param {?} args.tenant - Tenant.
|
|
165
|
-
* @returns {Promise<void>}
|
|
166
|
-
*/
|
|
167
|
-
async runTenantCallback({callback, tenant}) {
|
|
168
|
-
await this.configuration.runWithTenant(tenant, async () => {
|
|
169
|
-
if (!this.configuration.isDatabaseIdentifierActive(this.identifier)) {
|
|
170
|
-
throw new Error(`Tenant database identifier ${this.identifier} is inactive for tenant: ${this.tenantLabel(tenant)}`)
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
await callback({
|
|
174
|
-
databaseConfiguration: this.configuration.resolveDatabaseConfiguration(this.identifier),
|
|
175
|
-
tenant
|
|
176
|
-
})
|
|
177
|
-
})
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Runs tenant label.
|
|
182
|
-
* @param {?} tenant - Tenant.
|
|
183
|
-
* @returns {string} - Human readable tenant label.
|
|
184
|
-
*/
|
|
185
|
-
tenantLabel(tenant) {
|
|
186
|
-
if (tenant && typeof tenant === "object") {
|
|
187
|
-
const tenantObject = /** @type {{id?: ?, name?: ?, slug?: ?}} */ (tenant)
|
|
188
|
-
|
|
189
|
-
if (tenantObject.slug) return String(tenantObject.slug)
|
|
190
|
-
if (tenantObject.name) return String(tenantObject.name)
|
|
191
|
-
if (tenantObject.id) return String(tenantObject.id)
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
return JSON.stringify(tenant)
|
|
195
|
-
}
|
|
196
119
|
}
|