velocious 1.0.482 → 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.
Files changed (33) hide show
  1. package/README.md +2 -0
  2. package/build/cli/commands/db/tenants/drop.js +34 -0
  3. package/build/cli/tenant-database-command-helper.js +8 -85
  4. package/build/database/tenants/data-copier.js +269 -0
  5. package/build/database/tenants/tenant-table-plan.js +20 -0
  6. package/build/src/cli/commands/db/tenants/drop.d.ts +13 -0
  7. package/build/src/cli/commands/db/tenants/drop.d.ts.map +1 -0
  8. package/build/src/cli/commands/db/tenants/drop.js +31 -0
  9. package/build/src/cli/tenant-database-command-helper.d.ts +0 -20
  10. package/build/src/cli/tenant-database-command-helper.d.ts.map +1 -1
  11. package/build/src/cli/tenant-database-command-helper.js +8 -73
  12. package/build/src/database/tenants/data-copier.d.ts +125 -0
  13. package/build/src/database/tenants/data-copier.d.ts.map +1 -0
  14. package/build/src/database/tenants/data-copier.js +232 -0
  15. package/build/src/database/tenants/tenant-table-plan.d.ts +30 -0
  16. package/build/src/database/tenants/tenant-table-plan.d.ts.map +1 -0
  17. package/build/src/database/tenants/tenant-table-plan.js +3 -0
  18. package/build/src/tenants/tenant-iterator.d.ts +52 -0
  19. package/build/src/tenants/tenant-iterator.d.ts.map +1 -0
  20. package/build/src/tenants/tenant-iterator.js +97 -0
  21. package/build/src/tenants/tenant.d.ts +51 -0
  22. package/build/src/tenants/tenant.d.ts.map +1 -0
  23. package/build/src/tenants/tenant.js +76 -0
  24. package/build/tenants/tenant-iterator.js +111 -0
  25. package/build/tenants/tenant.js +86 -0
  26. package/build/tsconfig.tsbuildinfo +1 -1
  27. package/package.json +1 -1
  28. package/src/cli/commands/db/tenants/drop.js +34 -0
  29. package/src/cli/tenant-database-command-helper.js +8 -85
  30. package/src/database/tenants/data-copier.js +269 -0
  31. package/src/database/tenants/tenant-table-plan.js +20 -0
  32. package/src/tenants/tenant-iterator.js +111 -0
  33. package/src/tenants/tenant.js +86 -0
@@ -1,4 +1,5 @@
1
1
  // @ts-check
2
+ import TenantIterator from "../tenants/tenant-iterator.js";
2
3
  export default class TenantDatabaseCommandHelper {
3
4
  /**
4
5
  * Runs constructor.
@@ -64,43 +65,12 @@ export default class TenantDatabaseCommandHelper {
64
65
  */
65
66
  async eachTenant(callback) {
66
67
  const tenants = await this.listTenants();
67
- const parallelCount = this.parallelCount();
68
- if (parallelCount <= 1) {
69
- for (const tenant of tenants) {
70
- await this.runTenantCallback({ callback, tenant });
71
- }
72
- return tenants.length;
73
- }
74
- /**
75
- * Failures.
76
- * @type {Array<{error: Error, tenant: ?}>} */
77
- const failures = [];
78
- const workers = [];
79
- let tenantIndex = 0;
80
- const workerCount = Math.min(parallelCount, tenants.length);
81
- for (let workerIndex = 0; workerIndex < workerCount; workerIndex++) {
82
- workers.push((async () => {
83
- while (tenantIndex < tenants.length) {
84
- const tenant = tenants[tenantIndex];
85
- tenantIndex++;
86
- try {
87
- await this.runTenantCallback({ callback, tenant });
88
- }
89
- catch (error) {
90
- failures.push({
91
- error: error instanceof Error ? error : new Error(String(error)),
92
- tenant
93
- });
94
- }
95
- }
96
- })());
97
- }
98
- await Promise.all(workers);
99
- if (failures.length > 0) {
100
- const failedTenantLabels = failures.map((failure) => this.tenantLabel(failure.tenant)).join(", ");
101
- throw new AggregateError(failures.map((failure) => failure.error), `Failed tenant database command for tenant(s): ${failedTenantLabels}`);
102
- }
103
- return tenants.length;
68
+ const iterator = new TenantIterator({
69
+ configuration: this.configuration,
70
+ identifier: this.identifier,
71
+ parallelCount: this.parallelCount()
72
+ });
73
+ return await iterator.run(tenants, callback);
104
74
  }
105
75
  /**
106
76
  * Runs parallel count.
@@ -126,40 +96,5 @@ export default class TenantDatabaseCommandHelper {
126
96
  }
127
97
  return parallelCount;
128
98
  }
129
- /**
130
- * Runs run tenant callback.
131
- * @param {object} args - Tenant callback args.
132
- * @param {function({databaseConfiguration: import("../configuration-types.js").DatabaseConfigurationType, tenant: ?}) : Promise<void>} args.callback - Callback.
133
- * @param {?} args.tenant - Tenant.
134
- * @returns {Promise<void>}
135
- */
136
- async runTenantCallback({ callback, tenant }) {
137
- await this.configuration.runWithTenant(tenant, async () => {
138
- if (!this.configuration.isDatabaseIdentifierActive(this.identifier)) {
139
- throw new Error(`Tenant database identifier ${this.identifier} is inactive for tenant: ${this.tenantLabel(tenant)}`);
140
- }
141
- await callback({
142
- databaseConfiguration: this.configuration.resolveDatabaseConfiguration(this.identifier),
143
- tenant
144
- });
145
- });
146
- }
147
- /**
148
- * Runs tenant label.
149
- * @param {?} tenant - Tenant.
150
- * @returns {string} - Human readable tenant label.
151
- */
152
- tenantLabel(tenant) {
153
- if (tenant && typeof tenant === "object") {
154
- const tenantObject = /** @type {{id?: ?, name?: ?, slug?: ?}} */ (tenant);
155
- if (tenantObject.slug)
156
- return String(tenantObject.slug);
157
- if (tenantObject.name)
158
- return String(tenantObject.name);
159
- if (tenantObject.id)
160
- return String(tenantObject.id);
161
- }
162
- return JSON.stringify(tenant);
163
- }
164
99
  }
165
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVuYW50LWRhdGFiYXNlLWNvbW1hbmQtaGVscGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NsaS90ZW5hbnQtZGF0YWJhc2UtY29tbWFuZC1oZWxwZXIuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE1BQU0sQ0FBQyxPQUFPLE9BQU8sMkJBQTJCO0lBQzlDOzs7OztPQUtHO0lBQ0gsWUFBWSxFQUFDLE9BQU8sRUFBRSxVQUFVLEVBQUM7UUFDL0IsSUFBSSxDQUFDLFVBQVU7WUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLDZDQUE2QyxDQUFDLENBQUE7UUFFL0UsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUE7UUFDdEIsSUFBSSxDQUFDLGFBQWEsR0FBRyxPQUFPLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQTtRQUMvQyxJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQTtRQUM1QixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMseUJBQXlCLENBQUMsVUFBVSxDQUFDLENBQUE7SUFDMUUsQ0FBQztJQUVEOzt5QkFFcUI7SUFDckIsZ0NBQWdDO1FBQzlCLE1BQU0scUJBQXFCLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyx3QkFBd0IsRUFBRSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQTtRQUU1RixJQUFJLENBQUMscUJBQXFCLEVBQUUsQ0FBQztZQUMzQixNQUFNLElBQUksS0FBSyxDQUFDLDJDQUEyQyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQTtRQUMvRSxDQUFDO1FBRUQsSUFBSSxDQUFDLHFCQUFxQixDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ3RDLE1BQU0sSUFBSSxLQUFLLENBQUMsdUJBQXVCLElBQUksQ0FBQyxVQUFVLDBDQUEwQyxDQUFDLENBQUE7UUFDbkcsQ0FBQztRQUVELElBQUksSUFBSSxDQUFDLGFBQWEsQ0FBQyw4QkFBOEIsRUFB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Q3RILENBQUM7WUFFRCxNQUFNLFFBQVEsQ0FBQztnQkFDYixxQkFBcUIsRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLDRCQUE0QixDQUFDLElBQUksQ0FBQyxVQUFVLENBQUM7Z0JBQ3ZGLE1BQU07YUFDUCxDQUFDLENBQUE7UUFDSixDQUFDLENBQUMsQ0FBQTtJQUNKLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsV0FBVyxDQUFDLE1BQU07UUFDaEIsSUFBSSxNQUFNLElBQUksT0FBTyxNQUFNLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDekMsTUFBTSxZQUFZLEdBQUcsMkNBQTJDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQTtZQUV6RSxJQUFJLFlBQVksQ0FBQyxJQUFJO2dCQUFFLE9BQU8sTUFBTSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQTtZQUN2RCxJQUFJLFlBQVksQ0FBQyxJQUFJO2dCQUFFLE9BQU8sTUFBTSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsQ0FBQTtZQUN2RCxJQUFJLFlBQVksQ0FBQyxFQUFFO2dCQUFFLE9BQU8sTUFBTSxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUMsQ0FBQTtRQUNyRCxDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFBO0lBQy9CLENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBUZW5hbnREYXRhYmFzZUNvbW1hbmRIZWxwZXIge1xuICAvKipcbiAgICogUnVucyBjb25zdHJ1Y3Rvci5cbiAgICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBPcHRpb25zIG9iamVjdC5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuL2Jhc2UtY29tbWFuZC5qc1wiKS5kZWZhdWx0fSBhcmdzLmNvbW1hbmQgLSBDTEkgY29tbWFuZCBpbnN0YW5jZS5cbiAgICogQHBhcmFtIHtzdHJpbmcgfCB1bmRlZmluZWR9IGFyZ3MuaWRlbnRpZmllciAtIFRlbmFudCBkYXRhYmFzZSBpZGVudGlmaWVyLlxuICAgKi9cbiAgY29uc3RydWN0b3Ioe2NvbW1hbmQsIGlkZW50aWZpZXJ9KSB7XG4gICAgaWYgKCFpZGVudGlmaWVyKSB0aHJvdyBuZXcgRXJyb3IoXCJNaXNzaW5nIHRlbmFudCBkYXRhYmFzZSBpZGVudGlmaWVyIGFyZ3VtZW50XCIpXG5cbiAgICB0aGlzLmNvbW1hbmQgPSBjb21tYW5kXG4gICAgdGhpcy5jb25maWd1cmF0aW9uID0gY29tbWFuZC5nZXRDb25maWd1cmF0aW9uKClcbiAgICB0aGlzLmlkZW50aWZpZXIgPSBpZGVudGlmaWVyXG4gICAgdGhpcy5wcm92aWRlciA9IHRoaXMuY29uZmlndXJhdGlvbi5nZXRUZW5hbnREYXRhYmFzZVByb3ZpZGVyKGlkZW50aWZpZXIpXG4gIH1cblxuICAvKipcbiAgICogUnVucyB2YWxpZGF0ZSB0ZW5hbnQgZGF0YWJhc2UgaWRlbnRpZmllci5cbiAgICogQHJldHVybnMge3ZvaWR9ICovXG4gIHZhbGlkYXRlVGVuYW50RGF0YWJhc2VJZGVudGlmaWVyKCkge1xuICAgIGNvbnN0IGRhdGFiYXNlQ29uZmlndXJhdGlvbiA9IHRoaXMuY29uZmlndXJhdGlvbi5nZXREYXRhYmFzZUNvbmZpZ3VyYXRpb24oKVt0aGlzLmlkZW50aWZpZXJdXG5cbiAgICBpZiAoIWRhdGFiYXNlQ29uZmlndXJhdGlvbikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBObyBzdWNoIGRhdGFiYXNlIGlkZW50aWZpZXIgY29uZmlndXJlZDogJHt0aGlzLmlkZW50aWZpZXJ9YClcbiAgICB9XG5cbiAgICBpZiAoIWRhdGFiYXNlQ29uZmlndXJhdGlvbi50ZW5hbnRPbmx5KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYERhdGFiYXNlIGlkZW50aWZpZXIgJHt0aGlzLmlkZW50aWZpZXJ9IGlzIG5vdCBjb25maWd1cmVkIHdpdGggdGVuYW50T25seTogdHJ1ZWApXG4gICAgfVxuXG4gICAgaWYgKHRoaXMuY29uZmlndXJhdGlvbi5nZXREaXNhYmxlZERhdGFiYXNlSWRlbnRpZmllcnMoKS5oYXModGhpcy5pZGVudGlmaWVyKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBUZW5hbnQgZGF0YWJhc2UgaWRlbnRpZmllciAke3RoaXMuaWRlbnRpZmllcn0gaXMgZGlzYWJsZWQgYnkgVkVMT0NJT1VTX0RJU0FCTEVEX0RBVEFCQVNFX0lERU5USUZJRVJTYClcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIHRoaXMucHJvdmlkZXIubGlzdFRlbmFudHMgIT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBUZW5hbnQgZGF0YWJhc2UgcHJvdmlkZXIgZm9yICR7dGhpcy5pZGVudGlmaWVyfSBtdXN0IGRlZmluZSBsaXN0VGVuYW50c2ApXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgaW5pdGlhbGl6ZSBydW50aW1lLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBSZXNvbHZlcyB3aGVuIGFwcCBydW50aW1lIGlzIGluaXRpYWxpemVkLlxuICAgKi9cbiAgYXN5bmMgaW5pdGlhbGl6ZVJ1bnRpbWUoKSB7XG4gICAgYXdhaXQgdGhpcy5jb25maWd1cmF0aW9uLmluaXRpYWxpemUoe3R5cGU6IFwiZGItdGVuYW50c1wifSlcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGxpc3QgdGVuYW50cy5cbiAgICogQHJldHVybnMge1Byb21pc2U8QXJyYXk8Pz4+fSAtIFRlbmFudHMuXG4gICAqL1xuICBhc3luYyBsaXN0VGVuYW50cygpIHtcbiAgICB0aGlzLnZhbGlkYXRlVGVuYW50RGF0YWJhc2VJZGVudGlmaWVyKClcbiAgICBhd2FpdCB0aGlzLmluaXRpYWxpemVSdW50aW1lKClcblxuICAgIGNvbnN0IHRlbmFudHMgPSBhd2FpdCB0aGlzLmNvbmZpZ3VyYXRpb24uZW5zdXJlQ29ubmVjdGlvbnMoe25hbWU6IGBUZW5hbnQgZGF0YWJhc2UgbGlzdDogJHt0aGlzLmlkZW50aWZpZXJ9YH0sIGFzeW5jICgpID0+IHtcbiAgICAgIHJldHVybiBhd2FpdCB0aGlzLnByb3ZpZGVyLmxpc3RUZW5hbnRzKHtcbiAgICAgICAgY29uZmlndXJhdGlvbjogdGhpcy5jb25maWd1cmF0aW9uLFxuICAgICAgICBpZGVudGlmaWVyOiB0aGlzLmlkZW50aWZpZXJcbiAgICAgIH0pXG4gICAgfSlcblxuICAgIGlmICghQXJyYXkuaXNBcnJheSh0ZW5hbnRzKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBUZW5hbnQgZGF0YWJhc2UgcHJvdmlkZXIgZm9yICR7dGhpcy5pZGVudGlmaWVyfSBtdXN0IHJldHVybiBhbiBhcnJheSBmcm9tIGxpc3RUZW5hbnRzYClcbiAgICB9XG5cbiAgICByZXR1cm4gdGVuYW50c1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgZWFjaCB0ZW5hbnQuXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb24oe2RhdGFiYXNlQ29uZmlndXJhdGlvbjogaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5EYXRhYmFzZUNvbmZpZ3VyYXRpb25UeXBlLCB0ZW5hbnQ6ID99KSA6IFByb21pc2U8dm9pZD59IGNhbGxiYWNrIC0gQ2FsbGJhY2suXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPG51bWJlcj59IC0gTnVtYmVyIG9mIHRlbmFudHMgcHJvY2Vzc2VkLlxuICAgKi9cbiAgYXN5bmMgZWFjaFRlbmFudChjYWxsYmFjaykge1xuICAgIGNvbnN0IHRlbmFudHMgPSBhd2FpdCB0aGlzLmxpc3RUZW5hbnRzKClcbiAgICBjb25zdCBwYXJhbGxlbENvdW50ID0gdGhpcy5wYXJhbGxlbENvdW50KClcblxuICAgIGlmIChwYXJhbGxlbENvdW50IDw9IDEpIHtcbiAgICAgIGZvciAoY29uc3QgdGVuYW50IG9mIHRlbmFudHMpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5ydW5UZW5hbnRDYWxsYmFjayh7Y2FsbGJhY2ssIHRlbmFudH0pXG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0ZW5hbnRzLmxlbmd0aFxuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEZhaWx1cmVzLlxuICAgICAqIEB0eXBlIHtBcnJheTx7ZXJyb3I6IEVycm9yLCB0ZW5hbnQ6ID99Pn0gKi9cbiAgICBjb25zdCBmYWlsdXJlcyA9IFtdXG4gICAgY29uc3Qgd29ya2VycyA9IFtdXG4gICAgbGV0IHRlbmFudEluZGV4ID0gMFxuICAgIGNvbnN0IHdvcmtlckNvdW50ID0gTWF0aC5taW4ocGFyYWxsZWxDb3VudCwgdGVuYW50cy5sZW5ndGgpXG5cbiAgICBmb3IgKGxldCB3b3JrZXJJbmRleCA9IDA7IHdvcmtlckluZGV4IDwgd29ya2VyQ291bnQ7IHdvcmtlckluZGV4KyspIHtcbiAgICAgIHdvcmtlcnMucHVzaCgoYXN5bmMgKCkgPT4ge1xuICAgICAgICB3aGlsZSAodGVuYW50SW5kZXggPCB0ZW5hbnRzLmxlbmd0aCkge1xuICAgICAgICAgIGNvbnN0IHRlbmFudCA9IHRlbmFudHNbdGVuYW50SW5kZXhdXG5cbiAgICAgICAgICB0ZW5hbnRJbmRleCsrXG5cbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5ydW5UZW5hbnRDYWxsYmFjayh7Y2FsbGJhY2ssIHRlbmFudH0pXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIGZhaWx1cmVzLnB1c2goe1xuICAgICAgICAgICAgICBlcnJvcjogZXJyb3IgaW5zdGFuY2VvZiBFcnJvciA/IGVycm9yIDogbmV3IEVycm9yKFN0cmluZyhlcnJvcikpLFxuICAgICAgICAgICAgICB0ZW5hbnRcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KSgpKVxuICAgIH1cblxuICAgIGF3YWl0IFByb21pc2UuYWxsKHdvcmtlcnMpXG5cbiAgICBpZiAoZmFpbHVyZXMubGVuZ3RoID4gMCkge1xuICAgICAgY29uc3QgZmFpbGVkVGVuYW50TGFiZWxzID0gZmFpbHVyZXMubWFwKChmYWlsdXJlKSA9PiB0aGlzLnRlbmFudExhYmVsKGZhaWx1cmUudGVuYW50KSkuam9pbihcIiwgXCIpXG5cbiAgICAgIHRocm93IG5ldyBBZ2dyZWdhdGVFcnJvcihcbiAgICAgICAgZmFpbHVyZXMubWFwKChmYWlsdXJlKSA9PiBmYWlsdXJlLmVycm9yKSxcbiAgICAgICAgYEZhaWxlZCB0ZW5hbnQgZGF0YWJhc2UgY29tbWFuZCBmb3IgdGVuYW50KHMpOiAke2ZhaWxlZFRlbmFudExhYmVsc31gXG4gICAgICApXG4gICAgfVxuXG4gICAgcmV0dXJuIHRlbmFudHMubGVuZ3RoXG4gIH1cblxuICAvKipcbiAgICogUnVucyBwYXJhbGxlbCBjb3VudC5cbiAgICogQHJldHVybnMge251bWJlcn0gLSBOdW1iZXIgb2YgdGVuYW50cyB0byBwcm9jZXNzIGNvbmN1cnJlbnRseS5cbiAgICovXG4gIHBhcmFsbGVsQ291bnQoKSB7XG4gICAgY29uc3QgcGFyc2VkUHJvY2Vzc0FyZ3MgPSB0aGlzLmNvbW1hbmQuYXJncz8ucGFyc2VkUHJvY2Vzc0FyZ3MgfHwge31cbiAgICBsZXQgcGFyYWxsZWxBcmcgPSBwYXJzZWRQcm9jZXNzQXJncy5wYXJhbGxlbFxuXG4gICAgaWYgKHBhcmFsbGVsQXJnID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IHBhcmFsbGVsQXJnSW5kZXggPSB0aGlzLmNvbW1hbmQucHJvY2Vzc0FyZ3M/LmluZGV4T2YoXCItLXBhcmFsbGVsXCIpID8/IC0xXG5cbiAgICAgIGlmIChwYXJhbGxlbEFyZ0luZGV4ID49IDApIHtcbiAgICAgICAgY29uc3QgbmV4dEFyZyA9IHRoaXMuY29tbWFuZC5wcm9jZXNzQXJncz8uW3BhcmFsbGVsQXJnSW5kZXggKyAxXVxuXG4gICAgICAgIHBhcmFsbGVsQXJnID0gbmV4dEFyZyAmJiAhbmV4dEFyZy5zdGFydHNXaXRoKFwiLVwiKSA/IG5leHRBcmcgOiB0cnVlXG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHBhcmFsbGVsQXJnID09PSB1bmRlZmluZWQgfHwgcGFyYWxsZWxBcmcgPT09IGZhbHNlKSByZXR1cm4gMVxuICAgIGlmIChwYXJhbGxlbEFyZyA9PT0gdHJ1ZSkgcmV0dXJuIDIwXG5cbiAgICBjb25zdCBwYXJhbGxlbENvdW50ID0gTnVtYmVyKHBhcmFsbGVsQXJnKVxuXG4gICAgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKHBhcmFsbGVsQ291bnQpIHx8IHBhcmFsbGVsQ291bnQgPCAxKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYC0tcGFyYWxsZWwgbXVzdCBiZSBhIHBvc2l0aXZlIGludGVnZXIgd2hlbiBhIHZhbHVlIGlzIHByb3ZpZGVkOiAke3BhcmFsbGVsQXJnfWApXG4gICAgfVxuXG4gICAgcmV0dXJuIHBhcmFsbGVsQ291bnRcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHJ1biB0ZW5hbnQgY2FsbGJhY2suXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gVGVuYW50IGNhbGxiYWNrIGFyZ3MuXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb24oe2RhdGFiYXNlQ29uZmlndXJhdGlvbjogaW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi10eXBlcy5qc1wiKS5EYXRhYmFzZUNvbmZpZ3VyYXRpb25UeXBlLCB0ZW5hbnQ6ID99KSA6IFByb21pc2U8dm9pZD59IGFyZ3MuY2FsbGJhY2sgLSBDYWxsYmFjay5cbiAgICogQHBhcmFtIHs/fSBhcmdzLnRlbmFudCAtIFRlbmFudC5cbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBydW5UZW5hbnRDYWxsYmFjayh7Y2FsbGJhY2ssIHRlbmFudH0pIHtcbiAgICBhd2FpdCB0aGlzLmNvbmZpZ3VyYXRpb24ucnVuV2l0aFRlbmFudCh0ZW5hbnQsIGFzeW5jICgpID0+IHtcbiAgICAgIGlmICghdGhpcy5jb25maWd1cmF0aW9uLmlzRGF0YWJhc2VJZGVudGlmaWVyQWN0aXZlKHRoaXMuaWRlbnRpZmllcikpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBUZW5hbnQgZGF0YWJhc2UgaWRlbnRpZmllciAke3RoaXMuaWRlbnRpZmllcn0gaXMgaW5hY3RpdmUgZm9yIHRlbmFudDogJHt0aGlzLnRlbmFudExhYmVsKHRlbmFudCl9YClcbiAgICAgIH1cblxuICAgICAgYXdhaXQgY2FsbGJhY2soe1xuICAgICAgICBkYXRhYmFzZUNvbmZpZ3VyYXRpb246IHRoaXMuY29uZmlndXJhdGlvbi5yZXNvbHZlRGF0YWJhc2VDb25maWd1cmF0aW9uKHRoaXMuaWRlbnRpZmllciksXG4gICAgICAgIHRlbmFudFxuICAgICAgfSlcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgdGVuYW50IGxhYmVsLlxuICAgKiBAcGFyYW0gez99IHRlbmFudCAtIFRlbmFudC5cbiAgICogQHJldHVybnMge3N0cmluZ30gLSBIdW1hbiByZWFkYWJsZSB0ZW5hbnQgbGFiZWwuXG4gICAqL1xuICB0ZW5hbnRMYWJlbCh0ZW5hbnQpIHtcbiAgICBpZiAodGVuYW50ICYmIHR5cGVvZiB0ZW5hbnQgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgIGNvbnN0IHRlbmFudE9iamVjdCA9IC8qKiBAdHlwZSB7e2lkPzogPywgbmFtZT86ID8sIHNsdWc/OiA/fX0gKi8gKHRlbmFudClcblxuICAgICAgaWYgKHRlbmFudE9iamVjdC5zbHVnKSByZXR1cm4gU3RyaW5nKHRlbmFudE9iamVjdC5zbHVnKVxuICAgICAgaWYgKHRlbmFudE9iamVjdC5uYW1lKSByZXR1cm4gU3RyaW5nKHRlbmFudE9iamVjdC5uYW1lKVxuICAgICAgaWYgKHRlbmFudE9iamVjdC5pZCkgcmV0dXJuIFN0cmluZyh0ZW5hbnRPYmplY3QuaWQpXG4gICAgfVxuXG4gICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHRlbmFudClcbiAgfVxufVxuIl19
100
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVuYW50LWRhdGFiYXNlLWNvbW1hbmQtaGVscGVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NsaS90ZW5hbnQtZGF0YWJhc2UtY29tbWFuZC1oZWxwZXIuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWTtBQUVaLE9BQU8sY0FBYyxNQUFNLCtCQUErQixDQUFBO0FBRTFELE1BQU0sQ0FBQyxPQUFPLE9BQU8sMkJBQTJCO0lBQzlDOzs7OztPQUtHO0lBQ0gsWUFBWSxFQUFDLE9BQU8sRUFBRSxVQUFVLEVBQUM7UUFDL0IsSUFBSSxDQUFDLFVBQVU7WUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLDZDQUE2QyxDQUFDLENBQUE7UUFFL0UsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUE7UUFDdEIsSUFBSSxDQUFDLGFBQWEsR0FBRyxPQUFPLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQTtRQUMvQyxJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQTtRQUM1QixJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMseUJBQXlCLENBQUMsVUFBVSxDQUFDLENBQUE7SUFDMUUsQ0FBQztJQUVEOzt5QkFFcUI7SUFDckIsZ0NBQWdDO1FBQzlCLE1BQU0scUJBQXFCLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyx3QkFBd0IsRUFBRSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQTtRQUU1RixJQUFJLENBQUMscUJBQXFCLEVBQUUsQ0FBQztZQUMzQixNQUFNLElBQUksS0FBSyxDQUFDLDJDQUEyQyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUMsQ0FBQTtRQUMvRSxDQUFDO1FBRUQsSUFBSSxDQUFDLHFCQUFxQixDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ3RDLE1BQU0sSUFBSSxLQUFLLENBQUMsdUJBQXVCLElBQUksQ0FBQyxVQUFVLDBDQUEwQyxDQUFDLENBQUE7UUFDbkcsQ0FBQztRQUVELElB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LFdBQVcsS0FBSyxTQUFTLElBQUksV0FBVyxLQUFLLEtBQUs7WUFBRSxPQUFPLENBQUMsQ0FBQTtRQUNoRSxJQUFJLFdBQVcsS0FBSyxJQUFJO1lBQUUsT0FBTyxFQUFFLENBQUE7UUFFbkMsTUFBTSxhQUFhLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFBO1FBRXpDLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxJQUFJLGFBQWEsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUMxRCxNQUFNLElBQUksS0FBSyxDQUFDLG1FQUFtRSxXQUFXLEVBQUUsQ0FBQyxDQUFBO1FBQ25HLENBQUM7UUFFRCxPQUFPLGFBQWEsQ0FBQTtJQUN0QixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAdHMtY2hlY2tcblxuaW1wb3J0IFRlbmFudEl0ZXJhdG9yIGZyb20gXCIuLi90ZW5hbnRzL3RlbmFudC1pdGVyYXRvci5qc1wiXG5cbmV4cG9ydCBkZWZhdWx0IGNsYXNzIFRlbmFudERhdGFiYXNlQ29tbWFuZEhlbHBlciB7XG4gIC8qKlxuICAgKiBSdW5zIGNvbnN0cnVjdG9yLlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIE9wdGlvbnMgb2JqZWN0LlxuICAgKiBAcGFyYW0ge2ltcG9ydChcIi4vYmFzZS1jb21tYW5kLmpzXCIpLmRlZmF1bHR9IGFyZ3MuY29tbWFuZCAtIENMSSBjb21tYW5kIGluc3RhbmNlLlxuICAgKiBAcGFyYW0ge3N0cmluZyB8IHVuZGVmaW5lZH0gYXJncy5pZGVudGlmaWVyIC0gVGVuYW50IGRhdGFiYXNlIGlkZW50aWZpZXIuXG4gICAqL1xuICBjb25zdHJ1Y3Rvcih7Y29tbWFuZCwgaWRlbnRpZmllcn0pIHtcbiAgICBpZiAoIWlkZW50aWZpZXIpIHRocm93IG5ldyBFcnJvcihcIk1pc3NpbmcgdGVuYW50IGRhdGFiYXNlIGlkZW50aWZpZXIgYXJndW1lbnRcIilcblxuICAgIHRoaXMuY29tbWFuZCA9IGNvbW1hbmRcbiAgICB0aGlzLmNvbmZpZ3VyYXRpb24gPSBjb21tYW5kLmdldENvbmZpZ3VyYXRpb24oKVxuICAgIHRoaXMuaWRlbnRpZmllciA9IGlkZW50aWZpZXJcbiAgICB0aGlzLnByb3ZpZGVyID0gdGhpcy5jb25maWd1cmF0aW9uLmdldFRlbmFudERhdGFiYXNlUHJvdmlkZXIoaWRlbnRpZmllcilcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIHZhbGlkYXRlIHRlbmFudCBkYXRhYmFzZSBpZGVudGlmaWVyLlxuICAgKiBAcmV0dXJucyB7dm9pZH0gKi9cbiAgdmFsaWRhdGVUZW5hbnREYXRhYmFzZUlkZW50aWZpZXIoKSB7XG4gICAgY29uc3QgZGF0YWJhc2VDb25maWd1cmF0aW9uID0gdGhpcy5jb25maWd1cmF0aW9uLmdldERhdGFiYXNlQ29uZmlndXJhdGlvbigpW3RoaXMuaWRlbnRpZmllcl1cblxuICAgIGlmICghZGF0YWJhc2VDb25maWd1cmF0aW9uKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYE5vIHN1Y2ggZGF0YWJhc2UgaWRlbnRpZmllciBjb25maWd1cmVkOiAke3RoaXMuaWRlbnRpZmllcn1gKVxuICAgIH1cblxuICAgIGlmICghZGF0YWJhc2VDb25maWd1cmF0aW9uLnRlbmFudE9ubHkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgRGF0YWJhc2UgaWRlbnRpZmllciAke3RoaXMuaWRlbnRpZmllcn0gaXMgbm90IGNvbmZpZ3VyZWQgd2l0aCB0ZW5hbnRPbmx5OiB0cnVlYClcbiAgICB9XG5cbiAgICBpZiAodGhpcy5jb25maWd1cmF0aW9uLmdldERpc2FibGVkRGF0YWJhc2VJZGVudGlmaWVycygpLmhhcyh0aGlzLmlkZW50aWZpZXIpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFRlbmFudCBkYXRhYmFzZSBpZGVudGlmaWVyICR7dGhpcy5pZGVudGlmaWVyfSBpcyBkaXNhYmxlZCBieSBWRUxPQ0lPVVNfRElTQUJMRURfREFUQUJBU0VfSURFTlRJRklFUlNgKVxuICAgIH1cblxuICAgIGlmICh0eXBlb2YgdGhpcy5wcm92aWRlci5saXN0VGVuYW50cyAhPT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFRlbmFudCBkYXRhYmFzZSBwcm92aWRlciBmb3IgJHt0aGlzLmlkZW50aWZpZXJ9IG11c3QgZGVmaW5lIGxpc3RUZW5hbnRzYClcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUnVucyBpbml0aWFsaXplIHJ1bnRpbWUuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIFJlc29sdmVzIHdoZW4gYXBwIHJ1bnRpbWUgaXMgaW5pdGlhbGl6ZWQuXG4gICAqL1xuICBhc3luYyBpbml0aWFsaXplUnVudGltZSgpIHtcbiAgICBhd2FpdCB0aGlzLmNvbmZpZ3VyYXRpb24uaW5pdGlhbGl6ZSh7dHlwZTogXCJkYi10ZW5hbnRzXCJ9KVxuICB9XG5cbiAgLyoqXG4gICAqIFJ1bnMgbGlzdCB0ZW5hbnRzLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxBcnJheTw/Pj59IC0gVGVuYW50cy5cbiAgICovXG4gIGFzeW5jIGxpc3RUZW5hbnRzKCkge1xuICAgIHRoaXMudmFsaWRhdGVUZW5hbnREYXRhYmFzZUlkZW50aWZpZXIoKVxuICAgIGF3YWl0IHRoaXMuaW5pdGlhbGl6ZVJ1bnRpbWUoKVxuXG4gICAgY29uc3QgdGVuYW50cyA9IGF3YWl0IHRoaXMuY29uZmlndXJhdGlvbi5lbnN1cmVDb25uZWN0aW9ucyh7bmFtZTogYFRlbmFudCBkYXRhYmFzZSBsaXN0OiAke3RoaXMuaWRlbnRpZmllcn1gfSwgYXN5bmMgKCkgPT4ge1xuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMucHJvdmlkZXIubGlzdFRlbmFudHMoe1xuICAgICAgICBjb25maWd1cmF0aW9uOiB0aGlzLmNvbmZpZ3VyYXRpb24sXG4gICAgICAgIGlkZW50aWZpZXI6IHRoaXMuaWRlbnRpZmllclxuICAgICAgfSlcbiAgICB9KVxuXG4gICAgaWYgKCFBcnJheS5pc0FycmF5KHRlbmFudHMpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYFRlbmFudCBkYXRhYmFzZSBwcm92aWRlciBmb3IgJHt0aGlzLmlkZW50aWZpZXJ9IG11c3QgcmV0dXJuIGFuIGFycmF5IGZyb20gbGlzdFRlbmFudHNgKVxuICAgIH1cblxuICAgIHJldHVybiB0ZW5hbnRzXG4gIH1cblxuICAvKipcbiAgICogUnVucyBlYWNoIHRlbmFudC5cbiAgICogQHBhcmFtIHtmdW5jdGlvbih7ZGF0YWJhc2VDb25maWd1cmF0aW9uOiBpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLXR5cGVzLmpzXCIpLkRhdGFiYXNlQ29uZmlndXJhdGlvblR5cGUsIHRlbmFudDogP30pIDogUHJvbWlzZTx2b2lkPn0gY2FsbGJhY2sgLSBDYWxsYmFjay5cbiAgICogQHJldHVybnMge1Byb21pc2U8bnVtYmVyPn0gLSBOdW1iZXIgb2YgdGVuYW50cyBwcm9jZXNzZWQuXG4gICAqL1xuICBhc3luYyBlYWNoVGVuYW50KGNhbGxiYWNrKSB7XG4gICAgY29uc3QgdGVuYW50cyA9IGF3YWl0IHRoaXMubGlzdFRlbmFudHMoKVxuICAgIGNvbnN0IGl0ZXJhdG9yID0gbmV3IFRlbmFudEl0ZXJhdG9yKHtcbiAgICAgIGNvbmZpZ3VyYXRpb246IHRoaXMuY29uZmlndXJhdGlvbixcbiAgICAgIGlkZW50aWZpZXI6IHRoaXMuaWRlbnRpZmllcixcbiAgICAgIHBhcmFsbGVsQ291bnQ6IHRoaXMucGFyYWxsZWxDb3VudCgpXG4gICAgfSlcblxuICAgIHJldHVybiBhd2FpdCBpdGVyYXRvci5ydW4odGVuYW50cywgY2FsbGJhY2spXG4gIH1cblxuICAvKipcbiAgICogUnVucyBwYXJhbGxlbCBjb3VudC5cbiAgICogQHJldHVybnMge251bWJlcn0gLSBOdW1iZXIgb2YgdGVuYW50cyB0byBwcm9jZXNzIGNvbmN1cnJlbnRseS5cbiAgICovXG4gIHBhcmFsbGVsQ291bnQoKSB7XG4gICAgY29uc3QgcGFyc2VkUHJvY2Vzc0FyZ3MgPSB0aGlzLmNvbW1hbmQuYXJncz8ucGFyc2VkUHJvY2Vzc0FyZ3MgfHwge31cbiAgICBsZXQgcGFyYWxsZWxBcmcgPSBwYXJzZWRQcm9jZXNzQXJncy5wYXJhbGxlbFxuXG4gICAgaWYgKHBhcmFsbGVsQXJnID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IHBhcmFsbGVsQXJnSW5kZXggPSB0aGlzLmNvbW1hbmQucHJvY2Vzc0FyZ3M/LmluZGV4T2YoXCItLXBhcmFsbGVsXCIpID8/IC0xXG5cbiAgICAgIGlmIChwYXJhbGxlbEFyZ0luZGV4ID49IDApIHtcbiAgICAgICAgY29uc3QgbmV4dEFyZyA9IHRoaXMuY29tbWFuZC5wcm9jZXNzQXJncz8uW3BhcmFsbGVsQXJnSW5kZXggKyAxXVxuXG4gICAgICAgIHBhcmFsbGVsQXJnID0gbmV4dEFyZyAmJiAhbmV4dEFyZy5zdGFydHNXaXRoKFwiLVwiKSA/IG5leHRBcmcgOiB0cnVlXG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHBhcmFsbGVsQXJnID09PSB1bmRlZmluZWQgfHwgcGFyYWxsZWxBcmcgPT09IGZhbHNlKSByZXR1cm4gMVxuICAgIGlmIChwYXJhbGxlbEFyZyA9PT0gdHJ1ZSkgcmV0dXJuIDIwXG5cbiAgICBjb25zdCBwYXJhbGxlbENvdW50ID0gTnVtYmVyKHBhcmFsbGVsQXJnKVxuXG4gICAgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKHBhcmFsbGVsQ291bnQpIHx8IHBhcmFsbGVsQ291bnQgPCAxKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYC0tcGFyYWxsZWwgbXVzdCBiZSBhIHBvc2l0aXZlIGludGVnZXIgd2hlbiBhIHZhbHVlIGlzIHByb3ZpZGVkOiAke3BhcmFsbGVsQXJnfWApXG4gICAgfVxuXG4gICAgcmV0dXJuIHBhcmFsbGVsQ291bnRcbiAgfVxufVxuIl19
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Copies a single tenant's rows from a source database into a target database, following a
3
+ * table plan that partitions each table either by a direct tenant key column or by
4
+ * parent-id traversal. This is the row-level counterpart to schema cloning: multi-tenant
5
+ * apps that keep each tenant's data in its own database use it to (re)materialise the
6
+ * tenant's rows from a global/template database.
7
+ *
8
+ * The copy is delete-then-reinsert and therefore idempotent, and it mirrors the source
9
+ * snapshot: the rows to delete are the tenant's *current* rows in the target (selected with
10
+ * the same plan traversal run against the target), so a row that was removed from the source
11
+ * since the last copy is dropped from the target too rather than lingering. The deletes run
12
+ * children first and the source inserts parents first, all inside one target transaction with
13
+ * foreign-key enforcement disabled so the ordering never trips a constraint. Reads, deletes
14
+ * and inserts are chunked to bound statement size.
15
+ *
16
+ * The copier is policy-free: the caller supplies the plan, the source/target databases and
17
+ * the tenant key, and {@link DataCopier#copy} returns the loaded rows keyed by table name so
18
+ * the caller can perform any app-specific post-copy work (for example registering record
19
+ * locations) without that policy leaking into the framework.
20
+ */
21
+ export default class DataCopier {
22
+ /**
23
+ * Creates a copier that moves tenant-owned rows from `sourceDb` into `targetDb`.
24
+ * @param {{
25
+ * sourceDb: import("../drivers/base.js").default,
26
+ * targetDb: import("../drivers/base.js").default,
27
+ * tablePlan: import("./tenant-table-plan.js").TenantTablePlanEntry[],
28
+ * idColumn?: string,
29
+ * insertChunkSize?: number,
30
+ * queryChunkSize?: number,
31
+ * onProgress?: (message: string) => void
32
+ * }} args
33
+ */
34
+ constructor({ sourceDb, targetDb, tablePlan, idColumn, insertChunkSize, queryChunkSize, onProgress }: {
35
+ sourceDb: import("../drivers/base.js").default;
36
+ targetDb: import("../drivers/base.js").default;
37
+ tablePlan: import("./tenant-table-plan.js").TenantTablePlanEntry[];
38
+ idColumn?: string;
39
+ insertChunkSize?: number;
40
+ queryChunkSize?: number;
41
+ onProgress?: (message: string) => void;
42
+ });
43
+ sourceDb: import("../drivers/base.js").default;
44
+ targetDb: import("../drivers/base.js").default;
45
+ tablePlan: import("./tenant-table-plan.js").TenantTablePlanEntry[];
46
+ idColumn: string;
47
+ insertChunkSize: number;
48
+ queryChunkSize: number;
49
+ onProgress: ((message: string) => void) | undefined;
50
+ /**
51
+ * Copies every plan table's rows for `keyValue` from the source into the target and
52
+ * returns the copied source rows keyed by table name. The target's current tenant rows
53
+ * are deleted (children first) and the source rows inserted (parents first) in a single
54
+ * target transaction with foreign keys disabled.
55
+ * @param {string} keyValue
56
+ * @returns {Promise<Map<string, Record<string, unknown>[]>>}
57
+ */
58
+ copy(keyValue: string): Promise<Map<string, Record<string, unknown>[]>>;
59
+ /**
60
+ * Loads the rows for `keyValue` for every table in the plan from `db`, resolving
61
+ * parent-scoped tables from the ids already selected for their parent table. Used for
62
+ * both the source rows to copy and the target's current tenant rows to delete.
63
+ * @param {import("../drivers/base.js").default} db
64
+ * @param {string} keyValue
65
+ * @returns {Promise<Map<string, Record<string, unknown>[]>>}
66
+ */
67
+ loadRows(db: import("../drivers/base.js").default, keyValue: string): Promise<Map<string, Record<string, unknown>[]>>;
68
+ /**
69
+ * Selects all rows of `tableName` in `db` whose `columnName` is in `values`, chunked.
70
+ * @param {{columnName: string, db: import("../drivers/base.js").default, tableName: string, values: string[]}} args
71
+ * @returns {Promise<Record<string, unknown>[]>}
72
+ */
73
+ queryRowsByColumn({ columnName, db, tableName, values }: {
74
+ columnName: string;
75
+ db: import("../drivers/base.js").default;
76
+ tableName: string;
77
+ values: string[];
78
+ }): Promise<Record<string, unknown>[]>;
79
+ /**
80
+ * Deletes the matching target rows for every plan table, children before parents, so the
81
+ * reinsert that follows starts from a clean slate without violating foreign keys.
82
+ * @param {Map<string, Record<string, unknown>[]>} rowsByTableName
83
+ * @returns {Promise<void>}
84
+ */
85
+ deleteTargetRows(rowsByTableName: Map<string, Record<string, unknown>[]>): Promise<void>;
86
+ /**
87
+ * Inserts the loaded source rows into the target for every plan table, parents before
88
+ * children, chunked to bound statement size.
89
+ * @param {Map<string, Record<string, unknown>[]>} rowsByTableName
90
+ * @returns {Promise<void>}
91
+ */
92
+ insertTargetRows(rowsByTableName: Map<string, Record<string, unknown>[]>): Promise<void>;
93
+ /**
94
+ * Quotes and comma-joins values for an SQL `IN (...)` list against the given database.
95
+ * @param {import("../drivers/base.js").default} db
96
+ * @param {string[]} values
97
+ * @returns {string}
98
+ */
99
+ quotedValuesSql(db: import("../drivers/base.js").default, values: string[]): string;
100
+ /**
101
+ * Runs a query without per-query logging, used for the high-volume copy statements.
102
+ * @param {import("../drivers/base.js").default} db
103
+ * @param {string} sql
104
+ * @returns {Promise<Record<string, unknown>[]>}
105
+ */
106
+ executeQuietQuery(db: import("../drivers/base.js").default, sql: string): Promise<Record<string, unknown>[]>;
107
+ /**
108
+ * Inserts column-aligned row tuples into a table without per-query logging.
109
+ * @param {{columns: string[], db: import("../drivers/base.js").default, rows: Array<Array<unknown>>, tableName: string}} args
110
+ * @returns {Promise<void>}
111
+ */
112
+ insertRowsQuietly({ columns, db, rows, tableName }: {
113
+ columns: string[];
114
+ db: import("../drivers/base.js").default;
115
+ rows: Array<Array<unknown>>;
116
+ tableName: string;
117
+ }): Promise<void>;
118
+ /**
119
+ * Forwards a progress message to the optional `onProgress` callback when one was given.
120
+ * @param {string} message
121
+ * @returns {void}
122
+ */
123
+ reportProgress(message: string): void;
124
+ }
125
+ //# sourceMappingURL=data-copier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-copier.d.ts","sourceRoot":"","sources":["../../../../src/database/tenants/data-copier.js"],"names":[],"mappings":"AA+BA;;;;;;;;;;;;;;;;;;;GAmBG;AACH;IACE;;;;;;;;;;;OAWG;IACH,sGAVW;QACN,QAAQ,EAAE,OAAO,oBAAoB,EAAE,OAAO,CAAC;QAC/C,QAAQ,EAAE,OAAO,oBAAoB,EAAE,OAAO,CAAC;QAC/C,SAAS,EAAE,OAAO,wBAAwB,EAAE,oBAAoB,EAAE,CAAC;QACnE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,eAAe,CAAC,EAAE,MAAM,CAAC;QACzB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,UAAU,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;KACvC,EAUH;IAPC,+CAAwB;IACxB,+CAAwB;IACxB,mEAA0B;IAC1B,iBAAwB;IACxB,wBAAsC;IACtC,uBAAoC;IACpC,uBAV0B,MAAM,KAAK,IAAI,cAUb;IAG9B;;;;;;;OAOG;IACH,eAHW,MAAM,GACJ,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAc3D;IAED;;;;;;;OAOG;IACH,aAJW,OAAO,oBAAoB,EAAE,OAAO,YACpC,MAAM,GACJ,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CA4C3D;IAED;;;;OAIG;IACH,yDAHW;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,OAAO,oBAAoB,EAAE,OAAO,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAC,GACjG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAoB9C;IAED;;;;;OAKG;IACH,kCAHW,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,GACpC,OAAO,CAAC,IAAI,CAAC,CAoBzB;IAED;;;;;OAKG;IACH,kCAHW,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,GACpC,OAAO,CAAC,IAAI,CAAC,CAwBzB;IAED;;;;;OAKG;IACH,oBAJW,OAAO,oBAAoB,EAAE,OAAO,UACpC,MAAM,EAAE,GACN,MAAM,CAIlB;IAED;;;;;OAKG;IACH,sBAJW,OAAO,oBAAoB,EAAE,OAAO,OACpC,MAAM,GACJ,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC,CAI9C;IAED;;;;OAIG;IACH,oDAHW;QAAC,OAAO,EAAE,MAAM,EAAE,CAAC;QAAC,EAAE,EAAE,OAAO,oBAAoB,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAC,GAC3G,OAAO,CAAC,IAAI,CAAC,CAIzB;IAED;;;;OAIG;IACH,wBAHW,MAAM,GACJ,IAAI,CAMhB;CACF"}
@@ -0,0 +1,232 @@
1
+ // @ts-check
2
+ const DEFAULT_INSERT_CHUNK_SIZE = 100;
3
+ const DEFAULT_QUERY_CHUNK_SIZE = 500;
4
+ /**
5
+ * Splits an array into chunks of at most `chunkSize` items.
6
+ * @template T
7
+ * @param {T[]} values
8
+ * @param {number} chunkSize
9
+ * @returns {T[][]}
10
+ */
11
+ function chunks(values, chunkSize) {
12
+ const chunkedValues = [];
13
+ for (let index = 0; index < values.length; index += chunkSize) {
14
+ chunkedValues.push(values.slice(index, index + chunkSize));
15
+ }
16
+ return chunkedValues;
17
+ }
18
+ /**
19
+ * Stringifies values and returns the distinct, non-blank ones, preserving first-seen order.
20
+ * @param {unknown[]} values
21
+ * @returns {string[]}
22
+ */
23
+ function uniqueStrings(values) {
24
+ return Array.from(new Set(values.map((value) => String(value)).filter((value) => value.trim())));
25
+ }
26
+ /**
27
+ * Copies a single tenant's rows from a source database into a target database, following a
28
+ * table plan that partitions each table either by a direct tenant key column or by
29
+ * parent-id traversal. This is the row-level counterpart to schema cloning: multi-tenant
30
+ * apps that keep each tenant's data in its own database use it to (re)materialise the
31
+ * tenant's rows from a global/template database.
32
+ *
33
+ * The copy is delete-then-reinsert and therefore idempotent, and it mirrors the source
34
+ * snapshot: the rows to delete are the tenant's *current* rows in the target (selected with
35
+ * the same plan traversal run against the target), so a row that was removed from the source
36
+ * since the last copy is dropped from the target too rather than lingering. The deletes run
37
+ * children first and the source inserts parents first, all inside one target transaction with
38
+ * foreign-key enforcement disabled so the ordering never trips a constraint. Reads, deletes
39
+ * and inserts are chunked to bound statement size.
40
+ *
41
+ * The copier is policy-free: the caller supplies the plan, the source/target databases and
42
+ * the tenant key, and {@link DataCopier#copy} returns the loaded rows keyed by table name so
43
+ * the caller can perform any app-specific post-copy work (for example registering record
44
+ * locations) without that policy leaking into the framework.
45
+ */
46
+ export default class DataCopier {
47
+ /**
48
+ * Creates a copier that moves tenant-owned rows from `sourceDb` into `targetDb`.
49
+ * @param {{
50
+ * sourceDb: import("../drivers/base.js").default,
51
+ * targetDb: import("../drivers/base.js").default,
52
+ * tablePlan: import("./tenant-table-plan.js").TenantTablePlanEntry[],
53
+ * idColumn?: string,
54
+ * insertChunkSize?: number,
55
+ * queryChunkSize?: number,
56
+ * onProgress?: (message: string) => void
57
+ * }} args
58
+ */
59
+ constructor({ sourceDb, targetDb, tablePlan, idColumn = "id", insertChunkSize = DEFAULT_INSERT_CHUNK_SIZE, queryChunkSize = DEFAULT_QUERY_CHUNK_SIZE, onProgress }) {
60
+ this.sourceDb = sourceDb;
61
+ this.targetDb = targetDb;
62
+ this.tablePlan = tablePlan;
63
+ this.idColumn = idColumn;
64
+ this.insertChunkSize = insertChunkSize;
65
+ this.queryChunkSize = queryChunkSize;
66
+ this.onProgress = onProgress;
67
+ }
68
+ /**
69
+ * Copies every plan table's rows for `keyValue` from the source into the target and
70
+ * returns the copied source rows keyed by table name. The target's current tenant rows
71
+ * are deleted (children first) and the source rows inserted (parents first) in a single
72
+ * target transaction with foreign keys disabled.
73
+ * @param {string} keyValue
74
+ * @returns {Promise<Map<string, Record<string, unknown>[]>>}
75
+ */
76
+ async copy(keyValue) {
77
+ const sourceRowsByTableName = await this.loadRows(this.sourceDb, keyValue);
78
+ const targetRowsByTableName = await this.loadRows(this.targetDb, keyValue);
79
+ await this.targetDb.withDisabledForeignKeys(async () => {
80
+ await this.targetDb.transaction(async () => {
81
+ await this.deleteTargetRows(targetRowsByTableName);
82
+ await this.insertTargetRows(sourceRowsByTableName);
83
+ });
84
+ });
85
+ return sourceRowsByTableName;
86
+ }
87
+ /**
88
+ * Loads the rows for `keyValue` for every table in the plan from `db`, resolving
89
+ * parent-scoped tables from the ids already selected for their parent table. Used for
90
+ * both the source rows to copy and the target's current tenant rows to delete.
91
+ * @param {import("../drivers/base.js").default} db
92
+ * @param {string} keyValue
93
+ * @returns {Promise<Map<string, Record<string, unknown>[]>>}
94
+ */
95
+ async loadRows(db, keyValue) {
96
+ /** @type {Map<string, string[]>} */
97
+ const idsByTableName = new Map();
98
+ /** @type {Map<string, Record<string, unknown>[]>} */
99
+ const rowsByTableName = new Map();
100
+ for (const tableConfig of this.tablePlan) {
101
+ let rows;
102
+ if (tableConfig.keyColumn) {
103
+ rows = await this.queryRowsByColumn({
104
+ columnName: tableConfig.keyColumn,
105
+ db,
106
+ tableName: tableConfig.tableName,
107
+ values: [keyValue]
108
+ });
109
+ }
110
+ else {
111
+ if (!tableConfig.parentColumn || !tableConfig.parentTableName) {
112
+ throw new Error(`Expected keyColumn or parentTableName+parentColumn for table ${tableConfig.tableName} in the tenant table plan.`);
113
+ }
114
+ if (!idsByTableName.has(tableConfig.parentTableName)) {
115
+ throw new Error(`Tenant table plan entry ${tableConfig.tableName} references parent table ${tableConfig.parentTableName}, which has not been loaded; parent tables must appear before their children in the plan.`);
116
+ }
117
+ rows = await this.queryRowsByColumn({
118
+ columnName: tableConfig.parentColumn,
119
+ db,
120
+ tableName: tableConfig.tableName,
121
+ values: idsByTableName.get(tableConfig.parentTableName) || []
122
+ });
123
+ }
124
+ if (rows.length > 0) {
125
+ this.reportProgress(`${tableConfig.tableName}: loaded ${rows.length} row(s)`);
126
+ }
127
+ idsByTableName.set(tableConfig.tableName, uniqueStrings(rows.map((row) => row[this.idColumn])));
128
+ rowsByTableName.set(tableConfig.tableName, rows);
129
+ }
130
+ return rowsByTableName;
131
+ }
132
+ /**
133
+ * Selects all rows of `tableName` in `db` whose `columnName` is in `values`, chunked.
134
+ * @param {{columnName: string, db: import("../drivers/base.js").default, tableName: string, values: string[]}} args
135
+ * @returns {Promise<Record<string, unknown>[]>}
136
+ */
137
+ async queryRowsByColumn({ columnName, db, tableName, values }) {
138
+ const normalizedValues = uniqueStrings(values);
139
+ if (normalizedValues.length <= 0) {
140
+ return [];
141
+ }
142
+ const rows = [];
143
+ const quotedTable = db.quoteTable(tableName);
144
+ const quotedColumn = db.quoteColumn(columnName);
145
+ for (const valuesChunk of chunks(normalizedValues, this.queryChunkSize)) {
146
+ const sql = `SELECT ${quotedTable}.* FROM ${quotedTable} WHERE ${quotedColumn} IN (${this.quotedValuesSql(db, valuesChunk)})`;
147
+ rows.push(...await this.executeQuietQuery(db, sql));
148
+ }
149
+ return rows;
150
+ }
151
+ /**
152
+ * Deletes the matching target rows for every plan table, children before parents, so the
153
+ * reinsert that follows starts from a clean slate without violating foreign keys.
154
+ * @param {Map<string, Record<string, unknown>[]>} rowsByTableName
155
+ * @returns {Promise<void>}
156
+ */
157
+ async deleteTargetRows(rowsByTableName) {
158
+ for (const tableConfig of [...this.tablePlan].reverse()) {
159
+ const rowIds = uniqueStrings((rowsByTableName.get(tableConfig.tableName) || []).map((row) => row[this.idColumn]));
160
+ if (rowIds.length <= 0) {
161
+ continue;
162
+ }
163
+ const quotedTable = this.targetDb.quoteTable(tableConfig.tableName);
164
+ const quotedIdColumn = this.targetDb.quoteColumn(this.idColumn);
165
+ for (const rowIdsChunk of chunks(rowIds, this.queryChunkSize)) {
166
+ await this.executeQuietQuery(this.targetDb, `DELETE FROM ${quotedTable} WHERE ${quotedIdColumn} IN (${this.quotedValuesSql(this.targetDb, rowIdsChunk)})`);
167
+ }
168
+ }
169
+ }
170
+ /**
171
+ * Inserts the loaded source rows into the target for every plan table, parents before
172
+ * children, chunked to bound statement size.
173
+ * @param {Map<string, Record<string, unknown>[]>} rowsByTableName
174
+ * @returns {Promise<void>}
175
+ */
176
+ async insertTargetRows(rowsByTableName) {
177
+ for (const tableConfig of this.tablePlan) {
178
+ const rows = rowsByTableName.get(tableConfig.tableName) || [];
179
+ if (rows.length <= 0) {
180
+ continue;
181
+ }
182
+ const columns = Object.keys(rows[0]);
183
+ const insertChunks = chunks(rows, this.insertChunkSize);
184
+ this.reportProgress(`${tableConfig.tableName}: inserting ${rows.length} row(s) in ${insertChunks.length} chunk(s)`);
185
+ for (const rowsChunk of insertChunks) {
186
+ await this.insertRowsQuietly({
187
+ columns,
188
+ db: this.targetDb,
189
+ rows: rowsChunk.map((row) => columns.map((column) => row[column])),
190
+ tableName: tableConfig.tableName
191
+ });
192
+ }
193
+ }
194
+ }
195
+ /**
196
+ * Quotes and comma-joins values for an SQL `IN (...)` list against the given database.
197
+ * @param {import("../drivers/base.js").default} db
198
+ * @param {string[]} values
199
+ * @returns {string}
200
+ */
201
+ quotedValuesSql(db, values) {
202
+ return values.map((value) => db.quote(value)).join(", ");
203
+ }
204
+ /**
205
+ * Runs a query without per-query logging, used for the high-volume copy statements.
206
+ * @param {import("../drivers/base.js").default} db
207
+ * @param {string} sql
208
+ * @returns {Promise<Record<string, unknown>[]>}
209
+ */
210
+ async executeQuietQuery(db, sql) {
211
+ return await db.query(sql, { logQuery: false });
212
+ }
213
+ /**
214
+ * Inserts column-aligned row tuples into a table without per-query logging.
215
+ * @param {{columns: string[], db: import("../drivers/base.js").default, rows: Array<Array<unknown>>, tableName: string}} args
216
+ * @returns {Promise<void>}
217
+ */
218
+ async insertRowsQuietly({ columns, db, rows, tableName }) {
219
+ await this.executeQuietQuery(db, db.insertSql({ columns, tableName, rows }));
220
+ }
221
+ /**
222
+ * Forwards a progress message to the optional `onProgress` callback when one was given.
223
+ * @param {string} message
224
+ * @returns {void}
225
+ */
226
+ reportProgress(message) {
227
+ if (this.onProgress) {
228
+ this.onProgress(message);
229
+ }
230
+ }
231
+ }
232
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YS1jb3BpZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvZGF0YWJhc2UvdGVuYW50cy9kYXRhLWNvcGllci5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosTUFBTSx5QkFBeUIsR0FBRyxHQUFHLENBQUE7QUFDckMsTUFBTSx3QkFBd0IsR0FBRyxHQUFHLENBQUE7QUFFcEM7Ozs7OztHQU1HO0FBQ0gsU0FBUyxNQUFNLENBQUMsTUFBTSxFQUFFLFNBQVM7SUFDL0IsTUFBTSxhQUFhLEdBQUcsRUFBRSxDQUFBO0lBRXhCLEtBQUssSUFBSSxLQUFLLEdBQUcsQ0FBQyxFQUFFLEtBQUssR0FBRyxNQUFNLENBQUMsTUFBTSxFQUFFLEtBQUssSUFBSSxTQUFTLEVBQUUsQ0FBQztRQUM5RCxhQUFhLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLEtBQUssR0FBRyxTQUFTLENBQUMsQ0FBQyxDQUFBO0lBQzVELENBQUM7SUFFRCxPQUFPLGFBQWEsQ0FBQTtBQUN0QixDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILFNBQVMsYUFBYSxDQUFDLE1BQU07SUFDM0IsT0FBTyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksR0FBRyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFBO0FBQ2xHLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQW1CRztBQUNILE1BQU0sQ0FBQyxPQUFPLE9BQU8sVUFBVTtJQUM3Qjs7Ozs7Ozs7Ozs7T0FXRztJQUNILFlBQVksRUFBQyxRQUFRLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxRQUFRLEdBQUcsSUFBSSxFQUFFLGVBQWUsR0FBRyx5QkFBeUIsRUFBRSxjQUFjLEdBQUcsd0JBQXdCLEVBQUUsVUFBVSxFQUFDO1FBQzlKLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFBO1FBQ3hCLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFBO1FBQ3hCLElBQUksQ0FBQyxTQUFTLEdBQUcsU0FBUyxDQUFBO1FBQzFCLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFBO1FBQ3hCLElBQUksQ0FBQyxlQUFlLEdBQUcsZUFBZSxDQUFBO1FBQ3RDLElBQUksQ0FBQyxjQUFjLEdBQUcsY0FBYyxDQUFBO1FBQ3BDLElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFBO0lBQzlCLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0gsS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRO1FBQ2pCLE1BQU0scUJBQXFCLEdBQUcsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDLENBQUE7UUFDMUUsTUFBTSxxQkFBcUIsR0FBRyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsQ0FBQTtRQUUxRSxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsdUJBQXVCLENBQUMsS0FBSyxJQUFJLEVBQUU7WUFDckQsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxLQUFLLElBQUksRUFBRTtnQkFDekMsTUFBTSxJQUFJLENBQUMsZ0JBQWdCLENBQUMscUJBQXFCLENBQUMsQ0FBQTtnQkFDbEQsTUFBTSxJQUFJLENBQUMsZ0JBQWdCLENBQUMscUJBQXFCLENBQUMsQ0FBQTtZQUNwRCxDQUFDLENBQUMsQ0FBQTtRQUNKLENBQUMsQ0FBQyxDQUFBO1FBRUYsT0FBTyxxQkFBcUIsQ0FBQTtJQUM5QixDQUFDO0lBRUQ7Ozs7Ozs7T0FPRztJQUNILEtBQUssQ0FBQyxRQUFRLENBQUMsRUFBRSxFQUFFLFFBQVE7UUFDekIsb0NBQW9DO1FBQ3BDLE1BQU0sY0FBYyxHQUFHLElBQUksR0FBRyxFQUFFLENBQUE7UUFDaEMscURBQXFEO1FBQ3JELE1BQU0sZUFBZSxHQUFHLElBQUksR0FBRyxFQUFFLENBQUE7UUFFakMsS0FBSyxNQUFNLFdBQVcsSUFBSSxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDekMsSUFBSSxJQUFJLENBQUE7WUFFUixJQUFJLFdBQVcsQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDMUIsSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDO29CQUNsQyxVQUFVLEVBQUUsV0FBVyxDQUFDLFNBQVM7b0JBQ2pDLEVBQUU7b0JBQ0YsU0FBUyxFQUFFLFdBQVcsQ0FBQyxTQUFTO29CQUNoQyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUM7aUJBQ25CLENBQUMsQ0FBQTtZQUNKLENBQUM7aUJBQU0sQ0FBQztnQkFDTixJQUFJLENBQUMsV0FBVyxDQUFDLFlBQVksSUFBSSxDQUFDLFdBQVcsQ0FBQyxlQUFlLEVBQUUsQ0FBQztvQkFDOUQsTUFBTSxJQUFJLEtBQUssQ0FBQyxnRUFBZ0UsV0FBVyxDQUFDLFNBQVMsNEJBQTRCLENBQUMsQ0FBQTtnQkFDcEksQ0FBQztnQkFFRCxJQUFJLENBQUMsY0FBYyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsZUFBZSxDQUFDLEVBQUUsQ0FBQztvQkFDckQsTUFBTSxJQUFJLEtBQUssQ0FBQywyQkFBMkIsV0FBVyxDQUFDLFNBQVMsNEJBQTRCLFdBQVcsQ0FBQyxlQUFlLDJGQUEyRixDQUFDLENBQUE7Z0JBQ3JOLENBQUM7Z0JBRUQsSUFBSSxHQUFHLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDO29CQUNsQyxVQUFVLEVBQUUsV0FBVyxDQUFDLFlBQVk7b0JBQ3BDLEVBQUU7b0JBQ0YsU0FBUyxFQUFFLFdBQVcsQ0FBQyxTQUFTO29CQUNoQyxNQUFNLEVBQUUsY0FBYyxDQUFDLEdBQUcsQ0FBQyxXQUFXLENBQUMsZUFBZSxDQUFDLElBQUksRUFBRTtpQkFDOUQsQ0FBQyxDQUFBO1lBQ0osQ0FBQztZQUVELElBQUksSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDcEIsSUFBSSxDQUFDLGNBQWMsQ0FBQyxHQUFHLFdBQVcsQ0FBQyxTQUFTLFlBQVksSUFBSSxDQUFDLE1BQU0sU0FBUyxDQUFDLENBQUE7WUFDL0UsQ0FBQztZQUVELGNBQWMsQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLFNBQVMsRUFBRSxhQUFhLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQTtZQUMvRixlQUFlLENBQUMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLENBQUE7UUFDbEQsQ0FBQztRQUVELE9BQU8sZUFBZSxDQUFBO0lBQ3hCLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLGlCQUFpQixDQUFDLEVBQUMsVUFBVSxFQUFFLEVBQUUsRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFDO1FBQ3pELE1BQU0sZ0JBQWdCLEdBQUcsYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFBO1FBRTlDLElBQUksZ0JBQWdCLENBQUMsTUFBTSxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQ2pDLE9BQU8sRUFBRSxDQUFBO1FBQ1gsQ0FBQztRQUVELE1BQU0sSUFBSSxHQUFHLEVBQUUsQ0FBQTtRQUNmLE1BQU0sV0FBVyxHQUFHLEVBQUUsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLENBQUE7UUFDNUMsTUFBTSxZQUFZLEdBQUcsRUFBRSxDQUFDLFdBQVcsQ0FBQyxVQUFVLENBQUMsQ0FBQTtRQUUvQyxLQUFLLE1BQU0sV0FBVyxJQUFJLE1BQU0sQ0FBQyxnQkFBZ0IsRUFBRSxJQUFJLENBQUMsY0FBYyxDQUFDLEVBQUUsQ0FBQztZQUN4RSxNQUFNLEdBQUcsR0FBRyxVQUFVLFdBQVcsV0FBVyxXQUFXLFVBQVUsWUFBWSxRQUFRLElBQUksQ0FBQyxlQUFlLENBQUMsRUFBRSxFQUFFLFdBQVcsQ0FBQyxHQUFHLENBQUE7WUFFN0gsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLEVBQUUsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFBO1FBQ3JELENBQUM7UUFFRCxPQUFPLElBQUksQ0FBQTtJQUNiLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxlQUFlO1FBQ3BDLEtBQUssTUFBTSxXQUFXLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDO1lBQ3hELE1BQU0sTUFBTSxHQUFHLGFBQWEsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUE7WUFFakgsSUFBSSxNQUFNLENBQUMsTUFBTSxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUN2QixTQUFRO1lBQ1YsQ0FBQztZQUVELE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLFdBQVcsQ0FBQyxTQUFTLENBQUMsQ0FBQTtZQUNuRSxNQUFNLGNBQWMsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUE7WUFFL0QsS0FBSyxNQUFNLFdBQVcsSUFBSSxNQUFNLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxjQUFjLENBQUMsRUFBRSxDQUFDO2dCQUM5RCxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FDMUIsSUFBSSxDQUFDLFFBQVEsRUFDYixlQUFlLFdBQVcsVUFBVSxjQUFjLFFBQVEsSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLFdBQVcsQ0FBQyxHQUFHLENBQzlHLENBQUE7WUFDSCxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRDs7Ozs7T0FLRztJQUNILEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQyxlQUFlO1FBQ3BDLEtBQUssTUFBTSxXQUFXLElBQUksSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDO1lBQ3pDLE1BQU0sSUFBSSxHQUFHLGVBQWUsQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLFNBQVMsQ0FBQyxJQUFJLEVBQUUsQ0FBQTtZQUU3RCxJQUFJLElBQUksQ0FBQyxNQUFNLElBQUksQ0FBQyxFQUFFLENBQUM7Z0JBQ3JCLFNBQVE7WUFDVixDQUFDO1lBRUQsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQTtZQUNwQyxNQUFNLFlBQVksR0FBRyxNQUFNLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQTtZQUV2RCxJQUFJLENBQUMsY0FBYyxDQUFDLEdBQUcsV0FBVyxDQUFDLFNBQVMsZUFBZSxJQUFJLENBQUMsTUFBTSxjQUFjLFlBQVksQ0FBQyxNQUFNLFdBQVcsQ0FBQyxDQUFBO1lBRW5ILEtBQUssTUFBTSxTQUFTLElBQUksWUFBWSxFQUFFLENBQUM7Z0JBQ3JDLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDO29CQUMzQixPQUFPO29CQUNQLEVBQUUsRUFBRSxJQUFJLENBQUMsUUFBUTtvQkFDakIsSUFBSSxFQUFFLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO29CQUNsRSxTQUFTLEVBQUUsV0FBVyxDQUFDLFNBQVM7aUJBQ2pDLENBQUMsQ0FBQTtZQUNKLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0gsZUFBZSxDQUFDLEVBQUUsRUFBRSxNQUFNO1FBQ3hCLE9BQU8sTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQTtJQUMxRCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxLQUFLLENBQUMsaUJBQWlCLENBQUMsRUFBRSxFQUFFLEdBQUc7UUFDN0IsT0FBTyxNQUFNLEVBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxFQUFFLEVBQUMsUUFBUSxFQUFFLEtBQUssRUFBQyxDQUFDLENBQUE7SUFDL0MsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxLQUFLLENBQUMsaUJBQWlCLENBQUMsRUFBQyxPQUFPLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUM7UUFDcEQsTUFBTSxJQUFJLENBQUMsaUJBQWlCLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FBQyxTQUFTLENBQUMsRUFBQyxPQUFPLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBQyxDQUFDLENBQUMsQ0FBQTtJQUM1RSxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILGNBQWMsQ0FBQyxPQUFPO1FBQ3BCLElBQUksSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ3BCLElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDMUIsQ0FBQztJQUNILENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5jb25zdCBERUZBVUxUX0lOU0VSVF9DSFVOS19TSVpFID0gMTAwXG5jb25zdCBERUZBVUxUX1FVRVJZX0NIVU5LX1NJWkUgPSA1MDBcblxuLyoqXG4gKiBTcGxpdHMgYW4gYXJyYXkgaW50byBjaHVua3Mgb2YgYXQgbW9zdCBgY2h1bmtTaXplYCBpdGVtcy5cbiAqIEB0ZW1wbGF0ZSBUXG4gKiBAcGFyYW0ge1RbXX0gdmFsdWVzXG4gKiBAcGFyYW0ge251bWJlcn0gY2h1bmtTaXplXG4gKiBAcmV0dXJucyB7VFtdW119XG4gKi9cbmZ1bmN0aW9uIGNodW5rcyh2YWx1ZXMsIGNodW5rU2l6ZSkge1xuICBjb25zdCBjaHVua2VkVmFsdWVzID0gW11cblxuICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgdmFsdWVzLmxlbmd0aDsgaW5kZXggKz0gY2h1bmtTaXplKSB7XG4gICAgY2h1bmtlZFZhbHVlcy5wdXNoKHZhbHVlcy5zbGljZShpbmRleCwgaW5kZXggKyBjaHVua1NpemUpKVxuICB9XG5cbiAgcmV0dXJuIGNodW5rZWRWYWx1ZXNcbn1cblxuLyoqXG4gKiBTdHJpbmdpZmllcyB2YWx1ZXMgYW5kIHJldHVybnMgdGhlIGRpc3RpbmN0LCBub24tYmxhbmsgb25lcywgcHJlc2VydmluZyBmaXJzdC1zZWVuIG9yZGVyLlxuICogQHBhcmFtIHt1bmtub3duW119IHZhbHVlc1xuICogQHJldHVybnMge3N0cmluZ1tdfVxuICovXG5mdW5jdGlvbiB1bmlxdWVTdHJpbmdzKHZhbHVlcykge1xuICByZXR1cm4gQXJyYXkuZnJvbShuZXcgU2V0KHZhbHVlcy5tYXAoKHZhbHVlKSA9PiBTdHJpbmcodmFsdWUpKS5maWx0ZXIoKHZhbHVlKSA9PiB2YWx1ZS50cmltKCkpKSlcbn1cblxuLyoqXG4gKiBDb3BpZXMgYSBzaW5nbGUgdGVuYW50J3Mgcm93cyBmcm9tIGEgc291cmNlIGRhdGFiYXNlIGludG8gYSB0YXJnZXQgZGF0YWJhc2UsIGZvbGxvd2luZyBhXG4gKiB0YWJsZSBwbGFuIHRoYXQgcGFydGl0aW9ucyBlYWNoIHRhYmxlIGVpdGhlciBieSBhIGRpcmVjdCB0ZW5hbnQga2V5IGNvbHVtbiBvciBieVxuICogcGFyZW50LWlkIHRyYXZlcnNhbC4gVGhpcyBpcyB0aGUgcm93LWxldmVsIGNvdW50ZXJwYXJ0IHRvIHNjaGVtYSBjbG9uaW5nOiBtdWx0aS10ZW5hbnRcbiAqIGFwcHMgdGhhdCBrZWVwIGVhY2ggdGVuYW50J3MgZGF0YSBpbiBpdHMgb3duIGRhdGFiYXNlIHVzZSBpdCB0byAocmUpbWF0ZXJpYWxpc2UgdGhlXG4gKiB0ZW5hbnQncyByb3dzIGZyb20gYSBnbG9iYWwvdGVtcGxhdGUgZGF0YWJhc2UuXG4gKlxuICogVGhlIGNvcHkgaXMgZGVsZXRlLXRoZW4tcmVpbnNlcnQgYW5kIHRoZXJlZm9yZSBpZGVtcG90ZW50LCBhbmQgaXQgbWlycm9ycyB0aGUgc291cmNlXG4gKiBzbmFwc2hvdDogdGhlIHJvd3MgdG8gZGVsZXRlIGFyZSB0aGUgdGVuYW50J3MgKmN1cnJlbnQqIHJvd3MgaW4gdGhlIHRhcmdldCAoc2VsZWN0ZWQgd2l0aFxuICogdGhlIHNhbWUgcGxhbiB0cmF2ZXJzYWwgcnVuIGFnYWluc3QgdGhlIHRhcmdldCksIHNvIGEgcm93IHRoYXQgd2FzIHJlbW92ZWQgZnJvbSB0aGUgc291cmNlXG4gKiBzaW5jZSB0aGUgbGFzdCBjb3B5IGlzIGRyb3BwZWQgZnJvbSB0aGUgdGFyZ2V0IHRvbyByYXRoZXIgdGhhbiBsaW5nZXJpbmcuIFRoZSBkZWxldGVzIHJ1blxuICogY2hpbGRyZW4gZmlyc3QgYW5kIHRoZSBzb3VyY2UgaW5zZXJ0cyBwYXJlbnRzIGZpcnN0LCBhbGwgaW5zaWRlIG9uZSB0YXJnZXQgdHJhbnNhY3Rpb24gd2l0aFxuICogZm9yZWlnbi1rZXkgZW5mb3JjZW1lbnQgZGlzYWJsZWQgc28gdGhlIG9yZGVyaW5nIG5ldmVyIHRyaXBzIGEgY29uc3RyYWludC4gUmVhZHMsIGRlbGV0ZXNcbiAqIGFuZCBpbnNlcnRzIGFyZSBjaHVua2VkIHRvIGJvdW5kIHN0YXRlbWVudCBzaXplLlxuICpcbiAqIFRoZSBjb3BpZXIgaXMgcG9saWN5LWZyZWU6IHRoZSBjYWxsZXIgc3VwcGxpZXMgdGhlIHBsYW4sIHRoZSBzb3VyY2UvdGFyZ2V0IGRhdGFiYXNlcyBhbmRcbiAqIHRoZSB0ZW5hbnQga2V5LCBhbmQge0BsaW5rIERhdGFDb3BpZXIjY29weX0gcmV0dXJucyB0aGUgbG9hZGVkIHJvd3Mga2V5ZWQgYnkgdGFibGUgbmFtZSBzb1xuICogdGhlIGNhbGxlciBjYW4gcGVyZm9ybSBhbnkgYXBwLXNwZWNpZmljIHBvc3QtY29weSB3b3JrIChmb3IgZXhhbXBsZSByZWdpc3RlcmluZyByZWNvcmRcbiAqIGxvY2F0aW9ucykgd2l0aG91dCB0aGF0IHBvbGljeSBsZWFraW5nIGludG8gdGhlIGZyYW1ld29yay5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgRGF0YUNvcGllciB7XG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgY29waWVyIHRoYXQgbW92ZXMgdGVuYW50LW93bmVkIHJvd3MgZnJvbSBgc291cmNlRGJgIGludG8gYHRhcmdldERiYC5cbiAgICogQHBhcmFtIHt7XG4gICAqICAgc291cmNlRGI6IGltcG9ydChcIi4uL2RyaXZlcnMvYmFzZS5qc1wiKS5kZWZhdWx0LFxuICAgKiAgIHRhcmdldERiOiBpbXBvcnQoXCIuLi9kcml2ZXJzL2Jhc2UuanNcIikuZGVmYXVsdCxcbiAgICogICB0YWJsZVBsYW46IGltcG9ydChcIi4vdGVuYW50LXRhYmxlLXBsYW4uanNcIikuVGVuYW50VGFibGVQbGFuRW50cnlbXSxcbiAgICogICBpZENvbHVtbj86IHN0cmluZyxcbiAgICogICBpbnNlcnRDaHVua1NpemU/OiBudW1iZXIsXG4gICAqICAgcXVlcnlDaHVua1NpemU/OiBudW1iZXIsXG4gICAqICAgb25Qcm9ncmVzcz86IChtZXNzYWdlOiBzdHJpbmcpID0+IHZvaWRcbiAgICogfX0gYXJnc1xuICAgKi9cbiAgY29uc3RydWN0b3Ioe3NvdXJjZURiLCB0YXJnZXREYiwgdGFibGVQbGFuLCBpZENvbHVtbiA9IFwiaWRcIiwgaW5zZXJ0Q2h1bmtTaXplID0gREVGQVVMVF9JTlNFUlRfQ0hVTktfU0laRSwgcXVlcnlDaHVua1NpemUgPSBERUZBVUxUX1FVRVJZX0NIVU5LX1NJWkUsIG9uUHJvZ3Jlc3N9KSB7XG4gICAgdGhpcy5zb3VyY2VEYiA9IHNvdXJjZURiXG4gICAgdGhpcy50YXJnZXREYiA9IHRhcmdldERiXG4gICAgdGhpcy50YWJsZVBsYW4gPSB0YWJsZVBsYW5cbiAgICB0aGlzLmlkQ29sdW1uID0gaWRDb2x1bW5cbiAgICB0aGlzLmluc2VydENodW5rU2l6ZSA9IGluc2VydENodW5rU2l6ZVxuICAgIHRoaXMucXVlcnlDaHVua1NpemUgPSBxdWVyeUNodW5rU2l6ZVxuICAgIHRoaXMub25Qcm9ncmVzcyA9IG9uUHJvZ3Jlc3NcbiAgfVxuXG4gIC8qKlxuICAgKiBDb3BpZXMgZXZlcnkgcGxhbiB0YWJsZSdzIHJvd3MgZm9yIGBrZXlWYWx1ZWAgZnJvbSB0aGUgc291cmNlIGludG8gdGhlIHRhcmdldCBhbmRcbiAgICogcmV0dXJucyB0aGUgY29waWVkIHNvdXJjZSByb3dzIGtleWVkIGJ5IHRhYmxlIG5hbWUuIFRoZSB0YXJnZXQncyBjdXJyZW50IHRlbmFudCByb3dzXG4gICAqIGFyZSBkZWxldGVkIChjaGlsZHJlbiBmaXJzdCkgYW5kIHRoZSBzb3VyY2Ugcm93cyBpbnNlcnRlZCAocGFyZW50cyBmaXJzdCkgaW4gYSBzaW5nbGVcbiAgICogdGFyZ2V0IHRyYW5zYWN0aW9uIHdpdGggZm9yZWlnbiBrZXlzIGRpc2FibGVkLlxuICAgKiBAcGFyYW0ge3N0cmluZ30ga2V5VmFsdWVcbiAgICogQHJldHVybnMge1Byb21pc2U8TWFwPHN0cmluZywgUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXT4+fVxuICAgKi9cbiAgYXN5bmMgY29weShrZXlWYWx1ZSkge1xuICAgIGNvbnN0IHNvdXJjZVJvd3NCeVRhYmxlTmFtZSA9IGF3YWl0IHRoaXMubG9hZFJvd3ModGhpcy5zb3VyY2VEYiwga2V5VmFsdWUpXG4gICAgY29uc3QgdGFyZ2V0Um93c0J5VGFibGVOYW1lID0gYXdhaXQgdGhpcy5sb2FkUm93cyh0aGlzLnRhcmdldERiLCBrZXlWYWx1ZSlcblxuICAgIGF3YWl0IHRoaXMudGFyZ2V0RGIud2l0aERpc2FibGVkRm9yZWlnbktleXMoYXN5bmMgKCkgPT4ge1xuICAgICAgYXdhaXQgdGhpcy50YXJnZXREYi50cmFuc2FjdGlvbihhc3luYyAoKSA9PiB7XG4gICAgICAgIGF3YWl0IHRoaXMuZGVsZXRlVGFyZ2V0Um93cyh0YXJnZXRSb3dzQnlUYWJsZU5hbWUpXG4gICAgICAgIGF3YWl0IHRoaXMuaW5zZXJ0VGFyZ2V0Um93cyhzb3VyY2VSb3dzQnlUYWJsZU5hbWUpXG4gICAgICB9KVxuICAgIH0pXG5cbiAgICByZXR1cm4gc291cmNlUm93c0J5VGFibGVOYW1lXG4gIH1cblxuICAvKipcbiAgICogTG9hZHMgdGhlIHJvd3MgZm9yIGBrZXlWYWx1ZWAgZm9yIGV2ZXJ5IHRhYmxlIGluIHRoZSBwbGFuIGZyb20gYGRiYCwgcmVzb2x2aW5nXG4gICAqIHBhcmVudC1zY29wZWQgdGFibGVzIGZyb20gdGhlIGlkcyBhbHJlYWR5IHNlbGVjdGVkIGZvciB0aGVpciBwYXJlbnQgdGFibGUuIFVzZWQgZm9yXG4gICAqIGJvdGggdGhlIHNvdXJjZSByb3dzIHRvIGNvcHkgYW5kIHRoZSB0YXJnZXQncyBjdXJyZW50IHRlbmFudCByb3dzIHRvIGRlbGV0ZS5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi9kcml2ZXJzL2Jhc2UuanNcIikuZGVmYXVsdH0gZGJcbiAgICogQHBhcmFtIHtzdHJpbmd9IGtleVZhbHVlXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPE1hcDxzdHJpbmcsIFJlY29yZDxzdHJpbmcsIHVua25vd24+W10+Pn1cbiAgICovXG4gIGFzeW5jIGxvYWRSb3dzKGRiLCBrZXlWYWx1ZSkge1xuICAgIC8qKiBAdHlwZSB7TWFwPHN0cmluZywgc3RyaW5nW10+fSAqL1xuICAgIGNvbnN0IGlkc0J5VGFibGVOYW1lID0gbmV3IE1hcCgpXG4gICAgLyoqIEB0eXBlIHtNYXA8c3RyaW5nLCBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdPn0gKi9cbiAgICBjb25zdCByb3dzQnlUYWJsZU5hbWUgPSBuZXcgTWFwKClcblxuICAgIGZvciAoY29uc3QgdGFibGVDb25maWcgb2YgdGhpcy50YWJsZVBsYW4pIHtcbiAgICAgIGxldCByb3dzXG5cbiAgICAgIGlmICh0YWJsZUNvbmZpZy5rZXlDb2x1bW4pIHtcbiAgICAgICAgcm93cyA9IGF3YWl0IHRoaXMucXVlcnlSb3dzQnlDb2x1bW4oe1xuICAgICAgICAgIGNvbHVtbk5hbWU6IHRhYmxlQ29uZmlnLmtleUNvbHVtbixcbiAgICAgICAgICBkYixcbiAgICAgICAgICB0YWJsZU5hbWU6IHRhYmxlQ29uZmlnLnRhYmxlTmFtZSxcbiAgICAgICAgICB2YWx1ZXM6IFtrZXlWYWx1ZV1cbiAgICAgICAgfSlcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmICghdGFibGVDb25maWcucGFyZW50Q29sdW1uIHx8ICF0YWJsZUNvbmZpZy5wYXJlbnRUYWJsZU5hbWUpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEV4cGVjdGVkIGtleUNvbHVtbiBvciBwYXJlbnRUYWJsZU5hbWUrcGFyZW50Q29sdW1uIGZvciB0YWJsZSAke3RhYmxlQ29uZmlnLnRhYmxlTmFtZX0gaW4gdGhlIHRlbmFudCB0YWJsZSBwbGFuLmApXG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIWlkc0J5VGFibGVOYW1lLmhhcyh0YWJsZUNvbmZpZy5wYXJlbnRUYWJsZU5hbWUpKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBUZW5hbnQgdGFibGUgcGxhbiBlbnRyeSAke3RhYmxlQ29uZmlnLnRhYmxlTmFtZX0gcmVmZXJlbmNlcyBwYXJlbnQgdGFibGUgJHt0YWJsZUNvbmZpZy5wYXJlbnRUYWJsZU5hbWV9LCB3aGljaCBoYXMgbm90IGJlZW4gbG9hZGVkOyBwYXJlbnQgdGFibGVzIG11c3QgYXBwZWFyIGJlZm9yZSB0aGVpciBjaGlsZHJlbiBpbiB0aGUgcGxhbi5gKVxuICAgICAgICB9XG5cbiAgICAgICAgcm93cyA9IGF3YWl0IHRoaXMucXVlcnlSb3dzQnlDb2x1bW4oe1xuICAgICAgICAgIGNvbHVtbk5hbWU6IHRhYmxlQ29uZmlnLnBhcmVudENvbHVtbixcbiAgICAgICAgICBkYixcbiAgICAgICAgICB0YWJsZU5hbWU6IHRhYmxlQ29uZmlnLnRhYmxlTmFtZSxcbiAgICAgICAgICB2YWx1ZXM6IGlkc0J5VGFibGVOYW1lLmdldCh0YWJsZUNvbmZpZy5wYXJlbnRUYWJsZU5hbWUpIHx8IFtdXG4gICAgICAgIH0pXG4gICAgICB9XG5cbiAgICAgIGlmIChyb3dzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgdGhpcy5yZXBvcnRQcm9ncmVzcyhgJHt0YWJsZUNvbmZpZy50YWJsZU5hbWV9OiBsb2FkZWQgJHtyb3dzLmxlbmd0aH0gcm93KHMpYClcbiAgICAgIH1cblxuICAgICAgaWRzQnlUYWJsZU5hbWUuc2V0KHRhYmxlQ29uZmlnLnRhYmxlTmFtZSwgdW5pcXVlU3RyaW5ncyhyb3dzLm1hcCgocm93KSA9PiByb3dbdGhpcy5pZENvbHVtbl0pKSlcbiAgICAgIHJvd3NCeVRhYmxlTmFtZS5zZXQodGFibGVDb25maWcudGFibGVOYW1lLCByb3dzKVxuICAgIH1cblxuICAgIHJldHVybiByb3dzQnlUYWJsZU5hbWVcbiAgfVxuXG4gIC8qKlxuICAgKiBTZWxlY3RzIGFsbCByb3dzIG9mIGB0YWJsZU5hbWVgIGluIGBkYmAgd2hvc2UgYGNvbHVtbk5hbWVgIGlzIGluIGB2YWx1ZXNgLCBjaHVua2VkLlxuICAgKiBAcGFyYW0ge3tjb2x1bW5OYW1lOiBzdHJpbmcsIGRiOiBpbXBvcnQoXCIuLi9kcml2ZXJzL2Jhc2UuanNcIikuZGVmYXVsdCwgdGFibGVOYW1lOiBzdHJpbmcsIHZhbHVlczogc3RyaW5nW119fSBhcmdzXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPFJlY29yZDxzdHJpbmcsIHVua25vd24+W10+fVxuICAgKi9cbiAgYXN5bmMgcXVlcnlSb3dzQnlDb2x1bW4oe2NvbHVtbk5hbWUsIGRiLCB0YWJsZU5hbWUsIHZhbHVlc30pIHtcbiAgICBjb25zdCBub3JtYWxpemVkVmFsdWVzID0gdW5pcXVlU3RyaW5ncyh2YWx1ZXMpXG5cbiAgICBpZiAobm9ybWFsaXplZFZhbHVlcy5sZW5ndGggPD0gMCkge1xuICAgICAgcmV0dXJuIFtdXG4gICAgfVxuXG4gICAgY29uc3Qgcm93cyA9IFtdXG4gICAgY29uc3QgcXVvdGVkVGFibGUgPSBkYi5xdW90ZVRhYmxlKHRhYmxlTmFtZSlcbiAgICBjb25zdCBxdW90ZWRDb2x1bW4gPSBkYi5xdW90ZUNvbHVtbihjb2x1bW5OYW1lKVxuXG4gICAgZm9yIChjb25zdCB2YWx1ZXNDaHVuayBvZiBjaHVua3Mobm9ybWFsaXplZFZhbHVlcywgdGhpcy5xdWVyeUNodW5rU2l6ZSkpIHtcbiAgICAgIGNvbnN0IHNxbCA9IGBTRUxFQ1QgJHtxdW90ZWRUYWJsZX0uKiBGUk9NICR7cXVvdGVkVGFibGV9IFdIRVJFICR7cXVvdGVkQ29sdW1ufSBJTiAoJHt0aGlzLnF1b3RlZFZhbHVlc1NxbChkYiwgdmFsdWVzQ2h1bmspfSlgXG5cbiAgICAgIHJvd3MucHVzaCguLi5hd2FpdCB0aGlzLmV4ZWN1dGVRdWlldFF1ZXJ5KGRiLCBzcWwpKVxuICAgIH1cblxuICAgIHJldHVybiByb3dzXG4gIH1cblxuICAvKipcbiAgICogRGVsZXRlcyB0aGUgbWF0Y2hpbmcgdGFyZ2V0IHJvd3MgZm9yIGV2ZXJ5IHBsYW4gdGFibGUsIGNoaWxkcmVuIGJlZm9yZSBwYXJlbnRzLCBzbyB0aGVcbiAgICogcmVpbnNlcnQgdGhhdCBmb2xsb3dzIHN0YXJ0cyBmcm9tIGEgY2xlYW4gc2xhdGUgd2l0aG91dCB2aW9sYXRpbmcgZm9yZWlnbiBrZXlzLlxuICAgKiBAcGFyYW0ge01hcDxzdHJpbmcsIFJlY29yZDxzdHJpbmcsIHVua25vd24+W10+fSByb3dzQnlUYWJsZU5hbWVcbiAgICogQHJldHVybnMge1Byb21pc2U8dm9pZD59XG4gICAqL1xuICBhc3luYyBkZWxldGVUYXJnZXRSb3dzKHJvd3NCeVRhYmxlTmFtZSkge1xuICAgIGZvciAoY29uc3QgdGFibGVDb25maWcgb2YgWy4uLnRoaXMudGFibGVQbGFuXS5yZXZlcnNlKCkpIHtcbiAgICAgIGNvbnN0IHJvd0lkcyA9IHVuaXF1ZVN0cmluZ3MoKHJvd3NCeVRhYmxlTmFtZS5nZXQodGFibGVDb25maWcudGFibGVOYW1lKSB8fCBbXSkubWFwKChyb3cpID0+IHJvd1t0aGlzLmlkQ29sdW1uXSkpXG5cbiAgICAgIGlmIChyb3dJZHMubGVuZ3RoIDw9IDApIHtcbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgY29uc3QgcXVvdGVkVGFibGUgPSB0aGlzLnRhcmdldERiLnF1b3RlVGFibGUodGFibGVDb25maWcudGFibGVOYW1lKVxuICAgICAgY29uc3QgcXVvdGVkSWRDb2x1bW4gPSB0aGlzLnRhcmdldERiLnF1b3RlQ29sdW1uKHRoaXMuaWRDb2x1bW4pXG5cbiAgICAgIGZvciAoY29uc3Qgcm93SWRzQ2h1bmsgb2YgY2h1bmtzKHJvd0lkcywgdGhpcy5xdWVyeUNodW5rU2l6ZSkpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5leGVjdXRlUXVpZXRRdWVyeShcbiAgICAgICAgICB0aGlzLnRhcmdldERiLFxuICAgICAgICAgIGBERUxFVEUgRlJPTSAke3F1b3RlZFRhYmxlfSBXSEVSRSAke3F1b3RlZElkQ29sdW1ufSBJTiAoJHt0aGlzLnF1b3RlZFZhbHVlc1NxbCh0aGlzLnRhcmdldERiLCByb3dJZHNDaHVuayl9KWBcbiAgICAgICAgKVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBJbnNlcnRzIHRoZSBsb2FkZWQgc291cmNlIHJvd3MgaW50byB0aGUgdGFyZ2V0IGZvciBldmVyeSBwbGFuIHRhYmxlLCBwYXJlbnRzIGJlZm9yZVxuICAgKiBjaGlsZHJlbiwgY2h1bmtlZCB0byBib3VuZCBzdGF0ZW1lbnQgc2l6ZS5cbiAgICogQHBhcmFtIHtNYXA8c3RyaW5nLCBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdPn0gcm93c0J5VGFibGVOYW1lXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgaW5zZXJ0VGFyZ2V0Um93cyhyb3dzQnlUYWJsZU5hbWUpIHtcbiAgICBmb3IgKGNvbnN0IHRhYmxlQ29uZmlnIG9mIHRoaXMudGFibGVQbGFuKSB7XG4gICAgICBjb25zdCByb3dzID0gcm93c0J5VGFibGVOYW1lLmdldCh0YWJsZUNvbmZpZy50YWJsZU5hbWUpIHx8IFtdXG5cbiAgICAgIGlmIChyb3dzLmxlbmd0aCA8PSAwKSB7XG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGNvbHVtbnMgPSBPYmplY3Qua2V5cyhyb3dzWzBdKVxuICAgICAgY29uc3QgaW5zZXJ0Q2h1bmtzID0gY2h1bmtzKHJvd3MsIHRoaXMuaW5zZXJ0Q2h1bmtTaXplKVxuXG4gICAgICB0aGlzLnJlcG9ydFByb2dyZXNzKGAke3RhYmxlQ29uZmlnLnRhYmxlTmFtZX06IGluc2VydGluZyAke3Jvd3MubGVuZ3RofSByb3cocykgaW4gJHtpbnNlcnRDaHVua3MubGVuZ3RofSBjaHVuayhzKWApXG5cbiAgICAgIGZvciAoY29uc3Qgcm93c0NodW5rIG9mIGluc2VydENodW5rcykge1xuICAgICAgICBhd2FpdCB0aGlzLmluc2VydFJvd3NRdWlldGx5KHtcbiAgICAgICAgICBjb2x1bW5zLFxuICAgICAgICAgIGRiOiB0aGlzLnRhcmdldERiLFxuICAgICAgICAgIHJvd3M6IHJvd3NDaHVuay5tYXAoKHJvdykgPT4gY29sdW1ucy5tYXAoKGNvbHVtbikgPT4gcm93W2NvbHVtbl0pKSxcbiAgICAgICAgICB0YWJsZU5hbWU6IHRhYmxlQ29uZmlnLnRhYmxlTmFtZVxuICAgICAgICB9KVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBRdW90ZXMgYW5kIGNvbW1hLWpvaW5zIHZhbHVlcyBmb3IgYW4gU1FMIGBJTiAoLi4uKWAgbGlzdCBhZ2FpbnN0IHRoZSBnaXZlbiBkYXRhYmFzZS5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi9kcml2ZXJzL2Jhc2UuanNcIikuZGVmYXVsdH0gZGJcbiAgICogQHBhcmFtIHtzdHJpbmdbXX0gdmFsdWVzXG4gICAqIEByZXR1cm5zIHtzdHJpbmd9XG4gICAqL1xuICBxdW90ZWRWYWx1ZXNTcWwoZGIsIHZhbHVlcykge1xuICAgIHJldHVybiB2YWx1ZXMubWFwKCh2YWx1ZSkgPT4gZGIucXVvdGUodmFsdWUpKS5qb2luKFwiLCBcIilcbiAgfVxuXG4gIC8qKlxuICAgKiBSdW5zIGEgcXVlcnkgd2l0aG91dCBwZXItcXVlcnkgbG9nZ2luZywgdXNlZCBmb3IgdGhlIGhpZ2gtdm9sdW1lIGNvcHkgc3RhdGVtZW50cy5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi9kcml2ZXJzL2Jhc2UuanNcIikuZGVmYXVsdH0gZGJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNxbFxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdPn1cbiAgICovXG4gIGFzeW5jIGV4ZWN1dGVRdWlldFF1ZXJ5KGRiLCBzcWwpIHtcbiAgICByZXR1cm4gYXdhaXQgZGIucXVlcnkoc3FsLCB7bG9nUXVlcnk6IGZhbHNlfSlcbiAgfVxuXG4gIC8qKlxuICAgKiBJbnNlcnRzIGNvbHVtbi1hbGlnbmVkIHJvdyB0dXBsZXMgaW50byBhIHRhYmxlIHdpdGhvdXQgcGVyLXF1ZXJ5IGxvZ2dpbmcuXG4gICAqIEBwYXJhbSB7e2NvbHVtbnM6IHN0cmluZ1tdLCBkYjogaW1wb3J0KFwiLi4vZHJpdmVycy9iYXNlLmpzXCIpLmRlZmF1bHQsIHJvd3M6IEFycmF5PEFycmF5PHVua25vd24+PiwgdGFibGVOYW1lOiBzdHJpbmd9fSBhcmdzXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fVxuICAgKi9cbiAgYXN5bmMgaW5zZXJ0Um93c1F1aWV0bHkoe2NvbHVtbnMsIGRiLCByb3dzLCB0YWJsZU5hbWV9KSB7XG4gICAgYXdhaXQgdGhpcy5leGVjdXRlUXVpZXRRdWVyeShkYiwgZGIuaW5zZXJ0U3FsKHtjb2x1bW5zLCB0YWJsZU5hbWUsIHJvd3N9KSlcbiAgfVxuXG4gIC8qKlxuICAgKiBGb3J3YXJkcyBhIHByb2dyZXNzIG1lc3NhZ2UgdG8gdGhlIG9wdGlvbmFsIGBvblByb2dyZXNzYCBjYWxsYmFjayB3aGVuIG9uZSB3YXMgZ2l2ZW4uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlXG4gICAqIEByZXR1cm5zIHt2b2lkfVxuICAgKi9cbiAgcmVwb3J0UHJvZ3Jlc3MobWVzc2FnZSkge1xuICAgIGlmICh0aGlzLm9uUHJvZ3Jlc3MpIHtcbiAgICAgIHRoaXMub25Qcm9ncmVzcyhtZXNzYWdlKVxuICAgIH1cbiAgfVxufVxuIl19
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Describes how one table's rows are partitioned between tenants so a DataCopier can select
3
+ * the subset that belongs to a given tenant key.
4
+ *
5
+ * A row belongs to the tenant when its `keyColumn` equals the tenant key value, or — for
6
+ * tables that have no direct tenant column — when its `parentColumn` references a row of
7
+ * `parentTableName` that was itself already selected as belonging to the tenant. Exactly
8
+ * one of `keyColumn` or the (`parentTableName` + `parentColumn`) pair must be set; a
9
+ * parent-scoped entry must appear after its parent in the plan so the parent ids are known
10
+ * by the time the child is loaded.
11
+ */
12
+ export type TenantTablePlanEntry = {
13
+ /**
14
+ * Name of the table whose rows are partitioned by tenant.
15
+ */
16
+ tableName: string;
17
+ /**
18
+ * Column matched directly against the tenant key value.
19
+ */
20
+ keyColumn?: string | undefined;
21
+ /**
22
+ * Earlier-in-plan table whose selected rows scope this one.
23
+ */
24
+ parentTableName?: string | undefined;
25
+ /**
26
+ * Column on this table referencing the parent table's primary key.
27
+ */
28
+ parentColumn?: string | undefined;
29
+ };
30
+ //# sourceMappingURL=tenant-table-plan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-table-plan.d.ts","sourceRoot":"","sources":["../../../../src/database/tenants/tenant-table-plan.js"],"names":[],"mappings":";;;;;;;;;;;;;;;eAac,MAAM"}
@@ -0,0 +1,3 @@
1
+ // @ts-check
2
+ export {};
3
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVuYW50LXRhYmxlLXBsYW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvZGF0YWJhc2UvdGVuYW50cy90ZW5hbnQtdGFibGUtcGxhbi5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbi8qKlxuICogRGVzY3JpYmVzIGhvdyBvbmUgdGFibGUncyByb3dzIGFyZSBwYXJ0aXRpb25lZCBiZXR3ZWVuIHRlbmFudHMgc28gYSBEYXRhQ29waWVyIGNhbiBzZWxlY3RcbiAqIHRoZSBzdWJzZXQgdGhhdCBiZWxvbmdzIHRvIGEgZ2l2ZW4gdGVuYW50IGtleS5cbiAqXG4gKiBBIHJvdyBiZWxvbmdzIHRvIHRoZSB0ZW5hbnQgd2hlbiBpdHMgYGtleUNvbHVtbmAgZXF1YWxzIHRoZSB0ZW5hbnQga2V5IHZhbHVlLCBvciDigJQgZm9yXG4gKiB0YWJsZXMgdGhhdCBoYXZlIG5vIGRpcmVjdCB0ZW5hbnQgY29sdW1uIOKAlCB3aGVuIGl0cyBgcGFyZW50Q29sdW1uYCByZWZlcmVuY2VzIGEgcm93IG9mXG4gKiBgcGFyZW50VGFibGVOYW1lYCB0aGF0IHdhcyBpdHNlbGYgYWxyZWFkeSBzZWxlY3RlZCBhcyBiZWxvbmdpbmcgdG8gdGhlIHRlbmFudC4gRXhhY3RseVxuICogb25lIG9mIGBrZXlDb2x1bW5gIG9yIHRoZSAoYHBhcmVudFRhYmxlTmFtZWAgKyBgcGFyZW50Q29sdW1uYCkgcGFpciBtdXN0IGJlIHNldDsgYVxuICogcGFyZW50LXNjb3BlZCBlbnRyeSBtdXN0IGFwcGVhciBhZnRlciBpdHMgcGFyZW50IGluIHRoZSBwbGFuIHNvIHRoZSBwYXJlbnQgaWRzIGFyZSBrbm93blxuICogYnkgdGhlIHRpbWUgdGhlIGNoaWxkIGlzIGxvYWRlZC5cbiAqIEB0eXBlZGVmIHtvYmplY3R9IFRlbmFudFRhYmxlUGxhbkVudHJ5XG4gKiBAcHJvcGVydHkge3N0cmluZ30gdGFibGVOYW1lIE5hbWUgb2YgdGhlIHRhYmxlIHdob3NlIHJvd3MgYXJlIHBhcnRpdGlvbmVkIGJ5IHRlbmFudC5cbiAqIEBwcm9wZXJ0eSB7c3RyaW5nfSBba2V5Q29sdW1uXSBDb2x1bW4gbWF0Y2hlZCBkaXJlY3RseSBhZ2FpbnN0IHRoZSB0ZW5hbnQga2V5IHZhbHVlLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IFtwYXJlbnRUYWJsZU5hbWVdIEVhcmxpZXItaW4tcGxhbiB0YWJsZSB3aG9zZSBzZWxlY3RlZCByb3dzIHNjb3BlIHRoaXMgb25lLlxuICogQHByb3BlcnR5IHtzdHJpbmd9IFtwYXJlbnRDb2x1bW5dIENvbHVtbiBvbiB0aGlzIHRhYmxlIHJlZmVyZW5jaW5nIHRoZSBwYXJlbnQgdGFibGUncyBwcmltYXJ5IGtleS5cbiAqL1xuXG5leHBvcnQge31cbiJdfQ==