s3db.js 7.1.0 → 7.2.1
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/PLUGINS.md +200 -10
- package/dist/s3db.cjs.js +62 -31
- package/dist/s3db.cjs.min.js +1 -1
- package/dist/s3db.d.ts +14 -15
- package/dist/s3db.es.js +62 -31
- package/dist/s3db.es.min.js +1 -1
- package/dist/s3db.iife.js +62 -31
- package/dist/s3db.iife.min.js +1 -1
- package/package.json +5 -1
- package/src/plugins/replicators/bigquery-replicator.class.js +102 -68
- package/src/plugins/replicators/postgres-replicator.class.js +19 -109
- package/src/plugins/replicators/s3db-replicator.class.js +21 -49
- package/src/plugins/replicators/sqs-replicator.class.js +17 -116
- package/src/s3db.d.ts +14 -15
package/dist/s3db.d.ts
CHANGED
|
@@ -418,23 +418,22 @@ declare module 's3db.js' {
|
|
|
418
418
|
export interface BigQueryReplicatorConfig {
|
|
419
419
|
projectId: string;
|
|
420
420
|
datasetId: string;
|
|
421
|
-
keyFilename?: string;
|
|
422
421
|
credentials?: Record<string, any>;
|
|
423
|
-
|
|
424
|
-
|
|
422
|
+
location?: string;
|
|
423
|
+
logTable?: string;
|
|
425
424
|
batchSize?: number;
|
|
426
425
|
maxRetries?: number;
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
426
|
+
writeDisposition?: string;
|
|
427
|
+
createDisposition?: string;
|
|
428
|
+
tableMapping?: Record<string, string>;
|
|
429
|
+
logOperations?: boolean;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/** BigQuery Resource Configuration */
|
|
433
|
+
export interface BigQueryResourceConfig {
|
|
434
|
+
table: string;
|
|
435
|
+
actions?: ('insert' | 'update' | 'delete')[];
|
|
436
|
+
transform?: (data: any) => any;
|
|
438
437
|
}
|
|
439
438
|
|
|
440
439
|
/** Postgres Replicator config */
|
|
@@ -1041,7 +1040,7 @@ declare module 's3db.js' {
|
|
|
1041
1040
|
|
|
1042
1041
|
/** BigQuery Replicator class */
|
|
1043
1042
|
export class BigqueryReplicator extends BaseReplicator {
|
|
1044
|
-
constructor(config: BigQueryReplicatorConfig);
|
|
1043
|
+
constructor(config: BigQueryReplicatorConfig, resources: Record<string, string | BigQueryResourceConfig | BigQueryResourceConfig[]>);
|
|
1045
1044
|
}
|
|
1046
1045
|
|
|
1047
1046
|
/** Postgres Replicator class */
|
package/dist/s3db.es.js
CHANGED
|
@@ -8002,22 +8002,25 @@ class BigqueryReplicator extends base_replicator_class_default {
|
|
|
8002
8002
|
if (typeof config === "string") {
|
|
8003
8003
|
parsed[resourceName] = [{
|
|
8004
8004
|
table: config,
|
|
8005
|
-
actions: ["insert"]
|
|
8005
|
+
actions: ["insert"],
|
|
8006
|
+
transform: null
|
|
8006
8007
|
}];
|
|
8007
8008
|
} else if (Array.isArray(config)) {
|
|
8008
8009
|
parsed[resourceName] = config.map((item) => {
|
|
8009
8010
|
if (typeof item === "string") {
|
|
8010
|
-
return { table: item, actions: ["insert"] };
|
|
8011
|
+
return { table: item, actions: ["insert"], transform: null };
|
|
8011
8012
|
}
|
|
8012
8013
|
return {
|
|
8013
8014
|
table: item.table,
|
|
8014
|
-
actions: item.actions || ["insert"]
|
|
8015
|
+
actions: item.actions || ["insert"],
|
|
8016
|
+
transform: item.transform || null
|
|
8015
8017
|
};
|
|
8016
8018
|
});
|
|
8017
8019
|
} else if (typeof config === "object") {
|
|
8018
8020
|
parsed[resourceName] = [{
|
|
8019
8021
|
table: config.table,
|
|
8020
|
-
actions: config.actions || ["insert"]
|
|
8022
|
+
actions: config.actions || ["insert"],
|
|
8023
|
+
transform: config.transform || null
|
|
8021
8024
|
}];
|
|
8022
8025
|
}
|
|
8023
8026
|
}
|
|
@@ -8041,6 +8044,9 @@ class BigqueryReplicator extends base_replicator_class_default {
|
|
|
8041
8044
|
if (invalidActions.length > 0) {
|
|
8042
8045
|
errors.push(`Invalid actions for resource '${resourceName}': ${invalidActions.join(", ")}. Valid actions: ${validActions.join(", ")}`);
|
|
8043
8046
|
}
|
|
8047
|
+
if (tableConfig.transform && typeof tableConfig.transform !== "function") {
|
|
8048
|
+
errors.push(`Transform must be a function for resource '${resourceName}'`);
|
|
8049
|
+
}
|
|
8044
8050
|
}
|
|
8045
8051
|
}
|
|
8046
8052
|
return { isValid: errors.length === 0, errors };
|
|
@@ -8076,7 +8082,16 @@ class BigqueryReplicator extends base_replicator_class_default {
|
|
|
8076
8082
|
}
|
|
8077
8083
|
getTablesForResource(resourceName, operation) {
|
|
8078
8084
|
if (!this.resources[resourceName]) return [];
|
|
8079
|
-
return this.resources[resourceName].filter((tableConfig) => tableConfig.actions.includes(operation)).map((tableConfig) =>
|
|
8085
|
+
return this.resources[resourceName].filter((tableConfig) => tableConfig.actions.includes(operation)).map((tableConfig) => ({
|
|
8086
|
+
table: tableConfig.table,
|
|
8087
|
+
transform: tableConfig.transform
|
|
8088
|
+
}));
|
|
8089
|
+
}
|
|
8090
|
+
applyTransform(data, transformFn) {
|
|
8091
|
+
if (!transformFn) return data;
|
|
8092
|
+
let transformedData = JSON.parse(JSON.stringify(data));
|
|
8093
|
+
if (transformedData._length) delete transformedData._length;
|
|
8094
|
+
return transformFn(transformedData);
|
|
8080
8095
|
}
|
|
8081
8096
|
async replicate(resourceName, operation, data, id, beforeData = null) {
|
|
8082
8097
|
if (!this.enabled || !this.shouldReplicateResource(resourceName)) {
|
|
@@ -8085,40 +8100,56 @@ class BigqueryReplicator extends base_replicator_class_default {
|
|
|
8085
8100
|
if (!this.shouldReplicateAction(resourceName, operation)) {
|
|
8086
8101
|
return { skipped: true, reason: "action_not_included" };
|
|
8087
8102
|
}
|
|
8088
|
-
const
|
|
8089
|
-
if (
|
|
8103
|
+
const tableConfigs = this.getTablesForResource(resourceName, operation);
|
|
8104
|
+
if (tableConfigs.length === 0) {
|
|
8090
8105
|
return { skipped: true, reason: "no_tables_for_action" };
|
|
8091
8106
|
}
|
|
8092
8107
|
const results = [];
|
|
8093
8108
|
const errors = [];
|
|
8094
8109
|
const [ok, err, result] = await try_fn_default(async () => {
|
|
8095
8110
|
const dataset = this.bigqueryClient.dataset(this.datasetId);
|
|
8096
|
-
for (const
|
|
8111
|
+
for (const tableConfig of tableConfigs) {
|
|
8097
8112
|
const [okTable, errTable] = await try_fn_default(async () => {
|
|
8098
|
-
const table = dataset.table(
|
|
8113
|
+
const table = dataset.table(tableConfig.table);
|
|
8099
8114
|
let job;
|
|
8100
8115
|
if (operation === "insert") {
|
|
8101
|
-
const
|
|
8102
|
-
job = await table.insert([
|
|
8116
|
+
const transformedData = this.applyTransform(data, tableConfig.transform);
|
|
8117
|
+
job = await table.insert([transformedData]);
|
|
8103
8118
|
} else if (operation === "update") {
|
|
8104
|
-
const
|
|
8105
|
-
const
|
|
8106
|
-
const
|
|
8107
|
-
|
|
8108
|
-
|
|
8109
|
-
|
|
8110
|
-
|
|
8111
|
-
|
|
8112
|
-
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
|
|
8116
|
-
|
|
8119
|
+
const transformedData = this.applyTransform(data, tableConfig.transform);
|
|
8120
|
+
const keys = Object.keys(transformedData).filter((k) => k !== "id");
|
|
8121
|
+
const setClause = keys.map((k) => `${k} = @${k}`).join(", ");
|
|
8122
|
+
const params = { id, ...transformedData };
|
|
8123
|
+
const query = `UPDATE \`${this.projectId}.${this.datasetId}.${tableConfig.table}\` SET ${setClause} WHERE id = @id`;
|
|
8124
|
+
const maxRetries = 2;
|
|
8125
|
+
let lastError = null;
|
|
8126
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
8127
|
+
try {
|
|
8128
|
+
const [updateJob] = await this.bigqueryClient.createQueryJob({
|
|
8129
|
+
query,
|
|
8130
|
+
params,
|
|
8131
|
+
location: this.location
|
|
8132
|
+
});
|
|
8133
|
+
await updateJob.getQueryResults();
|
|
8134
|
+
job = [updateJob];
|
|
8135
|
+
break;
|
|
8136
|
+
} catch (error) {
|
|
8137
|
+
lastError = error;
|
|
8138
|
+
if (error?.message?.includes("streaming buffer") && attempt < maxRetries) {
|
|
8139
|
+
const delaySeconds = 30;
|
|
8140
|
+
await new Promise((resolve) => setTimeout(resolve, delaySeconds * 1e3));
|
|
8141
|
+
continue;
|
|
8142
|
+
}
|
|
8143
|
+
throw error;
|
|
8144
|
+
}
|
|
8145
|
+
}
|
|
8146
|
+
if (!job) throw lastError;
|
|
8117
8147
|
} else if (operation === "delete") {
|
|
8118
|
-
const query = `DELETE FROM \`${this.projectId}.${this.datasetId}.${
|
|
8148
|
+
const query = `DELETE FROM \`${this.projectId}.${this.datasetId}.${tableConfig.table}\` WHERE id = @id`;
|
|
8119
8149
|
const [deleteJob] = await this.bigqueryClient.createQueryJob({
|
|
8120
8150
|
query,
|
|
8121
|
-
params: { id }
|
|
8151
|
+
params: { id },
|
|
8152
|
+
location: this.location
|
|
8122
8153
|
});
|
|
8123
8154
|
await deleteJob.getQueryResults();
|
|
8124
8155
|
job = [deleteJob];
|
|
@@ -8126,14 +8157,14 @@ class BigqueryReplicator extends base_replicator_class_default {
|
|
|
8126
8157
|
throw new Error(`Unsupported operation: ${operation}`);
|
|
8127
8158
|
}
|
|
8128
8159
|
results.push({
|
|
8129
|
-
table:
|
|
8160
|
+
table: tableConfig.table,
|
|
8130
8161
|
success: true,
|
|
8131
8162
|
jobId: job[0]?.id
|
|
8132
8163
|
});
|
|
8133
8164
|
});
|
|
8134
8165
|
if (!okTable) {
|
|
8135
8166
|
errors.push({
|
|
8136
|
-
table:
|
|
8167
|
+
table: tableConfig.table,
|
|
8137
8168
|
error: errTable.message
|
|
8138
8169
|
});
|
|
8139
8170
|
}
|
|
@@ -8159,7 +8190,7 @@ class BigqueryReplicator extends base_replicator_class_default {
|
|
|
8159
8190
|
resourceName,
|
|
8160
8191
|
operation,
|
|
8161
8192
|
id,
|
|
8162
|
-
tables,
|
|
8193
|
+
tables: tableConfigs.map((t) => t.table),
|
|
8163
8194
|
results,
|
|
8164
8195
|
errors,
|
|
8165
8196
|
success
|
|
@@ -8168,7 +8199,7 @@ class BigqueryReplicator extends base_replicator_class_default {
|
|
|
8168
8199
|
success,
|
|
8169
8200
|
results,
|
|
8170
8201
|
errors,
|
|
8171
|
-
tables
|
|
8202
|
+
tables: tableConfigs.map((t) => t.table)
|
|
8172
8203
|
};
|
|
8173
8204
|
});
|
|
8174
8205
|
if (ok) return result;
|
|
@@ -12207,7 +12238,7 @@ class Database extends EventEmitter {
|
|
|
12207
12238
|
super();
|
|
12208
12239
|
this.version = "1";
|
|
12209
12240
|
this.s3dbVersion = (() => {
|
|
12210
|
-
const [ok, err, version] = try_fn_default(() => true ? "7.
|
|
12241
|
+
const [ok, err, version] = try_fn_default(() => true ? "7.2.0" : "latest");
|
|
12211
12242
|
return ok ? version : "latest";
|
|
12212
12243
|
})();
|
|
12213
12244
|
this.resources = {};
|