@ductape/sdk 0.4.5 → 0.4.6

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.
@@ -41,12 +41,26 @@ var __importStar = (this && this.__importStar) || (function () {
41
41
  return result;
42
42
  };
43
43
  })();
44
+ var __rest = (this && this.__rest) || function (s, e) {
45
+ var t = {};
46
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
47
+ t[p] = s[p];
48
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
49
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
50
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
51
+ t[p[i]] = s[p[i]];
52
+ }
53
+ return t;
54
+ };
44
55
  var __importDefault = (this && this.__importDefault) || function (mod) {
45
56
  return (mod && mod.__esModule) ? mod : { "default": mod };
46
57
  };
47
58
  Object.defineProperty(exports, "__esModule", { value: true });
48
59
  exports.databaseService = exports.DatabaseConnection = exports.DatabaseService = void 0;
49
60
  const enums_1 = require("./types/enums");
61
+ const pipeline_interface_1 = require("./types/pipeline.interface");
62
+ const atomic_pipeline_1 = require("./atomic-pipeline");
63
+ const sql_context_1 = require("./sql-context");
50
64
  const presave_processor_1 = require("./presave/presave-processor");
51
65
  const atomic_batch_1 = require("./atomic-batch");
52
66
  const dynamodb_adapter_1 = require("./adapters/dynamodb.adapter");
@@ -1364,6 +1378,9 @@ class DatabaseService {
1364
1378
  */
1365
1379
  async raw(options) {
1366
1380
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
1381
+ // A cached response cannot represent this transaction's snapshot or own writes.
1382
+ if (options.transaction && options.cache)
1383
+ options = Object.assign(Object.assign({}, options), { cache: undefined });
1367
1384
  const process_id = (0, processor_utils_1.generateObjectId)();
1368
1385
  const start = Date.now();
1369
1386
  this.initializeLogService();
@@ -1868,6 +1885,104 @@ class DatabaseService {
1868
1885
  * where: { status: 'completed' },
1869
1886
  * });
1870
1887
  */
1888
+ async atomicPipeline(options) {
1889
+ const { context: _context } = options, batchInput = __rest(options, ["context"]);
1890
+ (0, atomic_batch_1.validateAtomicBatch)(batchInput);
1891
+ // Retain only the opaque session and transaction by identity across awaits.
1892
+ options = Object.assign(Object.assign({}, options), { context: JSON.parse(JSON.stringify(options.context)), operations: JSON.parse(JSON.stringify(options.operations)) });
1893
+ return (0, atomic_pipeline_1.executeAtomicPipeline)(options, {
1894
+ preflight: async (scope) => {
1895
+ try {
1896
+ await this.ensureAdapterFor(scope);
1897
+ const adapter = this.getAdapter(scope);
1898
+ if (!(adapter instanceof mongodb_adapter_1.MongoDBAdapter || adapter instanceof postgresql_adapter_1.PostgreSQLAdapter || adapter instanceof mysql_adapter_1.MySQLAdapter))
1899
+ throw new Error('Adapter cannot provide a transactional context pipeline');
1900
+ if ((adapter instanceof mongodb_adapter_1.MongoDBAdapter) === !!scope.context.sql)
1901
+ throw new Error('Context dialect does not match adapter');
1902
+ if (scope.transaction && (!(scope.transaction instanceof transaction_manager_1.Transaction) || !scope.transaction.belongsTo(adapter)
1903
+ || !scope.transaction.isActive() || this.transactionScopes.get(scope.transaction) !== JSON.stringify([scope.product, scope.env, scope.database])))
1904
+ throw new Error('Transaction scope mismatch');
1905
+ if (adapter instanceof mongodb_adapter_1.MongoDBAdapter)
1906
+ await adapter.assertAtomicBatchSupport([...new Set([scope.context.table, ...scope.operations.map(op => op.table)])]);
1907
+ else if (scope.transaction && scope.transaction.isolationLevel !== enums_1.IsolationLevel.SERIALIZABLE)
1908
+ throw new Error('SQL pipeline requires SERIALIZABLE isolation');
1909
+ }
1910
+ catch (_a) {
1911
+ throw new atomic_batch_1.AtomicBatchError('BATCH_PREFLIGHT_FAILED', 'not_started');
1912
+ }
1913
+ },
1914
+ begin: () => this.beginTransaction({ product: options.product, env: options.env, database: options.database, isolationLevel: enums_1.IsolationLevel.SERIALIZABLE }),
1915
+ read: async (transaction) => {
1916
+ if (!options.context.sql)
1917
+ return this.aggregatePipeline({ product: options.product, env: options.env, database: options.database,
1918
+ session: options.session, transaction, table: options.context.table, pipeline: options.context.pipeline, maxTimeMS: options.context.maxTimeMS });
1919
+ const adapter = this.getAdapter(options);
1920
+ await adapter.assertAtomicBatchSupport([...new Set([options.context.table, ...(options.context.sql.joins || []).map(join => join.table), ...options.operations.map(op => op.table)])], transaction);
1921
+ let context = options.context.sql;
1922
+ if (options.session) {
1923
+ const builder = await this.getProductBuilder(options.product);
1924
+ const key = builder.fetchPrivateKey();
1925
+ if (!key)
1926
+ throw new Error('Cannot verify pipeline session');
1927
+ const { processSessionForExecution } = await Promise.resolve().then(() => __importStar(require('../sessions')));
1928
+ const result = await processSessionForExecution(options.session, key, context, options.env, { fetchSessionSelector: async (tag) => { var _a; return (_a = (await builder.fetchSession(tag))) === null || _a === void 0 ? void 0 : _a.selector; } });
1929
+ if (result.error)
1930
+ throw new Error('Pipeline session validation failed');
1931
+ context = result.input;
1932
+ }
1933
+ const query = (0, sql_context_1.compileSqlContext)(options.context.table, context, adapter instanceof postgresql_adapter_1.PostgreSQLAdapter);
1934
+ return adapter.raw(Object.assign(Object.assign({}, query), { table: options.context.table, transaction }));
1935
+ },
1936
+ write: batch => this.atomicBatch(batch),
1937
+ });
1938
+ }
1939
+ async aggregatePipeline(options) {
1940
+ var _a, _b, _c;
1941
+ for (const key of ['product', 'env', 'database', 'table']) {
1942
+ if (typeof options[key] !== 'string' || !options[key].trim())
1943
+ throw new Error(`aggregatePipeline requires ${key}`);
1944
+ }
1945
+ (0, pipeline_interface_1.validateReadPipeline)(options.pipeline);
1946
+ await this.ensureAdapterFor(options);
1947
+ const adapter = this.getAdapter(options);
1948
+ if (!(adapter instanceof mongodb_adapter_1.MongoDBAdapter))
1949
+ throw new Error('aggregatePipeline requires MongoDB');
1950
+ const transaction = options.transaction;
1951
+ if (transaction && (!(transaction instanceof transaction_manager_1.Transaction) || !transaction.belongsTo(adapter) || !transaction.isActive()
1952
+ || this.transactionScopes.get(transaction) !== JSON.stringify([options.product, options.env, options.database]))) {
1953
+ throw new Error('Pipeline transaction does not belong to this product/environment/database');
1954
+ }
1955
+ let resolved = options;
1956
+ let sessionLogFields = {};
1957
+ if (options.session) {
1958
+ const builder = await this.getProductBuilder(options.product);
1959
+ const privateKey = builder.fetchPrivateKey();
1960
+ if (!privateKey)
1961
+ throw new Error('Cannot verify pipeline session');
1962
+ const { processSessionForExecution } = await Promise.resolve().then(() => __importStar(require('../sessions')));
1963
+ // Never recursively transform the driver session or replace the original opaque token.
1964
+ const { transaction: _transaction } = options, input = __rest(options, ["transaction"]);
1965
+ const result = await processSessionForExecution(options.session, privateKey, input, options.env, {
1966
+ fetchSessionSelector: async (tag) => { var _a; return (_a = (await builder.fetchSession(tag))) === null || _a === void 0 ? void 0 : _a.selector; },
1967
+ });
1968
+ if (result.error)
1969
+ throw new Error('Pipeline session validation failed');
1970
+ resolved = Object.assign(Object.assign({}, options), { pipeline: result.input.pipeline, transaction, session: options.session });
1971
+ sessionLogFields = result.logFields;
1972
+ }
1973
+ this.initializeLogService();
1974
+ const start = Date.now();
1975
+ let successful = false;
1976
+ try {
1977
+ const result = await adapter.aggregatePipeline(resolved);
1978
+ successful = true;
1979
+ return result;
1980
+ }
1981
+ finally {
1982
+ (_a = this.logService) === null || _a === void 0 ? void 0 : _a.add(Object.assign(Object.assign({ product_tag: options.product, workspace_id: ((_b = this.config) === null || _b === void 0 ? void 0 : _b.workspace_id) || '', env: options.env, app_env: options.env, process_id: (0, processor_utils_1.generateObjectId)(), type: logs_types_1.LogEventTypes.DATABASE, parent_tag: options.database, child_tag: 'aggregatePipeline' }, sessionLogFields), { start, end: Date.now(), message: `Database pipeline - ${successful ? 'success' : 'failed'}`, status: successful ? logs_types_1.LogEventStatus.SUCCESS : logs_types_1.LogEventStatus.FAIL, successful_execution: successful, failed_execution: !successful, data: { table: options.table, stages: options.pipeline.length } }));
1983
+ void ((_c = this.logService) === null || _c === void 0 ? void 0 : _c.publish().catch(() => { }));
1984
+ }
1985
+ }
1871
1986
  async aggregate(options) {
1872
1987
  var _a, _b, _c, _d, _e, _f, _g, _h;
1873
1988
  const process_id = (0, processor_utils_1.generateObjectId)();
@@ -3580,6 +3695,9 @@ class DatabaseConnection {
3580
3695
  aggregate(options) {
3581
3696
  return this.service.aggregate(Object.assign(Object.assign({}, options), { database: this._database, env: this._env }));
3582
3697
  }
3698
+ aggregatePipeline(options) {
3699
+ return this.service.aggregatePipeline(Object.assign(Object.assign({}, options), { product: this._product, database: this._database, env: this._env }));
3700
+ }
3583
3701
  groupBy(options) {
3584
3702
  return this.service.groupBy(Object.assign(Object.assign({}, options), { database: this._database, env: this._env }));
3585
3703
  }