diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 39396fc5..09842933 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,5 +1,6 @@ # FROM node:18-alpine -FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-20-bullseye +FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:dev-22-bookworm + # [Optional] Uncomment this section to install additional OS packages. @@ -11,19 +12,7 @@ FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-20-bullseye # RUN su node -c "source /usr/local/share/nvm/nvm.sh && nvm install ${EXTRA_NODE_VERSION}" #alpine -# RUN apk update -# RUN apk add git -# RUN apk add libnsl -# RUN apk add gcompat -# RUN ln -s /usr/lib/libnsl.so.3 /usr/lib/libnsl.so.1 -# RUN apk --no-cache add curl -# RUN apk --no-cache add unixodbc -# RUN apk add sudo -# odbc alpine -# https://docs.microsoft.com/en-us/sql/connect/odbc/linux-mac/installing-the-microsoft-odbc-driver-for-sql-server?view=sql-server-ver16 -# RUN curl -O https://download.microsoft.com/download/b/9/f/b9f3cce4-3925-46d4-9f46-da08869c6486/msodbcsql18_18.1.1.1-1_amd64.apk -# RUN curl -O https://download.microsoft.com/download/b/9/f/b9f3cce4-3925-46d4-9f46-da08869c6486/mssql-tools18_18.1.1.1-1_amd64.apk -# RUN sudo apk add --allow-untrusted msodbcsql18_18.1.1.1-1_amd64.apk + # RUN sudo apk add --allow-untrusted mssql-tools18_18.1.1.1-1_amd64.apk #debian @@ -35,6 +24,21 @@ RUN sudo ACCEPT_EULA=Y apt-get install -y msodbcsql18 #RUN ~/.bashrc RUN apt-get install -y unixodbc-dev +#alpine +# RUN apk update +# RUN apk --no-cache add curl +# RUN apk --no-cache add unixodbc +# RUN apk add sudo +# # - RUN apk add unzip +# RUN curl -O https://download.microsoft.com/download/b/9/f/b9f3cce4-3925-46d4-9f46-da08869c6486/msodbcsql18_18.1.1.1-1_amd64.apk +# RUN curl -O https://download.microsoft.com/download/b/9/f/b9f3cce4-3925-46d4-9f46-da08869c6486/mssql-tools18_18.1.1.1-1_amd64.apk +# RUN sudo apk add --allow-untrusted msodbcsql18_18.1.1.1-1_amd64.apk +# RUN sudo apk add --allow-untrusted mssql-tools18_18.1.1.1-1_amd64.apk +# RUN sudo apk add libnsl +# RUN sudo apk add gcompat +# RUN ln -s /usr/lib/libnsl.so.3 /usr/lib/libnsl.so.1 + + # RUN mkdir -p /usr/config # WORKDIR /usr/config diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ae5f0e31..04ba3da8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - container: ["node:18-alpine", "node:20-alpine", "node:22-alpine"] + container: ["node:18-bookworm", "node:20-bookworm", "node:22-bookworm"] container: image: ${{ matrix.container }} services: @@ -69,28 +69,17 @@ jobs: uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} - - run: apk update - - run: apk --no-cache add curl - - run: apk --no-cache add unixodbc - - run: apk add sudo - # - run: apk add unzip - - run: curl -O https://download.microsoft.com/download/b/9/f/b9f3cce4-3925-46d4-9f46-da08869c6486/msodbcsql18_18.1.1.1-1_amd64.apk - - run: curl -O https://download.microsoft.com/download/b/9/f/b9f3cce4-3925-46d4-9f46-da08869c6486/mssql-tools18_18.1.1.1-1_amd64.apk - - run: sudo apk add --allow-untrusted msodbcsql18_18.1.1.1-1_amd64.apk - - run: sudo apk add --allow-untrusted mssql-tools18_18.1.1.1-1_amd64.apk - - run: sudo apk add libnsl - - run: sudo apk add gcompat - - run: ln -s /usr/lib/libnsl.so.3 /usr/lib/libnsl.so.1 - # - run: npm install - # - run: wget https://download.oracle.com/otn_software/linux/instantclient/193000/instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && unzip instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && cp -r instantclient_19_3/* /lib && rm -rf instantclient-basic-linux.x64-19.3.0.0.0dbru.zip && apk --no-cache add libaio && cd /lib && ln -s libnsl.so.2 /usr/lib/libnsl.so.1 && ln -s libc.so /usr/lib/libresolv.so.2 - # - run: ldd /__w/rdb/rdb/tests/libsybdrvodb.so + - run: curl https://packages.microsoft.com/keys/microsoft.asc | apt-key add - + - run: curl https://packages.microsoft.com/config/debian/11/prod.list > /etc/apt/sources.list.d/mssql-release.list + - run: apt-get update + - run: ACCEPT_EULA=Y apt-get install -y msodbcsql18 + - run: apt-get install -y unixodbc-dev - run: npm install - run: npm run lint - run: npm run tscheck - run: npm run test - - run: npm run coverage - # Only run the coverage once - - if: ${{ matrix.container == 'node:16-alpine' && github.ref == 'refs/heads/master'}} + - run: npm run coverage # Only run the coverage once + - if: ${{ matrix.container == 'node:18-bookworm' && github.ref == 'refs/heads/master'}} name: Get Coverage for badge run: | # var SUMMARY = [ diff --git a/.gitignore b/.gitignore index 30834652..e8606379 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ package-lock.json .vscode demo.db demo*.db* -coverage \ No newline at end of file +coverage +.env \ No newline at end of file diff --git a/README.md b/README.md index 443f25be..e476107a 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,8 @@ The ultimate Object Relational Mapper for Node.js and Typescript, offering seaml ✅ MySQL ✅ Oracle ✅ SAP ASE -✅ SQLite +✅ SQLite +✅ Cloudflare D1 This is the _Modern Typescript Documentation_. Are you looking for the [_Classic Documentation_](https://github.com/alfateam/orange-orm/blob/master/docs/docs.md) ? @@ -319,6 +320,7 @@ import map from './map'; const db = map.http('http://localhost:3000/orange'); ``` + __MySQL__ ```bash $ npm install mysql2 @@ -364,6 +366,38 @@ With schema import map from './map'; const db = map.postgres('postgres://postgres:postgres@postgres/postgres?search_path=custom'); ``` +__Cloudflare D1__ +📄 wrangler.toml +```toml +name = "d1-tutorial" +main = "src/index.ts" +compatibility_date = "2025-02-04" + +# Bind a D1 database. D1 is Cloudflare’s native serverless SQL database. +# Docs: https://developers.cloudflare.com/workers/wrangler/configuration/#d1-databases +[[d1_databases]] +binding = "DB" +database_name = "" +database_id = "" +``` + +📄 src/index.ts +```javascript +import map from './map'; + +export interface Env { + // Must match the binding name in wrangler.toml + DB: D1Database; +} + +export default { + async fetch(request, env): Promise { + const db = map.d1(env.DB); + const customers = await db.customer.getAll(); + return Response.json(customers); + }, +} satisfies ExportedHandler; +``` __Oracle__ ```bash npm install oracledb @@ -468,7 +502,7 @@ Currently, there are three concurrency strategies: - `overwrite` Overwrites the property, regardless of changes by others. - `skipOnConflict` Silently avoids updating the property if another user has modified it in the interim. -The concurrency option can be set either for the whole table or individually for each column. In the example below, we are using the overwrite strategy on the vendor table except on the column balance which uses the skipOnConflict strategy. In this particular case, a row with id: 1 already exists, the name and isActive fields will be overwritten, but the balance will remain the same as in the original record, demonstrating the effectiveness of combining multiple concurrency strategies. +The concurrency option can be set either for the whole table or individually for each column. In the example below, we've set the concurrency strategy on vendor table to overwrite except for the column balance which uses the skipOnConflict strategy. In this particular case, a row with id: 1 already exists, the name and isActive fields will be overwritten, but the balance will remain the same as in the original record, demonstrating the effectiveness of combining multiple concurrency strategies. ```javascript import map from './map'; @@ -885,7 +919,7 @@ Currently, there are three concurrency strategies: - `overwrite` Overwrites the property, regardless of changes by others. - `skipOnConflict` Silently avoids updating the property if another user has modified it in the interim. -The concurrency option can be set either for the whole table or individually for each column. In the example below, we are using the overwrite strategy on the table vendor except on the column balance which uses the skipOnConflict strategy. In this particular case, a row with id: 1 already exists, the name and isActive fields will be overwritten, but the balance will remain the same as in the original record, demonstrating the effectiveness of combining multiple concurrency strategies. +The concurrency option can be set either for the whole table or individually for each column. In the example below, we've set the concurrency strategy on vendor table to overwrite except for the column balance which uses the skipOnConflict strategy. In this particular case, a row with id: 1 already exists, the name and isActive fields will be overwritten, but the balance will remain the same as in the original record, demonstrating the effectiveness of combining multiple concurrency strategies. ```javascript import map from './map'; @@ -1580,6 +1614,8 @@ async function getRows() { Within the transaction, a customer is retrieved and its balance updated using the tx object to ensure operations are transactional. An error is deliberately thrown to demonstrate a rollback, ensuring all previous changes within the transaction are reverted. Always use the provided tx object for operations within the transaction to maintain data integrity.

+

(NOTE: Transactions are not supported for Cloudflare D1)

+ ```javascript import map from './map'; @@ -1597,6 +1633,7 @@ async function execute() { } ``` +
Data types @@ -1966,7 +2003,7 @@ async function getRows() {
Logging -

You enable logging by listening to the query event on the `orange` object. During this event, both the SQL statement and any associated parameters are logged.

+

You enable logging by listening to the query event on the `orange` object. During this event, both the SQL statement and any associated parameters are logged. The logged output reveals the sequence of SQL commands executed, offering developers a transparent view into database operations, which aids in debugging and ensures data integrity.

```javascript import orange from 'orange-orm'; @@ -1996,8 +2033,10 @@ async function updateRow() { output: ```bash +BEGIN select _order.id as s_order0,_order.orderDate as s_order1,_order.customerId as s_order2 from _order _order where _order.id=2 order by _order.id limit 1 select orderLine.id as sorderLine0,orderLine.orderId as sorderLine1,orderLine.product as sorderLine2,orderLine.amount as sorderLine3 from orderLine orderLine where orderLine.orderId in (2) order by orderLine.id +COMMIT BEGIN select _order.id as s_order0,_order.orderDate as s_order1,_order.customerId as s_order2 from _order _order where _order.id=2 order by _order.id limit 1 INSERT INTO orderLine (orderId,product,amount) VALUES (2,?,300) diff --git a/docs/changelog.md b/docs/changelog.md index 34215c7e..2367bfd6 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,4 +1,6 @@ ## Changelog +__4.5.0__ +Support for Cloudflare D1. __4.4.2__ Support for schema in connection string. Postgrs only. [#116](https://github.com/alfateam/orange-orm/issues/118) __4.4.1__ diff --git a/package.json b/package.json index 1ebd2736..0500fa72 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "orange-orm", - "version": "4.4.2", + "version": "4.5.0", "main": "./src/index.js", "browser": "./src/client/index.mjs", "bin": { @@ -48,23 +48,21 @@ "lint": "eslint ./", "fix": "eslint ./ --fix", "owasp": "owasp-dependency-check --project \"MY_PROJECT\" --scan \"package-lock.json\" --exclude \"dependency-check-bin\" --out \"owasp\" --format HTML", - "beta": "publish --tag beta" + "beta": "npm publish --tag beta" }, "dependencies": { "@lroal/on-change": "^4.0.2", "@tediousjs/connection-string": "^0.4.1", "@types/express": "^4.17.13", + "@cloudflare/workers-types": "^4.20241106.0", "@types/oracledb": "^6.0.4", "@types/tedious": "^4.0.14", "ajv": "^6.10.2", "axios": "^1.6.2", - "deferred": "^0.7.5", "fast-json-patch": "^3.1.1", "findup-sync": "^5.0.0", "glob": "^10.3.4", "module-definition": "^4.0.0", - "node-cls": "^1.0.5", - "promise": "^8.0.3", "rfdc": "^1.2.0", "uuid": "^8.3.2" }, @@ -99,10 +97,15 @@ }, "tedious": { "optional": true + }, + "oracledb": { + "optional": true } }, - "devDependencies": { - "@rollup/plugin-commonjs": "^21.0.1", + "devDependencies": { + "@miniflare/d1": "^2.14.4", + "@rollup/plugin-commonjs": "^28.0.2", + "@rollup/plugin-json": "^6.1.0", "@rollup/plugin-node-resolve": "^13.0.0", "@typescript-eslint/eslint-plugin": "^6.x", "@typescript-eslint/parser": "^6.x", @@ -111,6 +114,7 @@ "eslint": "^8.57.0", "eslint-plugin-jest": "^27.1.7", "express": "^4.18.2", + "miniflare": "^3.20250129.0", "msnodesqlv8": "^4.1.0", "mysql2": "^3.9.4", "oracledb": "^6.3.0", @@ -121,7 +125,7 @@ "sqlite3": "^5.0.2", "tedious": "^18.2.0", "typescript": "^5.4.5", - "vitest": "^0.34.1" + "vitest": "^0.34.6" }, "engines": { "node": ">= 8.0.0" diff --git a/src/applyPatch.js b/src/applyPatch.js index aba898be..82b0f301 100644 --- a/src/applyPatch.js +++ b/src/applyPatch.js @@ -1,6 +1,4 @@ const fastjson = require('fast-json-patch'); -let { inspect } = require('util'); -let assert = require('assert'); let fromCompareObject = require('./fromCompareObject'); let toCompareObject = require('./toCompareObject'); @@ -43,12 +41,12 @@ function applyPatch({ options = {} }, dto, changes, column) { assertDatesEqual(oldValue, expectedOldValue); } else - assert.deepEqual(oldValue, expectedOldValue); + assertDeepEqual(oldValue, expectedOldValue); } catch (e) { if (concurrency === 'skipOnConflict') return false; - throw new Error(`The field ${change.path.replace('/', '')} was changed by another user. Expected ${inspect(fromCompareObject(expectedOldValue), false, 10)}, but was ${inspect(fromCompareObject(oldValue), false, 10)}.`); + throw new Error(`The field ${change.path.replace('/', '')} was changed by another user. Expected ${inspect(fromCompareObject(expectedOldValue))}, but was ${inspect(fromCompareObject(oldValue))}.`); } } return true; @@ -99,7 +97,16 @@ function assertDatesEqual(date1, date2) { date1 = `${parts1[0]}T${time1parts[0]}`; date2 = `${parts2[0]}T${time2parts[0]}`; } - assert.deepEqual(date1, date2); + assertDeepEqual(date1, date2); +} + +function assertDeepEqual(a, b) { + if (JSON.stringify(a) !== JSON.stringify(b)) + throw new Error('A, b are not equal'); +} + +function inspect(obj) { + return JSON.stringify(obj, null, 2); } module.exports = applyPatch; \ No newline at end of file diff --git a/src/client/clientMap.js b/src/client/clientMap.js index 880e0d01..2a957225 100644 --- a/src/client/clientMap.js +++ b/src/client/clientMap.js @@ -39,6 +39,7 @@ function map(index, _fn) { dbMap.sap = throwDb; dbMap.oracle = throwDb; dbMap.sqlite = throwDb; + dbMap.d1 = throwDb; function throwDb() { throw new Error('Cannot create pool for database outside node'); @@ -65,6 +66,7 @@ function map(index, _fn) { onFinal.sap = () => index({ db: throwDb, providers: dbMap }); onFinal.oracle = () => index({ db: throwDb, providers: dbMap }); onFinal.sqlite = () => index({ db: throwDb, providers: dbMap }); + onFinal.d1 = () => index({ db: throwDb, providers: dbMap }); return new Proxy(onFinal, handler); } diff --git a/src/client/createProviders.js b/src/client/createProviders.js index 780d29c0..83419278 100644 --- a/src/client/createProviders.js +++ b/src/client/createProviders.js @@ -48,6 +48,11 @@ function createProviders(index) { return createPool.bind(null, 'sqlite'); } }); + Object.defineProperty(dbMap, 'd1', { + get: function() { + return createPool.bind(null, 'd1'); + } + }); Object.defineProperty(dbMap, 'http', { get: function() { return createPool.bind(null, 'http'); @@ -97,12 +102,19 @@ function negotiateCachedPool(fn, providers) { get sqlite() { return createPool.bind(null, 'sqlite'); }, + get d1() { + return createPool.bind(null, 'd1'); + }, get http() { return createPool.bind(null, 'http'); } }; function createPool(providerName, ...args) { + //todo + if (providerName === 'd1') { + return providers[providerName].apply(null, args); + } const key = JSON.stringify(args); if (!cache[providerName]) cache[providerName] = {}; diff --git a/src/client/index.js b/src/client/index.js index 48330ed9..016226a9 100644 --- a/src/client/index.js +++ b/src/client/index.js @@ -57,6 +57,7 @@ function rdbClient(options = {}) { client.mssqlNative = onProvider.bind(null, 'mssqlNative'); client.pg = onProvider.bind(null, 'pg'); client.postgres = onProvider.bind(null, 'postgres'); + client.d1 = onProvider.bind(null, 'd1'); client.sqlite = onProvider.bind(null, 'sqlite'); client.sap = onProvider.bind(null, 'sap'); client.oracle = onProvider.bind(null, 'oracle'); @@ -128,7 +129,8 @@ function rdbClient(options = {}) { } async function query() { - return netAdapter(baseUrl, undefined, { tableOptions: { db: baseUrl, transaction } }).query.apply(null, arguments); + const adapter = netAdapter(baseUrl, undefined, { tableOptions: { db: baseUrl, transaction } }); + return adapter.query.apply(null, arguments); } function express(arg) { @@ -168,13 +170,14 @@ function rdbClient(options = {}) { if (!db.createTransaction) throw new Error('Transaction not supported through http'); const transaction = db.createTransaction(_options); + try { const nextClient = client({ transaction }); await fn(nextClient); - await transaction(db.commit); + await transaction(transaction.commit); } catch (e) { - await transaction(db.rollback.bind(null, e)); + await transaction(transaction.rollback.bind(null, e)); } } diff --git a/src/client/index.mjs b/src/client/index.mjs index 59e81add..6bb149a6 100644 --- a/src/client/index.mjs +++ b/src/client/index.mjs @@ -1,6927 +1,13992 @@ void !function() { typeof self === 'undefined' && typeof global === 'object' ? global.self = global : null; -}();var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}; - -function getAugmentedNamespace(n) { - if (n.__esModule) return n; - var a = Object.defineProperty({}, '__esModule', {value: true}); - Object.keys(n).forEach(function (k) { - var d = Object.getOwnPropertyDescriptor(n, k); - Object.defineProperty(a, k, d.get ? d : { - enumerable: true, - get: function () { - return n[k]; - } - }); - }); - return a; -} - -/*! - * https://github.com/Starcounter-Jack/JSON-Patch - * (c) 2017-2022 Joachim Wester - * MIT licensed - */ -var __extends = (undefined && undefined.__extends) || (function () { - var extendStatics = function (d, b) { - extendStatics = Object.setPrototypeOf || - ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || - function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; - return extendStatics(d, b); - }; - return function (d, b) { - extendStatics(d, b); - function __() { this.constructor = d; } - d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); - }; -})(); -var _hasOwnProperty = Object.prototype.hasOwnProperty; -function hasOwnProperty$1(obj, key) { - return _hasOwnProperty.call(obj, key); -} -function _objectKeys(obj) { - if (Array.isArray(obj)) { - var keys_1 = new Array(obj.length); - for (var k = 0; k < keys_1.length; k++) { - keys_1[k] = "" + k; - } - return keys_1; - } - if (Object.keys) { - return Object.keys(obj); - } - var keys = []; - for (var i in obj) { - if (hasOwnProperty$1(obj, i)) { - keys.push(i); - } - } - return keys; -} -/** -* Deeply clone the object. -* https://jsperf.com/deep-copy-vs-json-stringify-json-parse/25 (recursiveDeepCopy) -* @param {any} obj value to clone -* @return {any} cloned obj -*/ -function _deepClone(obj) { - switch (typeof obj) { - case "object": - return JSON.parse(JSON.stringify(obj)); //Faster than ES5 clone - http://jsperf.com/deep-cloning-of-objects/5 - case "undefined": - return null; //this is how JSON.stringify behaves for array items - default: - return obj; //no need to clone primitives - } -} -//3x faster than cached /^\d+$/.test(str) -function isInteger(str) { - var i = 0; - var len = str.length; - var charCode; - while (i < len) { - charCode = str.charCodeAt(i); - if (charCode >= 48 && charCode <= 57) { - i++; - continue; - } - return false; - } - return true; -} -/** -* Escapes a json pointer path -* @param path The raw pointer -* @return the Escaped path -*/ -function escapePathComponent(path) { - if (path.indexOf('/') === -1 && path.indexOf('~') === -1) - return path; - return path.replace(/~/g, '~0').replace(/\//g, '~1'); -} -/** - * Unescapes a json pointer path - * @param path The escaped pointer - * @return The unescaped path - */ -function unescapePathComponent(path) { - return path.replace(/~1/g, '/').replace(/~0/g, '~'); -} -/** -* Recursively checks whether an object has any undefined values inside. -*/ -function hasUndefined(obj) { - if (obj === undefined) { - return true; - } - if (obj) { - if (Array.isArray(obj)) { - for (var i_1 = 0, len = obj.length; i_1 < len; i_1++) { - if (hasUndefined(obj[i_1])) { - return true; - } - } - } - else if (typeof obj === "object") { - var objKeys = _objectKeys(obj); - var objKeysLength = objKeys.length; - for (var i = 0; i < objKeysLength; i++) { - if (hasUndefined(obj[objKeys[i]])) { - return true; - } - } - } - } - return false; -} -function patchErrorMessageFormatter(message, args) { - var messageParts = [message]; - for (var key in args) { - var value = typeof args[key] === 'object' ? JSON.stringify(args[key], null, 2) : args[key]; // pretty print - if (typeof value !== 'undefined') { - messageParts.push(key + ": " + value); - } - } - return messageParts.join('\n'); -} -var PatchError = /** @class */ (function (_super) { - __extends(PatchError, _super); - function PatchError(message, name, index, operation, tree) { - var _newTarget = this.constructor; - var _this = _super.call(this, patchErrorMessageFormatter(message, { name: name, index: index, operation: operation, tree: tree })) || this; - _this.name = name; - _this.index = index; - _this.operation = operation; - _this.tree = tree; - Object.setPrototypeOf(_this, _newTarget.prototype); // restore prototype chain, see https://stackoverflow.com/a/48342359 - _this.message = patchErrorMessageFormatter(message, { name: name, index: index, operation: operation, tree: tree }); - return _this; - } - return PatchError; -}(Error)); - -var JsonPatchError = PatchError; -var deepClone = _deepClone; -/* We use a Javascript hash to store each - function. Each hash entry (property) uses - the operation identifiers specified in rfc6902. - In this way, we can map each patch operation - to its dedicated function in efficient way. - */ -/* The operations applicable to an object */ -var objOps = { - add: function (obj, key, document) { - obj[key] = this.value; - return { newDocument: document }; - }, - remove: function (obj, key, document) { - var removed = obj[key]; - delete obj[key]; - return { newDocument: document, removed: removed }; - }, - replace: function (obj, key, document) { - var removed = obj[key]; - obj[key] = this.value; - return { newDocument: document, removed: removed }; - }, - move: function (obj, key, document) { - /* in case move target overwrites an existing value, - return the removed value, this can be taxing performance-wise, - and is potentially unneeded */ - var removed = getValueByPointer(document, this.path); - if (removed) { - removed = _deepClone(removed); - } - var originalValue = applyOperation(document, { op: "remove", path: this.from }).removed; - applyOperation(document, { op: "add", path: this.path, value: originalValue }); - return { newDocument: document, removed: removed }; - }, - copy: function (obj, key, document) { - var valueToCopy = getValueByPointer(document, this.from); - // enforce copy by value so further operations don't affect source (see issue #177) - applyOperation(document, { op: "add", path: this.path, value: _deepClone(valueToCopy) }); - return { newDocument: document }; - }, - test: function (obj, key, document) { - return { newDocument: document, test: _areEquals(obj[key], this.value) }; - }, - _get: function (obj, key, document) { - this.value = obj[key]; - return { newDocument: document }; - } -}; -/* The operations applicable to an array. Many are the same as for the object */ -var arrOps = { - add: function (arr, i, document) { - if (isInteger(i)) { - arr.splice(i, 0, this.value); - } - else { // array props - arr[i] = this.value; - } - // this may be needed when using '-' in an array - return { newDocument: document, index: i }; - }, - remove: function (arr, i, document) { - var removedList = arr.splice(i, 1); - return { newDocument: document, removed: removedList[0] }; - }, - replace: function (arr, i, document) { - var removed = arr[i]; - arr[i] = this.value; - return { newDocument: document, removed: removed }; - }, - move: objOps.move, - copy: objOps.copy, - test: objOps.test, - _get: objOps._get -}; -/** - * Retrieves a value from a JSON document by a JSON pointer. - * Returns the value. - * - * @param document The document to get the value from - * @param pointer an escaped JSON pointer - * @return The retrieved value - */ -function getValueByPointer(document, pointer) { - if (pointer == '') { - return document; - } - var getOriginalDestination = { op: "_get", path: pointer }; - applyOperation(document, getOriginalDestination); - return getOriginalDestination.value; -} -/** - * Apply a single JSON Patch Operation on a JSON document. - * Returns the {newDocument, result} of the operation. - * It modifies the `document` and `operation` objects - it gets the values by reference. - * If you would like to avoid touching your values, clone them: - * `jsonpatch.applyOperation(document, jsonpatch._deepClone(operation))`. - * - * @param document The document to patch - * @param operation The operation to apply - * @param validateOperation `false` is without validation, `true` to use default jsonpatch's validation, or you can pass a `validateOperation` callback to be used for validation. - * @param mutateDocument Whether to mutate the original document or clone it before applying - * @param banPrototypeModifications Whether to ban modifications to `__proto__`, defaults to `true`. - * @return `{newDocument, result}` after the operation - */ -function applyOperation(document, operation, validateOperation, mutateDocument, banPrototypeModifications, index) { - if (validateOperation === void 0) { validateOperation = false; } - if (mutateDocument === void 0) { mutateDocument = true; } - if (banPrototypeModifications === void 0) { banPrototypeModifications = true; } - if (index === void 0) { index = 0; } - if (validateOperation) { - if (typeof validateOperation == 'function') { - validateOperation(operation, 0, document, operation.path); - } - else { - validator$1(operation, 0); - } - } - /* ROOT OPERATIONS */ - if (operation.path === "") { - var returnValue = { newDocument: document }; - if (operation.op === 'add') { - returnValue.newDocument = operation.value; - return returnValue; - } - else if (operation.op === 'replace') { - returnValue.newDocument = operation.value; - returnValue.removed = document; //document we removed - return returnValue; - } - else if (operation.op === 'move' || operation.op === 'copy') { // it's a move or copy to root - returnValue.newDocument = getValueByPointer(document, operation.from); // get the value by json-pointer in `from` field - if (operation.op === 'move') { // report removed item - returnValue.removed = document; - } - return returnValue; - } - else if (operation.op === 'test') { - returnValue.test = _areEquals(document, operation.value); - if (returnValue.test === false) { - throw new JsonPatchError("Test operation failed", 'TEST_OPERATION_FAILED', index, operation, document); - } - returnValue.newDocument = document; - return returnValue; - } - else if (operation.op === 'remove') { // a remove on root - returnValue.removed = document; - returnValue.newDocument = null; - return returnValue; - } - else if (operation.op === '_get') { - operation.value = document; - return returnValue; - } - else { /* bad operation */ - if (validateOperation) { - throw new JsonPatchError('Operation `op` property is not one of operations defined in RFC-6902', 'OPERATION_OP_INVALID', index, operation, document); - } - else { - return returnValue; - } - } - } /* END ROOT OPERATIONS */ - else { - if (!mutateDocument) { - document = _deepClone(document); - } - var path = operation.path || ""; - var keys = path.split('/'); - var obj = document; - var t = 1; //skip empty element - http://jsperf.com/to-shift-or-not-to-shift - var len = keys.length; - var existingPathFragment = undefined; - var key = void 0; - var validateFunction = void 0; - if (typeof validateOperation == 'function') { - validateFunction = validateOperation; - } - else { - validateFunction = validator$1; - } - while (true) { - key = keys[t]; - if (key && key.indexOf('~') != -1) { - key = unescapePathComponent(key); - } - if (banPrototypeModifications && - (key == '__proto__' || - (key == 'prototype' && t > 0 && keys[t - 1] == 'constructor'))) { - throw new TypeError('JSON-Patch: modifying `__proto__` or `constructor/prototype` prop is banned for security reasons, if this was on purpose, please set `banPrototypeModifications` flag false and pass it to this function. More info in fast-json-patch README'); - } - if (validateOperation) { - if (existingPathFragment === undefined) { - if (obj[key] === undefined) { - existingPathFragment = keys.slice(0, t).join('/'); - } - else if (t == len - 1) { - existingPathFragment = operation.path; - } - if (existingPathFragment !== undefined) { - validateFunction(operation, 0, document, existingPathFragment); - } - } - } - t++; - if (Array.isArray(obj)) { - if (key === '-') { - key = obj.length; - } - else { - if (validateOperation && !isInteger(key)) { - throw new JsonPatchError("Expected an unsigned base-10 integer value, making the new referenced value the array element with the zero-based index", "OPERATION_PATH_ILLEGAL_ARRAY_INDEX", index, operation, document); - } // only parse key when it's an integer for `arr.prop` to work - else if (isInteger(key)) { - key = ~~key; - } - } - if (t >= len) { - if (validateOperation && operation.op === "add" && key > obj.length) { - throw new JsonPatchError("The specified index MUST NOT be greater than the number of elements in the array", "OPERATION_VALUE_OUT_OF_BOUNDS", index, operation, document); - } - var returnValue = arrOps[operation.op].call(operation, obj, key, document); // Apply patch - if (returnValue.test === false) { - throw new JsonPatchError("Test operation failed", 'TEST_OPERATION_FAILED', index, operation, document); - } - return returnValue; - } - } - else { - if (t >= len) { - var returnValue = objOps[operation.op].call(operation, obj, key, document); // Apply patch - if (returnValue.test === false) { - throw new JsonPatchError("Test operation failed", 'TEST_OPERATION_FAILED', index, operation, document); - } - return returnValue; - } - } - obj = obj[key]; - // If we have more keys in the path, but the next value isn't a non-null object, - // throw an OPERATION_PATH_UNRESOLVABLE error instead of iterating again. - if (validateOperation && t < len && (!obj || typeof obj !== "object")) { - throw new JsonPatchError('Cannot perform operation at the desired path', 'OPERATION_PATH_UNRESOLVABLE', index, operation, document); - } - } - } -} -/** - * Apply a full JSON Patch array on a JSON document. - * Returns the {newDocument, result} of the patch. - * It modifies the `document` object and `patch` - it gets the values by reference. - * If you would like to avoid touching your values, clone them: - * `jsonpatch.applyPatch(document, jsonpatch._deepClone(patch))`. - * - * @param document The document to patch - * @param patch The patch to apply - * @param validateOperation `false` is without validation, `true` to use default jsonpatch's validation, or you can pass a `validateOperation` callback to be used for validation. - * @param mutateDocument Whether to mutate the original document or clone it before applying - * @param banPrototypeModifications Whether to ban modifications to `__proto__`, defaults to `true`. - * @return An array of `{newDocument, result}` after the patch - */ -function applyPatch(document, patch, validateOperation, mutateDocument, banPrototypeModifications) { - if (mutateDocument === void 0) { mutateDocument = true; } - if (banPrototypeModifications === void 0) { banPrototypeModifications = true; } - if (validateOperation) { - if (!Array.isArray(patch)) { - throw new JsonPatchError('Patch sequence must be an array', 'SEQUENCE_NOT_AN_ARRAY'); - } - } - if (!mutateDocument) { - document = _deepClone(document); - } - var results = new Array(patch.length); - for (var i = 0, length_1 = patch.length; i < length_1; i++) { - // we don't need to pass mutateDocument argument because if it was true, we already deep cloned the object, we'll just pass `true` - results[i] = applyOperation(document, patch[i], validateOperation, true, banPrototypeModifications, i); - document = results[i].newDocument; // in case root was replaced - } - results.newDocument = document; - return results; -} -/** - * Apply a single JSON Patch Operation on a JSON document. - * Returns the updated document. - * Suitable as a reducer. - * - * @param document The document to patch - * @param operation The operation to apply - * @return The updated document - */ -function applyReducer(document, operation, index) { - var operationResult = applyOperation(document, operation); - if (operationResult.test === false) { // failed test - throw new JsonPatchError("Test operation failed", 'TEST_OPERATION_FAILED', index, operation, document); - } - return operationResult.newDocument; -} -/** - * Validates a single operation. Called from `jsonpatch.validate`. Throws `JsonPatchError` in case of an error. - * @param {object} operation - operation object (patch) - * @param {number} index - index of operation in the sequence - * @param {object} [document] - object where the operation is supposed to be applied - * @param {string} [existingPathFragment] - comes along with `document` - */ -function validator$1(operation, index, document, existingPathFragment) { - if (typeof operation !== 'object' || operation === null || Array.isArray(operation)) { - throw new JsonPatchError('Operation is not an object', 'OPERATION_NOT_AN_OBJECT', index, operation, document); - } - else if (!objOps[operation.op]) { - throw new JsonPatchError('Operation `op` property is not one of operations defined in RFC-6902', 'OPERATION_OP_INVALID', index, operation, document); - } - else if (typeof operation.path !== 'string') { - throw new JsonPatchError('Operation `path` property is not a string', 'OPERATION_PATH_INVALID', index, operation, document); - } - else if (operation.path.indexOf('/') !== 0 && operation.path.length > 0) { - // paths that aren't empty string should start with "/" - throw new JsonPatchError('Operation `path` property must start with "/"', 'OPERATION_PATH_INVALID', index, operation, document); - } - else if ((operation.op === 'move' || operation.op === 'copy') && typeof operation.from !== 'string') { - throw new JsonPatchError('Operation `from` property is not present (applicable in `move` and `copy` operations)', 'OPERATION_FROM_REQUIRED', index, operation, document); - } - else if ((operation.op === 'add' || operation.op === 'replace' || operation.op === 'test') && operation.value === undefined) { - throw new JsonPatchError('Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)', 'OPERATION_VALUE_REQUIRED', index, operation, document); - } - else if ((operation.op === 'add' || operation.op === 'replace' || operation.op === 'test') && hasUndefined(operation.value)) { - throw new JsonPatchError('Operation `value` property is not present (applicable in `add`, `replace` and `test` operations)', 'OPERATION_VALUE_CANNOT_CONTAIN_UNDEFINED', index, operation, document); - } - else if (document) { - if (operation.op == "add") { - var pathLen = operation.path.split("/").length; - var existingPathLen = existingPathFragment.split("/").length; - if (pathLen !== existingPathLen + 1 && pathLen !== existingPathLen) { - throw new JsonPatchError('Cannot perform an `add` operation at the desired path', 'OPERATION_PATH_CANNOT_ADD', index, operation, document); - } - } - else if (operation.op === 'replace' || operation.op === 'remove' || operation.op === '_get') { - if (operation.path !== existingPathFragment) { - throw new JsonPatchError('Cannot perform the operation at a path that does not exist', 'OPERATION_PATH_UNRESOLVABLE', index, operation, document); - } - } - else if (operation.op === 'move' || operation.op === 'copy') { - var existingValue = { op: "_get", path: operation.from, value: undefined }; - var error = validate$1([existingValue], document); - if (error && error.name === 'OPERATION_PATH_UNRESOLVABLE') { - throw new JsonPatchError('Cannot perform the operation from a path that does not exist', 'OPERATION_FROM_UNRESOLVABLE', index, operation, document); - } - } - } -} -/** - * Validates a sequence of operations. If `document` parameter is provided, the sequence is additionally validated against the object document. - * If error is encountered, returns a JsonPatchError object - * @param sequence - * @param document - * @returns {JsonPatchError|undefined} - */ -function validate$1(sequence, document, externalValidator) { - try { - if (!Array.isArray(sequence)) { - throw new JsonPatchError('Patch sequence must be an array', 'SEQUENCE_NOT_AN_ARRAY'); - } - if (document) { - //clone document and sequence so that we can safely try applying operations - applyPatch(_deepClone(document), _deepClone(sequence), externalValidator || true); - } - else { - externalValidator = externalValidator || validator$1; - for (var i = 0; i < sequence.length; i++) { - externalValidator(sequence[i], i, document, undefined); - } - } - } - catch (e) { - if (e instanceof JsonPatchError) { - return e; - } - else { - throw e; - } - } -} -// based on https://github.com/epoberezkin/fast-deep-equal -// MIT License -// Copyright (c) 2017 Evgeny Poberezkin -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. -function _areEquals(a, b) { - if (a === b) - return true; - if (a && b && typeof a == 'object' && typeof b == 'object') { - var arrA = Array.isArray(a), arrB = Array.isArray(b), i, length, key; - if (arrA && arrB) { - length = a.length; - if (length != b.length) - return false; - for (i = length; i-- !== 0;) - if (!_areEquals(a[i], b[i])) - return false; - return true; - } - if (arrA != arrB) - return false; - var keys = Object.keys(a); - length = keys.length; - if (length !== Object.keys(b).length) - return false; - for (i = length; i-- !== 0;) - if (!b.hasOwnProperty(keys[i])) - return false; - for (i = length; i-- !== 0;) { - key = keys[i]; - if (!_areEquals(a[key], b[key])) - return false; - } - return true; - } - return a !== a && b !== b; -} - -var core = /*#__PURE__*/Object.freeze({ - __proto__: null, - JsonPatchError: JsonPatchError, - deepClone: deepClone, - getValueByPointer: getValueByPointer, - applyOperation: applyOperation, - applyPatch: applyPatch, - applyReducer: applyReducer, - validator: validator$1, - validate: validate$1, - _areEquals: _areEquals -}); - -/*! - * https://github.com/Starcounter-Jack/JSON-Patch - * (c) 2017-2021 Joachim Wester - * MIT license - */ -var beforeDict = new WeakMap(); -var Mirror = /** @class */ (function () { - function Mirror(obj) { - this.observers = new Map(); - this.obj = obj; - } - return Mirror; -}()); -var ObserverInfo = /** @class */ (function () { - function ObserverInfo(callback, observer) { - this.callback = callback; - this.observer = observer; - } - return ObserverInfo; -}()); -function getMirror(obj) { - return beforeDict.get(obj); -} -function getObserverFromMirror(mirror, callback) { - return mirror.observers.get(callback); -} -function removeObserverFromMirror(mirror, observer) { - mirror.observers.delete(observer.callback); -} -/** - * Detach an observer from an object - */ -function unobserve(root, observer) { - observer.unobserve(); -} -/** - * Observes changes made to an object, which can then be retrieved using generate - */ -function observe(obj, callback) { - var patches = []; - var observer; - var mirror = getMirror(obj); - if (!mirror) { - mirror = new Mirror(obj); - beforeDict.set(obj, mirror); - } - else { - var observerInfo = getObserverFromMirror(mirror, callback); - observer = observerInfo && observerInfo.observer; - } - if (observer) { - return observer; - } - observer = {}; - mirror.value = _deepClone(obj); - if (callback) { - observer.callback = callback; - observer.next = null; - var dirtyCheck = function () { - generate(observer); - }; - var fastCheck = function () { - clearTimeout(observer.next); - observer.next = setTimeout(dirtyCheck); - }; - if (typeof window !== 'undefined') { //not Node - window.addEventListener('mouseup', fastCheck); - window.addEventListener('keyup', fastCheck); - window.addEventListener('mousedown', fastCheck); - window.addEventListener('keydown', fastCheck); - window.addEventListener('change', fastCheck); - } - } - observer.patches = patches; - observer.object = obj; - observer.unobserve = function () { - generate(observer); - clearTimeout(observer.next); - removeObserverFromMirror(mirror, observer); - if (typeof window !== 'undefined') { - window.removeEventListener('mouseup', fastCheck); - window.removeEventListener('keyup', fastCheck); - window.removeEventListener('mousedown', fastCheck); - window.removeEventListener('keydown', fastCheck); - window.removeEventListener('change', fastCheck); - } - }; - mirror.observers.set(callback, new ObserverInfo(callback, observer)); - return observer; -} -/** - * Generate an array of patches from an observer - */ -function generate(observer, invertible) { - if (invertible === void 0) { invertible = false; } - var mirror = beforeDict.get(observer.object); - _generate(mirror.value, observer.object, observer.patches, "", invertible); - if (observer.patches.length) { - applyPatch(mirror.value, observer.patches); - } - var temp = observer.patches; - if (temp.length > 0) { - observer.patches = []; - if (observer.callback) { - observer.callback(temp); - } - } - return temp; -} -// Dirty check if obj is different from mirror, generate patches and update mirror -function _generate(mirror, obj, patches, path, invertible) { - if (obj === mirror) { - return; - } - if (typeof obj.toJSON === "function") { - obj = obj.toJSON(); - } - var newKeys = _objectKeys(obj); - var oldKeys = _objectKeys(mirror); - var deleted = false; - //if ever "move" operation is implemented here, make sure this test runs OK: "should not generate the same patch twice (move)" - for (var t = oldKeys.length - 1; t >= 0; t--) { - var key = oldKeys[t]; - var oldVal = mirror[key]; - if (hasOwnProperty$1(obj, key) && !(obj[key] === undefined && oldVal !== undefined && Array.isArray(obj) === false)) { - var newVal = obj[key]; - if (typeof oldVal == "object" && oldVal != null && typeof newVal == "object" && newVal != null && Array.isArray(oldVal) === Array.isArray(newVal)) { - _generate(oldVal, newVal, patches, path + "/" + escapePathComponent(key), invertible); - } - else { - if (oldVal !== newVal) { - if (invertible) { - patches.push({ op: "test", path: path + "/" + escapePathComponent(key), value: _deepClone(oldVal) }); - } - patches.push({ op: "replace", path: path + "/" + escapePathComponent(key), value: _deepClone(newVal) }); - } - } - } - else if (Array.isArray(mirror) === Array.isArray(obj)) { - if (invertible) { - patches.push({ op: "test", path: path + "/" + escapePathComponent(key), value: _deepClone(oldVal) }); - } - patches.push({ op: "remove", path: path + "/" + escapePathComponent(key) }); - deleted = true; // property has been deleted - } - else { - if (invertible) { - patches.push({ op: "test", path: path, value: mirror }); - } - patches.push({ op: "replace", path: path, value: obj }); - } - } - if (!deleted && newKeys.length == oldKeys.length) { - return; - } - for (var t = 0; t < newKeys.length; t++) { - var key = newKeys[t]; - if (!hasOwnProperty$1(mirror, key) && obj[key] !== undefined) { - patches.push({ op: "add", path: path + "/" + escapePathComponent(key), value: _deepClone(obj[key]) }); - } - } -} -/** - * Create an array of patches from the differences in two objects - */ -function compare(tree1, tree2, invertible) { - if (invertible === void 0) { invertible = false; } - var patches = []; - _generate(tree1, tree2, patches, '', invertible); - return patches; -} - -var duplex = /*#__PURE__*/Object.freeze({ - __proto__: null, - unobserve: unobserve, - observe: observe, - generate: generate, - compare: compare -}); - -var index = Object.assign({}, core, duplex, { - JsonPatchError: PatchError, - deepClone: _deepClone, - escapePathComponent, - unescapePathComponent -}); - -var fastJsonPatch = /*#__PURE__*/Object.freeze({ - __proto__: null, - 'default': index, - JsonPatchError: PatchError, - deepClone: _deepClone, - escapePathComponent: escapePathComponent, - unescapePathComponent: unescapePathComponent, - getValueByPointer: getValueByPointer, - applyOperation: applyOperation, - applyPatch: applyPatch, - applyReducer: applyReducer, - validator: validator$1, - validate: validate$1, - _areEquals: _areEquals, - unobserve: unobserve, - observe: observe, - generate: generate, - compare: compare -}); - -var require$$0 = /*@__PURE__*/getAugmentedNamespace(fastJsonPatch); - -function dateToISOString$2(date) { - let tzo = -date.getTimezoneOffset(); - let dif = tzo >= 0 ? '+' : '-'; - - function pad(num) { - let norm = Math.floor(Math.abs(num)); - return (norm < 10 ? '0' : '') + norm; - } - - function padMilli(d) { - return (d.getMilliseconds() + '').padStart(3, '0'); - } - - return date.getFullYear() + - '-' + pad(date.getMonth() + 1) + - '-' + pad(date.getDate()) + - 'T' + pad(date.getHours()) + - ':' + pad(date.getMinutes()) + - ':' + pad(date.getSeconds()) + - '.' + padMilli(date) + - dif + pad(tzo / 60) + - ':' + pad(tzo % 60); -} - -var dateToISOString_1 = dateToISOString$2; - -let dateToISOString$1 = dateToISOString_1; -const isNode = (typeof window === 'undefined'); - -function stringify$4(value) { - return JSON.stringify(value, replacer); -} - -function replacer(key, value) { - if (isNode && isNodeBuffer(value)) - return value.toString('base64'); - // @ts-ignore - else if (value instanceof Date && !isNaN(value)) - return dateToISOString$1(value); - else - return value; +}();import * as fastJsonPatch from 'fast-json-patch'; +import * as uuid from 'uuid'; +import * as axios from 'axios'; +import * as _default from 'rfdc/default'; +import * as ajv from 'ajv'; +import * as onChange from '@lroal/on-change'; + +function getDefaultExportFromCjs (x) { + return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x; } -function isNodeBuffer(object) { - return Buffer.isBuffer(object); +function getDefaultExportFromNamespaceIfPresent (n) { + return n && Object.prototype.hasOwnProperty.call(n, 'default') ? n['default'] : n; } -var stringify_1 = stringify$4; - -// Unique ID creation requires a high quality random # generator. In the browser we therefore -// require the crypto API and do not support built-in fallback to lower quality random number -// generators (like Math.random()). -var getRandomValues; -var rnds8 = new Uint8Array(16); -function rng() { - // lazy load so that environments that need to polyfill have a chance to do so - if (!getRandomValues) { - // getRandomValues needs to be invoked in a context where "this" is a Crypto implementation. Also, - // find the complete implementation of crypto (msCrypto) on IE11. - getRandomValues = typeof crypto !== 'undefined' && crypto.getRandomValues && crypto.getRandomValues.bind(crypto) || typeof msCrypto !== 'undefined' && typeof msCrypto.getRandomValues === 'function' && msCrypto.getRandomValues.bind(msCrypto); +var getTSDefinition_1; +var hasRequiredGetTSDefinition; + +function requireGetTSDefinition () { + if (hasRequiredGetTSDefinition) return getTSDefinition_1; + hasRequiredGetTSDefinition = 1; + const typeMap = { + StringColumn: 'string', + BooleanColumn: 'boolean', + UUIDColumn: 'string', + BinaryColumn: 'string', + JSONColumn: 'object', + DateColumn: 'Date | string', + NumberColumn: 'number', + }; - if (!getRandomValues) { - throw new Error('crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported'); - } - } + function getTSDefinition(tableConfigs, {isNamespace = false, isHttp = false} = {}) { + const rootTablesAdded = new Map(); + const tableNames = new Set(); + const tablesAdded = new Map(); + let src = ''; + const defs = tableConfigs.map(getTSDefinitionTable).join(''); + const tables = tableConfigs.reduce((tables, x) => { + tables[x.name] = x.table; + return tables; + }, {}); + src += getPrefixTs(isNamespace); + if (isNamespace) + src += startNamespace(tables, isHttp); + src += defs; + src += getRdbClientTs(tables, isHttp); + if (isNamespace) + src += '}'; + return src; + + + function getTSDefinitionTable({table, customFilters, name}) { + let Name = name.substr(0, 1).toUpperCase() + name.substr(1); + name = name.substr(0, 1).toLowerCase() + name.substr(1); + let result = '' + getTable(table, Name, name, customFilters); + return result; + } - return getRandomValues(rnds8); + function getTable(table, Name, name, customFilters) { + const _columns = columns(table); + const _tableRelations = tableRelations(table); + return ` +export interface ${Name}Table { + count(filter?: RawFilter): Promise; + getAll(): Promise<${Name}Array>; + getAll(fetchingStrategy: ${Name}Strategy): Promise<${Name}Array>; + getMany(filter?: RawFilter): Promise<${Name}Array>; + getMany(filter: RawFilter, fetchingStrategy: ${Name}Strategy): Promise<${Name}Array>; + getMany(${name}s: Array<${Name}>): Promise<${Name}Array>; + getMany(${name}s: Array<${Name}>, fetchingStrategy: ${Name}Strategy): Promise<${Name}Array>; + getOne(filter?: RawFilter): Promise<${Name}Row>; + getOne(filter?: RawFilter, fetchingStrategy?: ${Name}Strategy): Promise<${Name}Row>; + getOne(${name}: ${Name}): Promise<${Name}Row>; + getOne(${name}: ${Name}, fetchingStrategy: ${Name}Strategy): Promise<${Name}Row>; + getById(${getIdArgs(table)}): Promise<${Name}Row>; + getById(${getIdArgs(table)}, fetchingStrategy: ${Name}Strategy): Promise<${Name}Row>; + + replace(${name}s: ${Name}[] | ${Name}): Promise; + replace(${name}s: ${Name}[], fetchingStrategy: ${Name}Strategy): Promise<${Name}Array>; + replace(${name}: ${Name}, fetchingStrategy: ${Name}Strategy): Promise<${Name}Row>; + + update(${name}: ${Name}): Promise; + update(${name}: ${Name}, whereStrategy: ${Name}Strategy): Promise; + update(${name}: ${Name}, whereStrategy: ${Name}Strategy): Promise; + update(${name}: ${Name}, whereStrategy: ${Name}Strategy, fetchingStrategy: ${Name}Strategy): Promise<${Name}Row[]>; + + updateChanges(${name}s: ${Name}[], old${name}s: ${Name}[]): Promise<${Name}Array>; + updateChanges(${name}s: ${Name}[],old${name}s: ${Name}[], fetchingStrategy: ${Name}Strategy): Promise<${Name}Array>; + updateChanges(${name}: ${Name}, old${name}: ${Name}): Promise<${Name}Row>; + updateChanges(${name}: ${Name},old${name}: ${Name}, fetchingStrategy: ${Name}Strategy): Promise<${Name}Row>; + + insert(${name}s: ${Name}[]): Promise<${Name}Array>; + insert(${name}s: ${Name}[], fetchingStrategy: ${Name}Strategy): Promise<${Name}Array>; + insert(${name}: ${Name}): Promise<${Name}Row>; + insert(${name}: ${Name}, fetchingStrategy: ${Name}Strategy): Promise<${Name}Row>; + insertAndForget(${name}s: ${Name}[]): Promise; + insertAndForget(${name}: ${Name}): Promise; + delete(filter?: RawFilter): Promise; + delete(${name}s: Array<${Name}>): Promise; + deleteCascade(filter?: RawFilter): Promise; + deleteCascade(${name}s: Array<${Name}>): Promise; + proxify(${name}s: ${Name}[]): ${Name}Array; + proxify(${name}s: ${Name}[], fetchingStrategy: ${Name}Strategy): ${Name}Array; + proxify(${name}: ${Name}): ${Name}Row; + proxify(${name}: ${Name}, fetchingStrategy: ${Name}Strategy): ${Name}Row; + patch(patch: JsonPatch): Promise; + patch(patch: JsonPatch, concurrency: ${Name}Concurrency, fetchingStrategy?: ${Name}Strategy): Promise; + customFilters: ${Name}CustomFilters; + ${_columns} + ${_tableRelations} } -var REGEX = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i; - -function validate(uuid) { - return typeof uuid === 'string' && REGEX.test(uuid); +export interface ${Name}ExpressConfig { + baseFilter?: RawFilter | ((context: ExpressContext) => RawFilter | Promise); + customFilters?: Record RawFilter | Promise>; + concurrency?: ${Name}Concurrency; + readonly?: boolean; + disableBulkDeletes?: boolean; } -/** - * Convert array of 16 byte values to UUID string format of the form: - * XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX - */ - -var byteToHex = []; - -for (var i = 0; i < 256; ++i) { - byteToHex.push((i + 0x100).toString(16).substr(1)); +export interface ${Name}CustomFilters { + ${getCustomFilters(customFilters)} } -function stringify$3(arr) { - var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; - // Note: Be careful editing this code! It's been tuned for performance - // and works in ways you may not expect. See https://github.com/uuidjs/uuid/pull/434 - var uuid = (byteToHex[arr[offset + 0]] + byteToHex[arr[offset + 1]] + byteToHex[arr[offset + 2]] + byteToHex[arr[offset + 3]] + '-' + byteToHex[arr[offset + 4]] + byteToHex[arr[offset + 5]] + '-' + byteToHex[arr[offset + 6]] + byteToHex[arr[offset + 7]] + '-' + byteToHex[arr[offset + 8]] + byteToHex[arr[offset + 9]] + '-' + byteToHex[arr[offset + 10]] + byteToHex[arr[offset + 11]] + byteToHex[arr[offset + 12]] + byteToHex[arr[offset + 13]] + byteToHex[arr[offset + 14]] + byteToHex[arr[offset + 15]]).toLowerCase(); // Consistency check for valid UUID. If this throws, it's likely due to one - // of the following: - // - One or more input array values don't map to a hex octet (leading to - // "undefined" in the uuid) - // - Invalid input values for the RFC `version` or `variant` fields - - if (!validate(uuid)) { - throw TypeError('Stringified UUID is invalid'); - } - - return uuid; +export interface ${Name}Array extends Array<${Name}> { + saveChanges(): Promise; + saveChanges(concurrency: ${Name}Concurrency, fetchingStrategy?: ${Name}Strategy): Promise; + acceptChanges(): void; + clearChanges(): void; + refresh(): Promise; + refresh(fetchingStrategy: ${Name}Strategy): Promise; + delete(): Promise; + delete(options: ${Name}Concurrency): Promise; } -// -// Inspired by https://github.com/LiosK/UUID.js -// and http://docs.python.org/library/uuid.html - -var _nodeId; - -var _clockseq; // Previous uuid creation time +export interface ${Name}Row extends ${Name} { + saveChanges(): Promise; + saveChanges(concurrency: ${Name}Concurrency, fetchingStrategy?: ${Name}Strategy): Promise; + acceptChanges(): void; + clearChanges(): void; + refresh(): Promise; + refresh(fetchingStrategy: ${Name}Strategy): Promise; + delete(): Promise; + delete(options: ${Name}Concurrency): Promise; +} +${Concurrency(table, Name, true)} +`; + } -var _lastMSecs = 0; -var _lastNSecs = 0; // See https://github.com/uuidjs/uuid for API details + function getIdArgs(table) { + let result = []; + for (let i = 0; i < table._primaryColumns.length; i++) { + let column = table._primaryColumns[i]; + result.push(`${column.alias}: ${typeMap[column.tsType]}`); + } + return result.join(', '); + } -function v1(options, buf, offset) { - var i = buf && offset || 0; - var b = buf || new Array(16); - options = options || {}; - var node = options.node || _nodeId; - var clockseq = options.clockseq !== undefined ? options.clockseq : _clockseq; // node and clockseq need to be initialized to random values if they're not - // specified. We do this lazily to minimize issues related to insufficient - // system entropy. See #189 - if (node == null || clockseq == null) { - var seedBytes = options.random || (options.rng || rng)(); + function tableRelations(table) { + let relations = table._relations; + let result = ''; + for (let relationName in relations) { + const tableName = getTableName(relations[relationName], relationName); + result += `${relationName}: ${tableName}RelatedTable;`; + } + return result; + } - if (node == null) { - // Per 4.5, create and 48-bit node id, (47 random bits + multicast bit = 1) - node = _nodeId = [seedBytes[0] | 0x01, seedBytes[1], seedBytes[2], seedBytes[3], seedBytes[4], seedBytes[5]]; - } - if (clockseq == null) { - // Per 4.2.2, randomize (14 bit) clockseq - clockseq = _clockseq = (seedBytes[6] << 8 | seedBytes[7]) & 0x3fff; - } - } // UUID timestamps are 100 nano-second units since the Gregorian epoch, - // (1582-10-15 00:00). JSNumbers aren't precise enough for this, so - // time is handled internally as 'msecs' (integer milliseconds) and 'nsecs' - // (100-nanoseconds offset from msecs) since unix epoch, 1970-01-01 00:00. + function columns(table) { + let result = ''; + let separator = ''; + for (let i = 0; i < table._columns.length; i++) { + let column = table._columns[i]; + result += `${separator}${column.alias} : ${column.tsType};`; + separator = ` + `; + } + return result; + } + function Concurrency(table, name, isRoot) { + name = pascalCase(name); + if (!isRoot) { + if (tablesAdded.has(table)) + return ''; + else { + tablesAdded.set(table, name); + } + } + let otherConcurrency = ''; + let concurrencyRelations = ''; + let strategyRelations = ''; + let regularRelations = ''; + let relations = table._relations; + let relationName; + + let separator = ` + `; + let visitor = {}; + visitor.visitJoin = function(relation) { + const tableTypeName = getTableName(relation, relationName); + + otherConcurrency += `${Concurrency(relation.childTable, tableTypeName)}`; + concurrencyRelations += `${relationName}?: ${tableTypeName}Concurrency;${separator}`; + strategyRelations += `${relationName}?: ${tableTypeName}Strategy | boolean;${separator}`; + regularRelations += `${relationName}?: ${tableTypeName} | null;${separator}`; + }; + visitor.visitOne = visitor.visitJoin; + visitor.visitMany = function(relation) { + const tableTypeName = getTableName(relation, relationName); + otherConcurrency += `${Concurrency(relation.childTable, tableTypeName)}`; + concurrencyRelations += `${relationName}?: ${tableTypeName}Concurrency;${separator}`; + strategyRelations += `${relationName}?: ${tableTypeName}Strategy | boolean;${separator}`; + regularRelations += `${relationName}?: ${tableTypeName}[] | null;${separator}`; + }; - var msecs = options.msecs !== undefined ? options.msecs : Date.now(); // Per 4.2.1.2, use count of uuid's generated during the current clock - // cycle to simulate higher resolution clock + for (relationName in relations) { + var relation = relations[relationName]; + relation.accept(visitor); + } - var nsecs = options.nsecs !== undefined ? options.nsecs : _lastNSecs + 1; // Time since last uuid creation (in msecs) + let row = ''; + if (!isRoot) { + row = `export interface ${name}RelatedTable { + ${columns(table)} + ${tableRelations(table)} + all: (selector: (table: ${name}RelatedTable) => RawFilter) => Filter; + any: (selector: (table: ${name}RelatedTable) => RawFilter) => Filter; + none: (selector: (table: ${name}RelatedTable) => RawFilter) => Filter; + exists: () => Filter; +}`; + } - var dt = msecs - _lastMSecs + (nsecs - _lastNSecs) / 10000; // Per 4.2.1.2, Bump clockseq on clock regression + return ` +export interface ${name}Concurrency { + readonly?: boolean; + concurrency?: Concurrency; + ${concurrencyColumns(table)} + ${concurrencyRelations} +} - if (dt < 0 && options.clockseq === undefined) { - clockseq = clockseq + 1 & 0x3fff; - } // Reset nsecs if clock regresses (new clockseq) or we've moved onto a new - // time interval +export interface ${name} { + ${regularColumns(table)} + ${regularRelations} +} +export interface ${name}TableBase { + ${columns(table)} + ${tableRelations(table)} +} - if ((dt < 0 || msecs > _lastMSecs) && options.nsecs === undefined) { - nsecs = 0; - } // Per 4.2.1.2 Throw error if too many uuids are requested +export interface ${name}Strategy { + ${strategyColumns(table)} + ${strategyRelations} + limit?: number; + offset?: number; + orderBy?: Array<${orderByColumns(table)}> | ${orderByColumns(table)}; + where?: (table: ${name}TableBase) => RawFilter; +} - if (nsecs >= 10000) { - throw new Error("uuid.v1(): Can't create more than 10M uuids/sec"); - } +${otherConcurrency} - _lastMSecs = msecs; - _lastNSecs = nsecs; - _clockseq = clockseq; // Per 4.1.4 - Convert from unix epoch to Gregorian epoch +${row}`; - msecs += 12219292800000; // `time_low` + } - var tl = ((msecs & 0xfffffff) * 10000 + nsecs) % 0x100000000; - b[i++] = tl >>> 24 & 0xff; - b[i++] = tl >>> 16 & 0xff; - b[i++] = tl >>> 8 & 0xff; - b[i++] = tl & 0xff; // `time_mid` + function getTableName(relation, relationName) { + let name = rootTablesAdded.get(relation.childTable); + if (name) + return name; + else { + let name = pascalCase(relationName); + let count = 2; + while (tableNames.has(name)) { + name = name + 'x' + count; + count++; + } + rootTablesAdded.set(relation.childTable, name); + tableNames.add(name); + return name; + } + } + } - var tmh = msecs / 0x100000000 * 10000 & 0xfffffff; - b[i++] = tmh >>> 8 & 0xff; - b[i++] = tmh & 0xff; // `time_high_and_version` + function regularColumns(table) { + let result = ''; + let separator = ''; + for (let i = 0; i < table._columns.length; i++) { + let column = table._columns[i]; + if (column._notNull) + result += `${separator}${column.alias} : ${typeMap[column.tsType]};`; + else + result += `${separator}${column.alias}? : ${typeMap[column.tsType]} | null;`; + separator = ` + `; + } + return result; + } - b[i++] = tmh >>> 24 & 0xf | 0x10; // include version + function orderByColumns(table) { + let result = ''; + let separator = ''; + for (let i = 0; i < table._columns.length; i++) { + let column = table._columns[i]; + result += `${separator}'${column.alias}' | '${column.alias} desc'`; + separator = '| '; + } + return result; + } - b[i++] = tmh >>> 16 & 0xff; // `clock_seq_hi_and_reserved` (Per 4.2.2 - include variant) - b[i++] = clockseq >>> 8 | 0x80; // `clock_seq_low` + function pascalCase(name) { + return name[0].toUpperCase() + name.substr(1); + } - b[i++] = clockseq & 0xff; // `node` + function concurrencyColumns(table) { + let result = ''; + let separator = ''; + for (let i = 0; i < table._columns.length; i++) { + let column = table._columns[i]; + result += `${separator}${column.alias}? : ColumnConcurrency;`; + separator = ` + `; + } + return result; + } - for (var n = 0; n < 6; ++n) { - b[i + n] = node[n]; - } + function strategyColumns(table) { + let primarySet = new Set(table._primaryColumns); + let result = ''; + let separator = ''; + for (let i = 0; i < table._columns.length; i++) { + let column = table._columns[i]; + if (primarySet.has(column)) + continue; + result += `${separator}${column.alias}? : boolean;`; + separator = ` + `; + } + return result; + } - return buf || stringify$3(b); -} + function getCustomFilters(filters) { + return getLeafNames(filters); -function parse(uuid) { - if (!validate(uuid)) { - throw TypeError('Invalid UUID'); - } + function getLeafNames(obj, tabs = '\t\t\t\t\t') { + let result = ''; + for (let p in obj) { + if (typeof obj[p] === 'object' && obj[p] !== null) { + result += '\n' + tabs + p + ': {' + tabs + getLeafNames(obj[p], tabs + '\t'); + result += '\n' + tabs + '}'; + } + else if (typeof obj[p] === 'function') + result += '\n' + tabs + p + ': (' + getParamNames(obj[p]) + ') => import(\'orange-orm\').Filter;'; + } + return result; + } + } - var v; - var arr = new Uint8Array(16); // Parse ########-....-....-....-............ + function getParamNames(func) { + let STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; + let ARGUMENT_NAMES = /([^\s,]+)/g; - arr[0] = (v = parseInt(uuid.slice(0, 8), 16)) >>> 24; - arr[1] = v >>> 16 & 0xff; - arr[2] = v >>> 8 & 0xff; - arr[3] = v & 0xff; // Parse ........-####-....-....-............ + let fnStr = func.toString().replace(STRIP_COMMENTS, ''); + let result = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(ARGUMENT_NAMES); + if (result === null) + return ''; + return result.slice(1).join(': unknown, ') + ': unknown'; + } - arr[4] = (v = parseInt(uuid.slice(9, 13), 16)) >>> 8; - arr[5] = v & 0xff; // Parse ........-....-####-....-............ + function getPrefixTs(isNamespace) { + if (isNamespace) + return ` +/* eslint-disable @typescript-eslint/no-empty-interface */ +/* eslint-disable @typescript-eslint/no-unused-vars */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import type { AxiosInterceptorManager, InternalAxiosRequestConfig, AxiosResponse } from 'axios'; +import type { BooleanColumn, JSONColumn, UUIDColumn, DateColumn, NumberColumn, BinaryColumn, StringColumn, Concurrency, Filter, RawFilter, TransactionOptions, Pool, Express, Url, ColumnConcurrency, JsonPatch } from 'orange-orm'; +export { RequestHandler } from 'express'; +export { Concurrency, Filter, RawFilter, Config, TransactionOptions, Pool } from 'orange-orm'; +export = r; +declare function r(config: Config): r.RdbClient; +`; + + return ` +/* eslint-disable @typescript-eslint/no-empty-interface */ +/* eslint-disable @typescript-eslint/no-unused-vars */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import schema from './schema'; +import type { AxiosInterceptorManager, InternalAxiosRequestConfig, AxiosResponse } from 'axios'; +import type { BooleanColumn, JSONColumn, UUIDColumn, DateColumn, NumberColumn, BinaryColumn, StringColumn, Concurrency, Filter, RawFilter, TransactionOptions, Pool, Express, Url, ColumnConcurrency, JsonPatch } from 'orange-orm'; +export default schema as RdbClient;`; + } - arr[6] = (v = parseInt(uuid.slice(14, 18), 16)) >>> 8; - arr[7] = v & 0xff; // Parse ........-....-....-####-............ + function startNamespace(tables, isHttp) { + return ` +declare namespace r {${getTables(isHttp)} +`; + + function getTables(isHttp) { + let result = ''; + for (let name in tables) { + let Name = name.substring(0, 1).toUpperCase() + name.substring(1); + result += + ` + const ${name}: ${Name}Table;`; + } + if (!isHttp) + result += ` + + function and(filter: RawFilter | RawFilter[], ...filters: RawFilter[]): Filter; + function or(filter: RawFilter | RawFilter[], ...filters: RawFilter[]): Filter; + function not(): Filter; + function transaction(fn: (transaction: RdbClient) => Promise, options?: TransactionOptions): Promise; + function query(filter: RawFilter | string): Promise; + function query(filter: RawFilter | string): Promise; + function transaction(fn: (transaction: RdbClient) => Promise, options?: TransactionOptions): Promise; + const filter: Filter; + function express(): Express; + function express(config: ExpressConfig): Express; +`; + else + result += ` - arr[8] = (v = parseInt(uuid.slice(19, 23), 16)) >>> 8; - arr[9] = v & 0xff; // Parse ........-....-....-....-############ - // (Use "/" to avoid 32-bit truncation when bit-shifting high-order bytes) + const interceptors: { + request: AxiosInterceptorManager; + response: AxiosInterceptorManager; + }; + function reactive(proxyMethod: (obj: unknown) => unknown): void; + function and(filter: RawFilter | RawFilter[], ...filters: RawFilter[]): Filter; + function or(filter: RawFilter | RawFilter[], ...filters: RawFilter[]): Filter; + function not(): Filter; + const filter: Filter; +`; + return result; + } + } - arr[10] = (v = parseInt(uuid.slice(24, 36), 16)) / 0x10000000000 & 0xff; - arr[11] = v / 0x100000000 & 0xff; - arr[12] = v >>> 24 & 0xff; - arr[13] = v >>> 16 & 0xff; - arr[14] = v >>> 8 & 0xff; - arr[15] = v & 0xff; - return arr; + function getRdbClientTs(tables, isHttp) { + return ` +export interface RdbClient {${getTables(isHttp)} } -function stringToBytes(str) { - str = unescape(encodeURIComponent(str)); // UTF8 escape - - var bytes = []; - - for (var i = 0; i < str.length; ++i) { - bytes.push(str.charCodeAt(i)); - } +export interface RdbConfig { + db?: Pool | (() => Pool); + readonly?: boolean; + concurrency?: Concurrency;${getConcurrencyTables()} +} - return bytes; +export interface MetaData { + readonly?: boolean; + concurrency?: Concurrency;${getConcurrencyTables()} } -var DNS = '6ba7b810-9dad-11d1-80b4-00c04fd430c8'; -var URL = '6ba7b811-9dad-11d1-80b4-00c04fd430c8'; -function v35 (name, version, hashfunc) { - function generateUUID(value, namespace, buf, offset) { - if (typeof value === 'string') { - value = stringToBytes(value); - } +export interface ExpressConfig { + db?: Pool | (() => Pool); + tables?: ExpressTables; + concurrency?: Concurrency; + readonly?: boolean; + disableBulkDeletes?: boolean; +} - if (typeof namespace === 'string') { - namespace = parse(namespace); - } +export interface ExpressContext { + request: import('express').Request; + response: import('express').Response; + client: RdbClient; +} - if (namespace.length !== 16) { - throw TypeError('Namespace must be array-like (16 iterable integer values, 0-255)'); - } // Compute hash of namespace and value, Per 4.3 - // Future: Use spread syntax when supported on all platforms, e.g. `bytes = - // hashfunc([...namespace, ... value])` +export interface ExpressTables {${getExpressTables()} +} +`; + function getConcurrencyTables() { + let result = ''; + for (let name in tables) { + let Name = name.substring(0, 1).toUpperCase() + name.substring(1); + result += + ` + ${name}?: ${Name}Concurrency;`; + } + return result; + } + function getTables(isHttp) { + let result = ''; + for (let name in tables) { + let Name = name.substring(0, 1).toUpperCase() + name.substring(1); + result += + ` + ${name}: ${Name}Table;`; + } + if (isHttp) + result += ` + (config: {db: Url}): RdbClient; + interceptors: { + request: AxiosInterceptorManager; + response: AxiosInterceptorManager; + }; + reactive(proxyMethod: (obj: unknown) => unknown): void; + and(filter: RawFilter | RawFilter[], ...filters: RawFilter[]): Filter; + or(filter: RawFilter | RawFilter[], ...filters: RawFilter[]): Filter; + not(): Filter; + transaction(fn: (transaction: RdbClient) => Promise, options?: TransactionOptions): Promise; + filter: Filter; + createPatch(original: any[], modified: any[]): JsonPatch; + createPatch(original: any, modified: any): JsonPatch;`; + else + result += ` + (config: RdbConfig): RdbClient; + and(filter: RawFilter | RawFilter[], ...filters: RawFilter[]): Filter; + or(filter: RawFilter | RawFilter[], ...filters: RawFilter[]): Filter; + not(): Filter; + query(filter: RawFilter | string): Promise; + query(filter: RawFilter | string): Promise; + transaction(fn: (transaction: RdbClient) => Promise, options?: TransactionOptions): Promise; + filter: Filter; + createPatch(original: any[], modified: any[]): JsonPatch; + createPatch(original: any, modified: any): JsonPatch; + express(): Express; + express(config: ExpressConfig): Express; + readonly metaData: MetaData;`; + return result; + } + function getExpressTables() { + let result = ''; + for (let name in tables) { + let Name = name.substring(0, 1).toUpperCase() + name.substring(1); + result += + ` + ${name}?: boolean | ${Name}ExpressConfig;`; + } + return result; + } + } - var bytes = new Uint8Array(16 + value.length); - bytes.set(namespace); - bytes.set(value, namespace.length); - bytes = hashfunc(bytes); - bytes[6] = bytes[6] & 0x0f | version; - bytes[8] = bytes[8] & 0x3f | 0x80; + getTSDefinition_1 = getTSDefinition; + return getTSDefinition_1; +} - if (buf) { - offset = offset || 0; +var getMeta_1; +var hasRequiredGetMeta; + +function requireGetMeta () { + if (hasRequiredGetMeta) return getMeta_1; + hasRequiredGetMeta = 1; + function getMeta(table, map = new Map()) { + if (map.has(table)) + return map.get(table).id; + let strategy = { + keys: table._primaryColumns.map(x => ({name: x.alias, type: x.tsType})), + columns: {}, + relations: {}, + id: map.size + }; + map.set(table, strategy); - for (var i = 0; i < 16; ++i) { - buf[offset + i] = bytes[i]; - } + for (let i = 0; i < table._columns.length; i++) { + const column = table._columns[i]; + strategy.columns[column.alias] = {}; + if ('serializable' in column && !column.serializable) + strategy.columns[column.alias].serializable = false; + else + strategy.columns[column.alias].serializable = true; + } - return buf; - } + let relations = table._relations; + let relationName; - return stringify$3(bytes); - } // Function#name is not settable on some platforms (#270) + let visitor = {}; + visitor.visitJoin = function(relation) { + strategy.relations[relationName] = getMeta(relation.childTable, map); + }; + visitor.visitMany = function(relation) { + strategy.relations[relationName] = getMeta(relation.childTable, map); + }; - try { - generateUUID.name = name; // eslint-disable-next-line no-empty - } catch (err) {} // For CommonJS default export support - - - generateUUID.DNS = DNS; - generateUUID.URL = URL; - return generateUUID; -} - -/* - * Browser-compatible JavaScript MD5 - * - * Modification of JavaScript MD5 - * https://github.com/blueimp/JavaScript-MD5 - * - * Copyright 2011, Sebastian Tschan - * https://blueimp.net - * - * Licensed under the MIT license: - * https://opensource.org/licenses/MIT - * - * Based on - * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message - * Digest Algorithm, as defined in RFC 1321. - * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009 - * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet - * Distributed under the BSD License - * See http://pajhome.org.uk/crypt/md5 for more info. - */ -function md5(bytes) { - if (typeof bytes === 'string') { - var msg = unescape(encodeURIComponent(bytes)); // UTF8 escape - - bytes = new Uint8Array(msg.length); - - for (var i = 0; i < msg.length; ++i) { - bytes[i] = msg.charCodeAt(i); - } - } - - return md5ToHexEncodedArray(wordsToMd5(bytesToWords(bytes), bytes.length * 8)); -} -/* - * Convert an array of little-endian words to an array of bytes - */ - - -function md5ToHexEncodedArray(input) { - var output = []; - var length32 = input.length * 32; - var hexTab = '0123456789abcdef'; - - for (var i = 0; i < length32; i += 8) { - var x = input[i >> 5] >>> i % 32 & 0xff; - var hex = parseInt(hexTab.charAt(x >>> 4 & 0x0f) + hexTab.charAt(x & 0x0f), 16); - output.push(hex); - } - - return output; -} -/** - * Calculate output length with padding and bit length - */ - - -function getOutputLength(inputLength8) { - return (inputLength8 + 64 >>> 9 << 4) + 14 + 1; -} -/* - * Calculate the MD5 of an array of little-endian words, and a bit length. - */ - - -function wordsToMd5(x, len) { - /* append padding */ - x[len >> 5] |= 0x80 << len % 32; - x[getOutputLength(len) - 1] = len; - var a = 1732584193; - var b = -271733879; - var c = -1732584194; - var d = 271733878; - - for (var i = 0; i < x.length; i += 16) { - var olda = a; - var oldb = b; - var oldc = c; - var oldd = d; - a = md5ff(a, b, c, d, x[i], 7, -680876936); - d = md5ff(d, a, b, c, x[i + 1], 12, -389564586); - c = md5ff(c, d, a, b, x[i + 2], 17, 606105819); - b = md5ff(b, c, d, a, x[i + 3], 22, -1044525330); - a = md5ff(a, b, c, d, x[i + 4], 7, -176418897); - d = md5ff(d, a, b, c, x[i + 5], 12, 1200080426); - c = md5ff(c, d, a, b, x[i + 6], 17, -1473231341); - b = md5ff(b, c, d, a, x[i + 7], 22, -45705983); - a = md5ff(a, b, c, d, x[i + 8], 7, 1770035416); - d = md5ff(d, a, b, c, x[i + 9], 12, -1958414417); - c = md5ff(c, d, a, b, x[i + 10], 17, -42063); - b = md5ff(b, c, d, a, x[i + 11], 22, -1990404162); - a = md5ff(a, b, c, d, x[i + 12], 7, 1804603682); - d = md5ff(d, a, b, c, x[i + 13], 12, -40341101); - c = md5ff(c, d, a, b, x[i + 14], 17, -1502002290); - b = md5ff(b, c, d, a, x[i + 15], 22, 1236535329); - a = md5gg(a, b, c, d, x[i + 1], 5, -165796510); - d = md5gg(d, a, b, c, x[i + 6], 9, -1069501632); - c = md5gg(c, d, a, b, x[i + 11], 14, 643717713); - b = md5gg(b, c, d, a, x[i], 20, -373897302); - a = md5gg(a, b, c, d, x[i + 5], 5, -701558691); - d = md5gg(d, a, b, c, x[i + 10], 9, 38016083); - c = md5gg(c, d, a, b, x[i + 15], 14, -660478335); - b = md5gg(b, c, d, a, x[i + 4], 20, -405537848); - a = md5gg(a, b, c, d, x[i + 9], 5, 568446438); - d = md5gg(d, a, b, c, x[i + 14], 9, -1019803690); - c = md5gg(c, d, a, b, x[i + 3], 14, -187363961); - b = md5gg(b, c, d, a, x[i + 8], 20, 1163531501); - a = md5gg(a, b, c, d, x[i + 13], 5, -1444681467); - d = md5gg(d, a, b, c, x[i + 2], 9, -51403784); - c = md5gg(c, d, a, b, x[i + 7], 14, 1735328473); - b = md5gg(b, c, d, a, x[i + 12], 20, -1926607734); - a = md5hh(a, b, c, d, x[i + 5], 4, -378558); - d = md5hh(d, a, b, c, x[i + 8], 11, -2022574463); - c = md5hh(c, d, a, b, x[i + 11], 16, 1839030562); - b = md5hh(b, c, d, a, x[i + 14], 23, -35309556); - a = md5hh(a, b, c, d, x[i + 1], 4, -1530992060); - d = md5hh(d, a, b, c, x[i + 4], 11, 1272893353); - c = md5hh(c, d, a, b, x[i + 7], 16, -155497632); - b = md5hh(b, c, d, a, x[i + 10], 23, -1094730640); - a = md5hh(a, b, c, d, x[i + 13], 4, 681279174); - d = md5hh(d, a, b, c, x[i], 11, -358537222); - c = md5hh(c, d, a, b, x[i + 3], 16, -722521979); - b = md5hh(b, c, d, a, x[i + 6], 23, 76029189); - a = md5hh(a, b, c, d, x[i + 9], 4, -640364487); - d = md5hh(d, a, b, c, x[i + 12], 11, -421815835); - c = md5hh(c, d, a, b, x[i + 15], 16, 530742520); - b = md5hh(b, c, d, a, x[i + 2], 23, -995338651); - a = md5ii(a, b, c, d, x[i], 6, -198630844); - d = md5ii(d, a, b, c, x[i + 7], 10, 1126891415); - c = md5ii(c, d, a, b, x[i + 14], 15, -1416354905); - b = md5ii(b, c, d, a, x[i + 5], 21, -57434055); - a = md5ii(a, b, c, d, x[i + 12], 6, 1700485571); - d = md5ii(d, a, b, c, x[i + 3], 10, -1894986606); - c = md5ii(c, d, a, b, x[i + 10], 15, -1051523); - b = md5ii(b, c, d, a, x[i + 1], 21, -2054922799); - a = md5ii(a, b, c, d, x[i + 8], 6, 1873313359); - d = md5ii(d, a, b, c, x[i + 15], 10, -30611744); - c = md5ii(c, d, a, b, x[i + 6], 15, -1560198380); - b = md5ii(b, c, d, a, x[i + 13], 21, 1309151649); - a = md5ii(a, b, c, d, x[i + 4], 6, -145523070); - d = md5ii(d, a, b, c, x[i + 11], 10, -1120210379); - c = md5ii(c, d, a, b, x[i + 2], 15, 718787259); - b = md5ii(b, c, d, a, x[i + 9], 21, -343485551); - a = safeAdd(a, olda); - b = safeAdd(b, oldb); - c = safeAdd(c, oldc); - d = safeAdd(d, oldd); - } - - return [a, b, c, d]; -} -/* - * Convert an array bytes to an array of little-endian words - * Characters >255 have their high-byte silently ignored. - */ - - -function bytesToWords(input) { - if (input.length === 0) { - return []; - } - - var length8 = input.length * 8; - var output = new Uint32Array(getOutputLength(length8)); - - for (var i = 0; i < length8; i += 8) { - output[i >> 5] |= (input[i / 8] & 0xff) << i % 32; - } - - return output; -} -/* - * Add integers, wrapping at 2^32. This uses 16-bit operations internally - * to work around bugs in some JS interpreters. - */ - - -function safeAdd(x, y) { - var lsw = (x & 0xffff) + (y & 0xffff); - var msw = (x >> 16) + (y >> 16) + (lsw >> 16); - return msw << 16 | lsw & 0xffff; -} -/* - * Bitwise rotate a 32-bit number to the left. - */ - - -function bitRotateLeft(num, cnt) { - return num << cnt | num >>> 32 - cnt; -} -/* - * These functions implement the four basic operations the algorithm uses. - */ - - -function md5cmn(q, a, b, x, s, t) { - return safeAdd(bitRotateLeft(safeAdd(safeAdd(a, q), safeAdd(x, t)), s), b); -} + visitor.visitOne = visitor.visitMany; -function md5ff(a, b, c, d, x, s, t) { - return md5cmn(b & c | ~b & d, a, b, x, s, t); -} + for (relationName in relations) { + let relation = relations[relationName]; + relation.accept(visitor); + } + return strategy; + } -function md5gg(a, b, c, d, x, s, t) { - return md5cmn(b & d | c & ~d, a, b, x, s, t); + getMeta_1 = getMeta; + return getMeta_1; } -function md5hh(a, b, c, d, x, s, t) { - return md5cmn(b ^ c ^ d, a, b, x, s, t); -} +var hostExpress_1; +var hasRequiredHostExpress; + +function requireHostExpress () { + if (hasRequiredHostExpress) return hostExpress_1; + hasRequiredHostExpress = 1; + const getTSDefinition = requireGetTSDefinition(); + // let hostLocal = _hostLocal; + const getMeta = requireGetMeta(); + + function hostExpress(hostLocal, client, options = {}) { + if ('db' in options && (options.db ?? undefined) === undefined || !client.db) + throw new Error('No db specified'); + const dbOptions = { db: options.db || client.db }; + let c = {}; + const readonly = { readonly: options.readonly}; + for (let tableName in client.tables) { + c[tableName] = hostLocal({ + ...dbOptions, + ...readonly, + ...options[tableName], + table: client.tables[tableName], + isHttp: true, client -function md5ii(a, b, c, d, x, s, t) { - return md5cmn(c ^ (b | ~d), a, b, x, s, t); -} + }); + } -var v3 = v35('v3', 0x30, md5); -var v3$1 = v3; + async function handler(req, res) { + if (req.method === 'POST') + return post.apply(null, arguments); + if (req.method === 'PATCH') + return patch.apply(null, arguments); + if (req.method === 'GET') + return get.apply(null, arguments); + if (req.method === 'OPTIONS') + return handleOptions(req, res); // assuming the second argument is `response` -function v4(options, buf, offset) { - options = options || {}; - var rnds = options.random || (options.rng || rng)(); // Per 4.4, set bits for version and `clock_seq_hi_and_reserved` + else + res.status(405).set('Allow', 'GET, POST, PATCH, OPTIONS').send('Method Not Allowed'); + } - rnds[6] = rnds[6] & 0x0f | 0x40; - rnds[8] = rnds[8] & 0x3f | 0x80; // Copy bytes to buffer, if provided + handler.db = handler; + handler.dts = get; + + function get(request, response) { + try { + if (request.query.table) { + if (!(request.query.table in c)) { + let e = new Error('Table is not exposed or does not exist'); + // @ts-ignore + e.status = 400; + throw e; + } - if (buf) { - offset = offset || 0; + const result = getMeta(client.tables[request.query.table]); + response.setHeader('content-type', 'text/plain'); + response.status(200).send(result); + } + else { + const isNamespace = request.query.isNamespace === 'true'; + let tsArg = Object.keys(c).map(x => { + return { table: client.tables[x], customFilters: options?.tables?.[x].customFilters, name: x }; + }); + response.setHeader('content-type', 'text/plain'); + response.status(200).send(getTSDefinition(tsArg, { isNamespace, isHttp: true })); + } + } + catch (e) { + if (e.status === undefined) + response.status(500).send(e.message || e); + else + response.status(e.status).send(e.message); + } + } - for (var i = 0; i < 16; ++i) { - buf[offset + i] = rnds[i]; - } + async function patch(request, response) { + try { + response.json(await c[request.query.table].patch(request.body, request, response)); + } + catch (e) { + if (e.status === undefined) + response.status(500).send(e.message || e); + else + response.status(e.status).send(e.message); - return buf; - } + } + } - return stringify$3(rnds); -} + async function post(request, response) { + try { + if (!request.query.table) { + let e = new Error('Table not defined'); + // @ts-ignore + e.status = 400; + throw e; + } + else if (!(request.query.table in c)) { + let e = new Error('Table is not exposed or does not exist'); + // @ts-ignore + e.status = 400; + throw e; + } -// Adapted from Chris Veness' SHA1 code at -// http://www.movable-type.co.uk/scripts/sha1.html -function f(s, x, y, z) { - switch (s) { - case 0: - return x & y ^ ~x & z; + response.json(await c[request.query.table].post(request.body, request, response)); + } + catch (e) { + if (e.status === undefined) + response.status(500).send(e.message || e); + else + response.status(e.status).send(e.message); + } - case 1: - return x ^ y ^ z; + } - case 2: - return x & y ^ x & z ^ y & z; + function handleOptions(req, response) { + response.setHeader('Access-Control-Allow-Origin', '*'); // Adjust this as per your CORS needs + response.setHeader('Access-Control-Allow-Methods', 'GET, POST, PATCH, OPTIONS'); // And any other methods you support + response.setHeader('Access-Control-Allow-Headers', 'Content-Type'); // And any other headers you expect in requests + response.setHeader('Access-Control-Max-Age', '86400'); // Cache preflight request for a day. Adjust as you see fit + response.status(204).send(); // 204 No Content response for successful OPTIONS requests + } - case 3: - return x ^ y ^ z; - } -} + return handler; + } -function ROTL(x, n) { - return x << n | x >>> 32 - n; + hostExpress_1 = hostExpress; + return hostExpress_1; } -function sha1(bytes) { - var K = [0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6]; - var H = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0]; - - if (typeof bytes === 'string') { - var msg = unescape(encodeURIComponent(bytes)); // UTF8 escape - - bytes = []; +var require$$0$3 = /*@__PURE__*/getDefaultExportFromNamespaceIfPresent(fastJsonPatch); - for (var i = 0; i < msg.length; ++i) { - bytes.push(msg.charCodeAt(i)); - } - } else if (!Array.isArray(bytes)) { - // Convert Array-like to Array - bytes = Array.prototype.slice.call(bytes); - } +var dateToISOString_1; +var hasRequiredDateToISOString; - bytes.push(0x80); - var l = bytes.length / 4 + 2; - var N = Math.ceil(l / 16); - var M = new Array(N); +function requireDateToISOString () { + if (hasRequiredDateToISOString) return dateToISOString_1; + hasRequiredDateToISOString = 1; + function dateToISOString(date) { + let tzo = -date.getTimezoneOffset(); + let dif = tzo >= 0 ? '+' : '-'; - for (var _i = 0; _i < N; ++_i) { - var arr = new Uint32Array(16); - - for (var j = 0; j < 16; ++j) { - arr[j] = bytes[_i * 64 + j * 4] << 24 | bytes[_i * 64 + j * 4 + 1] << 16 | bytes[_i * 64 + j * 4 + 2] << 8 | bytes[_i * 64 + j * 4 + 3]; - } - - M[_i] = arr; - } + function pad(num) { + let norm = Math.floor(Math.abs(num)); + return (norm < 10 ? '0' : '') + norm; + } - M[N - 1][14] = (bytes.length - 1) * 8 / Math.pow(2, 32); - M[N - 1][14] = Math.floor(M[N - 1][14]); - M[N - 1][15] = (bytes.length - 1) * 8 & 0xffffffff; + function padMilli(d) { + return (d.getMilliseconds() + '').padStart(3, '0'); + } - for (var _i2 = 0; _i2 < N; ++_i2) { - var W = new Uint32Array(80); + return date.getFullYear() + + '-' + pad(date.getMonth() + 1) + + '-' + pad(date.getDate()) + + 'T' + pad(date.getHours()) + + ':' + pad(date.getMinutes()) + + ':' + pad(date.getSeconds()) + + '.' + padMilli(date) + + dif + pad(tzo / 60) + + ':' + pad(tzo % 60); + } - for (var t = 0; t < 16; ++t) { - W[t] = M[_i2][t]; - } + dateToISOString_1 = dateToISOString; + return dateToISOString_1; +} - for (var _t = 16; _t < 80; ++_t) { - W[_t] = ROTL(W[_t - 3] ^ W[_t - 8] ^ W[_t - 14] ^ W[_t - 16], 1); - } +var stringify_1; +var hasRequiredStringify; - var a = H[0]; - var b = H[1]; - var c = H[2]; - var d = H[3]; - var e = H[4]; +function requireStringify () { + if (hasRequiredStringify) return stringify_1; + hasRequiredStringify = 1; + let dateToISOString = requireDateToISOString(); - for (var _t2 = 0; _t2 < 80; ++_t2) { - var s = Math.floor(_t2 / 20); - var T = ROTL(a, 5) + f(s, b, c, d) + e + K[s] + W[_t2] >>> 0; - e = d; - d = c; - c = ROTL(b, 30) >>> 0; - b = a; - a = T; - } - - H[0] = H[0] + a >>> 0; - H[1] = H[1] + b >>> 0; - H[2] = H[2] + c >>> 0; - H[3] = H[3] + d >>> 0; - H[4] = H[4] + e >>> 0; - } - - return [H[0] >> 24 & 0xff, H[0] >> 16 & 0xff, H[0] >> 8 & 0xff, H[0] & 0xff, H[1] >> 24 & 0xff, H[1] >> 16 & 0xff, H[1] >> 8 & 0xff, H[1] & 0xff, H[2] >> 24 & 0xff, H[2] >> 16 & 0xff, H[2] >> 8 & 0xff, H[2] & 0xff, H[3] >> 24 & 0xff, H[3] >> 16 & 0xff, H[3] >> 8 & 0xff, H[3] & 0xff, H[4] >> 24 & 0xff, H[4] >> 16 & 0xff, H[4] >> 8 & 0xff, H[4] & 0xff]; -} - -var v5 = v35('v5', 0x50, sha1); -var v5$1 = v5; - -var nil = '00000000-0000-0000-0000-000000000000'; - -function version(uuid) { - if (!validate(uuid)) { - throw TypeError('Invalid UUID'); - } - - return parseInt(uuid.substr(14, 1), 16); -} - -var esmBrowser = /*#__PURE__*/Object.freeze({ - __proto__: null, - v1: v1, - v3: v3$1, - v4: v4, - v5: v5$1, - NIL: nil, - version: version, - validate: validate, - stringify: stringify$3, - parse: parse -}); - -var require$$1 = /*@__PURE__*/getAugmentedNamespace(esmBrowser); - -const jsonpatch = require$$0; -let dateToIsoString = dateToISOString_1; -let stringify$2 = stringify_1; -let { v4: uuid$1 } = require$$1; - -var createPatch$1 = function createPatch(original, dto, options) { - let subject = toCompareObject({ d: original }, options, true); - let clonedDto = toCompareObject({ d: dto }, options, true); - let keyPositionMap = toKeyPositionMap(dto); - let observer = jsonpatch.observe(subject); - subject.d = clonedDto.d; - let changes = jsonpatch.generate(observer); - let clonedOriginal = toCompareObject(original, options); - let {inserted, deleted, updated} = splitChanges(changes); - updated.sort(comparePatch); - return [...inserted, ...updated, ...deleted]; - - function splitChanges(changes) { - let inserted = []; - let deleted = []; - let updated = []; - for (let change of changes) { - change.path = change.path.substring(2); - if (change.op === 'add' && change.path.split('/').length === 2) { - inserted.push(change); - } - else if (change.op === 'remove' && change.path.split('/').length === 2) { - addOldValue(change); - deleted.push(change); - } else { - addOldValue(change); - updated.push(change); - } - } - return { inserted, updated, deleted}; + function stringify(value) { + return JSON.stringify(value, replacer); } - function addOldValue(change) { - if (change.op === 'remove' || change.op === 'replace') { - let splitPath = change.path.split('/'); - splitPath.shift(); - change.oldValue = splitPath.reduce(extract, clonedOriginal); - } + function replacer(key, value) { + // // @ts-ignore + if (value instanceof Date && !isNaN(value)) + return dateToISOString(value); else - return change; - - function extract(obj, element) { - return obj[element]; - } - - return change; + return value; } - function toKeyPositionMap(rows) { - return rows.reduce((map, element, i) => { - if (options && options.keys && element === Object(element)) { - let key = []; - for (let i = 0; i < options.keys.length; i++) { - let keyName = options.keys[i].name; - key.push(negotiateTempKey(element[keyName])); + stringify_1 = stringify; + return stringify_1; +} + +var require$$0$2 = /*@__PURE__*/getDefaultExportFromNamespaceIfPresent(uuid); + +var createPatch; +var hasRequiredCreatePatch; + +function requireCreatePatch () { + if (hasRequiredCreatePatch) return createPatch; + hasRequiredCreatePatch = 1; + const jsonpatch = require$$0$3; + let dateToIsoString = requireDateToISOString(); + let stringify = requireStringify(); + let { v4: uuid } = require$$0$2; + + createPatch = function createPatch(original, dto, options) { + let subject = toCompareObject({ d: original }, options, true); + let clonedDto = toCompareObject({ d: dto }, options, true); + let keyPositionMap = toKeyPositionMap(dto); + let observer = jsonpatch.observe(subject); + subject.d = clonedDto.d; + let changes = jsonpatch.generate(observer); + let clonedOriginal = toCompareObject(original, options); + let {inserted, deleted, updated} = splitChanges(changes); + updated.sort(comparePatch); + return [...inserted, ...updated, ...deleted]; + + function splitChanges(changes) { + let inserted = []; + let deleted = []; + let updated = []; + for (let change of changes) { + change.path = change.path.substring(2); + if (change.op === 'add' && change.path.split('/').length === 2) { + inserted.push(change); + } + else if (change.op === 'remove' && change.path.split('/').length === 2) { + addOldValue(change); + deleted.push(change); + } else { + addOldValue(change); + updated.push(change); } - map[stringify$2(key)] = i; } - else if ('id' in element) - map[stringify$2([element.id])] = i; + return { inserted, updated, deleted}; + } + + function addOldValue(change) { + if (change.op === 'remove' || change.op === 'replace') { + let splitPath = change.path.split('/'); + splitPath.shift(); + change.oldValue = splitPath.reduce(extract, clonedOriginal); + } else - map[i] = i; - return map; - }, {}); + return change; - } + function extract(obj, element) { + return obj[element]; + } - function toCompareObject(object, options, isRoot) { - if (Array.isArray(object)) { - let copy = { __patchType: 'Array' }; - for (let i = 0; i < object.length; i++) { - let element = toCompareObject(object[i], options); + return change; + } + + function toKeyPositionMap(rows) { + return rows.reduce((map, element, i) => { if (options && options.keys && element === Object(element)) { let key = []; for (let i = 0; i < options.keys.length; i++) { let keyName = options.keys[i].name; key.push(negotiateTempKey(element[keyName])); } - copy[stringify$2(key)] = element; + map[stringify(key)] = i; } - else if (element === Object(element) && 'id' in element) - copy[stringify$2([element.id])] = element; + else if ('id' in element) + map[stringify([element.id])] = i; else - copy[i] = element; - } - return copy; + map[i] = i; + return map; + }, {}); + } - else if (isValidDate(object)) - return dateToIsoString(object); - else if (object === Object(object)) { - let copy = {}; - for (let name in object) { - copy[name] = toCompareObject(object[name], isRoot ? options : options && options.relations && options.relations[name]); + + function toCompareObject(object, options, isRoot) { + if (Array.isArray(object)) { + let copy = { __patchType: 'Array' }; + for (let i = 0; i < object.length; i++) { + let element = toCompareObject(object[i], options); + if (options && options.keys && element === Object(element)) { + let key = []; + for (let i = 0; i < options.keys.length; i++) { + let keyName = options.keys[i].name; + key.push(negotiateTempKey(element[keyName])); + } + copy[stringify(key)] = element; + } + else if (element === Object(element) && 'id' in element) + copy[stringify([element.id])] = element; + else + copy[i] = element; + } + return copy; } - return copy; + else if (isValidDate(object)) + return dateToIsoString(object); + else if (object === Object(object)) { + let copy = {}; + for (let name in object) { + copy[name] = toCompareObject(object[name], isRoot ? options : options && options.relations && options.relations[name]); + } + return copy; + } + return object; } - return object; - } - function isValidDate(d) { - return d instanceof Date && !isNaN(d); - } + function isValidDate(d) { + return d instanceof Date && !isNaN(d); + } - function negotiateTempKey(value) { - if (value === undefined) - return `~${uuid$1()}`; - else - return value; - } + function negotiateTempKey(value) { + if (value === undefined) + return `~${uuid()}`; + else + return value; + } + + function comparePatch(a, b) { + const aPathArray = a.path.split('/'); + const bPathArray = b.path.split('/'); + return (aPathArray.length - bPathArray.length) || (keyPositionMap[aPathArray[1]] ?? Infinity - keyPositionMap[bPathArray[1]] ?? Infinity) || a.path.localeCompare(b.path); + } + + }; + return createPatch; +} - function comparePatch(a, b) { - const aPathArray = a.path.split('/'); - const bPathArray = b.path.split('/'); - return (aPathArray.length - bPathArray.length) || (keyPositionMap[aPathArray[1]] ?? Infinity - keyPositionMap[bPathArray[1]] ?? Infinity) || a.path.localeCompare(b.path); +var extractSql; +var hasRequiredExtractSql; + +function requireExtractSql () { + if (hasRequiredExtractSql) return extractSql; + hasRequiredExtractSql = 1; + function extract(sql) { + if (sql && typeof(sql) === 'function') + return sql(); + else if (sql === undefined) + return ''; + else + return sql; } -}; + extractSql = extract; + return extractSql; +} -let dateToISOString = dateToISOString_1; +var extractParameters; +var hasRequiredExtractParameters; -function cloneFromDbFast(obj) { - if (obj === null || typeof obj !== 'object') - return obj; - if (Array.isArray(obj)) { - const arrClone = []; - for (let i = 0; i < obj.length; i++) { - arrClone[i] = cloneFromDbFast(obj[i]); +function requireExtractParameters () { + if (hasRequiredExtractParameters) return extractParameters; + hasRequiredExtractParameters = 1; + function extract(parameters) { + if (parameters) { + return parameters.slice(0); } - return arrClone; - } - const clone = {}; - const keys = Object.keys(obj); - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - clone[key] = cloneFromDbFast(obj[key]); + return []; } - return clone; -} -function cloneRegular(obj) { - if (obj === null || typeof obj !== 'object') - return obj; - if (Array.isArray(obj)) { - const arrClone = []; - for (let i = 0; i < obj.length; i++) { - arrClone[i] = cloneRegular(obj[i]); - } - return arrClone; - } - else if (obj instanceof Date && !isNaN(obj)) - return dateToISOString(obj); - const clone = {}; - const keys = Object.keys(obj); - for (let i = 0; i < keys.length; i++) { - const key = keys[i]; - clone[key] = cloneRegular(obj[key]); - } - return clone; -} - -function cloneFromDb$1(obj, isFast) { - if (isFast) - return cloneFromDbFast(obj); - else - return cloneRegular(obj); -} - -var cloneFromDb_1 = cloneFromDb$1; - -function bind(fn, thisArg) { - return function wrap() { - return fn.apply(thisArg, arguments); - }; -} - -// utils is a library of generic helper functions non-specific to axios - -const {toString} = Object.prototype; -const {getPrototypeOf} = Object; - -const kindOf = (cache => thing => { - const str = toString.call(thing); - return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase()); -})(Object.create(null)); - -const kindOfTest = (type) => { - type = type.toLowerCase(); - return (thing) => kindOf(thing) === type -}; - -const typeOfTest = type => thing => typeof thing === type; - -/** - * Determine if a value is an Array - * - * @param {Object} val The value to test - * - * @returns {boolean} True if value is an Array, otherwise false - */ -const {isArray} = Array; - -/** - * Determine if a value is undefined - * - * @param {*} val The value to test - * - * @returns {boolean} True if the value is undefined, otherwise false - */ -const isUndefined = typeOfTest('undefined'); - -/** - * Determine if a value is a Buffer - * - * @param {*} val The value to test - * - * @returns {boolean} True if value is a Buffer, otherwise false - */ -function isBuffer(val) { - return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor) - && isFunction(val.constructor.isBuffer) && val.constructor.isBuffer(val); -} - -/** - * Determine if a value is an ArrayBuffer - * - * @param {*} val The value to test - * - * @returns {boolean} True if value is an ArrayBuffer, otherwise false - */ -const isArrayBuffer = kindOfTest('ArrayBuffer'); - - -/** - * Determine if a value is a view on an ArrayBuffer - * - * @param {*} val The value to test - * - * @returns {boolean} True if value is a view on an ArrayBuffer, otherwise false - */ -function isArrayBufferView(val) { - let result; - if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) { - result = ArrayBuffer.isView(val); - } else { - result = (val) && (val.buffer) && (isArrayBuffer(val.buffer)); - } - return result; -} - -/** - * Determine if a value is a String - * - * @param {*} val The value to test - * - * @returns {boolean} True if value is a String, otherwise false - */ -const isString = typeOfTest('string'); - -/** - * Determine if a value is a Function - * - * @param {*} val The value to test - * @returns {boolean} True if value is a Function, otherwise false - */ -const isFunction = typeOfTest('function'); - -/** - * Determine if a value is a Number - * - * @param {*} val The value to test - * - * @returns {boolean} True if value is a Number, otherwise false - */ -const isNumber = typeOfTest('number'); - -/** - * Determine if a value is an Object - * - * @param {*} thing The value to test - * - * @returns {boolean} True if value is an Object, otherwise false - */ -const isObject = (thing) => thing !== null && typeof thing === 'object'; - -/** - * Determine if a value is a Boolean - * - * @param {*} thing The value to test - * @returns {boolean} True if value is a Boolean, otherwise false - */ -const isBoolean = thing => thing === true || thing === false; - -/** - * Determine if a value is a plain Object - * - * @param {*} val The value to test - * - * @returns {boolean} True if value is a plain Object, otherwise false - */ -const isPlainObject = (val) => { - if (kindOf(val) !== 'object') { - return false; - } - - const prototype = getPrototypeOf(val); - return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in val) && !(Symbol.iterator in val); -}; - -/** - * Determine if a value is a Date - * - * @param {*} val The value to test - * - * @returns {boolean} True if value is a Date, otherwise false - */ -const isDate = kindOfTest('Date'); - -/** - * Determine if a value is a File - * - * @param {*} val The value to test - * - * @returns {boolean} True if value is a File, otherwise false - */ -const isFile = kindOfTest('File'); - -/** - * Determine if a value is a Blob - * - * @param {*} val The value to test - * - * @returns {boolean} True if value is a Blob, otherwise false - */ -const isBlob = kindOfTest('Blob'); - -/** - * Determine if a value is a FileList - * - * @param {*} val The value to test - * - * @returns {boolean} True if value is a File, otherwise false - */ -const isFileList = kindOfTest('FileList'); - -/** - * Determine if a value is a Stream - * - * @param {*} val The value to test - * - * @returns {boolean} True if value is a Stream, otherwise false - */ -const isStream = (val) => isObject(val) && isFunction(val.pipe); - -/** - * Determine if a value is a FormData - * - * @param {*} thing The value to test - * - * @returns {boolean} True if value is an FormData, otherwise false - */ -const isFormData = (thing) => { - let kind; - return thing && ( - (typeof FormData === 'function' && thing instanceof FormData) || ( - isFunction(thing.append) && ( - (kind = kindOf(thing)) === 'formdata' || - // detect form-data instance - (kind === 'object' && isFunction(thing.toString) && thing.toString() === '[object FormData]') - ) - ) - ) -}; - -/** - * Determine if a value is a URLSearchParams object - * - * @param {*} val The value to test - * - * @returns {boolean} True if value is a URLSearchParams object, otherwise false - */ -const isURLSearchParams = kindOfTest('URLSearchParams'); - -const [isReadableStream, isRequest, isResponse, isHeaders] = ['ReadableStream', 'Request', 'Response', 'Headers'].map(kindOfTest); - -/** - * Trim excess whitespace off the beginning and end of a string - * - * @param {String} str The String to trim - * - * @returns {String} The String freed of excess whitespace - */ -const trim = (str) => str.trim ? - str.trim() : str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ''); - -/** - * Iterate over an Array or an Object invoking a function for each item. - * - * If `obj` is an Array callback will be called passing - * the value, index, and complete array for each item. - * - * If 'obj' is an Object callback will be called passing - * the value, key, and complete object for each property. - * - * @param {Object|Array} obj The object to iterate - * @param {Function} fn The callback to invoke for each item - * - * @param {Boolean} [allOwnKeys = false] - * @returns {any} - */ -function forEach(obj, fn, {allOwnKeys = false} = {}) { - // Don't bother if no value provided - if (obj === null || typeof obj === 'undefined') { - return; - } - - let i; - let l; - - // Force an array if not already something iterable - if (typeof obj !== 'object') { - /*eslint no-param-reassign:0*/ - obj = [obj]; - } - - if (isArray(obj)) { - // Iterate over array values - for (i = 0, l = obj.length; i < l; i++) { - fn.call(null, obj[i], i, obj); - } - } else { - // Iterate over object keys - const keys = allOwnKeys ? Object.getOwnPropertyNames(obj) : Object.keys(obj); - const len = keys.length; - let key; - - for (i = 0; i < len; i++) { - key = keys[i]; - fn.call(null, obj[key], key, obj); - } - } -} - -function findKey(obj, key) { - key = key.toLowerCase(); - const keys = Object.keys(obj); - let i = keys.length; - let _key; - while (i-- > 0) { - _key = keys[i]; - if (key === _key.toLowerCase()) { - return _key; - } - } - return null; -} - -const _global = (() => { - /*eslint no-undef:0*/ - if (typeof globalThis !== "undefined") return globalThis; - return typeof self !== "undefined" ? self : (typeof window !== 'undefined' ? window : commonjsGlobal) -})(); - -const isContextDefined = (context) => !isUndefined(context) && context !== _global; - -/** - * Accepts varargs expecting each argument to be an object, then - * immutably merges the properties of each object and returns result. - * - * When multiple objects contain the same key the later object in - * the arguments list will take precedence. - * - * Example: - * - * ```js - * var result = merge({foo: 123}, {foo: 456}); - * console.log(result.foo); // outputs 456 - * ``` - * - * @param {Object} obj1 Object to merge - * - * @returns {Object} Result of all merge properties - */ -function merge(/* obj1, obj2, obj3, ... */) { - const {caseless} = isContextDefined(this) && this || {}; - const result = {}; - const assignValue = (val, key) => { - const targetKey = caseless && findKey(result, key) || key; - if (isPlainObject(result[targetKey]) && isPlainObject(val)) { - result[targetKey] = merge(result[targetKey], val); - } else if (isPlainObject(val)) { - result[targetKey] = merge({}, val); - } else if (isArray(val)) { - result[targetKey] = val.slice(); - } else { - result[targetKey] = val; - } - }; - - for (let i = 0, l = arguments.length; i < l; i++) { - arguments[i] && forEach(arguments[i], assignValue); - } - return result; -} - -/** - * Extends object a by mutably adding to it the properties of object b. - * - * @param {Object} a The object to be extended - * @param {Object} b The object to copy properties from - * @param {Object} thisArg The object to bind function to - * - * @param {Boolean} [allOwnKeys] - * @returns {Object} The resulting value of object a - */ -const extend = (a, b, thisArg, {allOwnKeys}= {}) => { - forEach(b, (val, key) => { - if (thisArg && isFunction(val)) { - a[key] = bind(val, thisArg); - } else { - a[key] = val; - } - }, {allOwnKeys}); - return a; -}; - -/** - * Remove byte order marker. This catches EF BB BF (the UTF-8 BOM) - * - * @param {string} content with BOM - * - * @returns {string} content value without BOM - */ -const stripBOM = (content) => { - if (content.charCodeAt(0) === 0xFEFF) { - content = content.slice(1); - } - return content; -}; - -/** - * Inherit the prototype methods from one constructor into another - * @param {function} constructor - * @param {function} superConstructor - * @param {object} [props] - * @param {object} [descriptors] - * - * @returns {void} - */ -const inherits = (constructor, superConstructor, props, descriptors) => { - constructor.prototype = Object.create(superConstructor.prototype, descriptors); - constructor.prototype.constructor = constructor; - Object.defineProperty(constructor, 'super', { - value: superConstructor.prototype - }); - props && Object.assign(constructor.prototype, props); -}; - -/** - * Resolve object with deep prototype chain to a flat object - * @param {Object} sourceObj source object - * @param {Object} [destObj] - * @param {Function|Boolean} [filter] - * @param {Function} [propFilter] - * - * @returns {Object} - */ -const toFlatObject = (sourceObj, destObj, filter, propFilter) => { - let props; - let i; - let prop; - const merged = {}; - - destObj = destObj || {}; - // eslint-disable-next-line no-eq-null,eqeqeq - if (sourceObj == null) return destObj; - - do { - props = Object.getOwnPropertyNames(sourceObj); - i = props.length; - while (i-- > 0) { - prop = props[i]; - if ((!propFilter || propFilter(prop, sourceObj, destObj)) && !merged[prop]) { - destObj[prop] = sourceObj[prop]; - merged[prop] = true; - } - } - sourceObj = filter !== false && getPrototypeOf(sourceObj); - } while (sourceObj && (!filter || filter(sourceObj, destObj)) && sourceObj !== Object.prototype); - - return destObj; -}; - -/** - * Determines whether a string ends with the characters of a specified string - * - * @param {String} str - * @param {String} searchString - * @param {Number} [position= 0] - * - * @returns {boolean} - */ -const endsWith = (str, searchString, position) => { - str = String(str); - if (position === undefined || position > str.length) { - position = str.length; - } - position -= searchString.length; - const lastIndex = str.indexOf(searchString, position); - return lastIndex !== -1 && lastIndex === position; -}; - - -/** - * Returns new array from array like object or null if failed - * - * @param {*} [thing] - * - * @returns {?Array} - */ -const toArray = (thing) => { - if (!thing) return null; - if (isArray(thing)) return thing; - let i = thing.length; - if (!isNumber(i)) return null; - const arr = new Array(i); - while (i-- > 0) { - arr[i] = thing[i]; - } - return arr; -}; - -/** - * Checking if the Uint8Array exists and if it does, it returns a function that checks if the - * thing passed in is an instance of Uint8Array - * - * @param {TypedArray} - * - * @returns {Array} - */ -// eslint-disable-next-line func-names -const isTypedArray = (TypedArray => { - // eslint-disable-next-line func-names - return thing => { - return TypedArray && thing instanceof TypedArray; - }; -})(typeof Uint8Array !== 'undefined' && getPrototypeOf(Uint8Array)); - -/** - * For each entry in the object, call the function with the key and value. - * - * @param {Object} obj - The object to iterate over. - * @param {Function} fn - The function to call for each entry. - * - * @returns {void} - */ -const forEachEntry = (obj, fn) => { - const generator = obj && obj[Symbol.iterator]; - - const iterator = generator.call(obj); - - let result; - - while ((result = iterator.next()) && !result.done) { - const pair = result.value; - fn.call(obj, pair[0], pair[1]); - } -}; - -/** - * It takes a regular expression and a string, and returns an array of all the matches - * - * @param {string} regExp - The regular expression to match against. - * @param {string} str - The string to search. - * - * @returns {Array} - */ -const matchAll = (regExp, str) => { - let matches; - const arr = []; - - while ((matches = regExp.exec(str)) !== null) { - arr.push(matches); - } - - return arr; -}; - -/* Checking if the kindOfTest function returns true when passed an HTMLFormElement. */ -const isHTMLForm = kindOfTest('HTMLFormElement'); - -const toCamelCase = str => { - return str.toLowerCase().replace(/[-_\s]([a-z\d])(\w*)/g, - function replacer(m, p1, p2) { - return p1.toUpperCase() + p2; - } - ); -}; - -/* Creating a function that will check if an object has a property. */ -const hasOwnProperty = (({hasOwnProperty}) => (obj, prop) => hasOwnProperty.call(obj, prop))(Object.prototype); - -/** - * Determine if a value is a RegExp object - * - * @param {*} val The value to test - * - * @returns {boolean} True if value is a RegExp object, otherwise false - */ -const isRegExp = kindOfTest('RegExp'); - -const reduceDescriptors = (obj, reducer) => { - const descriptors = Object.getOwnPropertyDescriptors(obj); - const reducedDescriptors = {}; - - forEach(descriptors, (descriptor, name) => { - let ret; - if ((ret = reducer(descriptor, name, obj)) !== false) { - reducedDescriptors[name] = ret || descriptor; - } - }); - - Object.defineProperties(obj, reducedDescriptors); -}; - -/** - * Makes all methods read-only - * @param {Object} obj - */ - -const freezeMethods = (obj) => { - reduceDescriptors(obj, (descriptor, name) => { - // skip restricted props in strict mode - if (isFunction(obj) && ['arguments', 'caller', 'callee'].indexOf(name) !== -1) { - return false; - } - - const value = obj[name]; - - if (!isFunction(value)) return; - - descriptor.enumerable = false; - - if ('writable' in descriptor) { - descriptor.writable = false; - return; - } - - if (!descriptor.set) { - descriptor.set = () => { - throw Error('Can not rewrite read-only method \'' + name + '\''); - }; - } - }); -}; - -const toObjectSet = (arrayOrString, delimiter) => { - const obj = {}; - - const define = (arr) => { - arr.forEach(value => { - obj[value] = true; - }); - }; - - isArray(arrayOrString) ? define(arrayOrString) : define(String(arrayOrString).split(delimiter)); - - return obj; -}; - -const noop = () => {}; - -const toFiniteNumber = (value, defaultValue) => { - return value != null && Number.isFinite(value = +value) ? value : defaultValue; -}; - -const ALPHA = 'abcdefghijklmnopqrstuvwxyz'; - -const DIGIT = '0123456789'; - -const ALPHABET = { - DIGIT, - ALPHA, - ALPHA_DIGIT: ALPHA + ALPHA.toUpperCase() + DIGIT -}; - -const generateString = (size = 16, alphabet = ALPHABET.ALPHA_DIGIT) => { - let str = ''; - const {length} = alphabet; - while (size--) { - str += alphabet[Math.random() * length|0]; - } - - return str; -}; - -/** - * If the thing is a FormData object, return true, otherwise return false. - * - * @param {unknown} thing - The thing to check. - * - * @returns {boolean} - */ -function isSpecCompliantForm(thing) { - return !!(thing && isFunction(thing.append) && thing[Symbol.toStringTag] === 'FormData' && thing[Symbol.iterator]); -} - -const toJSONObject = (obj) => { - const stack = new Array(10); - - const visit = (source, i) => { - - if (isObject(source)) { - if (stack.indexOf(source) >= 0) { - return; - } - - if(!('toJSON' in source)) { - stack[i] = source; - const target = isArray(source) ? [] : {}; - - forEach(source, (value, key) => { - const reducedValue = visit(value, i + 1); - !isUndefined(reducedValue) && (target[key] = reducedValue); - }); - - stack[i] = undefined; - - return target; - } - } - - return source; - }; - - return visit(obj, 0); -}; - -const isAsyncFn = kindOfTest('AsyncFunction'); - -const isThenable = (thing) => - thing && (isObject(thing) || isFunction(thing)) && isFunction(thing.then) && isFunction(thing.catch); - -// original code -// https://github.com/DigitalBrainJS/AxiosPromise/blob/16deab13710ec09779922131f3fa5954320f83ab/lib/utils.js#L11-L34 - -const _setImmediate = ((setImmediateSupported, postMessageSupported) => { - if (setImmediateSupported) { - return setImmediate; - } - - return postMessageSupported ? ((token, callbacks) => { - _global.addEventListener("message", ({source, data}) => { - if (source === _global && data === token) { - callbacks.length && callbacks.shift()(); - } - }, false); - - return (cb) => { - callbacks.push(cb); - _global.postMessage(token, "*"); - } - })(`axios@${Math.random()}`, []) : (cb) => setTimeout(cb); -})( - typeof setImmediate === 'function', - isFunction(_global.postMessage) -); - -const asap = typeof queueMicrotask !== 'undefined' ? - queueMicrotask.bind(_global) : ( typeof process !== 'undefined' && process.nextTick || _setImmediate); - -// ********************* - -var utils$1 = { - isArray, - isArrayBuffer, - isBuffer, - isFormData, - isArrayBufferView, - isString, - isNumber, - isBoolean, - isObject, - isPlainObject, - isReadableStream, - isRequest, - isResponse, - isHeaders, - isUndefined, - isDate, - isFile, - isBlob, - isRegExp, - isFunction, - isStream, - isURLSearchParams, - isTypedArray, - isFileList, - forEach, - merge, - extend, - trim, - stripBOM, - inherits, - toFlatObject, - kindOf, - kindOfTest, - endsWith, - toArray, - forEachEntry, - matchAll, - isHTMLForm, - hasOwnProperty, - hasOwnProp: hasOwnProperty, // an alias to avoid ESLint no-prototype-builtins detection - reduceDescriptors, - freezeMethods, - toObjectSet, - toCamelCase, - noop, - toFiniteNumber, - findKey, - global: _global, - isContextDefined, - ALPHABET, - generateString, - isSpecCompliantForm, - toJSONObject, - isAsyncFn, - isThenable, - setImmediate: _setImmediate, - asap -}; - -/** - * Create an Error with the specified message, config, error code, request and response. - * - * @param {string} message The error message. - * @param {string} [code] The error code (for example, 'ECONNABORTED'). - * @param {Object} [config] The config. - * @param {Object} [request] The request. - * @param {Object} [response] The response. - * - * @returns {Error} The created error. - */ -function AxiosError(message, code, config, request, response) { - Error.call(this); - - if (Error.captureStackTrace) { - Error.captureStackTrace(this, this.constructor); - } else { - this.stack = (new Error()).stack; - } - - this.message = message; - this.name = 'AxiosError'; - code && (this.code = code); - config && (this.config = config); - request && (this.request = request); - if (response) { - this.response = response; - this.status = response.status ? response.status : null; - } -} - -utils$1.inherits(AxiosError, Error, { - toJSON: function toJSON() { - return { - // Standard - message: this.message, - name: this.name, - // Microsoft - description: this.description, - number: this.number, - // Mozilla - fileName: this.fileName, - lineNumber: this.lineNumber, - columnNumber: this.columnNumber, - stack: this.stack, - // Axios - config: utils$1.toJSONObject(this.config), - code: this.code, - status: this.status - }; - } -}); - -const prototype$1 = AxiosError.prototype; -const descriptors = {}; - -[ - 'ERR_BAD_OPTION_VALUE', - 'ERR_BAD_OPTION', - 'ECONNABORTED', - 'ETIMEDOUT', - 'ERR_NETWORK', - 'ERR_FR_TOO_MANY_REDIRECTS', - 'ERR_DEPRECATED', - 'ERR_BAD_RESPONSE', - 'ERR_BAD_REQUEST', - 'ERR_CANCELED', - 'ERR_NOT_SUPPORT', - 'ERR_INVALID_URL' -// eslint-disable-next-line func-names -].forEach(code => { - descriptors[code] = {value: code}; -}); - -Object.defineProperties(AxiosError, descriptors); -Object.defineProperty(prototype$1, 'isAxiosError', {value: true}); - -// eslint-disable-next-line func-names -AxiosError.from = (error, code, config, request, response, customProps) => { - const axiosError = Object.create(prototype$1); - - utils$1.toFlatObject(error, axiosError, function filter(obj) { - return obj !== Error.prototype; - }, prop => { - return prop !== 'isAxiosError'; - }); - - AxiosError.call(axiosError, error.message, code, config, request, response); - - axiosError.cause = error; - - axiosError.name = error.name; - - customProps && Object.assign(axiosError, customProps); - - return axiosError; -}; - -// eslint-disable-next-line strict -var httpAdapter$1 = null; - -/** - * Determines if the given thing is a array or js object. - * - * @param {string} thing - The object or array to be visited. - * - * @returns {boolean} - */ -function isVisitable(thing) { - return utils$1.isPlainObject(thing) || utils$1.isArray(thing); -} - -/** - * It removes the brackets from the end of a string - * - * @param {string} key - The key of the parameter. - * - * @returns {string} the key without the brackets. - */ -function removeBrackets(key) { - return utils$1.endsWith(key, '[]') ? key.slice(0, -2) : key; -} - -/** - * It takes a path, a key, and a boolean, and returns a string - * - * @param {string} path - The path to the current key. - * @param {string} key - The key of the current object being iterated over. - * @param {string} dots - If true, the key will be rendered with dots instead of brackets. - * - * @returns {string} The path to the current key. - */ -function renderKey(path, key, dots) { - if (!path) return key; - return path.concat(key).map(function each(token, i) { - // eslint-disable-next-line no-param-reassign - token = removeBrackets(token); - return !dots && i ? '[' + token + ']' : token; - }).join(dots ? '.' : ''); -} - -/** - * If the array is an array and none of its elements are visitable, then it's a flat array. - * - * @param {Array} arr - The array to check - * - * @returns {boolean} - */ -function isFlatArray(arr) { - return utils$1.isArray(arr) && !arr.some(isVisitable); -} - -const predicates = utils$1.toFlatObject(utils$1, {}, null, function filter(prop) { - return /^is[A-Z]/.test(prop); -}); - -/** - * Convert a data object to FormData - * - * @param {Object} obj - * @param {?Object} [formData] - * @param {?Object} [options] - * @param {Function} [options.visitor] - * @param {Boolean} [options.metaTokens = true] - * @param {Boolean} [options.dots = false] - * @param {?Boolean} [options.indexes = false] - * - * @returns {Object} - **/ - -/** - * It converts an object into a FormData object - * - * @param {Object} obj - The object to convert to form data. - * @param {string} formData - The FormData object to append to. - * @param {Object} options - * - * @returns - */ -function toFormData(obj, formData, options) { - if (!utils$1.isObject(obj)) { - throw new TypeError('target must be an object'); - } - - // eslint-disable-next-line no-param-reassign - formData = formData || new (FormData)(); - - // eslint-disable-next-line no-param-reassign - options = utils$1.toFlatObject(options, { - metaTokens: true, - dots: false, - indexes: false - }, false, function defined(option, source) { - // eslint-disable-next-line no-eq-null,eqeqeq - return !utils$1.isUndefined(source[option]); - }); - - const metaTokens = options.metaTokens; - // eslint-disable-next-line no-use-before-define - const visitor = options.visitor || defaultVisitor; - const dots = options.dots; - const indexes = options.indexes; - const _Blob = options.Blob || typeof Blob !== 'undefined' && Blob; - const useBlob = _Blob && utils$1.isSpecCompliantForm(formData); - - if (!utils$1.isFunction(visitor)) { - throw new TypeError('visitor must be a function'); - } - - function convertValue(value) { - if (value === null) return ''; - - if (utils$1.isDate(value)) { - return value.toISOString(); - } - - if (!useBlob && utils$1.isBlob(value)) { - throw new AxiosError('Blob is not supported. Use a Buffer instead.'); - } - - if (utils$1.isArrayBuffer(value) || utils$1.isTypedArray(value)) { - return useBlob && typeof Blob === 'function' ? new Blob([value]) : Buffer.from(value); - } - - return value; - } - - /** - * Default visitor. - * - * @param {*} value - * @param {String|Number} key - * @param {Array} path - * @this {FormData} - * - * @returns {boolean} return true to visit the each prop of the value recursively - */ - function defaultVisitor(value, key, path) { - let arr = value; - - if (value && !path && typeof value === 'object') { - if (utils$1.endsWith(key, '{}')) { - // eslint-disable-next-line no-param-reassign - key = metaTokens ? key : key.slice(0, -2); - // eslint-disable-next-line no-param-reassign - value = JSON.stringify(value); - } else if ( - (utils$1.isArray(value) && isFlatArray(value)) || - ((utils$1.isFileList(value) || utils$1.endsWith(key, '[]')) && (arr = utils$1.toArray(value)) - )) { - // eslint-disable-next-line no-param-reassign - key = removeBrackets(key); - - arr.forEach(function each(el, index) { - !(utils$1.isUndefined(el) || el === null) && formData.append( - // eslint-disable-next-line no-nested-ternary - indexes === true ? renderKey([key], index, dots) : (indexes === null ? key : key + '[]'), - convertValue(el) - ); - }); - return false; - } - } - - if (isVisitable(value)) { - return true; - } - - formData.append(renderKey(path, key, dots), convertValue(value)); - - return false; - } - - const stack = []; - - const exposedHelpers = Object.assign(predicates, { - defaultVisitor, - convertValue, - isVisitable - }); - - function build(value, path) { - if (utils$1.isUndefined(value)) return; - - if (stack.indexOf(value) !== -1) { - throw Error('Circular reference detected in ' + path.join('.')); - } - - stack.push(value); - - utils$1.forEach(value, function each(el, key) { - const result = !(utils$1.isUndefined(el) || el === null) && visitor.call( - formData, el, utils$1.isString(key) ? key.trim() : key, path, exposedHelpers - ); - - if (result === true) { - build(el, path ? path.concat(key) : [key]); - } - }); - - stack.pop(); - } - - if (!utils$1.isObject(obj)) { - throw new TypeError('data must be an object'); - } - - build(obj); - - return formData; -} - -/** - * It encodes a string by replacing all characters that are not in the unreserved set with - * their percent-encoded equivalents - * - * @param {string} str - The string to encode. - * - * @returns {string} The encoded string. - */ -function encode$1(str) { - const charMap = { - '!': '%21', - "'": '%27', - '(': '%28', - ')': '%29', - '~': '%7E', - '%20': '+', - '%00': '\x00' - }; - return encodeURIComponent(str).replace(/[!'()~]|%20|%00/g, function replacer(match) { - return charMap[match]; - }); -} - -/** - * It takes a params object and converts it to a FormData object - * - * @param {Object} params - The parameters to be converted to a FormData object. - * @param {Object} options - The options object passed to the Axios constructor. - * - * @returns {void} - */ -function AxiosURLSearchParams(params, options) { - this._pairs = []; - - params && toFormData(params, this, options); -} - -const prototype = AxiosURLSearchParams.prototype; - -prototype.append = function append(name, value) { - this._pairs.push([name, value]); -}; - -prototype.toString = function toString(encoder) { - const _encode = encoder ? function(value) { - return encoder.call(this, value, encode$1); - } : encode$1; - - return this._pairs.map(function each(pair) { - return _encode(pair[0]) + '=' + _encode(pair[1]); - }, '').join('&'); -}; - -/** - * It replaces all instances of the characters `:`, `$`, `,`, `+`, `[`, and `]` with their - * URI encoded counterparts - * - * @param {string} val The value to be encoded. - * - * @returns {string} The encoded value. - */ -function encode(val) { - return encodeURIComponent(val). - replace(/%3A/gi, ':'). - replace(/%24/g, '$'). - replace(/%2C/gi, ','). - replace(/%20/g, '+'). - replace(/%5B/gi, '['). - replace(/%5D/gi, ']'); -} - -/** - * Build a URL by appending params to the end - * - * @param {string} url The base of the url (e.g., http://www.google.com) - * @param {object} [params] The params to be appended - * @param {?object} options - * - * @returns {string} The formatted url - */ -function buildURL(url, params, options) { - /*eslint no-param-reassign:0*/ - if (!params) { - return url; - } - - const _encode = options && options.encode || encode; - - const serializeFn = options && options.serialize; - - let serializedParams; - - if (serializeFn) { - serializedParams = serializeFn(params, options); - } else { - serializedParams = utils$1.isURLSearchParams(params) ? - params.toString() : - new AxiosURLSearchParams(params, options).toString(_encode); - } - - if (serializedParams) { - const hashmarkIndex = url.indexOf("#"); - - if (hashmarkIndex !== -1) { - url = url.slice(0, hashmarkIndex); - } - url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams; - } - - return url; -} - -class InterceptorManager { - constructor() { - this.handlers = []; - } - - /** - * Add a new interceptor to the stack - * - * @param {Function} fulfilled The function to handle `then` for a `Promise` - * @param {Function} rejected The function to handle `reject` for a `Promise` - * - * @return {Number} An ID used to remove interceptor later - */ - use(fulfilled, rejected, options) { - this.handlers.push({ - fulfilled, - rejected, - synchronous: options ? options.synchronous : false, - runWhen: options ? options.runWhen : null - }); - return this.handlers.length - 1; - } - - /** - * Remove an interceptor from the stack - * - * @param {Number} id The ID that was returned by `use` - * - * @returns {Boolean} `true` if the interceptor was removed, `false` otherwise - */ - eject(id) { - if (this.handlers[id]) { - this.handlers[id] = null; - } - } - - /** - * Clear all interceptors from the stack - * - * @returns {void} - */ - clear() { - if (this.handlers) { - this.handlers = []; - } - } - - /** - * Iterate over all the registered interceptors - * - * This method is particularly useful for skipping over any - * interceptors that may have become `null` calling `eject`. - * - * @param {Function} fn The function to call for each interceptor - * - * @returns {void} - */ - forEach(fn) { - utils$1.forEach(this.handlers, function forEachHandler(h) { - if (h !== null) { - fn(h); - } - }); - } -} - -var InterceptorManager$1 = InterceptorManager; - -var transitionalDefaults = { - silentJSONParsing: true, - forcedJSONParsing: true, - clarifyTimeoutError: false -}; - -var URLSearchParams$1 = typeof URLSearchParams !== 'undefined' ? URLSearchParams : AxiosURLSearchParams; - -var FormData$1 = typeof FormData !== 'undefined' ? FormData : null; - -var Blob$1 = typeof Blob !== 'undefined' ? Blob : null; - -var platform$1 = { - isBrowser: true, - classes: { - URLSearchParams: URLSearchParams$1, - FormData: FormData$1, - Blob: Blob$1 - }, - protocols: ['http', 'https', 'file', 'blob', 'url', 'data'] -}; - -const hasBrowserEnv = typeof window !== 'undefined' && typeof document !== 'undefined'; - -const _navigator = typeof navigator === 'object' && navigator || undefined; - -/** - * Determine if we're running in a standard browser environment - * - * This allows axios to run in a web worker, and react-native. - * Both environments support XMLHttpRequest, but not fully standard globals. - * - * web workers: - * typeof window -> undefined - * typeof document -> undefined - * - * react-native: - * navigator.product -> 'ReactNative' - * nativescript - * navigator.product -> 'NativeScript' or 'NS' - * - * @returns {boolean} - */ -const hasStandardBrowserEnv = hasBrowserEnv && - (!_navigator || ['ReactNative', 'NativeScript', 'NS'].indexOf(_navigator.product) < 0); - -/** - * Determine if we're running in a standard browser webWorker environment - * - * Although the `isStandardBrowserEnv` method indicates that - * `allows axios to run in a web worker`, the WebWorker will still be - * filtered out due to its judgment standard - * `typeof window !== 'undefined' && typeof document !== 'undefined'`. - * This leads to a problem when axios post `FormData` in webWorker - */ -const hasStandardBrowserWebWorkerEnv = (() => { - return ( - typeof WorkerGlobalScope !== 'undefined' && - // eslint-disable-next-line no-undef - self instanceof WorkerGlobalScope && - typeof self.importScripts === 'function' - ); -})(); - -const origin = hasBrowserEnv && window.location.href || 'http://localhost'; - -var utils = /*#__PURE__*/Object.freeze({ - __proto__: null, - hasBrowserEnv: hasBrowserEnv, - hasStandardBrowserWebWorkerEnv: hasStandardBrowserWebWorkerEnv, - hasStandardBrowserEnv: hasStandardBrowserEnv, - navigator: _navigator, - origin: origin -}); - -var platform = { - ...utils, - ...platform$1 -}; - -function toURLEncodedForm(data, options) { - return toFormData(data, new platform.classes.URLSearchParams(), Object.assign({ - visitor: function(value, key, path, helpers) { - if (platform.isNode && utils$1.isBuffer(value)) { - this.append(key, value.toString('base64')); - return false; - } - - return helpers.defaultVisitor.apply(this, arguments); - } - }, options)); -} - -/** - * It takes a string like `foo[x][y][z]` and returns an array like `['foo', 'x', 'y', 'z'] - * - * @param {string} name - The name of the property to get. - * - * @returns An array of strings. - */ -function parsePropPath(name) { - // foo[x][y][z] - // foo.x.y.z - // foo-x-y-z - // foo x y z - return utils$1.matchAll(/\w+|\[(\w*)]/g, name).map(match => { - return match[0] === '[]' ? '' : match[1] || match[0]; - }); -} - -/** - * Convert an array to an object. - * - * @param {Array} arr - The array to convert to an object. - * - * @returns An object with the same keys and values as the array. - */ -function arrayToObject(arr) { - const obj = {}; - const keys = Object.keys(arr); - let i; - const len = keys.length; - let key; - for (i = 0; i < len; i++) { - key = keys[i]; - obj[key] = arr[key]; - } - return obj; -} - -/** - * It takes a FormData object and returns a JavaScript object - * - * @param {string} formData The FormData object to convert to JSON. - * - * @returns {Object | null} The converted object. - */ -function formDataToJSON(formData) { - function buildPath(path, value, target, index) { - let name = path[index++]; - - if (name === '__proto__') return true; - - const isNumericKey = Number.isFinite(+name); - const isLast = index >= path.length; - name = !name && utils$1.isArray(target) ? target.length : name; - - if (isLast) { - if (utils$1.hasOwnProp(target, name)) { - target[name] = [target[name], value]; - } else { - target[name] = value; - } - - return !isNumericKey; - } - - if (!target[name] || !utils$1.isObject(target[name])) { - target[name] = []; - } - - const result = buildPath(path, value, target[name], index); - - if (result && utils$1.isArray(target[name])) { - target[name] = arrayToObject(target[name]); - } - - return !isNumericKey; - } - - if (utils$1.isFormData(formData) && utils$1.isFunction(formData.entries)) { - const obj = {}; - - utils$1.forEachEntry(formData, (name, value) => { - buildPath(parsePropPath(name), value, obj, 0); - }); - - return obj; - } - - return null; -} - -/** - * It takes a string, tries to parse it, and if it fails, it returns the stringified version - * of the input - * - * @param {any} rawValue - The value to be stringified. - * @param {Function} parser - A function that parses a string into a JavaScript object. - * @param {Function} encoder - A function that takes a value and returns a string. - * - * @returns {string} A stringified version of the rawValue. - */ -function stringifySafely(rawValue, parser, encoder) { - if (utils$1.isString(rawValue)) { - try { - (parser || JSON.parse)(rawValue); - return utils$1.trim(rawValue); - } catch (e) { - if (e.name !== 'SyntaxError') { - throw e; - } - } - } - - return (encoder || JSON.stringify)(rawValue); -} - -const defaults = { - - transitional: transitionalDefaults, - - adapter: ['xhr', 'http', 'fetch'], - - transformRequest: [function transformRequest(data, headers) { - const contentType = headers.getContentType() || ''; - const hasJSONContentType = contentType.indexOf('application/json') > -1; - const isObjectPayload = utils$1.isObject(data); - - if (isObjectPayload && utils$1.isHTMLForm(data)) { - data = new FormData(data); - } - - const isFormData = utils$1.isFormData(data); - - if (isFormData) { - return hasJSONContentType ? JSON.stringify(formDataToJSON(data)) : data; - } - - if (utils$1.isArrayBuffer(data) || - utils$1.isBuffer(data) || - utils$1.isStream(data) || - utils$1.isFile(data) || - utils$1.isBlob(data) || - utils$1.isReadableStream(data) - ) { - return data; - } - if (utils$1.isArrayBufferView(data)) { - return data.buffer; - } - if (utils$1.isURLSearchParams(data)) { - headers.setContentType('application/x-www-form-urlencoded;charset=utf-8', false); - return data.toString(); - } - - let isFileList; - - if (isObjectPayload) { - if (contentType.indexOf('application/x-www-form-urlencoded') > -1) { - return toURLEncodedForm(data, this.formSerializer).toString(); - } - - if ((isFileList = utils$1.isFileList(data)) || contentType.indexOf('multipart/form-data') > -1) { - const _FormData = this.env && this.env.FormData; - - return toFormData( - isFileList ? {'files[]': data} : data, - _FormData && new _FormData(), - this.formSerializer - ); - } - } - - if (isObjectPayload || hasJSONContentType ) { - headers.setContentType('application/json', false); - return stringifySafely(data); - } - - return data; - }], - - transformResponse: [function transformResponse(data) { - const transitional = this.transitional || defaults.transitional; - const forcedJSONParsing = transitional && transitional.forcedJSONParsing; - const JSONRequested = this.responseType === 'json'; - - if (utils$1.isResponse(data) || utils$1.isReadableStream(data)) { - return data; - } - - if (data && utils$1.isString(data) && ((forcedJSONParsing && !this.responseType) || JSONRequested)) { - const silentJSONParsing = transitional && transitional.silentJSONParsing; - const strictJSONParsing = !silentJSONParsing && JSONRequested; - - try { - return JSON.parse(data); - } catch (e) { - if (strictJSONParsing) { - if (e.name === 'SyntaxError') { - throw AxiosError.from(e, AxiosError.ERR_BAD_RESPONSE, this, null, this.response); - } - throw e; - } - } - } - - return data; - }], - - /** - * A timeout in milliseconds to abort a request. If set to 0 (default) a - * timeout is not created. - */ - timeout: 0, - - xsrfCookieName: 'XSRF-TOKEN', - xsrfHeaderName: 'X-XSRF-TOKEN', - - maxContentLength: -1, - maxBodyLength: -1, - - env: { - FormData: platform.classes.FormData, - Blob: platform.classes.Blob - }, - - validateStatus: function validateStatus(status) { - return status >= 200 && status < 300; - }, - - headers: { - common: { - 'Accept': 'application/json, text/plain, */*', - 'Content-Type': undefined - } - } -}; - -utils$1.forEach(['delete', 'get', 'head', 'post', 'put', 'patch'], (method) => { - defaults.headers[method] = {}; -}); - -var defaults$1 = defaults; - -// RawAxiosHeaders whose duplicates are ignored by node -// c.f. https://nodejs.org/api/http.html#http_message_headers -const ignoreDuplicateOf = utils$1.toObjectSet([ - 'age', 'authorization', 'content-length', 'content-type', 'etag', - 'expires', 'from', 'host', 'if-modified-since', 'if-unmodified-since', - 'last-modified', 'location', 'max-forwards', 'proxy-authorization', - 'referer', 'retry-after', 'user-agent' -]); - -/** - * Parse headers into an object - * - * ``` - * Date: Wed, 27 Aug 2014 08:58:49 GMT - * Content-Type: application/json - * Connection: keep-alive - * Transfer-Encoding: chunked - * ``` - * - * @param {String} rawHeaders Headers needing to be parsed - * - * @returns {Object} Headers parsed into an object - */ -var parseHeaders = rawHeaders => { - const parsed = {}; - let key; - let val; - let i; - - rawHeaders && rawHeaders.split('\n').forEach(function parser(line) { - i = line.indexOf(':'); - key = line.substring(0, i).trim().toLowerCase(); - val = line.substring(i + 1).trim(); - - if (!key || (parsed[key] && ignoreDuplicateOf[key])) { - return; - } - - if (key === 'set-cookie') { - if (parsed[key]) { - parsed[key].push(val); - } else { - parsed[key] = [val]; - } - } else { - parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val; - } - }); - - return parsed; -}; - -const $internals = Symbol('internals'); - -function normalizeHeader(header) { - return header && String(header).trim().toLowerCase(); -} - -function normalizeValue(value) { - if (value === false || value == null) { - return value; - } - - return utils$1.isArray(value) ? value.map(normalizeValue) : String(value); -} - -function parseTokens(str) { - const tokens = Object.create(null); - const tokensRE = /([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g; - let match; - - while ((match = tokensRE.exec(str))) { - tokens[match[1]] = match[2]; - } - - return tokens; -} - -const isValidHeaderName = (str) => /^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(str.trim()); - -function matchHeaderValue(context, value, header, filter, isHeaderNameFilter) { - if (utils$1.isFunction(filter)) { - return filter.call(this, value, header); - } - - if (isHeaderNameFilter) { - value = header; - } - - if (!utils$1.isString(value)) return; - - if (utils$1.isString(filter)) { - return value.indexOf(filter) !== -1; - } - - if (utils$1.isRegExp(filter)) { - return filter.test(value); - } -} - -function formatHeader(header) { - return header.trim() - .toLowerCase().replace(/([a-z\d])(\w*)/g, (w, char, str) => { - return char.toUpperCase() + str; - }); + extractParameters = extract; + return extractParameters; } -function buildAccessors(obj, header) { - const accessorName = utils$1.toCamelCase(' ' + header); +var newParameterized_1; +var hasRequiredNewParameterized; - ['get', 'set', 'has'].forEach(methodName => { - Object.defineProperty(obj, methodName + accessorName, { - value: function(arg1, arg2, arg3) { - return this[methodName].call(this, header, arg1, arg2, arg3); - }, - configurable: true - }); - }); -} +function requireNewParameterized () { + if (hasRequiredNewParameterized) return newParameterized_1; + hasRequiredNewParameterized = 1; + var extractSql = requireExtractSql(); + var extractParameters = requireExtractParameters(); -class AxiosHeaders { - constructor(headers) { - headers && this.set(headers); - } + function Parameterized(text, parameters) { + this._text = text; + this.parameters = parameters; + } - set(header, valueOrRewrite, rewrite) { - const self = this; + Parameterized.prototype.sql = function() { + return this._text; + }; - function setHeader(_value, _header, _rewrite) { - const lHeader = normalizeHeader(_header); + Parameterized.prototype.prepend = function(other) { + if (other.sql) { + var params = other.parameters.concat(this.parameters); + return newParameterized(other.sql() + this._text, params); + } else + return newParameterized(other + this._text, this.parameters); + }; - if (!lHeader) { - throw new Error('header name must be a non-empty string'); - } + Parameterized.prototype.append = function(other) { + if (other.sql) { + var params = this.parameters.concat(other.parameters); + return newParameterized(this._text + other.sql(), params); + } else + return newParameterized(this._text + other, this.parameters); + }; - const key = utils$1.findKey(self, lHeader); + function newParameterized(text, parameters) { + text = extractSql(text); + parameters = extractParameters(parameters); + return new Parameterized(text, parameters); + } - if(!key || self[key] === undefined || _rewrite === true || (_rewrite === undefined && self[key] !== false)) { - self[key || _header] = normalizeValue(_value); - } - } + newParameterized_1 = newParameterized; + return newParameterized_1; +} - const setHeaders = (headers, _rewrite) => - utils$1.forEach(headers, (_value, _header) => setHeader(_value, _header, _rewrite)); +var negotiateNextAndFilter_1; +var hasRequiredNegotiateNextAndFilter; - if (utils$1.isPlainObject(header) || header instanceof this.constructor) { - setHeaders(header, valueOrRewrite); - } else if(utils$1.isString(header) && (header = header.trim()) && !isValidHeaderName(header)) { - setHeaders(parseHeaders(header), valueOrRewrite); - } else if (utils$1.isHeaders(header)) { - for (const [key, value] of header.entries()) { - setHeader(value, key, rewrite); - } - } else { - header != null && setHeader(valueOrRewrite, header, rewrite); - } +function requireNegotiateNextAndFilter () { + if (hasRequiredNegotiateNextAndFilter) return negotiateNextAndFilter_1; + hasRequiredNegotiateNextAndFilter = 1; + function negotiateNextAndFilter(filter, other) { + if (!other.sql()) + return filter; + return filter.append(' AND ').append(other); + } - return this; - } + negotiateNextAndFilter_1 = negotiateNextAndFilter; + return negotiateNextAndFilter_1; +} - get(header, parser) { - header = normalizeHeader(header); +var negotiateNextOrFilter_1; +var hasRequiredNegotiateNextOrFilter; - if (header) { - const key = utils$1.findKey(this, header); +function requireNegotiateNextOrFilter () { + if (hasRequiredNegotiateNextOrFilter) return negotiateNextOrFilter_1; + hasRequiredNegotiateNextOrFilter = 1; + function negotiateNextOrFilter(filter, other) { + if (!other.sql()) + return filter; + return filter.prepend('(').append(' OR ').append(other).append(')'); + } - if (key) { - const value = this[key]; + negotiateNextOrFilter_1 = negotiateNextOrFilter; + return negotiateNextOrFilter_1; +} - if (!parser) { - return value; - } +var utils; +var hasRequiredUtils; - if (parser === true) { - return parseTokens(value); - } +function requireUtils () { + if (hasRequiredUtils) return utils; + hasRequiredUtils = 1; + const newParameterized = requireNewParameterized(); + const negotiateNextAndFilter = requireNegotiateNextAndFilter(); + const negotiateNextOrFilter = requireNegotiateNextOrFilter(); - if (utils$1.isFunction(parser)) { - return parser.call(this, value, key); - } + function newBoolean(filter) { + var c = {}; + c.sql = filter.sql.bind(filter); + c.parameters = filter.parameters; - if (utils$1.isRegExp(parser)) { - return parser.exec(value); - } + c.append = function(other) { + var nextFilter = filter.append(other); + return newBoolean(nextFilter); + }; - throw new TypeError('parser must be boolean|regexp|function'); - } - } - } + c.prepend = function(other) { + var nextFilter = filter.prepend(other); + return newBoolean(nextFilter); + }; - has(header, matcher) { - header = normalizeHeader(header); + c.and = function(context, other) { + other = negotiateRawSqlFilter(context, other); + var nextFilter = negotiateNextAndFilter(filter, other); + var next = newBoolean(nextFilter); + for (var i = 2; i < arguments.length; i++) { + next = next.and(context, arguments[i]); + } + return next; + }; - if (header) { - const key = utils$1.findKey(this, header); + c.or = function(context, other) { + other = negotiateRawSqlFilter(context, other); + var nextFilter = negotiateNextOrFilter(filter, other); + var next = newBoolean(nextFilter); + for (var i = 2; i < arguments.length; i++) { + next = next.or(context, arguments[i]); + } + return next; + }; - return !!(key && this[key] !== undefined && (!matcher || matchHeaderValue(this, this[key], key, matcher))); - } + c.not = function(_context) { + var nextFilter = filter.prepend('NOT (').append(')'); + return newBoolean(nextFilter); + }; - return false; - } + return c; + } - delete(header, matcher) { - const self = this; - let deleted = false; - function deleteHeader(_header) { - _header = normalizeHeader(_header); + function negotiateRawSqlFilter(context, filter, optionalTable, emptyArrayMeansFalse) { + if (Array.isArray(filter) && filter.length === 0) { + const sql = emptyArrayMeansFalse ? '1 = 2' : '1 = 1'; + return newBoolean(newParameterized(sql)); + } + else if (Array.isArray(filter)) { + let curFilter; + let curObjectFilter; + for (let i = 0; i < filter.length; i++) { + let nextFilter = negotiateRawSqlFilter(context,filter[i], optionalTable); + if (nextFilter.isObjectFilter) + curObjectFilter = curObjectFilter ? curObjectFilter.or(context, nextFilter) : nextFilter; + else + curFilter = curFilter ? curFilter.and(context, nextFilter) : nextFilter; + } + if (curFilter && curObjectFilter) + return curFilter.and(context, curObjectFilter); + else if (curFilter) + return curFilter; + else + return curObjectFilter; + } + else { + let params = []; + if (filter) { + if (filter.and) + return filter; + if (filter.sql) { + let sql = filter.sql; + if (typeof filter.sql === 'function') { + sql = filter.sql(); + } + params.push(sql, filter.parameters); + } + else if (isObjectFilter(filter, optionalTable)) + return newObjectFilter(context, filter, optionalTable); + else + params = [filter]; + } else { + params = [filter]; + } - if (_header) { - const key = utils$1.findKey(self, _header); + let parameterized = newParameterized.apply(null, params); + return newBoolean(parameterized); + } + } - if (key && (!matcher || matchHeaderValue(self, self[key], key, matcher))) { - delete self[key]; + function isObjectFilter(object, optionalTable) { + return optionalTable && object; + } - deleted = true; - } - } - } + function newObjectFilter(context, object, table) { + let primaryColumns = table._primaryColumns; + let filter; + for (let i = 0; i < primaryColumns.length; i++) { + let column = primaryColumns[i]; + let colFilter = column.equal(context, object[column.alias]); + filter = filter ? filter.and(context, colFilter) : colFilter ; + } + filter.isObjectFilter = true; + return filter; + } - if (utils$1.isArray(header)) { - header.forEach(deleteHeader); - } else { - deleteHeader(header); - } - return deleted; - } + utils = { negotiateRawSqlFilter, newBoolean}; + return utils; +} - clear(matcher) { - const keys = Object.keys(this); - let i = keys.length; - let deleted = false; +var negotiateRawSqlFilter_1; +var hasRequiredNegotiateRawSqlFilter; - while (i--) { - const key = keys[i]; - if(!matcher || matchHeaderValue(this, this[key], key, matcher, true)) { - delete this[key]; - deleted = true; - } - } +function requireNegotiateRawSqlFilter () { + if (hasRequiredNegotiateRawSqlFilter) return negotiateRawSqlFilter_1; + hasRequiredNegotiateRawSqlFilter = 1; + const { negotiateRawSqlFilter } = requireUtils(); - return deleted; - } + negotiateRawSqlFilter_1 = negotiateRawSqlFilter; + return negotiateRawSqlFilter_1; +} - normalize(format) { - const self = this; - const headers = {}; +var emptyFilter_1; +var hasRequiredEmptyFilter; - utils$1.forEach(this, (value, header) => { - const key = utils$1.findKey(headers, header); +function requireEmptyFilter () { + if (hasRequiredEmptyFilter) return emptyFilter_1; + hasRequiredEmptyFilter = 1; + var negotiateRawSqlFilter = requireNegotiateRawSqlFilter(); + var parameterized = requireNewParameterized()(''); + function emptyFilter() { + return emptyFilter.and.apply(null, arguments); + } - if (key) { - self[key] = normalizeValue(value); - delete self[header]; - return; - } + emptyFilter.sql = parameterized.sql; + emptyFilter.parameters = parameterized.parameters; - const normalized = format ? formatHeader(header) : String(header).trim(); + emptyFilter.and = function(context, other) { + other = negotiateRawSqlFilter(context, other); + for (var i = 2; i < arguments.length; i++) { + other = other.and(context, arguments[i]); + } + return other; + }; - if (normalized !== header) { - delete self[header]; - } + emptyFilter.or = function(context, other) { + other = negotiateRawSqlFilter(context, other); + for (var i = 2; i < arguments.length; i++) { + other = other.or(context, arguments[i]); + } + return other; + }; - self[normalized] = normalizeValue(value); + emptyFilter.not = function(context, other) { + other = negotiateRawSqlFilter(context, other).not(context); + for (var i = 2; i < arguments.length; i++) { + other = other.and(context, arguments[i]); + } + return other; + + }; + + emptyFilter_1 = emptyFilter; + return emptyFilter_1; +} + +var executePath; +var hasRequiredExecutePath; + +function requireExecutePath () { + if (hasRequiredExecutePath) return executePath; + hasRequiredExecutePath = 1; + const createPatch = requireCreatePatch(); + const emptyFilter = requireEmptyFilter(); + const negotiateRawSqlFilter = requireNegotiateRawSqlFilter(); + let getMeta = requireGetMeta(); + let isSafe = Symbol(); + + let _allowedOps = { + and: true, + or: true, + not: true, + AND: true, + OR: true, + NOT: true, + equal: true, + eq: true, + EQ: true, + notEqual: true, + ne: true, + NE: true, + lessThan: true, + lt: true, + LT: true, + lessThanOrEqual: true, + le: true, + LE: true, + greaterThan: true, + gt: true, + GT: true, + greaterThanOrEqual: true, + ge: true, + GE: true, + between: true, + in: true, + IN: true, + startsWith: true, + iStartsWith: true, + endsWith: true, + iEndsWith: true, + contains: true, + iContains: true, + iEqual: true, + iEq: true, + ieq: true, + IEQ: true, + exists: true, + all: true, + any: true, + none: true, + where: true, + sum: true, + avg: true, + max: true, + min: true, + count: true, + groupSum: true, + groupAvg: true, + groupMax: true, + groupMin: true, + groupCount: true, + _aggregate: true, + self: true, + }; + + function _executePath(context, ...rest) { + + const _ops = { + and: emptyFilter.and.bind(null, context), + or: emptyFilter.or.bind(null, context), + not: emptyFilter.not.bind(null, context), + AND: emptyFilter.and.bind(null, context), + OR: emptyFilter.or.bind(null, context), + NOT: emptyFilter.not.bind(null, context), + }; + + return executePath(...rest); + + async function executePath({ table, JSONFilter, baseFilter, customFilters = {}, request, response, readonly, disableBulkDeletes, isHttp, client }) { + let allowedOps = { ..._allowedOps, insert: !readonly, ...extractRelations(getMeta(table)) }; + let ops = { ..._ops, ...getCustomFilterPaths(customFilters), getManyDto, getMany, aggregate, count, delete: _delete, cascadeDelete, update, replace }; + + let res = await parseFilter(JSONFilter, table); + if (res === undefined) + return {}; + else + return res; + + function parseFilter(json, table) { + if (isFilter(json)) { + let subFilters = []; + + let anyAllNone = tryGetAnyAllNone(json.path, table); + if (anyAllNone) { + if (isHttp) + validateArgs(json.args[0]); + const f = anyAllNone(context, x => parseFilter(json.args[0], x)); + if(!('isSafe' in f)) + f.isSafe = isSafe; + return f; + } + else { + for (let i = 0; i < json.args.length; i++) { + subFilters.push(parseFilter(json.args[i], nextTable(json.path, table))); + } + } + return executePath(json.path, subFilters); + } + else if (Array.isArray(json)) { + const result = []; + for (let i = 0; i < json.length; i++) { + result.push(parseFilter(json[i], table)); + } + return result; + } + return json; + + function tryGetAnyAllNone(path, table) { + path = path.split('.'); + for (let i = 0; i < path.length; i++) { + table = table[path[i]]; + } + + let ops = new Set(['all', 'any', 'none', 'where', '_aggregate']); + // let ops = new Set(['all', 'any', 'none', 'where']); + let last = path.slice(-1)[0]; + if (ops.has(last) || (table && (table._primaryColumns || (table.any && table.all)))) + return table; + } + + function executePath(path, args) { + if (path in ops) { + if (isHttp) + validateArgs(args); + let op = ops[path].apply(null, args); + if (op.then) + return op.then((o) => { + setSafe(o); + return o; + }); + setSafe(op); + return op; + } + let pathArray = path.split('.'); + let target = table; + let op = pathArray[pathArray.length - 1]; + if (!allowedOps[op] && isHttp) { + + let e = new Error('Disallowed operator ' + op); + // @ts-ignore + e.status = 403; + throw e; + + } + for (let i = 0; i < pathArray.length; i++) { + target = target[pathArray[i]]; + } + + if (!target) + throw new Error(`Method '${path}' does not exist`); + let res = target.apply(null, [context, ...args]); + setSafe(res); + return res; + } + } + + async function invokeBaseFilter() { + if (typeof baseFilter === 'function') { + const res = await baseFilter.apply(null, [bindDb(client), request, response]); + if (!res) + return; + const JSONFilter = JSON.parse(JSON.stringify(res)); + //@ts-ignore + return executePath({ table, JSONFilter, request, response }); + } + else + return; + } + + function getCustomFilterPaths(customFilters) { + return getLeafNames(customFilters); + + function getLeafNames(obj, result = {}, current = 'customFilters.') { + for (let p in obj) { + if (typeof obj[p] === 'object' && obj[p] !== null) + getLeafNames(obj[p], result, current + p + '.'); + else + result[current + p] = resolveFilter.bind(null, obj[p]); + } + return result; + } + + async function resolveFilter(fn, ...args) { + const context = { db: bindDb(client), request, response }; + let res = fn.apply(null, [context, ...args]); + if (res.then) + res = await res; + const JSONFilter = JSON.parse(JSON.stringify(res)); + //@ts-ignore + return executePath({ table, JSONFilter, request, response }); + } + } + + function nextTable(path, table) { + path = path.split('.'); + let ops = new Set(['all', 'any', 'none']); + let last = path.slice(-1)[0]; + if (ops.has(last)) { + for (let i = 0; i < path.length - 1; i++) { + table = table[path[i]]; + } + return table; + } + else { + let lastObj = table; + for (let i = 0; i < path.length; i++) { + if (lastObj) + lastObj = lastObj[path[i]]; + } + if (lastObj?._shallow) + return lastObj._shallow; + else return table; + } + } + + async function _delete(filter) { + if (readonly || disableBulkDeletes) { + let e = new Error('Bulk deletes are not allowed. Parameter "disableBulkDeletes" must be true.'); + // @ts-ignore + e.status = 403; + throw e; + } + filter = negotiateFilter(filter); + const _baseFilter = await invokeBaseFilter(); + if (_baseFilter) + filter = filter.and(context, _baseFilter); + let args = [context, filter].concat(Array.prototype.slice.call(arguments).slice(1)); + return table.delete.apply(null, args); + } + + async function cascadeDelete(filter) { + if (readonly || disableBulkDeletes) { + const e = new Error('Bulk deletes are not allowed. Parameter "disableBulkDeletes" must be true.'); + // @ts-ignore + e.status = 403; + throw e; + + } + filter = negotiateFilter(filter); + const _baseFilter = await invokeBaseFilter(); + if (_baseFilter) + filter = filter.and(context, _baseFilter); + let args = [context, filter].concat(Array.prototype.slice.call(arguments).slice(1)); + return table.cascadeDelete.apply(null, args); + } + + function negotiateFilter(filter) { + if (filter) + return negotiateRawSqlFilter(context, filter, table, true); + else + return emptyFilter; + } + + async function count(filter, strategy) { + validateStrategy(table, strategy); + filter = negotiateFilter(filter); + const _baseFilter = await invokeBaseFilter(); + if (_baseFilter) + filter = filter.and(context, _baseFilter); + let args = [context, filter].concat(Array.prototype.slice.call(arguments).slice(1)); + return table.count.apply(null, args); + } + + async function getManyDto(filter, strategy) { + validateStrategy(table, strategy); + filter = negotiateFilter(filter); + const _baseFilter = await invokeBaseFilter(); + if (_baseFilter) + filter = filter.and(context, _baseFilter); + let args = [context, filter].concat(Array.prototype.slice.call(arguments).slice(1)); + await negotiateWhereAndAggregate(strategy); + return table.getManyDto.apply(null, args); + } + + async function replace(subject, strategy = { insertAndForget: true }) { + validateStrategy(table, strategy); + const refinedStrategy = objectToStrategy(subject, {}, table); + const JSONFilter2 = { + path: 'getManyDto', + args: [subject, refinedStrategy] + }; + const originals = await executePath({ table, JSONFilter: JSONFilter2, baseFilter, customFilters, request, response, readonly, disableBulkDeletes, isHttp, client }); + const meta = getMeta(table); + const patch = createPatch(originals, Array.isArray(subject) ? subject : [subject], meta); + const { changed } = await table.patch(context, patch, { strategy }); + if (Array.isArray(subject)) + return changed; + else + return changed[0]; + } + + async function update(subject, whereStrategy, strategy = { insertAndForget: true }) { + validateStrategy(table, strategy); + const refinedWhereStrategy = objectToStrategy(subject, whereStrategy, table); + const JSONFilter2 = { + path: 'getManyDto', + args: [null, refinedWhereStrategy] + }; + const rows = await executePath({ table, JSONFilter: JSONFilter2, baseFilter, customFilters, request, response, readonly, disableBulkDeletes, isHttp, client }); + const originals = new Array(rows.length); + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + originals[i] = { ...row }; + for (let p in subject) { + row[p] = subject[p]; + } + } + const meta = getMeta(table); + const patch = createPatch(originals, rows, meta); + const { changed } = await table.patch(context, patch, { strategy }); + return changed; + } + + function objectToStrategy(object, whereStrategy, table, strategy = {}) { + strategy = { ...whereStrategy, ...strategy }; + if (Array.isArray(object)) { + for (let i = 0; i < object.length; i++) { + objectToStrategy(object[i], table, strategy); + } + return; + } + for (let name in object) { + const relation = table[name]?._relation; + if (relation && !relation.columns) {//notJoin, that is one or many + strategy[name] = {}; + objectToStrategy(object[name], whereStrategy?.[name], table[name], strategy[name]); + } + else + strategy[name] = true; + } + return strategy; + } + + + async function aggregate(filter, strategy) { + validateStrategy(table, strategy); + filter = negotiateFilter(filter); + const _baseFilter = await invokeBaseFilter(); + if (_baseFilter) + filter = filter.and(context, _baseFilter); + let args = [context, filter].concat(Array.prototype.slice.call(arguments).slice(1)); + await negotiateWhereAndAggregate(strategy); + return table.aggregate.apply(null, args); + } + + + + async function negotiateWhereAndAggregate(strategy) { + if (typeof strategy !== 'object') + return; + + for (let name in strategy) { + const target = strategy[name]; + if (isFilter(target)) + strategy[name] = await parseFilter(strategy[name], table); + else + await negotiateWhereAndAggregate(strategy[name]); + } + + } + + async function getMany(filter, strategy) { + validateStrategy(table, strategy); + filter = negotiateFilter(filter); + const _baseFilter = await invokeBaseFilter(); + if (_baseFilter) + filter = filter.and(context, _baseFilter); + let args = [context, filter].concat(Array.prototype.slice.call(arguments).slice(1)); + await negotiateWhereAndAggregate(strategy); + return table.getMany.apply(null, args); + } + + } + + function validateStrategy(table, strategy) { + if (!strategy || !table) + return; + + for (let p in strategy) { + validateOffset(strategy); + validateLimit(strategy); + validateOrderBy(table, strategy); + validateStrategy(table[p], strategy[p]); + } + } + + function validateLimit(strategy) { + if (!('limit' in strategy) || Number.isInteger(strategy.limit)) + return; + const e = new Error('Invalid limit: ' + strategy.limit); + // @ts-ignore + e.status = 400; + } + + function validateOffset(strategy) { + if (!('offset' in strategy) || Number.isInteger(strategy.offset)) + return; + const e = new Error('Invalid offset: ' + strategy.offset); + // @ts-ignore + e.status = 400; + throw e; + } + + function validateOrderBy(table, strategy) { + if (!('orderBy' in strategy) || !table) + return; + let orderBy = strategy.orderBy; + if (!Array.isArray(orderBy)) + orderBy = [orderBy]; + orderBy.reduce(validate, []); + + function validate(_, element) { + let parts = element.split(' ').filter(x => { + x = x.toLowerCase(); + return (!(x === '' || x === 'asc' || x === 'desc')); + }); + for (let p of parts) { + let col = table[p]; + if (!(col && col.equal)) { + const e = new Error('Unknown column: ' + p); + // @ts-ignore + e.status = 400; + throw e; + } + } + } + } + + function validateArgs() { + for (let i = 0; i < arguments.length; i++) { + const filter = arguments[i]; + if (!filter) + continue; + if (filter && filter.isSafe === isSafe) + continue; + if (filter.sql || typeof (filter) === 'string') { + const e = new Error('Raw filters are disallowed'); + // @ts-ignore + e.status = 403; + throw e; + } + if (Array.isArray(filter)) + for (let i = 0; i < filter.length; i++) { + + validateArgs(filter[i]); + } + } + + } + + function isFilter(json) { + return json instanceof Object && 'path' in json && 'args' in json; + } + + function setSafe(o) { + if (o instanceof Object) + Object.defineProperty(o, 'isSafe', { + value: isSafe, + enumerable: false + + }); + } + + function extractRelations(obj) { + let flattened = {}; + + function helper(relations) { + Object.keys(relations).forEach(key => { + + flattened[key] = true; + + if (typeof relations[key] === 'object' && Object.keys(relations[key]?.relations)?.length > 0) { + helper(relations[key].relations); + } + }); + } + + helper(obj.relations); + + return flattened; + } + + function bindDb(client) { + var domain = context; + let p = domain.run(() => true); + + function run(fn) { + return p.then(domain.run.bind(domain, fn)); + } + + return client({ transaction: run }); + + } + } + executePath = _executePath; + return executePath; +} + +var tryGetSessionContext_1; +var hasRequiredTryGetSessionContext; + +function requireTryGetSessionContext () { + if (hasRequiredTryGetSessionContext) return tryGetSessionContext_1; + hasRequiredTryGetSessionContext = 1; + function tryGetSessionContext(context) { + if (context) + return context.rdb; + } + + tryGetSessionContext_1 = tryGetSessionContext; + return tryGetSessionContext_1; +} + +var getSessionContext_1; +var hasRequiredGetSessionContext; + +function requireGetSessionContext () { + if (hasRequiredGetSessionContext) return getSessionContext_1; + hasRequiredGetSessionContext = 1; + let tryGetSessionContext = requireTryGetSessionContext(); + + function getSessionContext(context) { + const rdb = tryGetSessionContext(context); + if (!rdb) + throw new Error('Rdb transaction is no longer available. Is promise chain broken ?'); + return rdb; + } + + getSessionContext_1 = getSessionContext; + return getSessionContext_1; +} + +var setSessionSingleton_1; +var hasRequiredSetSessionSingleton; + +function requireSetSessionSingleton () { + if (hasRequiredSetSessionSingleton) return setSessionSingleton_1; + hasRequiredSetSessionSingleton = 1; + var getSessionContext = requireGetSessionContext(); + + function setSessionSingleton(context, name, value) { + const rdb = getSessionContext(context); + rdb[name] = value; + } + + setSessionSingleton_1 = setSessionSingleton; + return setSessionSingleton_1; +} + +var getSessionSingleton; +var hasRequiredGetSessionSingleton; + +function requireGetSessionSingleton () { + if (hasRequiredGetSessionSingleton) return getSessionSingleton; + hasRequiredGetSessionSingleton = 1; + var getSessionContext = requireGetSessionContext(); + + getSessionSingleton = function(context, name) { + const rdb = getSessionContext(context); + return rdb[name]; + }; + return getSessionSingleton; +} + +var resolveExecuteQuery_1; +var hasRequiredResolveExecuteQuery; + +function requireResolveExecuteQuery () { + if (hasRequiredResolveExecuteQuery) return resolveExecuteQuery_1; + hasRequiredResolveExecuteQuery = 1; + const getSessionSingleton = requireGetSessionSingleton(); + + function resolveExecuteQuery(context, query) { + return resolve; + + function resolve(success, failed) { + try { + var client = getSessionSingleton(context, 'dbClient'); + query = negotiateNullParams(query); + client.executeQuery(query, onCompleted); + } catch (e) { + failed(e); + } + + function onCompleted(err, rows) { + if (!err) + success(rows); + else + failed(err); + } + } + + } + + function negotiateNullParams(query) { + if (query && query.parameters && query.parameters.length > 0 && (query.parameters.filter(x => x === null || x === undefined).length > 0)) { + var splitted = query.sql().split('?'); + var sql = ''; + var parameters = []; + var lastIndex = splitted.length - 1; + for (var i = 0; i < lastIndex; i++) { + if (query.parameters[i] === null || query.parameters[i] === undefined) + sql += splitted[i] + 'null'; + else { + sql += splitted[i] + '?'; + parameters.push(query.parameters[i]); + } + } + sql += splitted[lastIndex]; + return { + sql: () => sql, + parameters + }; + + } + else + return query; + } + + resolveExecuteQuery_1 = resolveExecuteQuery; + return resolveExecuteQuery_1; +} + +var executeQuery_1; +var hasRequiredExecuteQuery; + +function requireExecuteQuery () { + if (hasRequiredExecuteQuery) return executeQuery_1; + hasRequiredExecuteQuery = 1; + var newResolver = requireResolveExecuteQuery(); + + function executeQuery(context, query) { + var resolver = newResolver(context, query); + return new Promise(resolver); + } + + executeQuery_1 = executeQuery; + return executeQuery_1; +} + +var promise; +var hasRequiredPromise; + +function requirePromise () { + if (hasRequiredPromise) return promise; + hasRequiredPromise = 1; + function newPromise(func) { + if (!func) + return Promise.resolve.apply(Promise, arguments); + return new Promise(func); + } + + newPromise.all = Promise.all; + promise = newPromise; + return promise; +} + +var executeChanges_1; +var hasRequiredExecuteChanges; + +function requireExecuteChanges () { + if (hasRequiredExecuteChanges) return executeChanges_1; + hasRequiredExecuteChanges = 1; + var executeQuery = requireExecuteQuery(); + var newPromise = requirePromise(); + + function executeChanges(context, queries) { + if (queries.length === 0) + return newPromise(); + var i = -1; + return execute().then(emitChanged); + + + function execute() { + i++; + if (i + 1 === queries.length) + return executeQuery(context, queries[i]).then(notifyListener); + else { + return executeQuery(context, queries[i]).then(notifyListener).then(execute); + } + } + + function notifyListener(result) { + if (result && queries[i].onResult) + queries[i].onResult(result); + } + + async function emitChanged() { + for (let i = 0; i < queries.length; i++) { + if (queries[i].emitChanged) + await Promise.all(queries[i].emitChanged()); + } + } + + + } + + executeChanges_1 = executeChanges; + return executeChanges_1; +} + +var getChangeSet_1; +var hasRequiredGetChangeSet; + +function requireGetChangeSet () { + if (hasRequiredGetChangeSet) return getChangeSet_1; + hasRequiredGetChangeSet = 1; + var getSessionSingleton = requireGetSessionSingleton(); + function getChangeSet(context) { + return getSessionSingleton(context, 'changes'); + } + + getChangeSet_1 = getChangeSet; + return getChangeSet_1; +} + +var compressChanges; +var hasRequiredCompressChanges; + +function requireCompressChanges () { + if (hasRequiredCompressChanges) return compressChanges; + hasRequiredCompressChanges = 1; + var newParameterized = requireNewParameterized(); + var getSessionSingleton = requireGetSessionSingleton(); + + function compress(context, queries) { + var multipleStatements = getSessionSingleton(context, 'multipleStatements'); + var compressed = []; + var queryCount = queries.length; + + for (var i = 0; i < queryCount; i++) { + var current = queries[i]; + if (multipleStatements && current.parameters.length === 0 && !current.disallowCompress) { + for (var i2 = i+1; i2 < queryCount; i2++) { + var next = queries[i2]; + if (next.parameters.length > 0 || ! next.disallowCompress) + break; + current = newParameterized(current.sql() + ';' + next.sql()); + i++; + } + } + compressed.push(current); + } + return compressed; + } + + compressChanges = compress; + return compressChanges; +} + +var popChanges_1; +var hasRequiredPopChanges; + +function requirePopChanges () { + if (hasRequiredPopChanges) return popChanges_1; + hasRequiredPopChanges = 1; + var getChangeSet = requireGetChangeSet(); + var compressChanges = requireCompressChanges(); + + function popChanges(context) { + var changeSet = getChangeSet(context); + var length = changeSet.length; + if (length > 0) { + var lastCmd = changeSet[length-1]; + if (lastCmd.endEdit) + lastCmd.endEdit(); + var compressed = compressChanges(context, changeSet); + changeSet.length = 0; + return compressed; + } + return changeSet; + + } + + popChanges_1 = popChanges; + return popChanges_1; +} + +var executeQueriesCore_1; +var hasRequiredExecuteQueriesCore; + +function requireExecuteQueriesCore () { + if (hasRequiredExecuteQueriesCore) return executeQueriesCore_1; + hasRequiredExecuteQueriesCore = 1; + var executeQuery = requireExecuteQuery(); + + function executeQueriesCore(context, queries) { + var promises = []; + for (var i = 0; i < queries.length; i++) { + var q = executeQuery(context, queries[i]); + promises.push(q); + } + return promises; + } + + executeQueriesCore_1 = executeQueriesCore; + return executeQueriesCore_1; +} + +var executeQueries_1; +var hasRequiredExecuteQueries; + +function requireExecuteQueries () { + if (hasRequiredExecuteQueries) return executeQueries_1; + hasRequiredExecuteQueries = 1; + var executeChanges = requireExecuteChanges(); + var popChanges = requirePopChanges(); + var executeQueriesCore = requireExecuteQueriesCore(); + + function executeQueries(context, queries) { + var changes = popChanges(context); + + return executeChanges(context, changes).then(onDoneChanges); + + function onDoneChanges() { + return executeQueriesCore(context, queries); + } + } + + executeQueries_1 = executeQueries; + return executeQueries_1; +} + +var negotiateSql_1; +var hasRequiredNegotiateSql; + +function requireNegotiateSql () { + if (hasRequiredNegotiateSql) return negotiateSql_1; + hasRequiredNegotiateSql = 1; + function negotiateSql(query) { + if(typeof(query) === 'string') + return function() { return query; }; + + var sql = query.sql; + if(typeof(sql) === 'function') + return sql; + else if(typeof(sql) === 'string') + return function() { return sql; }; + else + throw new Error('Query lacks sql property string or function'); + } + + negotiateSql_1 = negotiateSql; + return negotiateSql_1; +} + +var negotiateParameters_1; +var hasRequiredNegotiateParameters; + +function requireNegotiateParameters () { + if (hasRequiredNegotiateParameters) return negotiateParameters_1; + hasRequiredNegotiateParameters = 1; + function negotiateParameters(parameters) { + if(parameters === undefined) + return []; + else if(parameters.length !== undefined) + return parameters; + else + throw new Error('Query has invalid parameters property. Must be undefined or array'); + } + + negotiateParameters_1 = negotiateParameters; + return negotiateParameters_1; +} + +var wrapQuery_1$1; +var hasRequiredWrapQuery$1; + +function requireWrapQuery$1 () { + if (hasRequiredWrapQuery$1) return wrapQuery_1$1; + hasRequiredWrapQuery$1 = 1; + var negotiateSql = requireNegotiateSql(); + var negotiateParameters = requireNegotiateParameters(); + + function wrapQuery(query) { + var safeSql = negotiateSql(query); + var safeParameters = negotiateParameters(query.parameters); + let obj = { + sql: safeSql, + parameters: safeParameters + }; + if (query.types) + obj.types = query.types; + return obj; + } + + + wrapQuery_1$1 = wrapQuery; + return wrapQuery_1$1; +} + +var query; +var hasRequiredQuery; + +function requireQuery () { + if (hasRequiredQuery) return query; + hasRequiredQuery = 1; + var executeQueries = requireExecuteQueries(); + var wrapQuery = requireWrapQuery$1(); + + function doQuery(context, query) { + var wrappedQuery = wrapQuery(query); + return executeQueries(context, [wrappedQuery]).then(unwrapResult); + } + + function unwrapResult(results) { + return results[0]; + } + + query = doQuery; + return query; +} + +var hostLocal_1; +var hasRequiredHostLocal; + +function requireHostLocal () { + if (hasRequiredHostLocal) return hostLocal_1; + hasRequiredHostLocal = 1; + let executePath = requireExecutePath(); + let getMeta = requireGetMeta(); + let setSessionSingleton = requireSetSessionSingleton(); + let executeQuery = requireQuery(); + let hostExpress = requireHostExpress(); + const readonlyOps = ['getManyDto', 'getMany', 'aggregate', 'count']; + // { db, table, defaultConcurrency, + // concurrency, + // customFilters, + // baseFilter, strategy, transaction, + // readonly, + // disableBulkDeletes, isBrowser } + function hostLocal() { + const _options = arguments[0]; + let { table, transaction, db, isHttp } = _options; + + let c = { get, post, patch, query, express }; + + function get() { + return getMeta(table); + + } + async function patch(body, _req, _res) { + if (!table) { + const error = new Error('Table is not exposed'); + // @ts-ignore + error.status = 400; + throw error; + } + body = typeof body === 'string' ? JSON.parse(body) : body; + let result; + + if (transaction) + await transaction(fn); + else { + if (typeof db === 'function') { + let dbPromise = db(); + if (dbPromise.then) + db = await dbPromise; + else + db = dbPromise; + } + await db.transaction(fn); + } + return result; + + async function fn(context) { + setSessionSingleton(context, 'ignoreSerializable', true); + let patch = body.patch; + result = await table.patch(context, patch, { ..._options, ...body.options, isHttp }); + } + } + + async function post(body, request, response) { + body = typeof body === 'string' ? JSON.parse(body) : body; + let result; + + if (transaction) + await transaction(fn); + else { + if (typeof db === 'function') { + let dbPromise = db(); + if (dbPromise.then) + db = await dbPromise; + else + db = dbPromise; + } + if (readonlyOps.includes(body.path)) + await db.transaction({ readonly: true }, fn); + else + await db.transaction(fn); + } + return result; + + async function fn(context) { + setSessionSingleton(context, 'ignoreSerializable', true); + const options = { ..._options, ...body.options, JSONFilter: body, request, response, isHttp }; + result = await executePath(context, options); + } + } + async function query() { + let args = arguments; + let result; + + if (transaction) + await transaction(fn); + else { + if (typeof db === 'function') { + let dbPromise = db(); + if (dbPromise.then) + db = await dbPromise; + else + db = dbPromise; + } + result = await db.query.apply(null, arguments); + } + + return result; + + async function fn(...args1) { + result = await executeQuery.apply(null, [...args1, ...args]); + } + + } + + function express(client, options) { + return hostExpress(hostLocal, client, options); + } + + return c; + } + + hostLocal_1 = hostLocal; + return hostLocal_1; +} + +var cloneFromDb_1; +var hasRequiredCloneFromDb; + +function requireCloneFromDb () { + if (hasRequiredCloneFromDb) return cloneFromDb_1; + hasRequiredCloneFromDb = 1; + let dateToISOString = requireDateToISOString(); + + function cloneFromDbFast(obj) { + if (obj === null || typeof obj !== 'object') + return obj; + if (Array.isArray(obj)) { + const arrClone = []; + for (let i = 0; i < obj.length; i++) { + arrClone[i] = cloneFromDbFast(obj[i]); + } + return arrClone; + } + const clone = {}; + const keys = Object.keys(obj); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + clone[key] = cloneFromDbFast(obj[key]); + } + return clone; + } + + function cloneRegular(obj) { + if (obj === null || typeof obj !== 'object') + return obj; + if (Array.isArray(obj)) { + const arrClone = []; + for (let i = 0; i < obj.length; i++) { + arrClone[i] = cloneRegular(obj[i]); + } + return arrClone; + } + else if (obj instanceof Date && !isNaN(obj)) + return dateToISOString(obj); + const clone = {}; + const keys = Object.keys(obj); + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + clone[key] = cloneRegular(obj[key]); + } + return clone; + } + + function cloneFromDb(obj, isFast) { + if (isFast) + return cloneFromDbFast(obj); + else + return cloneRegular(obj); + } + + cloneFromDb_1 = cloneFromDb; + return cloneFromDb_1; +} + +var require$$0$1 = /*@__PURE__*/getDefaultExportFromNamespaceIfPresent(axios); + +var netAdapter_1; +var hasRequiredNetAdapter; + +function requireNetAdapter () { + if (hasRequiredNetAdapter) return netAdapter_1; + hasRequiredNetAdapter = 1; + const _axios = require$$0$1; + + function httpAdapter(baseURL, path, axiosInterceptor) { + //@ts-ignore + const axios = _axios.default ? _axios.default.create({ baseURL }) : _axios.create({ baseURL }); + axiosInterceptor.applyTo(axios); + + let c = { + get, + post, + patch, + query, + express + }; + + return c; + + async function get() { + try { + const headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' }; + const res = await axios.request(path, { headers, method: 'get' }); + return res.data; + } + catch (e) { + if (typeof e.response?.data === 'string') + throw new Error(e.response.data.replace(/^Error: /, '')); + else + throw e; + } + + } + + async function patch(body) { + try { + + const headers = { 'Content-Type': 'application/json' }; + const res = await axios.request(path, { headers, method: 'patch', data: body }); + return res.data; + } + catch (e) { + if (typeof e.response?.data === 'string') + throw new Error(e.response.data.replace(/^Error: /, '')); + else + throw e; + } + + + } + + async function post(body) { + try { + const headers = { 'Content-Type': 'application/json' }; + const res = await axios.request(path, { headers, method: 'post', data: body }); + return res.data; + } + catch (e) { + if (typeof e.response?.data === 'string') + throw new Error(e.response.data.replace(/^Error: /, '')); + else throw e; + } + } + + + function query() { + throw new Error('Queries are not supported through http'); + } + + function express() { + throw new Error('Hosting in express is not supported on the client side'); + } + } + + function netAdapter(url, tableName, { axios, tableOptions }) { + + let c = { + get, + post, + patch, + query + }; + + return c; + + async function get() { + const adapter = await getInnerAdapter(); + return adapter.get.apply(null, arguments); + } + + async function patch(_body) { + const adapter = await getInnerAdapter(); + return adapter.patch.apply(null, arguments); + } + + async function post(_body) { + const adapter = await getInnerAdapter(); + return adapter.post.apply(null, arguments); + } + + async function query() { + const adapter = await getInnerAdapter(); + return adapter.query.apply(null, arguments); + } + + async function getInnerAdapter() { + const db = await getDb(); + if (typeof db === 'string') { + return httpAdapter(db, `?table=${tableName}`, axios); + } + else if (db && db.transaction) { + return db.hostLocal({ ...tableOptions, db, table: url }); + } + else + throw new Error('Invalid arguments'); + } + + async function getDb() { + let db = tableOptions.db; + if (db.transaction) + return db; + if (typeof db === 'function') { + let dbPromise = db(); + if (dbPromise.then) + db = await dbPromise; + else + db = dbPromise; + } + + return db; + } + + } + + netAdapter_1 = netAdapter; + return netAdapter_1; +} + +var toKeyPositionMap_1; +var hasRequiredToKeyPositionMap; + +function requireToKeyPositionMap () { + if (hasRequiredToKeyPositionMap) return toKeyPositionMap_1; + hasRequiredToKeyPositionMap = 1; + const stringify = requireStringify(); + const { v4: uuid } = require$$0$2; + + function toKeyPositionMap(rows, options) { + return rows.reduce((map, element, i) => { + if (options && options.keys && element === Object(element)) { + let key = []; + for (let i = 0; i < options.keys.length; i++) { + let keyName = options.keys[i].name; + key.push(negotiateTempKey(element[keyName])); + } + map[stringify(key)] = i; + } + else if ('id' in element) + map[stringify(element.id)] = i; + else + map[i] = i; + return map; + }, {}); + + } + + function negotiateTempKey(value) { + if (value === undefined) + return `~${uuid()}`; + else + return value; + } + + toKeyPositionMap_1 = toKeyPositionMap; + return toKeyPositionMap_1; +} + +var clientMap; +var hasRequiredClientMap; + +function requireClientMap () { + if (hasRequiredClientMap) return clientMap; + hasRequiredClientMap = 1; + function map(index, _fn) { + const handler = { + get(target, prop) { + if (prop === 'map') { + return () => { + return new Proxy(onFinal, handler); + }; + } else if (typeof target[prop] !== 'undefined') { + return target[prop]; + } else { + return () => { + return new Proxy({}, handler); + }; + } + }, + apply(target, _thisArg, argumentsList) { + if (target === onFinal) { + return target(...argumentsList); + } else { + return new Proxy({}, handler); + } + }, + set(target, prop, value) { + target[prop] = value; + return true; + }, + }; + + function dbMap(fn) { + return fn(dbMap); + } + + dbMap.http = (url) => url; + dbMap.pg = throwDb; + dbMap.postgres = throwDb; + dbMap.mssql = throwDb; + dbMap.mssqlNative = throwDb; + dbMap.mysql = throwDb; + dbMap.sap = throwDb; + dbMap.oracle = throwDb; + dbMap.sqlite = throwDb; + dbMap.d1 = throwDb; + + function throwDb() { + throw new Error('Cannot create pool for database outside node'); + } + + function onFinal(arg) { + if (arg && arg.db && typeof arg.db === 'function') { + return index({ + ...arg, + db: dbMap(arg.db), + providers: dbMap + }); + } + + return index({ ...arg, providers: dbMap }); + } + + onFinal.http = (url) => index({ db: url, providers: dbMap }); + onFinal.pg = () => index({ db: throwDb, providers: dbMap }); + onFinal.postgres = () => index({ db: throwDb, providers: dbMap }); + onFinal.mssql = () => index({ db: throwDb, providers: dbMap }); + onFinal.mssqlNative = () => index({ db: throwDb, providers: dbMap }); + onFinal.mysql = () => index({ db: throwDb, providers: dbMap }); + onFinal.sap = () => index({ db: throwDb, providers: dbMap }); + onFinal.oracle = () => index({ db: throwDb, providers: dbMap }); + onFinal.sqlite = () => index({ db: throwDb, providers: dbMap }); + onFinal.d1 = () => index({ db: throwDb, providers: dbMap }); + + return new Proxy(onFinal, handler); + } + + clientMap = map; + return clientMap; +} + +var require$$5 = /*@__PURE__*/getDefaultExportFromNamespaceIfPresent(_default); + +var axiosInterceptor; +var hasRequiredAxiosInterceptor; + +function requireAxiosInterceptor () { + if (hasRequiredAxiosInterceptor) return axiosInterceptor; + hasRequiredAxiosInterceptor = 1; + class InterceptorProxy { + constructor() { + this.requestInterceptors = []; + this.responseInterceptors = []; + } + + get request() { + return { + use: (onFulfilled, onRejected) => { + const id = Math.random().toString(36).substr(2, 9); // unique id + this.requestInterceptors.push({ id, onFulfilled, onRejected }); + return id; + }, + eject: (id) => { + this.requestInterceptors = this.requestInterceptors.filter(interceptor => interceptor.id !== id); + } + }; + } + + get response() { + return { + use: (onFulfilled, onRejected) => { + const id = Math.random().toString(36).substr(2, 9); // unique id + this.responseInterceptors.push({ id, onFulfilled, onRejected }); + return id; + }, + eject: (id) => { + this.responseInterceptors = this.responseInterceptors.filter(interceptor => interceptor.id !== id); + } + }; + } + + applyTo(axiosInstance) { + for (const { onFulfilled, onRejected } of this.requestInterceptors) { + axiosInstance.interceptors.request.use(onFulfilled, onRejected); + } + + for (const { onFulfilled, onRejected } of this.responseInterceptors) { + axiosInstance.interceptors.response.use(onFulfilled, onRejected); + } + } + } + + axiosInterceptor = function create() { + return new InterceptorProxy(); + }; + return axiosInterceptor; +} + +var flags_1; +var hasRequiredFlags; + +function requireFlags () { + if (hasRequiredFlags) return flags_1; + hasRequiredFlags = 1; + let flags = { + useProxy: true, + useLazyDefaults: true + }; + + flags_1 = flags; + return flags_1; +} + +var client; +var hasRequiredClient; + +function requireClient () { + if (hasRequiredClient) return client; + hasRequiredClient = 1; + const createPatch = requireCreatePatch(); + const stringify = requireStringify(); + const cloneFromDb = requireCloneFromDb(); + const netAdapter = requireNetAdapter(); + const toKeyPositionMap = requireToKeyPositionMap(); + const rootMap = new WeakMap(); + const fetchingStrategyMap = new WeakMap(); + const targetKey = Symbol(); + const map = requireClientMap(); + const clone = require$$5; + const createAxiosInterceptor = requireAxiosInterceptor(); + const flags = requireFlags(); + + function rdbClient(options = {}) { + flags.useLazyDefaults = false; + if (options.pg) + options = { db: options }; + let transaction = options.transaction; + let _reactive = options.reactive; + let providers = options.providers || {}; + let baseUrl = options.db; + if (typeof providers === 'function') + baseUrl = typeof options.db === 'function' ? providers(options.db) : options.db; + const axiosInterceptor = createAxiosInterceptor(); + + function client(_options = {}) { + if (_options.pg) + _options = { db: _options }; + return rdbClient({ ...options, ..._options }); + } + + client.reactive = (cb => _reactive = cb); + client.map = map.bind(null, client); + Object.defineProperty(client, 'metaData', { + get: getMetaData, + enumerable: true, + configurable: false + }); + client.interceptors = axiosInterceptor; + client.createPatch = _createPatch; + client.table = table; + client.or = column('or'); + client.and = column('and'); + client.not = column('not'); + client.filter = { + or: client.or, + and: client.and, + not: client.not, + toJSON: function() { + return; + } + }; + client.query = query; + client.transaction = runInTransaction; + client.db = baseUrl; + client.mssql = onProvider.bind(null, 'mssql'); + client.mssqlNative = onProvider.bind(null, 'mssqlNative'); + client.pg = onProvider.bind(null, 'pg'); + client.postgres = onProvider.bind(null, 'postgres'); + client.d1 = onProvider.bind(null, 'd1'); + client.sqlite = onProvider.bind(null, 'sqlite'); + client.sap = onProvider.bind(null, 'sap'); + client.oracle = onProvider.bind(null, 'oracle'); + client.http = onProvider.bind(null, 'http');//todo + client.mysql = onProvider.bind(null, 'mysql'); + client.express = express; + + function onProvider(name, ...args) { + let db = providers[name].apply(null, args); + return client({ db }); + } + + if (options.tables) { + // for (let name in options.tables) { + // client[name] = table(options.tables[name], name, { ...readonly, ...clone(options[name]) }); + // } + client.tables = options.tables; + // return client; + } + // else { + let handler = { + get(_target, property,) { + if (property in client) + return Reflect.get(...arguments); + else { + const readonly = { readonly: options.readonly, concurrency: options.concurrency }; + return table(options?.tables?.[property] || baseUrl, property, { ...readonly, ...clone(options[property]) }); + } + } + + }; + return new Proxy(client, handler); + // } + + function getMetaData() { + const result = { readonly: options.readonly, concurrency: options.concurrency }; + for (let name in options.tables) { + result[name] = getMetaDataTable(options.tables[name], inferOptions(options, name)); + } + return result; + } + + function inferOptions(defaults, property) { + const parent = {}; + if ('readonly' in defaults) + parent.readonly = defaults.readonly; + if ('concurrency' in defaults) + parent.concurrency = defaults.concurrency; + return { ...parent, ...(defaults[property] || {}) }; + } + + + function getMetaDataTable(table, options) { + const result = {}; + for (let i = 0; i < table._columns.length; i++) { + const name = table._columns[i].alias; + result[name] = inferOptions(options, name); + } + for (let name in table._relations) { + if (!isJoinRelation(name, table)) + result[name] = getMetaDataTable(table._relations[name].childTable, inferOptions(options, name)); + } + + return result; + + function isJoinRelation(name, table) { + return table[name] && table[name]._relation.columns; + } + } + + async function query() { + const adapter = netAdapter(baseUrl, undefined, { tableOptions: { db: baseUrl, transaction } }); + return adapter.query.apply(null, arguments); + } + + function express(arg) { + if (providers.express) { + return providers.express(client, { ...options, ...arg }); + } + else + throw new Error('Cannot host express clientside'); + } + + + + function _createPatch(original, modified, ...restArgs) { + if (!Array.isArray(original)) { + original = [original]; + modified = [modified]; + } + let args = [original, modified, ...restArgs]; + return createPatch(...args); + } + + async function getDb() { + let db = baseUrl; + if (typeof db === 'function') { + let dbPromise = db(); + if (dbPromise.then) + db = await dbPromise; + else + db = dbPromise; + } + + return db; + } + + async function runInTransaction(fn, _options) { + let db = await getDb(); + if (!db.createTransaction) + throw new Error('Transaction not supported through http'); + const transaction = db.createTransaction(_options); + + try { + const nextClient = client({ transaction }); + await fn(nextClient); + await transaction(transaction.commit); + } + catch (e) { + await transaction(transaction.rollback.bind(null, e)); + } + } + + function table(url, tableName, tableOptions) { + tableOptions = tableOptions || {}; + tableOptions = { db: baseUrl, ...tableOptions, transaction }; + let meta; + let c = { + count, + getMany, + aggregate: groupBy, + getAll, + getOne, + getById, + proxify, + update, + replace, + updateChanges, + insert, + insertAndForget, + delete: _delete, + deleteCascade, + patch, + expand, + }; + + + let handler = { + get(_target, property,) { + if (property in c) + return Reflect.get(...arguments); + else + return column(property); + } + + }; + let _table = new Proxy(c, handler); + return _table; + + function expand() { + return c; + } + + async function getAll() { + let _getMany = getMany.bind(null, undefined); + return _getMany.apply(null, arguments); + } + + async function getMany(_, strategy) { + let metaPromise = getMeta(); + strategy = extractFetchingStrategy({}, strategy); + let args = [_, strategy].concat(Array.prototype.slice.call(arguments).slice(2)); + let rows = await getManyCore.apply(null, args); + await metaPromise; + return proxify(rows, strategy, true); + } + + async function groupBy(strategy) { + let args = negotiateGroupBy(null, strategy); + let body = stringify({ + path: 'aggregate', + args + }); + let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); + return adapter.post(body); + } + + async function count(_) { + let args = [_].concat(Array.prototype.slice.call(arguments).slice(1)); + let body = stringify({ + path: 'count', + args + }); + let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); + return adapter.post(body); + } + + async function getOne(filter, strategy) { + let metaPromise = getMeta(); + strategy = extractFetchingStrategy({}, strategy); + let _strategy = { ...strategy, ...{ limit: 1 } }; + let args = [filter, _strategy].concat(Array.prototype.slice.call(arguments).slice(2)); + let rows = await getManyCore.apply(null, args); + await metaPromise; + if (rows.length === 0) + return; + return proxify(rows[0], strategy, true); + } + + async function getById() { + if (arguments.length === 0) + return; + let meta = await getMeta(); + let keyFilter = client.filter; + for (let i = 0; i < meta.keys.length; i++) { + let keyName = meta.keys[i].name; + let keyValue = arguments[i]; + keyFilter = keyFilter.and(_table[keyName].eq(keyValue)); + } + let args = [keyFilter].concat(Array.prototype.slice.call(arguments).slice(meta.keys.length)); + return getOne.apply(null, args); + } + + async function getManyCore() { + let args = negotiateWhere.apply(null, arguments); + let body = stringify({ + path: 'getManyDto', + args + }); + let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); + return adapter.post(body); + } + + function negotiateWhere(_, strategy, ...rest) { + const args = Array.prototype.slice.call(arguments); + if (strategy) + return [_, negotiateWhereSingle(strategy), ...rest]; + else + return args; + + + } + + function negotiateWhereSingle(_strategy, path = '') { + if (typeof _strategy !== 'object' || _strategy === null) + return _strategy; + + if (Array.isArray(_strategy)) { + return _strategy.map(item => negotiateWhereSingle(item, path)); + } + + const strategy = { ..._strategy }; + for (let name in _strategy) { + if (name === 'where' && typeof strategy[name] === 'function') + strategy.where = column(path + 'where')(strategy.where); // Assuming `column` is defined elsewhere. + else if (typeof strategy[name] === 'function') { + strategy[name] = aggregate(path, strategy[name]); + } + else + strategy[name] = negotiateWhereSingle(_strategy[name], path + name + '.'); + } + return strategy; + } + + + + function negotiateGroupBy(_, strategy, ...rest) { + const args = Array.prototype.slice.call(arguments); + if (strategy) + return [_, where(strategy), ...rest]; + else + return args; + + function where(_strategy, path = '') { + if (typeof _strategy !== 'object' || _strategy === null) + return _strategy; + + if (Array.isArray(_strategy)) { + return _strategy.map(item => where(item, path)); + } + + const strategy = { ..._strategy }; + for (let name in _strategy) { + if (name === 'where' && typeof strategy[name] === 'function') + strategy.where = column(path + 'where')(strategy.where); // Assuming `column` is defined elsewhere. + else if (typeof strategy[name] === 'function') { + strategy[name] = groupByAggregate(path, strategy[name]); + } + else + strategy[name] = where(_strategy[name], path + name + '.'); + } + return strategy; + } + + } + + + + + + async function _delete() { + let args = Array.prototype.slice.call(arguments); + let body = stringify({ + path: 'delete', + args + }); + let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); + return adapter.post(body); + } + + async function deleteCascade() { + let args = Array.prototype.slice.call(arguments); + let body = stringify({ + path: 'deleteCascade', + args + }); + let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); + return adapter.post(body); + } + + async function update(_row, _where, strategy) { + let args = [_row, negotiateWhereSingle(_where), negotiateWhereSingle(strategy)]; + let body = stringify({ + path: 'update', + args + }); + let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); + const result = await adapter.post(body); + if (strategy) + return proxify(result, strategy); + } + + async function replace(_row, strategy) { + let args = [_row, negotiateWhereSingle(strategy)]; + let body = stringify({ + path: 'replace', + args + }); + let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); + const result = await adapter.post(body); + if (strategy) + return proxify(result, strategy); + } + + async function updateChanges(rows, oldRows, ...rest) { + const concurrency = undefined; + const args = [concurrency].concat(rest); + if (Array.isArray(rows)) { + const proxy = await getMany.apply(null, [rows, ...rest]); + proxy.splice.apply(proxy, [0, proxy.length, ...rows]); + await proxy.saveChanges.apply(proxy, args); + return proxy; + } + else { + let proxy = proxify([oldRows], args[0]); + proxy.splice.apply(proxy, [0, 1, rows]); + await proxy.saveChanges.apply(proxy, args); + return proxify(proxy[0], args[0]); + } + } + + async function insert(rows, ...rest) { + const concurrency = undefined; + const args = [concurrency].concat(rest); + if (Array.isArray(rows)) { + let proxy = proxify([], rest[0]); + proxy.splice.apply(proxy, [0, 0, ...rows]); + await proxy.saveChanges.apply(proxy, args); + return proxy; + } + else { + let proxy = proxify([], args[0]); + proxy.splice.apply(proxy, [0, 0, rows]); + await proxy.saveChanges.apply(proxy, args); + return proxify(proxy[0], rest[0]); + } + } + + async function insertAndForget(rows) { + const concurrency = undefined; + let args = [concurrency, { insertAndForget: true }]; + if (Array.isArray(rows)) { + let proxy = proxify([], args[0]); + proxy.splice.apply(proxy, [0, 0, ...rows]); + await proxy.saveChanges.apply(proxy, args); + } + else { + let proxy = proxify([], args[0]); + proxy.splice.apply(proxy, [0, 0, rows]); + await proxy.saveChanges.apply(proxy, args); + } + } + + + function proxify(itemOrArray, strategy, fast) { + if (Array.isArray(itemOrArray)) + return proxifyArray(itemOrArray, strategy, fast); + else + return proxifyRow(itemOrArray, strategy, fast); + } + + function proxifyArray(array, strategy, fast) { + let _array = array; + if (_reactive) + array = _reactive(array); + let handler = { + get(_target, property) { + if (property === 'toJSON') + return () => { + return toJSON(array); + }; + else if (property === 'save' || property === 'saveChanges') + return saveArray.bind(null, array); + else if (property === 'delete') + return deleteArray.bind(null, array); + else if (property === 'refresh') + return refreshArray.bind(null, array); + else if (property === 'clearChanges') + return clearChangesArray.bind(null, array); + else if (property === 'acceptChanges') + return acceptChangesArray.bind(null, array); + else if (property === targetKey) + return _array; + else + return Reflect.get.apply(_array, arguments); + } + + }; + + let watcher = onChange(array, () => { + rootMap.set(array, { json: cloneFromDb(array, fast), strategy, originalArray: [...array] }); + }); + let innerProxy = new Proxy(watcher, handler); + if (strategy !== undefined) { + const { limit, ...cleanStrategy } = { ...strategy }; + fetchingStrategyMap.set(array, cleanStrategy); + } + return innerProxy; + } + + function proxifyRow(row, strategy, fast) { + let handler = { + get(_target, property,) { + if (property === 'save' || property === 'saveChanges') //call server then acceptChanges + return saveRow.bind(null, row); + else if (property === 'delete') //call server then remove from json and original + return deleteRow.bind(null, row); + else if (property === 'refresh') //refresh from server then acceptChanges + return refreshRow.bind(null, row); + else if (property === 'clearChanges') //refresh from json, update original if present + return clearChangesRow.bind(null, row); + else if (property === 'acceptChanges') //remove from json + return acceptChangesRow.bind(null, row); + else if (property === 'toJSON') + return () => { + return toJSON(row); + }; + else if (property === targetKey) + return row; + else + return Reflect.get(...arguments); + } + + }; + let watcher = onChange(row, () => { + rootMap.set(row, { json: cloneFromDb(row, fast), strategy }); + }); + let innerProxy = new Proxy(watcher, handler); + fetchingStrategyMap.set(row, strategy); + return innerProxy; + } + + function toJSON(row, _meta = meta) { + if (!row) + return null; + if (!_meta) + return row; + if (Array.isArray(row)) { + return row.map(x => toJSON(x, _meta)); + } + let result = {}; + for (let name in row) { + if (name in _meta.relations) + result[name] = toJSON(row[name], _meta.relations[name]); + else if (name in _meta.columns) { + if (_meta.columns[name].serializable) + result[name] = row[name]; + } + else + result[name] = row[name]; + } + return result; + } + + + + + async function getMeta() { + if (meta) + return meta; + let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); + meta = await adapter.get(); + + while (hasUnresolved(meta)) { + meta = parseMeta(meta); + } + return meta; + + function parseMeta(meta, map = new Map()) { + if (typeof meta === 'number') { + return map.get(meta) || meta; + } + map.set(meta.id, meta); + for (let p in meta.relations) { + meta.relations[p] = parseMeta(meta.relations[p], map); + } + return meta; + } + + function hasUnresolved(meta, set = new WeakSet()) { + if (typeof meta === 'number') + return true; + else if (set.has(meta)) + return false; + else { + set.add(meta); + return Object.values(meta.relations).reduce((prev, current) => { + return prev || hasUnresolved(current, set); + }, false); + } + } + + + } + + async function saveArray(array, concurrencyOptions, strategy) { + let deduceStrategy = false; + let json = rootMap.get(array)?.json; + if (!json) + return; + strategy = extractStrategy({ strategy }, array); + strategy = extractFetchingStrategy(array, strategy); + + let meta = await getMeta(); + const patch = createPatch(json, array, meta); + if (patch.length === 0) + return; + let body = stringify({ patch, options: { strategy, ...tableOptions, ...concurrencyOptions, deduceStrategy } }); + let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); + let p = adapter.patch(body); + if (strategy?.insertAndForget) { + await p; + return; + } + + let updatedPositions = extractChangedRowsPositions(array, patch, meta); + let insertedPositions = getInsertedRowsPosition(array); + let { changed, strategy: newStrategy } = await p; + copyIntoArray(changed, array, [...insertedPositions, ...updatedPositions]); + rootMap.set(array, { json: cloneFromDb(array), strategy: newStrategy, originalArray: [...array] }); + } + + async function patch(patch, concurrencyOptions, strategy) { + let deduceStrategy = false; + if (patch.length === 0) + return; + let body = stringify({ patch, options: { strategy, ...tableOptions, ...concurrencyOptions, deduceStrategy } }); + let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); + await adapter.patch(body); + return; + } + + function extractChangedRowsPositions(rows, patch, meta) { + const positions = []; + const originalSet = new Set(rootMap.get(rows).originalArray); + const positionsAdded = {}; + const keyPositionMap = toKeyPositionMap(rows, meta); + for (let i = 0; i < patch.length; i++) { + const element = patch[i]; + const pathArray = element.path.split('/'); + const position = keyPositionMap[pathArray[1]]; + if (position >= 0 && originalSet.has(rows[position]) && !positionsAdded[position]) { + positions.push(position); + positionsAdded[position] = true; + } + } + return positions; + } + + function getInsertedRowsPosition(array) { + const positions = []; + const originalSet = new Set(rootMap.get(array).originalArray); + for (let i = 0; i < array.length; i++) { + if (!originalSet.has(array[i])) + positions.push(i); + } + return positions; + } + + function copyInto(from, to) { + for (let i = 0; i < from.length; i++) { + for (let p in from[i]) { + to[i][p] = from[i][p]; + } + } + } + + function copyIntoArray(from, to, positions) { + for (let i = 0; i < from.length; i++) { + to[positions[i]] = from[i]; + } + } + + + function extractStrategy(options, obj) { + if (options?.strategy !== undefined) + return options.strategy; + if (obj) { + let context = rootMap.get(obj); + if (context?.strategy !== undefined) { + // @ts-ignore + let { limit, ...strategy } = { ...context.strategy }; + return strategy; + } + } + } + + function extractFetchingStrategy(obj, strategy) { + if (strategy !== undefined) + return strategy; + else if (fetchingStrategyMap.get(obj) !== undefined) { + // @ts-ignore + const { limit, ...strategy } = { ...fetchingStrategyMap.get(obj) }; + return strategy; + } + } + + function clearChangesArray(array) { + let json = rootMap.get(array)?.json; + if (!json) + return; + let old = cloneFromDb(json); + array.splice(0, old.length, ...old); + } + + function acceptChangesArray(array) { + const map = rootMap.get(array); + if (!map) + return; + map.json = cloneFromDb(array); + map.originalArray = [...array]; + } + + async function deleteArray(array, options) { + if (array.length === 0) + return; + let meta = await getMeta(); + let patch = createPatch(array, [], meta); + let body = stringify({ patch, options }); + let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); + let { strategy } = await adapter.patch(body); + array.length = 0; + rootMap.set(array, { json: cloneFromDb(array), strategy }); + } + + function setMapValue(rowsMap, keys, row, index) { + let keyValue = row[keys[0].name]; + if (keys.length > 1) { + let subMap = rowsMap.get(keyValue); + if (!subMap) { + subMap = new Map(); + rowsMap.set(keyValue, subMap); + } + setMapValue(subMap, keys.slice(1), row, index); + } + else + rowsMap.set(keyValue, index); + } + + function getMapValue(rowsMap, keys, row) { + let keyValue = row[keys[0].name]; + if (keys.length > 1) + return getMapValue(rowsMap.get(keyValue), keys.slice(1)); + else + return rowsMap.get(keyValue); + } + + async function refreshArray(array, strategy) { + clearChangesArray(array); + strategy = extractStrategy({ strategy }, array); + strategy = extractFetchingStrategy(array, strategy); + if (array.length === 0) + return; + let meta = await getMeta(); + let filter = client.filter; + let rowsMap = new Map(); + for (let rowIndex = 0; rowIndex < array.length; rowIndex++) { + let row = array[rowIndex]; + let keyFilter = client.filter; + for (let i = 0; i < meta.keys.length; i++) { + let keyName = meta.keys[i].name; + let keyValue = row[keyName]; + keyFilter = keyFilter.and(_table[keyName].eq(keyValue)); + } + setMapValue(rowsMap, meta.keys, row, rowIndex); + filter = filter.or(keyFilter); + } + let rows = await getManyCore(filter, strategy); + let removedIndexes = new Set(); + if (array.length !== rows.length) + for (var i = 0; i < array.length; i++) { + removedIndexes.add(i); + } + for (let i = 0; i < rows.length; i++) { + let row = rows[i]; + let originalIndex = getMapValue(rowsMap, meta.keys, row); + if (array.length !== rows.length) + removedIndexes.delete(originalIndex); + array[originalIndex] = row; + } + let offset = 0; + for (let i of removedIndexes) { + array.splice(i + offset, 1); + offset--; + } + rootMap.set(array, { json: cloneFromDb(array), strategy, originalArray: [...array] }); + fetchingStrategyMap.set(array, strategy); + } + + async function deleteRow(row, options) { + let strategy = extractStrategy(options, row); + let meta = await getMeta(); + let patch = createPatch([row], [], meta); + let body = stringify({ patch, options }); + let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); + await adapter.patch(body); + rootMap.set(row, { strategy }); + } + + async function saveRow(row, concurrencyOptions, strategy) { + let deduceStrategy; + if (arguments.length < 3) + deduceStrategy = false; + strategy = extractStrategy({ strategy }, row); + strategy = extractFetchingStrategy(row, strategy); + + let json = rootMap.get(row)?.json; + if (!json) + return; + let meta = await getMeta(); + + let patch = createPatch([json], [row], meta); + if (patch.length === 0) + return; + + let body = stringify({ patch, options: { ...tableOptions, ...concurrencyOptions, strategy, deduceStrategy } }); + + let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); + let { changed, strategy: newStrategy } = await adapter.patch(body); + copyInto(changed, [row]); + rootMap.set(row, { json: cloneFromDb(row), strategy: newStrategy }); + } + + async function refreshRow(row, strategy) { + clearChangesRow(row); + strategy = extractStrategy({ strategy }, row); + strategy = extractFetchingStrategy(row, strategy); + + let meta = await getMeta(); + let keyFilter = client.filter; + for (let i = 0; i < meta.keys.length; i++) { + let keyName = meta.keys[i].name; + let keyValue = row[keyName]; + keyFilter = keyFilter.and(_table[keyName].eq(keyValue)); + } + let rows = await getManyCore(keyFilter, strategy); + for (let p in row) { + delete row[p]; + } + if (rows.length === 0) + return; + for (let p in rows[0]) { + row[p] = rows[0][p]; + } + rootMap.set(row, { json: cloneFromDb(row), strategy }); + fetchingStrategyMap.set(row, strategy); + } + + function acceptChangesRow(row) { + const data = rootMap.get(row); + if (!data) + return; + const { strategy } = data; + rootMap.set(row, { json: cloneFromDb(row), strategy }); + } + + function clearChangesRow(row) { + let json = rootMap.get(row)?.json; + if (!json) + return; + let old = cloneFromDb(json); + for (let p in row) { + delete row[p]; + } + for (let p in old) { + row[p] = old[p]; + } + } + } + } + + function tableProxy() { + let handler = { + get(_target, property,) { + return column(property); + } + + }; + return new Proxy({}, handler); + } + + function aggregate(path, arg) { + + const c = { + sum, + count, + avg, + max, + min + }; + + let handler = { + get(_target, property,) { + if (property in c) + return Reflect.get(...arguments); + else { + subColumn = column(path + '_aggregate'); + return column(property); + } + } + + }; + let subColumn; + const proxy = new Proxy(c, handler); + + const result = arg(proxy); + + if (subColumn) + return subColumn(result.self()); + else + return result; + + + function sum(fn) { + return column(path + '_aggregate')(fn(column('')).groupSum()); + } + function avg(fn) { + return column(path + '_aggregate')(fn(column('')).groupAvg()); + } + function max(fn) { + return column(path + '_aggregate')(fn(column('')).groupMax()); + } + function min(fn) { + return column(path + '_aggregate')(fn(column('')).groupMin()); + } + function count(fn) { + return column(path + '_aggregate')(fn(column('')).groupCount()); + } + } + + function groupByAggregate(path, arg) { + + const c = { + sum, + count, + avg, + max, + min + }; + + let handler = { + get(_target, property,) { + if (property in c) + return Reflect.get(...arguments); + else { + subColumn = column(path + '_aggregate'); + return column(property); + } + } + + }; + let subColumn; + const proxy = new Proxy(c, handler); + + const result = arg(proxy); + + if (subColumn) + return subColumn(result.self()); + else + return result; + + + function sum(fn) { + return column(path + '_aggregate')(fn(column('')).sum()); + } + function avg(fn) { + return column(path + '_aggregate')(fn(column('')).avg()); + } + function max(fn) { + return column(path + '_aggregate')(fn(column('')).max()); + } + function min(fn) { + return column(path + '_aggregate')(fn(column('')).min()); + } + function count(fn) { + return column(path + '_aggregate')(fn(column('')).count()); + } + } + + function column(path, ...previous) { + function c() { + let args = []; + for (let i = 0; i < arguments.length; i++) { + if (typeof arguments[i] === 'function') + args[i] = arguments[i](tableProxy(path.split('.').slice(0, -1).join('.'))); + else + args[i] = arguments[i]; + } + args = previous.concat(Array.prototype.slice.call(args)); + let result = { path, args }; + let handler = { + get(_target, property) { + if (property === 'toJSON') + return result.toJSON; + else if (property === 'then') + return; + if (property in result) + return Reflect.get(...arguments); + else + return column(property, result); + + } + }; + return new Proxy(result, handler); + } + let handler = { + get(_target, property) { + if (property === 'toJSON') + return Reflect.get(...arguments); + else if (property === 'then') + return; + else { + const nextPath = path ? path + '.' : ''; + return column(nextPath + property); + } + } + + }; + return new Proxy(c, handler); + + } + + function onChange(target, onChange) { + + let notified = false; + const handler = { + get(target, prop, receiver) { + const value = Reflect.get(target, prop, receiver); + if (typeof value === 'object' && value !== null) { + return new Proxy(value, handler); + } + return value; + }, + set(target, prop, value, receiver) { + if (!notified) { + notified = true; + onChange(JSON.stringify(target)); + } + return Reflect.set(target, prop, value, receiver); + + }, + deleteProperty(target, prop) { + if (!notified) { + notified = true; + onChange(JSON.stringify(target)); + } + return Reflect.deleteProperty(target, prop); + } + }; + + return new Proxy(target, handler); + } + + + client = rdbClient(); + return client; +} + +var newBoolean_1; +var hasRequiredNewBoolean; + +function requireNewBoolean () { + if (hasRequiredNewBoolean) return newBoolean_1; + hasRequiredNewBoolean = 1; + const { newBoolean } = requireUtils(); + + newBoolean_1 = newBoolean; + return newBoolean_1; +} + +var encodeFilterArg_1; +var hasRequiredEncodeFilterArg; + +function requireEncodeFilterArg () { + if (hasRequiredEncodeFilterArg) return encodeFilterArg_1; + hasRequiredEncodeFilterArg = 1; + function encodeFilterArg(context, column, arg) { + if (column.encode.safe) + return column.encode.safe(context, arg); + else + return column.encode(context, arg); + } + + encodeFilterArg_1 = encodeFilterArg; + return encodeFilterArg_1; +} + +var quote_1; +var hasRequiredQuote$1; + +function requireQuote$1 () { + if (hasRequiredQuote$1) return quote_1; + hasRequiredQuote$1 = 1; + let tryGetSessionContext = requireTryGetSessionContext(); + + function quote(context, name) { + let rdb = tryGetSessionContext(context); + if (!rdb) + throw new Error('Rdb transaction is no longer available. Is promise chain broken ?'); + let fn = rdb.quote || (() => `"${name}"`); + return fn(name); + } + + quote_1 = quote; + return quote_1; +} + +var equal_1; +var hasRequiredEqual; + +function requireEqual () { + if (hasRequiredEqual) return equal_1; + hasRequiredEqual = 1; + var newBoolean = requireNewBoolean(); + var nullOperator = ' is '; + var encodeFilterArg = requireEncodeFilterArg(); + var quote = requireQuote$1(); + + function equal(context, column,arg,alias) { + var operator = '='; + var encoded = encodeFilterArg(context, column, arg); + if (encoded.sql() == 'null') + operator = nullOperator; + var firstPart = quote(context, alias) + '.' + quote(context, column._dbName) + operator; + var filter = encoded.prepend(firstPart); + return newBoolean(filter); + } + + equal_1 = equal; + return equal_1; +} + +var notEqual_1; +var hasRequiredNotEqual; + +function requireNotEqual () { + if (hasRequiredNotEqual) return notEqual_1; + hasRequiredNotEqual = 1; + var newBoolean = requireNewBoolean(); + var encodeFilterArg = requireEncodeFilterArg(); + var nullOperator = ' is not '; + var quote = requireQuote$1(); + + function notEqual(context, column,arg,alias) { + var operator = '<>'; + var encoded = encodeFilterArg(context, column, arg); + if (encoded.sql() == 'null') + operator = nullOperator; + var firstPart = quote(context, alias) + '.' + quote(context, column._dbName) + operator; + var filter = encoded.prepend(firstPart); + return newBoolean(filter); + } + + notEqual_1 = notEqual; + return notEqual_1; +} + +var lessThan; +var hasRequiredLessThan; + +function requireLessThan () { + if (hasRequiredLessThan) return lessThan; + hasRequiredLessThan = 1; + var newBoolean = requireNewBoolean(); + var encodeFilterArg = requireEncodeFilterArg(); + var quote = requireQuote$1(); + + function lessThanOrEqual(context, column,arg,alias) { + var operator = '<'; + var encoded = encodeFilterArg(context, column, arg); + var firstPart = quote(context, alias) + '.' + quote(context, column._dbName) + operator; + var filter = encoded.prepend(firstPart); + return newBoolean(filter); + } + + lessThan = lessThanOrEqual; + return lessThan; +} + +var lessThanOrEqual_1; +var hasRequiredLessThanOrEqual; + +function requireLessThanOrEqual () { + if (hasRequiredLessThanOrEqual) return lessThanOrEqual_1; + hasRequiredLessThanOrEqual = 1; + var newBoolean = requireNewBoolean(); + var encodeFilterArg = requireEncodeFilterArg(); + const getSessionSingleton = requireGetSessionSingleton(); + + function lessThanOrEqual(context, column,arg,alias) { + const quote = getSessionSingleton(context, 'quote'); + var operator = '<='; + var encoded = encodeFilterArg(context, column, arg); + var firstPart = quote(context, alias) + '.' + quote(context, column._dbName) + operator; + var filter = encoded.prepend(firstPart); + return newBoolean(filter); + } + + lessThanOrEqual_1 = lessThanOrEqual; + return lessThanOrEqual_1; +} + +var greaterThan_1; +var hasRequiredGreaterThan; + +function requireGreaterThan () { + if (hasRequiredGreaterThan) return greaterThan_1; + hasRequiredGreaterThan = 1; + var newBoolean = requireNewBoolean(); + var encodeFilterArg = requireEncodeFilterArg(); + var quote = requireQuote$1(); + + function greaterThan(context, column,arg,alias) { + var operator = '>'; + var encoded = encodeFilterArg(context, column, arg); + var firstPart = quote(context, alias) + '.' + quote(context, column._dbName) + operator; + var filter = encoded.prepend(firstPart); + return newBoolean(filter); + } + + greaterThan_1 = greaterThan; + return greaterThan_1; +} + +var greaterThanOrEqual_1; +var hasRequiredGreaterThanOrEqual; + +function requireGreaterThanOrEqual () { + if (hasRequiredGreaterThanOrEqual) return greaterThanOrEqual_1; + hasRequiredGreaterThanOrEqual = 1; + var newBoolean = requireNewBoolean(); + var encodeFilterArg = requireEncodeFilterArg(); + var quote = requireQuote$1(); + + function greaterThanOrEqual(context, column,arg,alias) { + var operator = '>='; + var encoded = encodeFilterArg(context, column, arg); + var firstPart = quote(context, alias) + '.' + quote(context, column._dbName) + operator; + var filter = encoded.prepend(firstPart); + return newBoolean(filter); + } + + greaterThanOrEqual_1 = greaterThanOrEqual; + return greaterThanOrEqual_1; +} + +var _in_1; +var hasRequired_in; + +function require_in () { + if (hasRequired_in) return _in_1; + hasRequired_in = 1; + const newParameterized = requireNewParameterized(); + const newBoolean = requireNewBoolean(); + const quote = requireQuote$1(); + + function _in(context, column,values,alias) { + let filter; + if (values.length === 0) { + filter = newParameterized('1=2'); + return newBoolean(filter); + } + const firstPart = `${quote(context, alias)}.${quote(context, column._dbName)} in (`; + + const encode = column.encode.direct; + const params = new Array(values.length); + for (let i = 0; i < values.length; i++) { + params[i] = encode(context, values[i]); + } + const sql = `${firstPart + new Array(values.length).fill('?').join(',')})`; + return newBoolean(newParameterized(sql, params)); + } + + _in_1 = _in; + return _in_1; +} + +var extractAlias; +var hasRequiredExtractAlias; + +function requireExtractAlias () { + if (hasRequiredExtractAlias) return extractAlias; + hasRequiredExtractAlias = 1; + function extract(table, optionalAlias) { + if (optionalAlias) + return optionalAlias; + return table._rootAlias || table._dbName; + } + + extractAlias = extract; + return extractAlias; +} + +var newColumn; +var hasRequiredNewColumn; + +function requireNewColumn () { + if (hasRequiredNewColumn) return newColumn; + hasRequiredNewColumn = 1; + const equal = requireEqual(); + const notEqual = requireNotEqual(); + const lessThan = requireLessThan(); + const lessThanOrEqual = requireLessThanOrEqual(); + const greaterThan = requireGreaterThan(); + const greaterThanOrEqual = requireGreaterThanOrEqual(); + const _in = require_in(); + const _extractAlias = requireExtractAlias(); + const quote = requireQuote$1(); + + newColumn = function(table, name) { + var c = {}; + var extractAlias = _extractAlias.bind(null, table); + c._dbName = name; + c.alias = name; + table._aliases.add(name); + + c.dbNull = null; + table._columns.push(c); + table[name] = c; + + c.equal = function(context, arg, alias) { + alias = extractAlias(alias); + return equal(context, c, arg, alias); + }; + + c.notEqual = function(context, arg, alias) { + alias = extractAlias(alias); + return notEqual(context, c, arg, alias); + }; + + c.lessThan = function(context, arg, alias) { + alias = extractAlias(alias); + return lessThan(context, c, arg, alias); + }; + + c.lessThanOrEqual = function(context, arg, alias) { + alias = extractAlias(alias); + return lessThanOrEqual(context, c, arg, alias); + }; + + c.greaterThan = function(context, arg, alias) { + alias = extractAlias(alias); + return greaterThan(context, c, arg, alias); + }; + + c.greaterThanOrEqual = function(context, arg, alias) { + alias = extractAlias(alias); + return greaterThanOrEqual(context, c, arg, alias); + }; + + c.between = function(context, from, to, alias) { + alias = extractAlias(alias); + from = c.greaterThanOrEqual(context, from, alias); + to = c.lessThanOrEqual(context, to, alias); + return from.and(to); + }; + + c.in = function(context, arg, alias) { + alias = extractAlias(alias); + return _in(context, c, arg, alias); + }; + + c.eq = c.equal; + c.EQ = c.eq; + c.ne = c.notEqual; + c.NE = c.ne; + c.gt = c.greaterThan; + c.GT = c.gt; + c.ge = c.greaterThanOrEqual; + c.GE = c.ge; + c.lt = c.lessThan; + c.LT = c.lt; + c.le = c.lessThanOrEqual; + c.LE = c.le; + c.IN = c.in; + c.self = self; + + function self(context) { + const tableAlias = quote(context,table._rootAlias || table._dbName); + const columnName = quote(context, c._dbName); + + return { + expression: (alias) => `${tableAlias}.${columnName} ${quote(context, alias)}`, + joins: [''], + column: c, + groupBy: `${tableAlias}.${columnName}` + }; + } + + return c; + }; + return newColumn; +} + +var require$$0 = /*@__PURE__*/getDefaultExportFromNamespaceIfPresent(ajv); + +var purify_1$5; +var hasRequiredPurify$6; + +function requirePurify$6 () { + if (hasRequiredPurify$6) return purify_1$5; + hasRequiredPurify$6 = 1; + function purify(value) { + if(value == null) + return null; + return value; + } + + purify_1$5 = purify; + return purify_1$5; +} + +var newEncode$7; +var hasRequiredNewEncode$7; + +function requireNewEncode$7 () { + if (hasRequiredNewEncode$7) return newEncode$7; + hasRequiredNewEncode$7 = 1; + var newPara = requireNewParameterized(); + var purify = requirePurify$6(); + + function _new(column) { + + var encode = function(_context, value) { + value = purify(value); + if (value == null) { + if (column.dbNull === null) + return newPara('null'); + return newPara('\'' + column.dbNull + '\''); + } + return newPara('?', [value]); + }; + + encode.unsafe = function(_context, value) { + value = purify(value); + if (value == null) { + if (column.dbNull === null) + return 'null'; + return '\'' + column.dbNull + '\''; + } + return '\'' + value + '\''; + }; + + encode.direct = function(_context, value) { + return value ; + }; + + return encode; + + } + + newEncode$7 = _new; + return newEncode$7; +} + +var newDecodeCore; +var hasRequiredNewDecodeCore; + +function requireNewDecodeCore () { + if (hasRequiredNewDecodeCore) return newDecodeCore; + hasRequiredNewDecodeCore = 1; + function _new(column) { + + return function(_context, value) { + if (value == column.dbNull) + return null; + return value; + }; + } + + newDecodeCore = _new; + return newDecodeCore; +} + +var startsWithCore_1; +var hasRequiredStartsWithCore; + +function requireStartsWithCore () { + if (hasRequiredStartsWithCore) return startsWithCore_1; + hasRequiredStartsWithCore = 1; + var newBoolean = requireNewBoolean(); + var nullOperator = ' is '; + var quote = requireQuote$1(); + + function startsWithCore(context, operator, column,arg,alias) { + operator = ' ' + operator + ' '; + var encoded = column.encode(context, arg); + if (encoded.sql() == 'null') + operator = nullOperator; + else + encoded = column.encode(context, arg + '%'); + var firstPart = quote(context, alias) + '.' + quote(context, column._dbName) + operator; + var filter = encoded.prepend(firstPart); + return newBoolean(filter); + } + + startsWithCore_1 = startsWithCore; + return startsWithCore_1; +} + +var startsWith; +var hasRequiredStartsWith; + +function requireStartsWith () { + if (hasRequiredStartsWith) return startsWith; + hasRequiredStartsWith = 1; + var startsWithCore = requireStartsWithCore(); + + startsWith = (context, ...rest) => startsWithCore.apply(null, [context, 'LIKE', ...rest]); + return startsWith; +} + +var endsWithCore_1; +var hasRequiredEndsWithCore; + +function requireEndsWithCore () { + if (hasRequiredEndsWithCore) return endsWithCore_1; + hasRequiredEndsWithCore = 1; + const quote = requireQuote$1(); + var newBoolean = requireNewBoolean(); + var nullOperator = ' is '; + + function endsWithCore(context, operator, column,arg,alias) { + alias = quote(alias); + operator = ' ' + operator + ' '; + var encoded = column.encode(context, arg); + if (encoded.sql() == 'null') + operator = nullOperator; + else + encoded = column.encode(context, '%' + arg); + var firstPart = alias + '.' + quote(context, column._dbName) + operator; + var filter = encoded.prepend(firstPart); + return newBoolean(filter); + } + + endsWithCore_1 = endsWithCore; + return endsWithCore_1; +} + +var endsWith; +var hasRequiredEndsWith; + +function requireEndsWith () { + if (hasRequiredEndsWith) return endsWith; + hasRequiredEndsWith = 1; + var endsWithCore = requireEndsWithCore(); + + endsWith = (context, ...rest) => endsWithCore.apply(null, [context, 'LIKE', ...rest]); + return endsWith; +} + +var containsCore; +var hasRequiredContainsCore; + +function requireContainsCore () { + if (hasRequiredContainsCore) return containsCore; + hasRequiredContainsCore = 1; + const quote = requireQuote$1(); + var newBoolean = requireNewBoolean(); + var nullOperator = ' is '; + + function endsWithCore(context, operator, column,arg,alias) { + alias = quote(context, alias); + operator = ' ' + operator + ' '; + var encoded = column.encode(context, arg); + if (encoded.sql() == 'null') + operator = nullOperator; + else + encoded = column.encode(context, '%' + arg + '%'); + var firstPart = alias + '.' + quote(context, column._dbName) + operator; + var filter = encoded.prepend(firstPart); + return newBoolean(filter); + } + + containsCore = endsWithCore; + return containsCore; +} + +var contains; +var hasRequiredContains; + +function requireContains () { + if (hasRequiredContains) return contains; + hasRequiredContains = 1; + var containsCore = requireContainsCore(); + + contains = (context, ...rest) => containsCore.apply(null, [context, 'LIKE', ...rest]); + return contains; +} + +var iStartsWith; +var hasRequiredIStartsWith; + +function requireIStartsWith () { + if (hasRequiredIStartsWith) return iStartsWith; + hasRequiredIStartsWith = 1; + var startsWithCore = requireStartsWithCore(); + + iStartsWith = (context, ...rest) => startsWithCore.apply(null, [context, 'ILIKE', ...rest]); + return iStartsWith; +} + +var iEndsWith; +var hasRequiredIEndsWith; + +function requireIEndsWith () { + if (hasRequiredIEndsWith) return iEndsWith; + hasRequiredIEndsWith = 1; + var endsWithCore = requireEndsWithCore(); + + iEndsWith = (context, ...rest) => endsWithCore.apply(null, [context, 'ILIKE', ...rest]); + return iEndsWith; +} + +var iContains; +var hasRequiredIContains; + +function requireIContains () { + if (hasRequiredIContains) return iContains; + hasRequiredIContains = 1; + var containsCore = requireContainsCore(); + + iContains = (context, ...rest) => containsCore.apply(null, [context, 'ILIKE', ...rest]); + return iContains; +} + +var iEqual_1; +var hasRequiredIEqual; + +function requireIEqual () { + if (hasRequiredIEqual) return iEqual_1; + hasRequiredIEqual = 1; + var newBoolean = requireNewBoolean(); + var nullOperator = ' is '; + var encodeFilterArg = requireEncodeFilterArg(); + const quote = requireQuote$1(); + + function iEqual(context, column,arg,alias) { + var operator = ' ILIKE '; + var encoded = encodeFilterArg(context, column, arg); + if (encoded.sql() == 'null') + operator = nullOperator; + var firstPart = alias + '.' + quote(context, column._dbName) + operator; + var filter = encoded.prepend(firstPart); + return newBoolean(filter); + } + + iEqual_1 = iEqual; + return iEqual_1; +} + +var string; +var hasRequiredString; + +function requireString () { + if (hasRequiredString) return string; + hasRequiredString = 1; + var newEncode = requireNewEncode$7(); + var newDecode = requireNewDecodeCore(); + var startsWith = requireStartsWith(); + var endsWith = requireEndsWith(); + var contains = requireContains(); + var iStartsWith = requireIStartsWith(); + var iEndsWith = requireIEndsWith(); + var iContains = requireIContains(); + var iEqual = requireIEqual(); + var purify = requirePurify$6(); + var _extractAlias = requireExtractAlias(); + + function _new(table, column) { + column.tsType = 'StringColumn'; + column.purify = purify; + column.encode = newEncode(column); + column.decode = newDecode(column); + var extractAlias = _extractAlias.bind(null, table); + + column.startsWith = function(context, arg, alias) { + alias = extractAlias(alias); + return startsWith(context, column, arg, alias); + }; + column.endsWith = function(context, arg, alias) { + alias = extractAlias(alias); + return endsWith(context, column, arg, alias); + }; + column.contains = function(context, arg, alias) { + alias = extractAlias(alias); + return contains(context, column, arg, alias); + }; + column.iStartsWith = function(context, arg, alias) { + alias = extractAlias(alias); + return iStartsWith(context, column, arg, alias); + }; + column.iEndsWith = function(context, arg, alias) { + alias = extractAlias(alias); + return iEndsWith(context, column, arg, alias); + }; + column.iContains = function(context, arg, alias) { + alias = extractAlias(alias); + return iContains(context, column, arg, alias); + }; + + column.iEqual = function(context, arg, alias) { + alias = extractAlias(alias); + return iEqual(context, column, arg, alias); + }; + + column.iEq = column.iEqual; + column.IEQ = column.iEqual; + column.ieq = column.iEqual; + } + + string = _new; + return string; +} + +var purify_1$4; +var hasRequiredPurify$5; + +function requirePurify$5 () { + if (hasRequiredPurify$5) return purify_1$4; + hasRequiredPurify$5 = 1; + function purify(value) { + if(value == null) + return null; + return value; + } + + purify_1$4 = purify; + return purify_1$4; +} + +var newEncode$6; +var hasRequiredNewEncode$6; + +function requireNewEncode$6 () { + if (hasRequiredNewEncode$6) return newEncode$6; + hasRequiredNewEncode$6 = 1; + var newPara = requireNewParameterized(); + var purify = requirePurify$5(); + var getSessionSingleton = requireGetSessionSingleton(); + + function _new(column) { + + const encode = function(context, candidate) { + var value = purify(candidate); + if (value == null) { + if(column.dbNull === null) + return newPara('null'); + return newPara('\'' + column.dbNull + '\''); + } + var encodeCore = getSessionSingleton(context, 'encodeJSON'); + + if (encodeCore) { + value = encodeCore(value); + } + return newPara('?', [value]); + + }; + + encode.unsafe = function(context, candidate) { + var value = purify(candidate); + if (value == null) { + if(column.dbNull === null) + return 'null'; + return '\'' + column.dbNull + '\''; + } + var encodeCore = getSessionSingleton(context, 'encodeJSON'); + + if (encodeCore) { + value = encodeCore(value); + } + return value; + }; + + encode.direct = function(context, value) { + var encodeCore = getSessionSingleton(context, 'encodeJSON'); + + if (encodeCore) { + value = encodeCore(value); + } + return value; + }; + + return encode; + } + + newEncode$6 = _new; + return newEncode$6; +} + +var newDecode$5; +var hasRequiredNewDecode$5; + +function requireNewDecode$5 () { + if (hasRequiredNewDecode$5) return newDecode$5; + hasRequiredNewDecode$5 = 1; + let newDecodeCore = requireNewDecodeCore(); + let getSessionContext = requireGetSessionContext(); + + function _new(column) { + let decodeCore = newDecodeCore(column); + + return function(context, value) { + value = decodeCore(context, value); + if (value === null) + return value; + if (typeof value !== 'object') { + let decode = getSessionContext(context).decodeJSON; + if (decode) + return decode(value); + return value; + } + return value; + }; + } + + newDecode$5 = _new; + return newDecode$5; +} + +var formatOut_1$1; +var hasRequiredFormatOut$1; + +function requireFormatOut$1 () { + if (hasRequiredFormatOut$1) return formatOut_1$1; + hasRequiredFormatOut$1 = 1; + var getSessionSingleton = requireGetSessionSingleton(); + const quote = requireQuote$1(); + + function formatOut(context, column, alias) { + var formatColumn = getSessionSingleton(context, 'formatJSONOut'); + if (formatColumn) + return formatColumn(column, alias); + else + return `${alias}.${quote(context, column._dbName)}`; + } + + formatOut_1$1 = formatOut; + return formatOut_1$1; +} + +var require$$10 = /*@__PURE__*/getDefaultExportFromNamespaceIfPresent(onChange); + +var json; +var hasRequiredJson; + +function requireJson () { + if (hasRequiredJson) return json; + hasRequiredJson = 1; + var newEncode = requireNewEncode$6(); + var newDecode = requireNewDecode$5(); + var formatOut = requireFormatOut$1(); + var purify = requirePurify$5(); + var onChange = require$$10; + let clone = require$$5; + + function _new(column) { + column.tsType = 'JSONColumn'; + column.purify = purify; + column.encode = newEncode(column); + column.decode = newDecode(column); + column.formatOut = (context, ...rest) => formatOut.apply(null, [context, column, ...rest]); + + column.onChange = onChange; + column.toDto = toDto; + } + + function toDto(value) { + return clone(value); + } + + json = _new; + return json; +} + +var purify; +var hasRequiredPurify$4; + +function requirePurify$4 () { + if (hasRequiredPurify$4) return purify; + hasRequiredPurify$4 = 1; + function negotiateGuidFormat(candidate) { + if(candidate == null) + return null; + var pattern = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i; + if(!pattern.test(candidate)) + throw new TypeError(candidate + ' is not a valid UUID'); + return candidate; + } + + purify = negotiateGuidFormat; + return purify; +} + +var newEncode$5; +var hasRequiredNewEncode$5; + +function requireNewEncode$5 () { + if (hasRequiredNewEncode$5) return newEncode$5; + hasRequiredNewEncode$5 = 1; + var newPara = requireNewParameterized(); + var purify = requirePurify$4(); + + function _new(column) { + + const encode = function(_context, candidate) { + var value = purify(candidate); + if (value == null) { + if (column.dbNull === null) + return newPara('null'); + return newPara('\'' + column.dbNull + '\''); + } + return newPara('\'' + value + '\''); + }; + + encode.unsafe = function(_context, candidate) { + var value = purify(candidate); + if (value == null) { + if (column.dbNull === null) + return 'null'; + return '\'' + column.dbNull + '\''; + } + return '\'' + value + '\''; + }; + + encode.direct = function(_context, value) { + return value ; + }; + + + return encode; + } + + newEncode$5 = _new; + return newEncode$5; +} + +var newDecode$4; +var hasRequiredNewDecode$4; + +function requireNewDecode$4 () { + if (hasRequiredNewDecode$4) return newDecode$4; + hasRequiredNewDecode$4 = 1; + function _new(column) { + + return function(_context, value) { + if (value == column.dbNull) + return null; + return value.toLowerCase(); + }; + } + + newDecode$4 = _new; + return newDecode$4; +} + +var guid; +var hasRequiredGuid; + +function requireGuid () { + if (hasRequiredGuid) return guid; + hasRequiredGuid = 1; + var newEncode = requireNewEncode$5(); + var newDecode = requireNewDecode$4(); + var purify = requirePurify$4(); + + function _new(column) { + column.tsType = 'UUIDColumn'; + column.purify = purify; + column.encode = newEncode(column); + column.decode = newDecode(column); + } + + guid = _new; + return guid; +} + +var tryParseISO_1; +var hasRequiredTryParseISO; + +function requireTryParseISO () { + if (hasRequiredTryParseISO) return tryParseISO_1; + hasRequiredTryParseISO = 1; + var patternWithTime = /(\d{4}-[01]\d-[0-3]\d(T| )[0-2]\d:[0-5]\d:[0-5]\d\.\d+)|(\d{4}-[01]\d-[0-3]\d(T| )[0-2]\d:[0-5]\d:[0-5]\d)|(\d{4}-[01]\d-[0-3]\d(T| )[0-2]\d:[0-5]\d)/; + var patternDateOnly = /^\d{4}-[01]\d-[0-3]\d$/; + + function tryParseISO(iso) { + if (patternWithTime.test(iso) || patternDateOnly.test(iso)) { + return iso; + } else { + throw new TypeError(iso + ' is not a valid Date'); + } + } + + tryParseISO_1 = tryParseISO; + return tryParseISO_1; +} + +var purify_1$3; +var hasRequiredPurify$3; + +function requirePurify$3 () { + if (hasRequiredPurify$3) return purify_1$3; + hasRequiredPurify$3 = 1; + var tryParseISO = requireTryParseISO(); + var dateToISOString = requireDateToISOString(); + + function purify(value) { + if(value == null) + return null; + if (value.toISOString) + return dateToISOString(value); + if (value.indexOf('Z') > -1) + return dateToISOString(new Date(value)); + var iso = tryParseISO(value); + if (iso) + return iso; + return value; + } + + purify_1$3 = purify; + return purify_1$3; +} + +var newEncode$4; +var hasRequiredNewEncode$4; + +function requireNewEncode$4 () { + if (hasRequiredNewEncode$4) return newEncode$4; + hasRequiredNewEncode$4 = 1; + var newPara = requireNewParameterized(); + var purify = requirePurify$3(); + var getSessionContext = requireGetSessionContext(); + var getSessionSingleton = requireGetSessionSingleton(); + + function _new(column) { + var encode = function(context, value) { + value = purify(value); + if (value == null) { + if (column.dbNull === null) + return newPara('null'); + return newPara('\'' + column.dbNull + '\''); + } + var ctx = getSessionContext(context); + var encodeCore = ctx.encodeDate || encodeDate; + var formatIn = ctx.formatDateIn; + return newPara(formatIn ? formatIn('?') : '?', [encodeCore(value)]); + }; + + encode.unsafe = function(context, value) { + value = purify(value); + if (value == null) { + if (column.dbNull === null) + ; + return '\'' + column.dbNull + '\''; + } + var encodeCore = getSessionSingleton(context, 'encodeDate') || encodeDate; + return encodeCore(value); + }; + + encode.direct = function(context, value) { + var encodeCore = getSessionSingleton(context, 'encodeDate') || encodeDate; + return encodeCore(value); + }; + + return encode; + + + } + function encodeDate(date) { + date = date.toISOString ? removeTimezone(date.toISOString(date)) : removeTimezone(date); + return date; + } + + function removeTimezone(isoString) { + let dateTimePattern = /\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?/; + let match = isoString.match(dateTimePattern); + return match ? match[0] : isoString; + } + + + newEncode$4 = _new; + return newEncode$4; +} + +var newDecode$3; +var hasRequiredNewDecode$3; + +function requireNewDecode$3 () { + if (hasRequiredNewDecode$3) return newDecode$3; + hasRequiredNewDecode$3 = 1; + var newDecodeCore = requireNewDecodeCore(); + var dateToISOString = requireDateToISOString(); + + function _new(column) { + var decodeCore = newDecodeCore(column); + + return function(context, value) { + value = decodeCore(context, value); + if (value === null) + return value; + else if (typeof value === 'string') + return value.replace(' ', 'T').replace(' ', ''); + return dateToISOString(value); + }; + } + + newDecode$3 = _new; + return newDecode$3; +} + +var formatOut_1; +var hasRequiredFormatOut; + +function requireFormatOut () { + if (hasRequiredFormatOut) return formatOut_1; + hasRequiredFormatOut = 1; + var getSessionSingleton = requireGetSessionSingleton(); + const quote = requireQuote$1(); + + function formatOut(context, column, alias) { + var formatColumn = getSessionSingleton(context, 'formatDateOut'); + if (formatColumn) + return formatColumn(column, alias); + else + return `${alias}.${quote(context, column._dbName)}`; + } + + formatOut_1 = formatOut; + return formatOut_1; +} + +var date; +var hasRequiredDate; + +function requireDate () { + if (hasRequiredDate) return date; + hasRequiredDate = 1; + var newEncode = requireNewEncode$4(); + var newDecode = requireNewDecode$3(); + var formatOut = requireFormatOut(); + var purify = requirePurify$3(); + + function _new(column) { + column.tsType = 'DateColumn'; + column.purify = purify; + column.encode = newEncode(column); + column.decode = newDecode(column); + column.formatOut = (context, ...rest) => formatOut.apply(null, [context, column, ...rest]); + } + + date = _new; + return date; +} + +var newEncode$3; +var hasRequiredNewEncode$3; + +function requireNewEncode$3 () { + if (hasRequiredNewEncode$3) return newEncode$3; + hasRequiredNewEncode$3 = 1; + var newPara = requireNewParameterized(); + var purify = requirePurify$3(); + + function _new(column) { + var encode = function(_context, value) { + value = purify(value); + if (value == null) { + if (column.dbNull === null) + return newPara('null'); + return newPara('\'' + column.dbNull + '\''); + } + return newPara('?', [encodeDate(value)]); + }; + + encode.unsafe = function(_context, value) { + value = purify(value); + if (value == null) { + if (column.dbNull === null) + return 'null'; + return '\'' + column.dbNull + '\''; + } + return encodeDate(value); + }; + + encode.direct = function(_context, value) { + return encodeDate(value); + }; + + return encode; + + + } + function encodeDate(date) { + if (date.toISOString) + return truncate(date.toISOString(date)); + return truncate(date); + } + + function truncate(date) { + return date; + } + + + newEncode$3 = _new; + return newEncode$3; +} + +var dateWithTimeZone; +var hasRequiredDateWithTimeZone; + +function requireDateWithTimeZone () { + if (hasRequiredDateWithTimeZone) return dateWithTimeZone; + hasRequiredDateWithTimeZone = 1; + var newEncode = requireNewEncode$3(); + var newDecode = requireNewDecode$3(); + var formatOut = requireFormatOut(); + var purify = requirePurify$3(); + + function _new(column) { + column.tsType = 'DateColumn'; + column.purify = purify; + column.encode = newEncode(column); + column.decode = newDecode(column); + column.formatOut = (context, ...rest) => formatOut.apply(null, [context, column, ...rest]); + } + + dateWithTimeZone = _new; + return dateWithTimeZone; +} + +var purify_1$2; +var hasRequiredPurify$2; + +function requirePurify$2 () { + if (hasRequiredPurify$2) return purify_1$2; + hasRequiredPurify$2 = 1; + function purify(value) { + if(value == null) + return null; + const parsedFloat = Number.parseFloat(value); + if (!isNaN(parsedFloat)) + return parsedFloat; + if (typeof(value) !== 'number') + throw new Error('\'' + value + '\'' + ' is not a number'); + return value; + } + + purify_1$2 = purify; + return purify_1$2; +} + +var newEncode$2; +var hasRequiredNewEncode$2; + +function requireNewEncode$2 () { + if (hasRequiredNewEncode$2) return newEncode$2; + hasRequiredNewEncode$2 = 1; + var purify = requirePurify$2(); + var newParam = requireNewParameterized(); + + newEncode$2 = function(column) { + + function encode(_context, value) { + value = purify(value); + if (value == null) { + var dbNull = column.dbNull; + return newParam('' + dbNull + ''); + } + return newParam('' + value); + } + + encode.unsafe = function(_context, value) { + value = purify(value); + if (value == null) { + var dbNull = column.dbNull; + return '' + dbNull + ''; + } + return '' + value; + }; + + encode.direct = function(_context, value) { + return value ; + }; + + return encode; + }; + return newEncode$2; +} + +var newDecode$2; +var hasRequiredNewDecode$2; + +function requireNewDecode$2 () { + if (hasRequiredNewDecode$2) return newDecode$2; + hasRequiredNewDecode$2 = 1; + var newDecodeCore = requireNewDecodeCore(); + + function _new(column) { + var decodeCore = newDecodeCore(column); + + return function(context, value) { + value = decodeCore(context, value); + if (value === null) + return value; + if (typeof(value) !== 'number') + return parseFloat(value); + return value; + }; + } + + newDecode$2 = _new; + return newDecode$2; +} + +var numeric; +var hasRequiredNumeric; + +function requireNumeric () { + if (hasRequiredNumeric) return numeric; + hasRequiredNumeric = 1; + var newEncode = requireNewEncode$2(); + var newDecode = requireNewDecode$2(); + var purify = requirePurify$2(); + + function _new(column) { + column.tsType = 'NumberColumn'; + // if (!column.isPrimary) + // column.default = 0; + column.lazyDefault = 0; + column.purify = purify; + column.encode = newEncode(column); + column.decode = newDecode(column); + } + + numeric = _new; + return numeric; +} + +var purify_1$1; +var hasRequiredPurify$1; + +function requirePurify$1 () { + if (hasRequiredPurify$1) return purify_1$1; + hasRequiredPurify$1 = 1; + function purify(value) { + if (value === null || typeof (value) === 'undefined') + return null; + return Boolean(value); + } + + purify_1$1 = purify; + return purify_1$1; +} + +var newEncode$1; +var hasRequiredNewEncode$1; + +function requireNewEncode$1 () { + if (hasRequiredNewEncode$1) return newEncode$1; + hasRequiredNewEncode$1 = 1; + var purify = requirePurify$1(); + var newParam = requireNewParameterized(); + var getSessionSingleton = requireGetSessionSingleton(); + + function _new(column) { + + function encode(context, value) { + value = purify(value); + if (value === null) { + if (column.dbNull === null) + return newParam('null'); + return newParam('\'' + column.dbNull + '\''); + } + var encodeCore = getSessionSingleton(context, 'encodeBoolean'); + + + return newParam('?', [encodeCore(value)]); + } + + encode.unsafe = function(context, value) { + value = purify(value); + if (value === null) { + if (column.dbNull === null) + return 'null'; + return '\'' + column.dbNull + '\''; + } + var encodeCore = getSessionSingleton(context, 'encodeBoolean'); + + + return encodeCore(value); + }; + + encode.direct = function(context, value) { + var encodeCore = getSessionSingleton(context, 'encodeBoolean'); + + return encodeCore(value); + }; + + return encode; + } + + newEncode$1 = _new; + return newEncode$1; +} + +var newDecode$1; +var hasRequiredNewDecode$1; + +function requireNewDecode$1 () { + if (hasRequiredNewDecode$1) return newDecode$1; + hasRequiredNewDecode$1 = 1; + var purify = requirePurify$1(); + + function _new(column) { + + return function(context, value) { + if (value == column.dbNull) + return null; + return purify(value); + }; + } + + newDecode$1 = _new; + return newDecode$1; +} + +var boolean; +var hasRequiredBoolean; + +function requireBoolean () { + if (hasRequiredBoolean) return boolean; + hasRequiredBoolean = 1; + var newEncode = requireNewEncode$1(); + var newDecode = requireNewDecode$1(); + var purify = requirePurify$1(); + + function _new(column) { + column.tsType = 'BooleanColumn'; + column.purify = purify; + // column.default = false; + column.lazyDefault = false; + column.encode = newEncode(column); + column.decode = newDecode(column); + } + + boolean = _new; + return boolean; +} + +var purify_1; +var hasRequiredPurify; + +function requirePurify () { + if (hasRequiredPurify) return purify_1; + hasRequiredPurify = 1; + function purify(value) { + if(value == null) + return null; + if (Buffer.isBuffer(value)) + return value.toString('base64'); + else if (typeof value === 'string') + return value; + else + throw new Error('\'' + value + '\'' + ' is not a base64'); + } + + purify_1 = purify; + return purify_1; +} + +var newEncode; +var hasRequiredNewEncode; + +function requireNewEncode () { + if (hasRequiredNewEncode) return newEncode; + hasRequiredNewEncode = 1; + var purify = requirePurify(); + var newParam = requireNewParameterized(); + + function _new(_column) { + + function encode(_context, value) { + value = purify(value); + if (value === null) + return newParam('null'); + return newParam('?', [Buffer.from(value, 'base64')]); + } + encode.unsafe = function(_context, value) { + value = purify(value); + if (value === null) + return 'null'; + return Buffer.from(value, 'base64'); + }; + + encode.direct = function(_context, value) { + return Buffer.from(value, 'base64'); + }; + + return encode; + } + + newEncode = _new; + return newEncode; +} + +var newDecode; +var hasRequiredNewDecode; + +function requireNewDecode () { + if (hasRequiredNewDecode) return newDecode; + hasRequiredNewDecode = 1; + var newDecodeCore = requireNewDecodeCore(); + + function _new(column) { + var decodeCore = newDecodeCore(column); + + return function(context, value) { + value = decodeCore(context, value); + if (value === null) + return value; + else + return value.toString('base64'); + }; + } + + newDecode = _new; + return newDecode; +} + +var binary; +var hasRequiredBinary; + +function requireBinary () { + if (hasRequiredBinary) return binary; + hasRequiredBinary = 1; + var newEncode = requireNewEncode(); + var newDecode = requireNewDecode(); + var purify = requirePurify(); + + function _new(column) { + column.tsType = 'BinaryColumn'; + column.purify = purify; + column.encode = newEncode(column); + column.decode = newDecode(column); + } + + binary = _new; + return binary; +} + +var column; +var hasRequiredColumn; + +function requireColumn () { + if (hasRequiredColumn) return column; + hasRequiredColumn = 1; + const Ajv = require$$0; + + function defineColumn(column, table) { + var c = {}; + + c.string = function() { + requireString()(table, column); + return c; + }; + + c.json = function() { + requireJson()(column); + return c; + }; + + c.guid = function() { + requireGuid()(column); + return c; + }; + c.uuid = c.guid; + + c.date = function() { + requireDate()(column); + return c; + }; + + c.date = function() { + requireDate()(column); + return c; + }; + + c.dateWithTimeZone = function() { + requireDateWithTimeZone()(column); + return c; + }; + + c.numeric = function(optionalPrecision,optionalScale) { + requireNumeric()(column,optionalPrecision,optionalScale); + return c; + }; + + c.boolean = function() { + requireBoolean()(column); + return c; + }; + + c.binary = function() { + requireBinary()(column); + return c; + }; + + c.default = function(value) { + column.default = value; + return c; + }; + + c.primary = function() { + column.isPrimary = true; + table._primaryColumns.push(column); + return c; + }; + + c.as = function(alias) { + var oldAlias = column.alias; + table._aliases.delete(oldAlias); + table._aliases.add(alias); + delete table[oldAlias]; + table[alias] = column; + column.alias = alias; + return c; + }; + + c.dbNull = function(value) { + column.dbNull = value; + return c; + }; + + c.serializable = function(value) { + column.serializable = value; + return c; + }; + + c.notNull = function() { + column._notNull = true; + function validate(value) { + if (value === undefined || value === null) { + const error = new Error(`Column ${column.alias} cannot be null or undefined`); + error.status = 400; + throw error; + } + } + + return c.validate(validate); + }; + + c.notNullExceptInsert = function() { + column._notNullExceptInsert = true; + function validate(value, _row, isInsert) { + if (isInsert) + return; + if (value === undefined || value === null) + throw new Error(`Column ${column.alias} cannot be null or undefined`); + } + + return c.validate(validate); + }; + + c.validate = function(value) { + let previousValue = column.validate; + if (previousValue) + column.validate = nestedValidate; + else + column.validate = value; + + function nestedValidate() { + try { + previousValue.apply(null, arguments); + value.apply(null, arguments); + } + catch (e) { + const error = new Error(e.message || e); + // @ts-ignore + error.status = 400; + throw error; + } + } + return c; + }; + + c.JSONSchema = function(schema, options) { + let previousValidate = column.validate; + let ajv = new Ajv(options); + let validate = ajv.compile(schema); + column.validate = _validate; + + function _validate() { + if (previousValidate) + previousValidate.apply(null, arguments); + let valid = validate.apply(null, arguments); + if (!valid) { + let e = new Error(`Column ${table._dbName}.${column._dbName} violates JSON Schema: ${inspect(validate.errors)}`); + e.errors = validate.errors; + e.status = 400; + throw e; + } + } + return c; + }; + + return c; + } + + function inspect(obj) { + return JSON.stringify(obj, null, 2); + } + + + column = defineColumn; + return column; +} + +var newCollection_1; +var hasRequiredNewCollection; + +function requireNewCollection () { + if (hasRequiredNewCollection) return newCollection_1; + hasRequiredNewCollection = 1; + function newCollection() { + var c = {}; + var initialArgs = []; + for (var i = 0; i < arguments.length; i++) { + initialArgs.push(arguments[i]); + } + var ranges = [initialArgs]; + + c.addRange = function(otherCollection) { + ranges.push(otherCollection); + }; + + c.add = function(element) { + c.addRange([element]); + }; + + c.toArray = function() { + var result = []; + c.forEach(onEach); + return result; + + function onEach(element) { + result.push(element); + } + }; + + c.forEach = function(callback) { + var index = 0; + for (var i = 0; i < ranges.length; i++) { + ranges[i].forEach(onEach); + } + + function onEach(element) { + callback(element, index); + index++; + } + + }; + + Object.defineProperty(c, 'length', { + enumerable: false, + get: function() { + var result = 0; + for (var i = 0; i < ranges.length; i++) { + result += ranges[i].length; + } + return result; + }, + }); + + + return c; + } + + newCollection_1 = newCollection; + return newCollection_1; +} + +var newQueryContext_1; +var hasRequiredNewQueryContext; + +function requireNewQueryContext () { + if (hasRequiredNewQueryContext) return newQueryContext_1; + hasRequiredNewQueryContext = 1; + function newQueryContext() { + var rows = []; + + var c = {}; + c.rows = rows; + + c.expand = function(relation) { + rows.forEach(function(row) { + relation.expand(row); + }); + }; + + c.add = function(row) { + rows.push(row); + }; + + return c; + } + + newQueryContext_1 = newQueryContext; + return newQueryContext_1; +} + +var newJoinLeg; +var hasRequiredNewJoinLeg; + +function requireNewJoinLeg () { + if (hasRequiredNewJoinLeg) return newJoinLeg; + hasRequiredNewJoinLeg = 1; + var newCollection = requireNewCollection(); + var newQueryContext = requireNewQueryContext(); + + function newLeg(relation) { + var c = {}; + var span = {}; + span.table = relation.childTable; + span.legs = newCollection(); + span.queryContext = newQueryContext(); + c.span = span; + c.name = relation.leftAlias; + c.table = relation.parentTable; + c.columns = relation.columns; + c.expand = relation.expand; + + c.accept = function(visitor) { + visitor.visitJoin(c); + }; + + return c; + } + + newJoinLeg = newLeg; + return newJoinLeg; +} + +var tryGetFromCacheById; +var hasRequiredTryGetFromCacheById; + +function requireTryGetFromCacheById () { + if (hasRequiredTryGetFromCacheById) return tryGetFromCacheById; + hasRequiredTryGetFromCacheById = 1; + function tryGet(context, table) { + var fakeRow = {}; + var args = arguments; + table._primaryColumns.forEach(addPkValue); + + function addPkValue(pkColumn, index){ + fakeRow[pkColumn.alias] = args[index + 2]; + } + + return table._cache.tryGet(context, fakeRow); + } + tryGetFromCacheById = tryGet; + return tryGetFromCacheById; +} + +var newPrimaryKeyFilter; +var hasRequiredNewPrimaryKeyFilter; + +function requireNewPrimaryKeyFilter () { + if (hasRequiredNewPrimaryKeyFilter) return newPrimaryKeyFilter; + hasRequiredNewPrimaryKeyFilter = 1; + function primaryKeyFilter(context, table) { + var primaryColumns = table._primaryColumns; + var key = arguments[2]; + var filter = primaryColumns[0].equal(context, key); + for (var i = 2; i < primaryColumns.length; i++) { + key = arguments[i+1]; + var colFilter = primaryColumns[i].equal(context, key); + filter = filter.and(context, colFilter); + } + return filter; + } + + newPrimaryKeyFilter = primaryKeyFilter; + return newPrimaryKeyFilter; +} + +var newShallowColumnSql; +var hasRequiredNewShallowColumnSql; + +function requireNewShallowColumnSql () { + if (hasRequiredNewShallowColumnSql) return newShallowColumnSql; + hasRequiredNewShallowColumnSql = 1; + const getSessionSingleton = requireGetSessionSingleton(); + + function _new(context, table, alias, span, ignoreNulls) { + const quote = getSessionSingleton(context, 'quote'); + const quotedAlias = quote(alias); + let columnsMap = span.columns; + var columns = table._columns; + var sql = ''; + var separator = ''; + + for (let i = 0; i < columns.length; i++) { + var column = columns[i]; + if (!columnsMap || (columnsMap.get(column))) { + sql = sql + separator + formatColumn(column) + ' as ' + quote('s' + alias + i); + separator = ','; + } + else if (!ignoreNulls) { + sql = sql + separator + 'null as ' + quote('s' + alias + i); + separator = ','; + } + } + + for (let name in span.aggregates || {}) { + sql = sql + separator + span.aggregates[name].expression(name); + separator = ','; + } + + return sql; + + function formatColumn(column) { + const formatted = column.formatOut ? column.formatOut(context, quotedAlias) : quotedAlias + '.' + quote(column._dbName); + if (column.dbNull === null) + return formatted; + else { + const encoded = column.encode.unsafe(context, column.dbNull); + return `CASE WHEN ${formatted}=${encoded} THEN null ELSE ${formatted} END`; + } + } + } + + newShallowColumnSql = _new; + return newShallowColumnSql; +} + +var sharedJoinUtils; +var hasRequiredSharedJoinUtils; + +function requireSharedJoinUtils () { + if (hasRequiredSharedJoinUtils) return sharedJoinUtils; + hasRequiredSharedJoinUtils = 1; + var newShallowColumnSql = requireNewShallowColumnSql(); + + function joinLegToColumnSql(context, leg, alias, ignoreNull) { + var span = leg.span; + var shallowColumnSql = newShallowColumnSql(context, span.table, alias, span, ignoreNull); + var joinedColumnSql = newJoinedColumnSql(context, span, alias, ignoreNull); + return ',' + shallowColumnSql + joinedColumnSql; + } + + function newJoinedColumnSql(context, span, alias, ignoreNull) { + var c = {}; + var sql = ''; + + c.visitJoin = function(leg) { + var joinSql = joinLegToColumnSql(context, leg, alias + leg.name, ignoreNull); + sql = sql + joinSql; + }; + + c.visitOne = function(leg) { + c.visitJoin(leg); + }; + + c.visitMany = function() { + }; + + + span.legs.forEach(onEach); + + function onEach(leg) { + leg.accept(c); + } + + return sql; + } + + + sharedJoinUtils = { joinLegToColumnSql, newJoinedColumnSql }; + return sharedJoinUtils; +} + +var newJoinedColumnSql_1; +var hasRequiredNewJoinedColumnSql; + +function requireNewJoinedColumnSql () { + if (hasRequiredNewJoinedColumnSql) return newJoinedColumnSql_1; + hasRequiredNewJoinedColumnSql = 1; + const { newJoinedColumnSql } = requireSharedJoinUtils(); + + + newJoinedColumnSql_1 = newJoinedColumnSql; + return newJoinedColumnSql_1; +} + +var newColumnSql; +var hasRequiredNewColumnSql; + +function requireNewColumnSql () { + if (hasRequiredNewColumnSql) return newColumnSql; + hasRequiredNewColumnSql = 1; + var newShallowColumnSql = requireNewShallowColumnSql(); + var newJoinedColumnSql = requireNewJoinedColumnSql(); + + newColumnSql = function(context,table,span,alias,ignoreNull) { + var shallowColumnSql = newShallowColumnSql(context,table,alias, span, ignoreNull); + var joinedColumnSql = newJoinedColumnSql(context, span,alias, ignoreNull); + return shallowColumnSql + joinedColumnSql; + }; + return newColumnSql; +} + +var newDiscriminatorSql_1$1; +var hasRequiredNewDiscriminatorSql$1; + +function requireNewDiscriminatorSql$1 () { + if (hasRequiredNewDiscriminatorSql$1) return newDiscriminatorSql_1$1; + hasRequiredNewDiscriminatorSql$1 = 1; + const getSessionSingleton = requireGetSessionSingleton(); + + function newDiscriminatorSql(context, table, alias) { + const quote = getSessionSingleton(context, 'quote'); + alias = quote(alias); + var result = ''; + var formulaDiscriminators = table._formulaDiscriminators; + var columnDiscriminators = table._columnDiscriminators; + addFormula(); + addColumn(); + return result; + + function addFormula() { + for (var i = 0; i 1) { + direction = ' ' + elements[1]; + } + return { + name: elements[0], + direction: direction + }; + } + function pushColumn(property, direction) { + direction = direction || ''; + var column = getTableColumn(property); + var jsonQuery = getJsonQuery(property, column.alias); + + dbNames.push(alias + '.' + quote(column._dbName) + jsonQuery + direction); + } + + function getTableColumn(property) { + var column = table[property] || table[property.split(/(-|#)>+/g)[0]]; + if(!column){ + throw new Error(`Unable to get column on orderBy '${property}'. If jsonb query, only #>, #>>, -> and ->> allowed. Only use ' ' to seperate between query and direction. Does currently not support casting.`); + } + return column; + } + function getJsonQuery(property, column) { + let containsJson = (/(-|#)>+/g).test(property); + if(!containsJson){ + return ''; + } + return property.replace(column, ''); + } + + return ' order by ' + dbNames.join(','); + } + + extractOrderBy_1 = extractOrderBy; + return extractOrderBy_1; +} + +var extractLimit_1; +var hasRequiredExtractLimit; + +function requireExtractLimit () { + if (hasRequiredExtractLimit) return extractLimit_1; + hasRequiredExtractLimit = 1; + var getSessionContext = requireGetSessionContext(); + + function extractLimit(context, span) { + let limit = getSessionContext(context).limit; + if (limit) + return limit(span); + else + return ''; + } + + extractLimit_1 = extractLimit; + return extractLimit_1; +} + +var extractOffset_1; +var hasRequiredExtractOffset; + +function requireExtractOffset () { + if (hasRequiredExtractOffset) return extractOffset_1; + hasRequiredExtractOffset = 1; + var getSessionContext = requireGetSessionContext(); + + function extractOffset(context, span) { + let {limitAndOffset} = getSessionContext(context); + if (limitAndOffset) + return limitAndOffset(span); + else + return ''; + } + + extractOffset_1 = extractOffset; + return extractOffset_1; +} + +var newQuery_1$2; +var hasRequiredNewQuery$2; + +function requireNewQuery$2 () { + if (hasRequiredNewQuery$2) return newQuery_1$2; + hasRequiredNewQuery$2 = 1; + var newSingleQuery = requireNewSingleQuery$1(); + var extractFilter = requireExtractFilter(); + var extractOrderBy = requireExtractOrderBy(); + var extractLimit = requireExtractLimit(); + var extractOffset = requireExtractOffset(); + + function newQuery(context, queries,table,filter,span,alias,innerJoin,orderBy,exclusive) { + filter = extractFilter(filter); + orderBy = extractOrderBy(context, table,alias,span.orderBy,orderBy); + var limit = extractLimit(context, span); + var offset = extractOffset(context, span); + var singleQuery = newSingleQuery(context, table,filter,span,alias,innerJoin,orderBy,limit,offset,exclusive); + queries.push(singleQuery); + + return queries; + } + + newQuery_1$2 = newQuery; + return newQuery_1$2; +} + +var negotiateQueryContext_1; +var hasRequiredNegotiateQueryContext; + +function requireNegotiateQueryContext () { + if (hasRequiredNegotiateQueryContext) return negotiateQueryContext_1; + hasRequiredNegotiateQueryContext = 1; + function negotiateQueryContext(queryContext, row) { + if (queryContext) + queryContext.add(row); + } + + negotiateQueryContext_1 = negotiateQueryContext; + return negotiateQueryContext_1; +} + +var newUpdateCommandCore_1; +var hasRequiredNewUpdateCommandCore; + +function requireNewUpdateCommandCore () { + if (hasRequiredNewUpdateCommandCore) return newUpdateCommandCore_1; + hasRequiredNewUpdateCommandCore = 1; + const getSessionSingleton = requireGetSessionSingleton(); + var newParameterized = requireNewParameterized(); + + function newUpdateCommandCore(context, table, columns, row) { + const quote = getSessionSingleton(context, 'quote'); + var command = newParameterized('UPDATE ' + quote(table._dbName) + ' SET'); + var separator = ' '; + + addColumns(); + addWhereId(); + addDiscriminators(); + + function addColumns() { + for (var alias in columns) { + var column = columns[alias]; + var encoded = column.encode(context, row[alias]); + command = command.append(separator + quote(column._dbName) + '=').append(encoded); + separator = ','; + } + } + + function addWhereId() { + separator = ' WHERE '; + var columns = table._primaryColumns; + for (var i = 0; i < columns.length; i++) { + var column = columns[i]; + var value = row[column.alias]; + var encoded = column.encode(context, value); + command = command.append(separator + quote(column._dbName) + '=').append(encoded); + separator = ' AND '; + } + } + + function addDiscriminators() { + var discriminators = table._columnDiscriminators; + if (discriminators.length === 0) + return; + discriminators = separator + discriminators.join(' AND '); + command = command.append(discriminators); + } + + return command; + + + } + + newUpdateCommandCore_1 = newUpdateCommandCore; + return newUpdateCommandCore_1; +} + +var newImmutable_1; +var hasRequiredNewImmutable; + +function requireNewImmutable () { + if (hasRequiredNewImmutable) return newImmutable_1; + hasRequiredNewImmutable = 1; + function newImmutable(fn) { + var result; + var _run = runFirst; + return run; + + function run() { + return _run([...arguments]); + } + + function runFirst(args) { + result = fn.apply(null, args); + _run = runNIgnoreArgs; + return result; + } + + function runNIgnoreArgs() { + return result; + } + } + + newImmutable_1 = newImmutable; + return newImmutable_1; +} + +var newObject_1; +var hasRequiredNewObject; + +function requireNewObject () { + if (hasRequiredNewObject) return newObject_1; + hasRequiredNewObject = 1; + function newObject() { + return {}; + } + + newObject_1 = newObject; + return newObject_1; +} + +var createDto; +var hasRequiredCreateDto; + +function requireCreateDto () { + if (hasRequiredCreateDto) return createDto; + hasRequiredCreateDto = 1; + let flags = requireFlags(); + + function _createDto(table, row) { + var dto = {}; + flags.useProxy = false; + for (let name in row) { + let column = table[name]; + if (table._aliases.has(name)) { + if (column.toDto) + dto[name] = column.toDto(row[name]); + else + dto[name] = row[name]; + } + } + + flags.useProxy = true; + return dto; + } + + createDto = _createDto; + return createDto; +} + +var newUpdateCommand_1; +var hasRequiredNewUpdateCommand; + +function requireNewUpdateCommand () { + if (hasRequiredNewUpdateCommand) return newUpdateCommand_1; + hasRequiredNewUpdateCommand = 1; + let newUpdateCommandCore = requireNewUpdateCommandCore(); + let newImmutable = requireNewImmutable(); + let newColumnList = requireNewObject(); + var createPatch = requireCreatePatch(); + let createDto = requireCreateDto(); + + function newUpdateCommand(context, table, column, row) { + return new UpdateCommand(context, table, column, row); + } + + function UpdateCommand(context, table, column, row) { + this._table = table; + this._row = row; + this.__getCoreCommand = newImmutable(newUpdateCommandCore.bind(null, context)); + this._columnList = newColumnList(); + this._columnList[column.alias] = column; + this.onFieldChanged = this.onFieldChanged.bind(this); + row.subscribeChanged(this.onFieldChanged); + } + + UpdateCommand.prototype.onFieldChanged = function(_row, column) { + this._columnList[column.alias] = column; + }; + + UpdateCommand.prototype.sql = function() { + return this._getCoreCommand().sql(); + }; + + Object.defineProperty(UpdateCommand.prototype, 'parameters', { + get: function() { + return this._getCoreCommand().parameters; + } + }); + + UpdateCommand.prototype._getCoreCommand = function() { + return this.__getCoreCommand(this._table, this._columnList, this._row); + }; + + UpdateCommand.prototype.endEdit = function() { + this._getCoreCommand(); + this._row.unsubscribeChanged(this.onFieldChanged); + let dto = JSON.parse(JSON.stringify(createDto(this._table, this._row))); + this._patch = createPatch([JSON.parse(this._row._oldValues)],[dto]); + this._row._oldValues = JSON.stringify(dto); + }; + + UpdateCommand.prototype.emitChanged = function() { + return this._table._emitChanged({row: this._row, patch: this._patch}); + }; + + UpdateCommand.prototype.matches = function(otherRow) { + return this._row === otherRow; + }; + + Object.defineProperty(UpdateCommand.prototype, 'disallowCompress', { + get: function() { + return this._table._emitChanged.callbacks.length > 0; + + } + }); + + newUpdateCommand_1 = newUpdateCommand; + return newUpdateCommand_1; +} + +var negotiateEndEdit_1; +var hasRequiredNegotiateEndEdit; + +function requireNegotiateEndEdit () { + if (hasRequiredNegotiateEndEdit) return negotiateEndEdit_1; + hasRequiredNegotiateEndEdit = 1; + function negotiateEndEdit(changes) { + var last = changes[changes.length - 1]; + if (last && last.endEdit) + last.endEdit(); + } + + negotiateEndEdit_1 = negotiateEndEdit; + return negotiateEndEdit_1; +} + +var pushCommand_1; +var hasRequiredPushCommand; + +function requirePushCommand () { + if (hasRequiredPushCommand) return pushCommand_1; + hasRequiredPushCommand = 1; + var getChangeSet = requireGetChangeSet(); + var negotiateEndEdit = requireNegotiateEndEdit(); + + function pushCommand(context, command) { + var changes = getChangeSet(context); + negotiateEndEdit(changes); + changes.push(command); + } + + pushCommand_1 = pushCommand; + return pushCommand_1; +} + +var lastCommandMatches_1; +var hasRequiredLastCommandMatches; + +function requireLastCommandMatches () { + if (hasRequiredLastCommandMatches) return lastCommandMatches_1; + hasRequiredLastCommandMatches = 1; + var getChangeSet = requireGetChangeSet(); + + function lastCommandMatches(context, row) { + var changeSet = getChangeSet(context); + var lastIndex = changeSet.length-1; + if (lastIndex >= 0 && changeSet[lastIndex].matches) + return changeSet[lastIndex].matches(row); + return false; + } + + lastCommandMatches_1 = lastCommandMatches; + return lastCommandMatches_1; +} + +var updateField_1; +var hasRequiredUpdateField; + +function requireUpdateField () { + if (hasRequiredUpdateField) return updateField_1; + hasRequiredUpdateField = 1; + var newUpdateCommand = requireNewUpdateCommand(); + var pushCommand = requirePushCommand(); + var lastCommandMatches = requireLastCommandMatches(); + + function updateField(context, table, column, row) { + if (lastCommandMatches(context, row)) + return; + var command = newUpdateCommand(context, table, column, row); + pushCommand(context, command); + } + + updateField_1 = updateField; + return updateField_1; +} + +var emitEvent_1; +var hasRequiredEmitEvent; + +function requireEmitEvent () { + if (hasRequiredEmitEvent) return emitEvent_1; + hasRequiredEmitEvent = 1; + function emitEvent() { + var callbacks = []; + var emit = function() { + + var copy = callbacks.slice(0, callbacks.length); + var result = []; + for (var i = 0; i < copy.length; i++) { + var callback = copy[i]; + result.push(callback.apply(null, arguments)); + } + return result; + }; + + emit.add = function(callback) { + if (!callback) + throw new Error('missing callback'); + callbacks.push(callback); + }; + + emit.tryAdd = function(callback) { + if (callback) + emit.add(callback); + }; + + emit.remove = function(callback) { + for (var i = 0; i < callbacks.length; i++) { + if (callbacks[i] === callback) { + callbacks.splice(i, 1); + return; + } + } + }; + + emit.tryRemove = function(callback) { + if (callback) + emit.remove(callback); + }; + + emit.clear = function() { + callbacks.splice(0, callbacks.length); + }; + + emit.callbacks = callbacks; + + return emit; + } + + emitEvent_1 = emitEvent; + return emitEvent_1; +} + +var extractStrategy_1; +var hasRequiredExtractStrategy$1; + +function requireExtractStrategy$1 () { + if (hasRequiredExtractStrategy$1) return extractStrategy_1; + hasRequiredExtractStrategy$1 = 1; + //either.. + //strategy, table + //or.. + //table + function extractStrategy(_strategyOrTable, _optinonalTable) { + let table; + if (arguments.length === 2 && _strategyOrTable !== undefined) + return arguments[0]; + else if (arguments.length === 2) + table = arguments[1]; + else + table = arguments[0]; + + let strategy = {}; + let relations = table._relations; + let relationName; + + let visitor = {}; + visitor.visitJoin = function() { }; + + visitor.visitMany = function(relation) { + strategy[relationName] = extractStrategy(relation.childTable); + }; + + visitor.visitOne = visitor.visitMany; + + for (relationName in relations) { + let relation = relations[relationName]; + relation.accept(visitor); + } + return strategy; + } + + + extractStrategy_1 = extractStrategy; + return extractStrategy_1; +} + +var extractDeleteStrategy_1; +var hasRequiredExtractDeleteStrategy; + +function requireExtractDeleteStrategy () { + if (hasRequiredExtractDeleteStrategy) return extractDeleteStrategy_1; + hasRequiredExtractDeleteStrategy = 1; + var emptyStrategy = requireNewObject()(); + + function extractDeleteStrategy(strategy) { + if (strategy) + return strategy; + return emptyStrategy; + } + + extractDeleteStrategy_1 = extractDeleteStrategy; + return extractDeleteStrategy_1; +} + +var newCascadeDeleteStrategy_1; +var hasRequiredNewCascadeDeleteStrategy; + +function requireNewCascadeDeleteStrategy () { + if (hasRequiredNewCascadeDeleteStrategy) return newCascadeDeleteStrategy_1; + hasRequiredNewCascadeDeleteStrategy = 1; + var newObject = requireNewObject(); + + function newCascadeDeleteStrategy(strategy, table) { + var relations = table._relations; + var relationName; + + var c = {}; + c.visitJoin = function(){}; + c.visitOne = function(relation) { + var subStrategy = newObject(); + strategy[relationName] = subStrategy; + newCascadeDeleteStrategy(subStrategy, relation.childTable); + }; + + c.visitMany = c.visitOne; + + for(relationName in relations) { + var relation = relations[relationName]; + relation.accept(c); + } + return strategy; + } + + newCascadeDeleteStrategy_1 = newCascadeDeleteStrategy; + return newCascadeDeleteStrategy_1; +} + +var removeFromCache_1; +var hasRequiredRemoveFromCache; + +function requireRemoveFromCache () { + if (hasRequiredRemoveFromCache) return removeFromCache_1; + hasRequiredRemoveFromCache = 1; + function removeFromCache(context, row, strategy, table) { + if (Array.isArray(row)) { + removeManyRows(); + return; + } + if (row) + removeSingleRow(); + + function removeManyRows() { + row.forEach( function(rowToRemove) { + removeFromCache(context, rowToRemove, strategy, table); + }); + } + + function removeSingleRow() { + var relations = table._relations; + for (var relationName in strategy) { + var relation = relations[relationName]; + var rows = relation.getRowsSync(row); + removeFromCache(context, rows, strategy[relationName], relation.childTable); + } + table._cache.tryRemove(context, row); + } + } + + removeFromCache_1 = removeFromCache; + return removeFromCache_1; +} + +var selectSql$1; +var hasRequiredSelectSql$1; + +function requireSelectSql$1 () { + if (hasRequiredSelectSql$1) return selectSql$1; + hasRequiredSelectSql$1 = 1; + const newParameterized = requireNewParameterized(); + const newBoolean = requireNewBoolean(); + const quote = requireQuote$1(); + + function newSelectSql(context, table, alias) { + const colName = quote(context, table._primaryColumns[0]._dbName); + alias = quote(context, alias); + let sql = 'SELECT ' + alias + '.' + colName + ' FROM ' + quote(context, table._dbName) + ' ' + alias; + sql = newParameterized(sql); + return newBoolean(sql); + } + + selectSql$1 = newSelectSql; + return selectSql$1; +} + +var createAlias_1; +var hasRequiredCreateAlias; + +function requireCreateAlias () { + if (hasRequiredCreateAlias) return createAlias_1; + hasRequiredCreateAlias = 1; + function createAlias(table, depth) { + if (depth === 0) + return table._dbName; + return 'x' + depth; + } + createAlias_1 = createAlias; + return createAlias_1; +} + +var joinSql$1; +var hasRequiredJoinSql$1; + +function requireJoinSql$1 () { + if (hasRequiredJoinSql$1) return joinSql$1; + hasRequiredJoinSql$1 = 1; + const newShallowJoinSql = requireNewShallowJoinSql(); + const createAlias = requireCreateAlias(); + + function newJoinSql(context, relations) { + const length = relations.length; + let leftAlias, + rightAlias; + let sql = ''; + + function addSql(relation) { + const rightColumns = relation.childTable._primaryColumns; + const leftColumns = relation.columns; + sql += ' INNER' + newShallowJoinSql(context, relation.childTable, leftColumns, rightColumns, leftAlias, rightAlias).sql(); + } + + relations.forEach(function(relation, i) { + leftAlias = 'x' + (length - i); + rightAlias = createAlias(relation.childTable, length - i - 1); + addSql(relation); + + }); + + return sql; + } + + joinSql$1 = newJoinSql; + return joinSql$1; +} + +var whereSql$1; +var hasRequiredWhereSql$1; + +function requireWhereSql$1 () { + if (hasRequiredWhereSql$1) return whereSql$1; + hasRequiredWhereSql$1 = 1; + var newShallowJoinSql = requireNewShallowJoinSqlCore(); + + function newWhereSql(context, relations, shallowFilter, rightAlias) { + var sql; + var relationCount = relations.length; + var relation = relations[0]; + var leftAlias = 'x' + relationCount; + var table = relation.childTable; + var leftColumns = relation.columns; + var rightColumns = table._primaryColumns; + where(); + + function where() { + var table = relation.childTable; + var joinCore = newShallowJoinSql(context, table, leftColumns, rightColumns, leftAlias, rightAlias); + if (shallowFilter.sql()) + sql = shallowFilter.prepend(' AND ').prepend(joinCore).prepend(' WHERE '); + else + sql = joinCore.prepend(' WHERE '); + } + + return sql; + } + + whereSql$1 = newWhereSql; + return whereSql$1; +} + +var subFilter$1; +var hasRequiredSubFilter$1; + +function requireSubFilter$1 () { + if (hasRequiredSubFilter$1) return subFilter$1; + hasRequiredSubFilter$1 = 1; + const newSelect = requireSelectSql$1(); + const newJoin = requireJoinSql$1(); + const newWhere = requireWhereSql$1(); + const createAlias = requireCreateAlias(); + + function newSubFilter(context,relations, shallowFilter) { + const relationCount = relations.length; + if (relationCount === 0) + return shallowFilter; + const table = relations[0].childTable; + const alias = createAlias(table, relationCount -1); + const filter = newSelect(context,table,alias).prepend('EXISTS ('); + const join = newJoin(context, relations.slice(1)); + const where = newWhere(context,relations,shallowFilter,alias); + return filter.append(join).append(where).append(')'); + + } + + subFilter$1 = newSubFilter; + return subFilter$1; +} + +var newSingleCommandCore_1; +var hasRequiredNewSingleCommandCore; + +function requireNewSingleCommandCore () { + if (hasRequiredNewSingleCommandCore) return newSingleCommandCore_1; + hasRequiredNewSingleCommandCore = 1; + var getSessionSingleton = requireGetSessionSingleton(); + + function newSingleCommandCore(context, table, filter, alias) { + var c = {}; + + c.sql = function() { + var whereSql = filter.sql(); + if (whereSql) + whereSql = ' where ' + whereSql; + var deleteFromSql = getSessionSingleton(context, 'deleteFromSql'); + return deleteFromSql(table, alias, whereSql); + }; + + c.parameters = filter.parameters; + + return c; + } + + newSingleCommandCore_1 = newSingleCommandCore; + return newSingleCommandCore_1; +} + +var newSingleCommand; +var hasRequiredNewSingleCommand; + +function requireNewSingleCommand () { + if (hasRequiredNewSingleCommand) return newSingleCommand; + hasRequiredNewSingleCommand = 1; + var newSubFilter = requireSubFilter$1(); + var newDiscriminatorSql = requireNewDiscriminatorSql$1(); + var extractFilter = requireExtractFilter(); + var newSingleCommandCore = requireNewSingleCommandCore(); + var createAlias = requireCreateAlias(); + + function _new(context, table, filter, relations) { + var alias = createAlias(table, relations.length); + filter = extractFilter(filter); + filter = newSubFilter(context, relations, filter); + var discriminator = newDiscriminatorSql(context, table, alias); + if (discriminator !== '') + filter = filter.and(context, discriminator); + return newSingleCommandCore(context, table, filter, alias); + } + + newSingleCommand = _new; + return newSingleCommand; +} + +var newDeleteCommand; +var hasRequiredNewDeleteCommand; + +function requireNewDeleteCommand () { + if (hasRequiredNewDeleteCommand) return newDeleteCommand; + hasRequiredNewDeleteCommand = 1; + var newSingleCommand = requireNewSingleCommand(); + + function newCommand(context, queries, table, filter, strategy, relations) { + var singleCommand = newSingleCommand(context, table, filter, relations); + for (var name in strategy) { + if (!(strategy[name] === null || strategy[name])) + continue; + var childStrategy = strategy[name]; + var childRelation = table._relations[name]; + var joinRelation = childRelation.joinRelation; + var childRelations = [joinRelation].concat(relations); + newCommand(context, queries, childRelation.childTable, filter, childStrategy, childRelations); + } + queries.push(singleCommand); + return queries; + } + + newDeleteCommand = newCommand; + return newDeleteCommand; +} + +var _delete_1$1; +var hasRequired_delete$1; + +function require_delete$1 () { + if (hasRequired_delete$1) return _delete_1$1; + hasRequired_delete$1 = 1; + var removeFromCache = requireRemoveFromCache(); + var pushCommand = requirePushCommand(); + var newDeleteCommand = requireNewDeleteCommand(); + var newPrimaryKeyFilter = requireNewPrimaryKeyFilter(); + var createPatch = requireCreatePatch(); + var createDto = requireCreateDto(); + + function _delete(context, row, strategy, table) { + var relations = []; + removeFromCache(context, row, strategy, table); + + var args = [context, table]; + table._primaryColumns.forEach(function(primary) { + args.push(row[primary.alias]); + }); + var filter = newPrimaryKeyFilter.apply(null, args); + var cmds = newDeleteCommand(context, [], table, filter, strategy, relations); + cmds.forEach(function(cmd) { + pushCommand(context, cmd); + }); + var cmd = cmds[0]; + if (table._emitChanged.callbacks.length > 0) { + cmd.disallowCompress = true; + var dto = createDto(table, row); + let patch = createPatch([dto],[]); + cmd.emitChanged = table._emitChanged.bind(null, {row: row, patch: patch}); //todo remove ? + } + + } + + _delete_1$1 = _delete; + return _delete_1$1; +} + +var toDto_1; +var hasRequiredToDto; + +function requireToDto () { + if (hasRequiredToDto) return toDto_1; + hasRequiredToDto = 1; + let flags = requireFlags(); + let tryGetSessionContext = requireTryGetSessionContext(); + + function toDto(context, strategy, table, row, joinRelationSet) { + let result; + flags.useProxy = false; + let rdb = tryGetSessionContext(context); + let ignoreSerializable = rdb && rdb.ignoreSerializable; + if (joinRelationSet) { + result = toDtoSync(table, row, joinRelationSet, strategy, ignoreSerializable); + } + else + result = _toDto(table, row, strategy, ignoreSerializable); + flags.useProxy = true; + return result; + } + + async function _toDto(table, row, strategy, ignoreSerializable) { + let dto = {}; + if (!row) + return; + for (let name in strategy) { + if (!strategy[name]) + continue; + let column = table[name]; + // eslint-disable-next-line no-prototype-builtins + if (table._aliases.has(name) && (ignoreSerializable || !('serializable' in column && !column.serializable) && row.propertyIsEnumerable(name))) { + if (column.toDto) + dto[name] = column.toDto(row[name]); + else + dto[name] = row[name]; + } + else if (table._relations[name] && strategy[name]) { + let child; + let relation = table._relations[name]; + if ((strategy && !(strategy[name] || strategy[name] === null))) + continue; + else if (!row.isExpanded(name)) + child = await row[name]; + else + child = relation.getRowsSync(row); + if (!child) + dto[name] = child; + else if (Array.isArray(child)) { + dto[name] = []; + for (let i = 0; i < child.length; i++) { + dto[name].push(await _toDto(relation.childTable, child[i], strategy && strategy[name], ignoreSerializable)); + } + } + else + dto[name] = await _toDto(relation.childTable, child, strategy && strategy[name], ignoreSerializable); + } + } + return dto; + } + + + function toDtoSync(table, row, joinRelationSet, strategy, ignoreSerializable) { + let dto = {}; + if (!row) + return; + for (let name in row) { + let column = table[name]; + if (table._aliases.has(name) && (ignoreSerializable || !('serializable' in column && !column.serializable))) { + if (column.toDto) + dto[name] = column.toDto(row[name]); + else + dto[name] = row[name]; + } + else if (table._relations[name]) { + let relation = table._relations[name]; + let join = relation.joinRelation || relation; + if (!row.isExpanded(name) || joinRelationSet.has(join) || (strategy && !(strategy[name] || strategy[name] === null))) + continue; + let child = relation.getRowsSync(row); + if (!child) + dto[name] = child; + else if (Array.isArray(child)) { + dto[name] = []; + for (let i = 0; i < child.length; i++) { + dto[name].push(toDtoSync(relation.childTable, child[i], new Set([...joinRelationSet, join]), strategy && strategy[name], ignoreSerializable)); + } + } + else + dto[name] = toDtoSync(relation.childTable, child, new Set([...joinRelationSet, join]), strategy && strategy[name], ignoreSerializable); + + } + } + return dto; + } + + toDto_1 = toDto; + return toDto_1; +} + +var fromCompareObject_1; +var hasRequiredFromCompareObject; + +function requireFromCompareObject () { + if (hasRequiredFromCompareObject) return fromCompareObject_1; + hasRequiredFromCompareObject = 1; + function fromCompareObject(object) { + if (object === null || object === undefined) return object; + if (object.__patchType === 'Array') { + let copy = []; + let i = 0; + for (let id in object) { + if (id !== '__patchType') { + copy[i] = fromCompareObject(object[id]); + i++; + } + } + return copy; + } else if (object === Object(object)) { + let copy = {}; + for (let name in object) { + if (name !== '__patchType') + copy[name] = fromCompareObject(object[name]); + } + return copy; + } + return object; + } + + fromCompareObject_1 = fromCompareObject; + return fromCompareObject_1; +} + +var toCompareObject_1; +var hasRequiredToCompareObject; + +function requireToCompareObject () { + if (hasRequiredToCompareObject) return toCompareObject_1; + hasRequiredToCompareObject = 1; + const dateToISOString = requireDateToISOString(); + const isNode = (typeof window === 'undefined'); + + function toCompareObject(object) { + if (Array.isArray(object)) { + let copy = {}; + Object.defineProperty(copy, '__patchType', { + value: 'Array', + writable: true, + enumerable: true + }); + + for (var i = 0; i < object.length; i++) { + let element = toCompareObject(object[i]); + if (element === Object(element) && 'id' in element) + copy[element.id] = element; + else + copy[i] = element; + } + return copy; + } + if (isNode && isNodeBuffer(object)) + return object.toString('base64'); + // @ts-ignore + else if (object instanceof Date && !isNaN(object)) + return dateToISOString(object); + else if (object === Object(object)) { + let copy = {}; + for (let name in object) { + copy[name] = toCompareObject(object[name]); + } + return copy; + } + return object; + } + + function isNodeBuffer(object) { + return Buffer.isBuffer(object); + } + + toCompareObject_1 = toCompareObject; + return toCompareObject_1; +} + +var applyPatch_1; +var hasRequiredApplyPatch; + +function requireApplyPatch () { + if (hasRequiredApplyPatch) return applyPatch_1; + hasRequiredApplyPatch = 1; + const fastjson = require$$0$3; + let fromCompareObject = requireFromCompareObject(); + let toCompareObject = requireToCompareObject(); + + function applyPatch({ options = {} }, dto, changes, column) { + let dtoCompare = toCompareObject(dto); + changes = validateConflict(dtoCompare, changes); + fastjson.applyPatch(dtoCompare, changes, true, true); + + let result = fromCompareObject(dtoCompare); + + if (Array.isArray(dto)) + dto.length = 0; + else + for (let name in dto) { + delete dto[name]; + } + + for (let name in result) { + dto[name] = result[name]; + } + + return dto; + + function validateConflict(object, changes) { + return changes.filter(change => { + let expectedOldValue = change.oldValue; + const option = getOption(change.path); + let readonly = option.readonly; + if (readonly) { + const e = new Error(`Cannot update column ${change.path.replace('/', '')} because it is readonly`); + // @ts-ignore + e.status = 405; + throw e; + } + let concurrency = option.concurrency || 'optimistic'; + if ((concurrency === 'optimistic') || (concurrency === 'skipOnConflict')) { + let oldValue = getOldValue(object, change.path); + try { + if (column?.tsType === 'DateColumn') { + assertDatesEqual(oldValue, expectedOldValue); + } + else + assertDeepEqual(oldValue, expectedOldValue); + } + catch (e) { + if (concurrency === 'skipOnConflict') + return false; + throw new Error(`The field ${change.path.replace('/', '')} was changed by another user. Expected ${inspect(fromCompareObject(expectedOldValue))}, but was ${inspect(fromCompareObject(oldValue))}.`); + } + } + return true; + }); + + function getOldValue(obj, path) { + let splitPath = path.split('/'); + splitPath.shift(); + return splitPath.reduce(extract, obj); + + function extract(obj, name) { + if (obj === Object(obj)) + return obj[name]; + return; + } + } + + } + + function getOption(path) { + let splitPath = path.split('/'); + splitPath.shift(); + return splitPath.reduce(extract, options); + + function extract(obj, name) { + if (Array.isArray(obj)) + return obj[0] || options; + if (obj === Object(obj)) + return obj[name] || options; + return obj; + } + + } + } + + function assertDatesEqual(date1, date2) { + if (date1 && date2) { + const parts1 = date1.split('T'); + const time1parts = (parts1[1] || '').split(/[-+.]/); + const parts2 = date2.split('T'); + const time2parts = (parts2[1] || '').split(/[-+.]/); + while (time1parts.length !== time2parts.length) { + if (time1parts.length > time2parts.length) + time1parts.pop(); + else if (time1parts.length < time2parts.length) + time2parts.pop(); + } + date1 = `${parts1[0]}T${time1parts[0]}`; + date2 = `${parts2[0]}T${time2parts[0]}`; + } + assertDeepEqual(date1, date2); + } + + function assertDeepEqual(a, b) { + if (JSON.stringify(a) !== JSON.stringify(b)) + throw new Error('A, b are not equal'); + } + + function inspect(obj) { + return JSON.stringify(obj, null, 2); + } + + applyPatch_1 = applyPatch; + return applyPatch_1; +} + +var validateDeleteConflict_1; +var hasRequiredValidateDeleteConflict; + +function requireValidateDeleteConflict () { + if (hasRequiredValidateDeleteConflict) return validateDeleteConflict_1; + hasRequiredValidateDeleteConflict = 1; + // @ts-nocheck + /* eslint-disable */ + const toCompareObject = requireToCompareObject(); + + async function validateDeleteConflict({ row, oldValue, options, table }) { + for (let p in oldValue) { + if (isColumn(p, table)) { + const option = inferOptions(options, p); + let strategy = option.concurrency || 'optimistic'; + if ((strategy === 'optimistic')) { + try { + const column = table[p]; + if (column?.tsType === 'DateColumn') { + assertDatesEqual(oldValue[p], toCompareObject(row[p])); + } + else + assertDeepEqual(oldValue[p], toCompareObject(row[p])); + } + catch (e) { + throw new Error(`The field ${p} was changed by another user. Expected ${inspect(oldValue[p])}, but was ${inspect(row[p])}.`); + } + } + } + else if (isManyRelation(p, table)) { + const childTable = table[p]._relation.childTable; + for (let name in oldValue[p]) { + if (name === '__patchType') + continue; + let childRow = await childTable.tryGetById.apply(null, JSON.parse(name)); + if (!childRow) + throw new Error(`${p} with id ${name} was deleted by another user`); + if (! await validateDeleteConflict({ row: childRow, oldValue: oldValue[p][name], options: inferOptions(options, p), table: childTable })) + return false; + } + } + else if (isOneRelation(p, table)) { + const childTable = table[p]._relation.childTable; + let childRow = await row[p]; + if (!childRow) + throw new Error(`${p} was deleted by another user`); + if (! await validateDeleteConflict({ row: childRow, oldValue: oldValue[p], options: inferOptions(options, p), table: childTable })) + return false; + } + + } + return true; + } + + function isColumn(name, table) { + return table[name] && table[name].equal; + } + + function isManyRelation(name, table) { + return table[name] && table[name]._relation.isMany; + } + + function isOneRelation(name, table) { + return table[name] && table[name]._relation.isOne; + + } + + function inferOptions(defaults, property) { + const parent = {}; + if ('readonly' in defaults) + parent.readonly = defaults.readonly; + if ('concurrency' in defaults) + parent.concurrency = defaults.concurrency; + return {...parent, ...(defaults[property] || {})}; + } + + function assertDatesEqual(date1, date2) { + if (date1 && date2) { + const parts1 = date1.split('T'); + const time1parts = (parts1[1] || '').split(/[-+.]/); + const parts2 = date2.split('T'); + const time2parts = (parts2[1] || '').split(/[-+.]/); + while (time1parts.length !== time2parts.length) { + if (time1parts.length > time2parts.length) + time1parts.pop(); + else if (time1parts.length < time2parts.length) + time2parts.pop(); + } + date1 = `${parts1[0]}T${time1parts[0]}`; + date2 = `${parts2[0]}T${time2parts[0]}`; + } + assertDeepEqual(date1, date2); + } + + function assertDeepEqual(a, b) { + if (JSON.stringify(a) !== JSON.stringify(b)) + throw new Error('A, b are not equal'); + } + + function inspect(obj) { + return JSON.stringify(obj, null, 2); + } + + validateDeleteConflict_1 = validateDeleteConflict; + return validateDeleteConflict_1; +} + +var validateDeleteAllowed_1; +var hasRequiredValidateDeleteAllowed; + +function requireValidateDeleteAllowed () { + if (hasRequiredValidateDeleteAllowed) return validateDeleteAllowed_1; + hasRequiredValidateDeleteAllowed = 1; + async function validateDeleteAllowed({ row, options, table }) { + if (options.readonly) { + const e = new Error(`Cannot delete ${table._dbName} because it is readonly`); + // @ts-ignore + e.status = 405; + throw e; + } + for (let p in options) + if (isColumn(p, table)) + return; + else if (isManyRelation(p, table)) { + const childTable = table[p]._relation.childTable; + const childOptions = inferOptions(options, p); + const children = await row[p]; + for (let i = 0; i < children.length; i++) { + const childRow = children[i]; + await validateDeleteAllowed({ row: childRow, options: childOptions, table: childTable }); + } + } + else if (isOneRelation(p, table)) { + const childOptions = inferOptions(options, p); + const childTable = table[p]._relation.childTable; + let childRow = await row[p]; + await validateDeleteAllowed({ row: childRow, options: childOptions, table: childTable }); + } + } + + function isColumn(name, table) { + return table[name] && table[name].equal; + } + + function isManyRelation(name, table) { + return table[name] && table[name]._relation.isMany; + } + + function isOneRelation(name, table) { + return table[name] && table[name]._relation.isOne; + } + + function inferOptions(defaults, property) { + const parent = {}; + if ('readonly' in defaults) + parent.readonly = defaults.readonly; + if ('concurrency' in defaults) + parent.concurrency = defaults.concurrency; + return {...parent, ...(defaults[property] || {})}; + } + + validateDeleteAllowed_1 = validateDeleteAllowed; + return validateDeleteAllowed_1; +} + +/* eslint-disable require-atomic-updates */ + +var patchTable_1; +var hasRequiredPatchTable; + +function requirePatchTable () { + if (hasRequiredPatchTable) return patchTable_1; + hasRequiredPatchTable = 1; + let applyPatch = requireApplyPatch(); + let fromCompareObject = requireFromCompareObject(); + let validateDeleteConflict = requireValidateDeleteConflict(); + let validateDeleteAllowed = requireValidateDeleteAllowed(); + + async function patchTable() { + // const dryrun = true; + //traverse all rows you want to update before updatinng or inserting anything. + //this is to avoid page locks in ms sql + // await patchTableCore.apply(null, [...arguments, dryrun]); + return patchTableCore.apply(null, arguments); + } + + async function patchTableCore(context, table, patches, { strategy = undefined, deduceStrategy = false, ...options } = {}, dryrun) { + options = cleanOptions(options); + strategy = JSON.parse(JSON.stringify(strategy || {})); + let changed = new Set(); + for (let i = 0; i < patches.length; i++) { + let patch = { path: undefined, value: undefined, op: undefined }; + Object.assign(patch, patches[i]); + patch.path = patches[i].path.split('/').slice(1); + let result; + if (patch.op === 'add' || patch.op === 'replace') { + result = await add({ path: patch.path, value: patch.value, op: patch.op, oldValue: patch.oldValue, strategy: deduceStrategy ? strategy : {}, options }, table); + } + else if (patch.op === 'remove') + result = await remove({ path: patch.path, op: patch.op, oldValue: patch.oldValue, options }, table); + + if (result.inserted) + changed.add(result.inserted); + else if (result.updated) + changed.add(result.updated); + } + if (strategy['insertAndForget']) + return { + changed: [], strategy + }; + return { changed: await toDtos(changed), strategy }; + + + async function toDtos(set) { + set = [...set]; + const result = await table.getManyDto(context, set, strategy); + return result; + } + + function toKey(property) { + if (typeof property === 'string' && property.charAt(0) === '[') + return JSON.parse(property); + else + return [property]; + } + + async function add({ path, value, op, oldValue, strategy, options }, table, row, parentRow, relation) { + let property = path[0]; + path = path.slice(1); + if (!row && path.length > 0) { + const key = toKey(property); + row = await table.tryGetById.apply(null, [context, ...key, strategy]); + if (!row) + throw new Error(`Row ${table._dbName} with id ${key} was not found.`); + } + + if (path.length === 0 && value === null) { + return remove({ path, op, oldValue, options }, table, row); + } + if (path.length === 0) { + if (dryrun) { + return {}; + } + let childInserts = []; + for (let name in value) { + if (isColumn(name, table)) + value[name] = fromCompareObject(value[name]); + else if (isJoinRelation(name, table)) { + strategy[name] = strategy[name] || {}; + value[name] && updateJoinedColumns(name, value, table, value); + } + else if (isManyRelation(name, table)) + value[name] && childInserts.push(insertManyRelation.bind(null, name, value, op, oldValue, table, strategy, options)); + else if (isOneRelation(name, table) && value) + value[name] && childInserts.push(insertOneRelation.bind(null, name, value, op, oldValue, table, strategy, options)); + } + for (let i = 0; i < table._primaryColumns.length; i++) { + let pkName = table._primaryColumns[i].alias; + let keyValue = value[pkName]; + if (keyValue && typeof (keyValue) === 'string' && keyValue.indexOf('~') === 0) + value[pkName] = undefined; + } + + if (relation && relation.joinRelation) { + for (let i = 0; i < relation.joinRelation.columns.length; i++) { + let column = relation.joinRelation.columns[i]; + let fkName = column.alias; + let parentPk = relation.joinRelation.childTable._primaryColumns[i].alias; + if (!value[fkName]) { + value[fkName] = parentRow[parentPk]; + } + } + } + let row = table.insertWithConcurrency.apply(null, [context, options, value]); + row = await row; + + for (let i = 0; i < childInserts.length; i++) { + await childInserts[i](row); + } + return { inserted: row }; + } + property = path[0]; + if (isColumn(property, table)) { + if (dryrun) + return { updated: row }; + let dto = {}; + dto[property] = row[property]; + let result = applyPatch({ options }, dto, [{ path: '/' + path.join('/'), op, value, oldValue }], table[property]); + row[property] = result[property]; + return { updated: row }; + } + else if (isOneRelation(property, table)) { + let relation = table[property]._relation; + let subRow = await row[property]; + strategy[property] = strategy[property] || {}; + options[property] = inferOptions(options, property); + + await add({ path, value, op, oldValue, strategy: strategy[property], options: options[property] }, relation.childTable, subRow, row, relation); + return { updated: row }; + } + else if (isManyRelation(property, table)) { + let relation = table[property]._relation; + strategy[property] = strategy[property] || {}; + options[property] = inferOptions(options, property); + + + if (path.length === 1) { + for (let id in value) { + if (id === '__patchType') + continue; + await add({ path: [id], value: value[id], op, oldValue, strategy: strategy[property], options: options[property] }, relation.childTable, undefined, row, relation); + } + } + else { + await add({ path: path.slice(1), value, oldValue, op, strategy: strategy[property], options: options[property] }, relation.childTable, undefined, row, relation); + } + return { updated: row }; + } + else if (isJoinRelation(property, table) && path.length === 1) { + let dto = toJoinedColumns(property, { [property]: value }, table); + oldValue = toJoinedColumns(property, { [property]: oldValue }, table); + let result; + for (let p in dto) { + result = await add({ path: ['dummy', p], value: dto[p], oldValue: (oldValue || {})[p], op, strategy: strategy, options: options }, table, row, parentRow, relation) || result; + } + return result || {}; + } + else if (isJoinRelation(property, table) && path.length === 2) { + let dto = toJoinedColumns(property, { [property]: { [path[1]]: value } }, table); + oldValue = toJoinedColumns(property, { [property]: { [path[1]]: oldValue } }, table); + let result; + for (let p in dto) { + result = await add({ path: ['dummy', p], value: dto[p], oldValue: (oldValue || {})[p], op, strategy: strategy, options: options }, table, row, parentRow, relation) || result; + } + return result || {}; + } + return {}; + } + + async function insertManyRelation(name, value, op, oldValue, table, strategy, options, row) { + let relation = table[name]._relation; + for (let childKey in value[name]) { + if (childKey != '__patchType') { + let child = value[name][childKey]; + strategy[name] = strategy[name] || {}; + options[name] = inferOptions(options, name); + + await add({ path: [childKey], value: child, op, oldValue, strategy: strategy[name], options: options[name] }, relation.childTable, {}, row, relation); + } + } + } + + async function insertOneRelation(name, value, op, oldValue, table, strategy, options, row) { + let relation = table[name]._relation; + let child = value[name]; + strategy[name] = strategy[name] || {}; + options[name] = inferOptions(options, name); + + await add({ path: [name], value: child, op, oldValue, strategy: strategy[name], options: options[name] }, relation.childTable, {}, row, relation); + } + + function updateJoinedColumns(name, value, table, row) { + let relation = table[name]._relation; + for (let i = 0; i < relation.columns.length; i++) { + let parentKey = relation.columns[i].alias; + let childKey = relation.childTable._primaryColumns[i].alias; + if (childKey in value[name]) + row[parentKey] = fromCompareObject(value[name][childKey]); + } + } + function toJoinedColumns(name, valueObject, table) { + let relation = table[name]._relation; + let dto = {}; + for (let i = 0; i < relation.columns.length; i++) { + let parentKey = relation.columns[i].alias; + let childKey = relation.childTable._primaryColumns[i].alias; + if (valueObject && valueObject[name] && childKey in valueObject[name]) + dto[parentKey] = fromCompareObject(valueObject[name][childKey]); + else + dto[parentKey] = null; + } + return dto; + } + + async function remove({ path, op, oldValue, options }, table, row) { + let property = path[0]; + path = path.slice(1); + row = row || await table.getById.apply(null, [context, ...toKey(property)]); + if (path.length === 0) { + await validateDeleteAllowed({ row, options, table }); + if (await validateDeleteConflict({ row, oldValue, options, table })) + await row.deleteCascade(); + } + property = path[0]; + if (isColumn(property, table)) { + let dto = {}; + dto[property] = row[property]; + let result = applyPatch({ options }, dto, [{ path: '/' + path.join('/'), op, oldValue }], table[property]); + + row[property] = result[property]; + return { updated: row }; + } + else if (isJoinRelation(property, table) && path.length === 1) { + oldValue = toJoinedColumns(property, { [property]: oldValue }, table); + let relation = table[property]._relation; + let result; + for (let i = 0; i < relation.columns.length; i++) { + let p = relation.columns[i].alias; + row[p]; + result = await remove({ path: ['dummy', p], oldValue: (oldValue || {})[p], op, options: options }, table, row) || result; + } + return result || {}; + } + else if (isJoinRelation(property, table) && path.length === 2) { + let relation = table[property]._relation; + oldValue = toJoinedColumns(property, { [property]: { [path[1]]: oldValue } }, table); + let result; + for (let i = 0; i < relation.columns.length; i++) { + let p = relation.columns[i].alias; + let childKey = relation.childTable._primaryColumns[i].alias; + if (path[1] === childKey) { + row[p]; + result = await remove({ path: ['dummy', p], oldValue: (oldValue || {})[p], op, options: options }, table, row) || result; + break; + } + } + return result || {}; + } + else if (isOneRelation(property, table)) { + let child = await row[property]; + if (!child) + throw new Error(property + ' does not exist'); + options[property] = inferOptions(options, property); + + await remove({ path, op, oldValue, options: options[property] }, table[property], child); + return { updated: row }; + } + else if (isManyRelation(property, table)) { + let relation = table[property]._relation; + options[property] = inferOptions(options, property); + if (path.length === 1) { + let children = (await row[property]).slice(0); + for (let i = 0; i < children.length; i++) { + let child = children[i]; + await remove({ path: path.slice(1), op, oldValue, options: options[property] }, table[property], child); + } + } + else { + await remove({ path: path.slice(1), op, oldValue, options: options[property] }, relation.childTable); + } + return { updated: row }; + } + return {}; + } + + function isColumn(name, table) { + return table[name] && table[name].equal; + } + + function isManyRelation(name, table) { + return table[name] && table[name]._relation.isMany; + } + + function isOneRelation(name, table) { + return table[name] && table[name]._relation.isOne; + + } + + function isJoinRelation(name, table) { + return table[name] && table[name]._relation.columns; + } + + function inferOptions(defaults, property) { + const parent = {}; + if ('readonly' in defaults) + parent.readonly = defaults.readonly; + if ('concurrency' in defaults) + parent.concurrency = defaults.concurrency; + return { ...parent, ...(defaults[property] || {}) }; + } + + function cleanOptions(options) { + const { table, transaction, db, ..._options } = options; + return _options; + } + } + + patchTable_1 = patchTable; + return patchTable_1; +} + +var patchRow_1; +var hasRequiredPatchRow; + +function requirePatchRow () { + if (hasRequiredPatchRow) return patchRow_1; + hasRequiredPatchRow = 1; + let patchTable = requirePatchTable(); + + function patchRow(context, table, row, patches, options) { + patches = JSON.parse(JSON.stringify(patches)); + let pkName = table._primaryColumns[0].alias; + let id = row[pkName]; + for (let i = 0; i < patches.length; i++) { + patches[i].path = '/' + id + patches[i].path; + } + return patchTable(context, table, patches, options); + } + + patchRow_1 = patchRow; + return patchRow_1; +} + +var purifyStrategy_1; +var hasRequiredPurifyStrategy; + +function requirePurifyStrategy () { + if (hasRequiredPurifyStrategy) return purifyStrategy_1; + hasRequiredPurifyStrategy = 1; + function purifyStrategy(table, strategy, columns = new Map()) { + strategy = { ...strategy }; + for (let p in strategy) { + if (strategy[p] === null) + strategy[p] = true; + } + + let hasIncludedColumns; + for (let name in strategy) { + if (table._relations[name] && !strategy[name]) + continue; + else if (table._relations[name]) + strategy[name] = addLeg(table._relations[name], strategy[name], columns); + else if (table[name] && table[name].eq ) { + if (!columns.has(table[name])) + columns.set(table[name], strategy[name]); + hasIncludedColumns = hasIncludedColumns || strategy[name]; + } + } + for (let i = 0; i < table._columns.length; i++) { + let column = table._columns[i]; + strategy[column.alias] = !hasIncludedColumns; + } + + table._primaryColumns.forEach(column => { + strategy[column.alias] = true; + }); + columns.forEach((value, key) => strategy[key.alias] = value); + + return strategy; + + } + + function addLeg(relation, strategy, columns) { + let nextColumns = new Map(); + if (!relation.joinRelation) + for (let i = 0; i < relation.columns.length; i++) { + columns.set(relation.columns[i], true); + } + else { + relation.joinRelation.columns.forEach(column => { + nextColumns.set(column, true); + }); + } + let childTable = relation.childTable; + return purifyStrategy(childTable, strategy, nextColumns); + } + + purifyStrategy_1 = purifyStrategy; + return purifyStrategy_1; +} + +var newDecodeDbRow_1; +var hasRequiredNewDecodeDbRow; + +function requireNewDecodeDbRow () { + if (hasRequiredNewDecodeDbRow) return newDecodeDbRow_1; + hasRequiredNewDecodeDbRow = 1; + let updateField = requireUpdateField(); + let newEmitEvent = requireEmitEvent(); + let extractStrategy = requireExtractStrategy$1(); + let extractDeleteStrategy = requireExtractDeleteStrategy(); + let newCascadeDeleteStrategy = requireNewCascadeDeleteStrategy(); + let _delete = require_delete$1(); + let newObject = requireNewObject(); + let toDto = requireToDto(); + let createDto = requireCreateDto(); + let patchRow = requirePatchRow(); + let onChange = require$$10; + let flags = requireFlags(); + let tryGetSessionContext = requireTryGetSessionContext(); + let purifyStrategy = requirePurifyStrategy(); + + + function newDecodeDbRow(table, dbRow, filteredAliases, shouldValidate, isInsert) { + let aliases = filteredAliases || table._aliases; + let columns = table._columns; + let numberOfColumns = columns.length; + if (dbRow.offset === undefined) { + dbRow.offset = 0; + } + + let offset = dbRow.offset; + let keys = Object.keys(dbRow); + + for (let i = 0; i < numberOfColumns; i++) { + defineColumnProperty(i); + } + + dbRow.offset += numberOfColumns; + + function defineColumnProperty(i) { + let column = columns[i]; + let purify = column.purify; + let name = column.alias; + let intName = '__' + name; + i = offset + i; + let key = keys[i]; + + Object.defineProperty(Row.prototype, intName, { + get: function() { + return this._dbRow[key]; + }, + + set: function(value) { + let oldValue = this[name]; + value = purify(value); + this._dbRow[key] = value; + if (column.validate) + column.validate(value, this._dbRow); + updateField(this._context, table, column, this); + let emit = this._emitColumnChanged[name]; + if (emit) + emit(this, column, value, oldValue); + this._emitChanged(this, column, value, oldValue); + } + }); + + Object.defineProperty(Row.prototype, name, { + enumerable: true, + configurable: false, + + get: function() { + if (column.onChange && flags.useProxy && (this[intName] !== null && this[intName] !== undefined) && typeof this[intName] === 'object') { + if (!(name in this._proxies)) { + let value = this[intName]; + this._proxies[name] = column.onChange(this._dbRow[key], () => { + if (this[intName] !== onChange.target(value)) { + return; + } + this[intName] = this._dbRow[key]; + }); + } + return this._proxies[name]; + } + return negotiateNull(this[intName]); + }, + set: function(value) { + if (column.onChange && (this[intName] !== null && this[intName] !== undefined) && typeof value === 'object') { + if (this[intName] === onChange.target(value)) + return; + this._proxies[name] = column.onChange(value, () => { + if (this[intName] !== onChange.target(value)) + return; + this[intName] = this._dbRow[key]; + }); + } + this[intName] = value; + } + }); + } + + setRelated(); + + function setRelated() { + let relations = table._relations; + for (let relationName in relations) { + setSingleRelated(relationName); + } + } + + function setSingleRelated(name) { + Object.defineProperty(Row.prototype, name, { + get: function() { + return createGetRelated(this, name)(); + } + }); + } + + function createGetRelated(row, alias) { + let get = row._related[alias]; + if (!get) { + let relation = table._relations[alias]; + get = relation.toGetRelated(row._context, row); + row._relationCacheMap.set(relation, relation.getInnerCache(row._context)); + row._related[alias] = get; + } + return get; + } + + Row.prototype.subscribeChanged = function(onChanged, name) { + let emit; + if (name) { + emit = this._emitColumnChanged[name] || (this._emitColumnChanged[name] = newEmitEvent()); + emit.add(onChanged); + return; + } + this._emitChanged.add(onChanged); + }; + + Row.prototype.unsubscribeChanged = function(onChanged, name) { + if (name) { + this._emitColumnChanged[name].tryRemove(onChanged); + return; + } + this._emitChanged.tryRemove(onChanged); + }; + + Row.prototype.toJSON = function() { + return toDto(undefined, table, this, new Set()); + }; + + + Row.prototype.hydrate = function(context, dbRow) { + const engine = tryGetSessionContext(context)?.engine; + let i = offset; + if (engine === 'sqlite') { + const errorSeparator = '12345678-1234-1234-1234-123456789012'; + for (let p in dbRow) { + if (typeof dbRow[p] === 'string' && dbRow[p].indexOf(errorSeparator) === 0) + throw new Error(dbRow[p].split(errorSeparator)[1]); + let key = keys[i]; + this._dbRow[key] = columns[i].decode(context, dbRow[p]); + i++; + } + } + else { + for (let p in dbRow) { + let key = keys[i]; + this._dbRow[key] = columns[i].decode(context, dbRow[p]); + i++; + } + } + }; + + Row.prototype.toDto = function(strategy) { + if (strategy === undefined) { + strategy = extractStrategy(table); + } + strategy = purifyStrategy(table, strategy); + if (!tryGetSessionContext(this._context)) { + return toDto(this._context, strategy, table, this, new Set()); + } + let p = toDto(this._context, strategy, table, this); + return Promise.resolve().then(() => p); + }; + + Row.prototype.expand = function(alias) { + let get = createGetRelated(this, alias); + get.expanded = true; + }; + + Row.prototype.isExpanded = function(alias) { + return this._related[alias] && this._related[alias].expanded; + }; + + Row.prototype.delete = function(strategy) { + strategy = extractDeleteStrategy(strategy); + _delete(this._context, this, strategy, table); + }; + + Row.prototype.cascadeDelete = function() { + let strategy = newCascadeDeleteStrategy(newObject(), table); + _delete(this._context, this, strategy, table); + }; + + Row.prototype.deleteCascade = Row.prototype.cascadeDelete; + + Row.prototype.patch = async function(patches, options) { + await patchRow(this._context, table, this, patches, options); + return this; + }; + + function decodeDbRow(context, row) { + for (let i = 0; i < numberOfColumns; i++) { + let index = offset + i; + let key = keys[index]; + if (row[key] !== undefined) + row[key] = columns[i].decode(context, row[key]); + if (shouldValidate && columns[i].validate) + columns[i].validate(row[key], row, isInsert); + } + let target = new Row(context, row); + const p = new Proxy(target, { + ownKeys: function() { + return Array.from(aliases).concat(Object.keys(target._related).filter(alias => { + return target._related[alias] && target._related[alias].expanded; + })); + }, + getOwnPropertyDescriptor(target, prop) { + if (table._aliases.has(prop) || (target._related[prop])) + return { + enumerable: aliases.has(prop) || (target._related[prop] && target._related[prop].expanded), + configurable: true, + writable: true + }; + } + }); + + return p; + } + + function negotiateNull(value) { + if (value === undefined) + return null; + return value; + } + + function Row(context, dbRow) { + this._context = context; + this._relationCacheMap = new Map(); + this._cache = table._cache.getInnerCache(context); + this._dbRow = dbRow; + this._related = {}; + this._emitColumnChanged = {}; + this._emitChanged = newEmitEvent(); + this._proxies = {}; + this._oldValues = JSON.stringify(createDto(table, this)); + } + + return decodeDbRow; + } + + newDecodeDbRow_1 = newDecodeDbRow; + return newDecodeDbRow_1; +} + +var decodeDbRow_1; +var hasRequiredDecodeDbRow; + +function requireDecodeDbRow () { + if (hasRequiredDecodeDbRow) return decodeDbRow_1; + hasRequiredDecodeDbRow = 1; + var newDecodeDbRow = requireNewDecodeDbRow(); + + function decodeDbRow(context, span, table, dbRow, shouldValidate, isInsert) { + var decode = span._decodeDbRow; + if (!decode) { + let aliases = new Set(); + if (span.columns) + span.columns.forEach((value, key) => { + if (value) + aliases.add(key.alias); + }); + if (aliases.size === 0) + aliases = undefined; + decode = newDecodeDbRow(table, dbRow, aliases, shouldValidate, isInsert); + Object.defineProperty(span, '_decodeDbRow', { + enumerable: false, + get: function() { + return decode; + }, + }); + } + return decode(context, dbRow); + } + + decodeDbRow_1 = decodeDbRow; + return decodeDbRow_1; +} + +var dbRowToRow_1; +var hasRequiredDbRowToRow; + +function requireDbRowToRow () { + if (hasRequiredDbRowToRow) return dbRowToRow_1; + hasRequiredDbRowToRow = 1; + var negotiateQueryContext = requireNegotiateQueryContext(); + var decodeDbRow = requireDecodeDbRow(); + + function dbRowToRow(context, span, dbRow) { + var table = span.table; + var row = decodeDbRow(context, span, table, dbRow); + var cache = table._cache; + if (!cache.tryGet(context, row)) { + var queryContext = span.queryContext; + negotiateQueryContext(queryContext, row); + Object.defineProperty(row, 'queryContext', { + writable: true, + configurable: true, + enumerable: false + }); + row.queryContext = queryContext; + } + row = cache.tryAdd(context, row); + + var c = {}; + + c.visitOne = function(leg) { + dbRowToRow(context, leg.span, dbRow); + leg.expand(row); + }; + + c.visitJoin = function(leg) { + dbRowToRow(context, leg.span, dbRow); + leg.expand(row); + }; + + c.visitMany = function() { + }; + + span.legs.forEach(onEach); + + function onEach(leg) { + leg.accept(c); + } + + return row; + } + + dbRowToRow_1 = dbRowToRow; + return dbRowToRow_1; +} + +var resultToPromise_1; +var hasRequiredResultToPromise; + +function requireResultToPromise () { + if (hasRequiredResultToPromise) return resultToPromise_1; + hasRequiredResultToPromise = 1; + function resultToPromise(result) { + return Promise.resolve(result); + } + + resultToPromise_1 = resultToPromise; + return resultToPromise_1; +} + +var orderBy_1; +var hasRequiredOrderBy; + +function requireOrderBy () { + if (hasRequiredOrderBy) return orderBy_1; + hasRequiredOrderBy = 1; + function orderBy(strategy, rows) { + if (strategy && strategy.orderBy) { + var comparer = createComparer(strategy.orderBy); + return rows.sort(comparer); + } + return rows; + } + + function createComparer(orderBy) { + var comparers = []; + if (typeof orderBy === 'string') + orderBy = [orderBy]; + orderBy.forEach(function(order) { + var elements = order.split(' '); + var name = elements[0]; + var direction = elements[1] || 'asc'; + + if (direction === 'asc') + comparers.push(compareAscending); + else + comparers.push(compareDescending); + + function compareAscending(a, b) { + a = a[name]; + b = b[name]; + if (a === b) + return 0; + if (a < b) + return -1; + return 1; + } + + function compareDescending(a, b) { + return compareAscending(b, a); + } + + }); + + function compareComposite(a, b) { + for (var i = 0; i < comparers.length; i++) { + var result = comparers[i](a, b); + if (result !== 0) + return result; + } + return 0; + } + + return compareComposite; + } + + orderBy_1 = orderBy; + return orderBy_1; +} + +var negotiateNextTick_1; +var hasRequiredNegotiateNextTick; + +function requireNegotiateNextTick () { + if (hasRequiredNegotiateNextTick) return negotiateNextTick_1; + hasRequiredNegotiateNextTick = 1; + function negotiateNextTick(i) { + if (i === 0) + return; + if (i % 1000 === 0) + return Promise.resolve(); + return; + } + + negotiateNextTick_1 = negotiateNextTick; + return negotiateNextTick_1; +} + +/* eslint-disable @typescript-eslint/no-this-alias */ + +var rowArray; +var hasRequiredRowArray; + +function requireRowArray () { + if (hasRequiredRowArray) return rowArray; + hasRequiredRowArray = 1; + var resultToPromise = requireResultToPromise(); + var orderBy = requireOrderBy(); + var negotiateNextTick = requireNegotiateNextTick(); + + function newRowArray() { + var c = []; + + Object.defineProperty(c, 'toDto', { + enumerable: false, + writable: true, + value: toDtoNativePromise + }); + + Object.defineProperty(c, '__toDto', { + enumerable: false, + writable: true, + value: toDto + }); + + async function toDtoNativePromise() { + let result = []; + for (let i = 0; i < c.length; i++) { + result.push(await c[i].toDto.apply(c[i], arguments)); + } + return result; + } + + return c; + } + + function toDto(optionalStrategy) { + var args = arguments; + var result = []; + var length = this.length; + var rows = this; + var i = -1; + + return resultToPromise().then(toDtoAtIndex); + + function toDtoAtIndex() { + i++; + if (i === length) { + return orderBy(optionalStrategy, result); + } + var row = rows[i]; + return getDto() + .then(onDto) + .then(toDtoAtIndex); + + function getDto() { + return row.__toDto.apply(row,args); + } + + function onDto(dto) { + result.push(dto); + return negotiateNextTick(i); + } + } + } + + rowArray = newRowArray; + return rowArray; +} + +var dbRowsToRows_1; +var hasRequiredDbRowsToRows; + +function requireDbRowsToRows () { + if (hasRequiredDbRowsToRows) return dbRowsToRows_1; + hasRequiredDbRowsToRows = 1; + var dbRowToRow = requireDbRowToRow(); + var newRowArray = requireRowArray(); + + function dbRowsToRows(context, span, dbRows) { + var rows = newRowArray(); + for (var i = 0; i < dbRows.length; i++) { + var row = dbRowToRow(context, span, dbRows[i]); + rows.push(row); + } + return rows; + } + + dbRowsToRows_1 = dbRowsToRows; + return dbRowsToRows_1; +} + +var resultToRows_1; +var hasRequiredResultToRows; + +function requireResultToRows () { + if (hasRequiredResultToRows) return resultToRows_1; + hasRequiredResultToRows = 1; + var dbRowsToRows = requireDbRowsToRows(); + + async function resultToRows(context, span, result) { + let rows = await result[0].then(onResult); + await expand(spanToStrategy(span), rows); + return rows; + + function onResult(result) { + return dbRowsToRows(context, span, result); + } + } + + async function expand(strategy, rows) { + if (!rows) + return; + if (!Array.isArray(rows)) + rows = [rows]; + for (let p in strategy) { + if (!(strategy[p] === null || strategy[p])) + continue; + for (let i = 0; i < rows.length; i++) { + await expand(strategy[p], await rows[i][p]); + } + } + } + + function spanToStrategy(span) { + let strategy = {}; + + span.legs.forEach((leg) => { + strategy[leg.name] = spanToStrategy(leg.span); + }); + return strategy; + + } + + resultToRows_1 = resultToRows; + return resultToRows_1; +} + +var strategyToSpan; +var hasRequiredStrategyToSpan; + +function requireStrategyToSpan () { + if (hasRequiredStrategyToSpan) return strategyToSpan; + hasRequiredStrategyToSpan = 1; + var newCollection = requireNewCollection(); + var newQueryContext = requireNewQueryContext(); + var purifyStrategy = requirePurifyStrategy(); + + function toSpan(table, strategy) { + var span = {}; + span.aggregates = {}; + span.legs = newCollection(); + span.table = table; + strategy = purifyStrategy(table, strategy); + applyStrategy(table,span,strategy); + span.queryContext = newQueryContext(); + span.queryContext.strategy = strategy; + return span; + + function applyStrategy(table,span,strategy) { + let columns = new Map(); + var legs = span.legs; + if(!strategy) + return; + for (var name in strategy) { + if (table._relations[name] && !strategy[name]) + continue; + if (table._relations[name]) + addLeg(legs,table,strategy,name); + else if (strategy[name]?.expression && (strategy[name]?.joins || strategy[name]?.join || strategy[name]?.column)) + span.aggregates[name] = strategy[name]; + else if (table[name] && table[name].eq) + columns.set(table[name], strategy[name]); + else + span[name] = strategy[name]; + } + span.columns = columns; + } + + function addLeg(legs,table,strategy,name) { + var relation = table._relations[name]; + var leg = relation.toLeg(); + leg.span.queryContext.strategy = strategy; + leg.span.where = strategy[name].where; + leg.span.aggregates = {}; + legs.add(leg); + var subStrategy = strategy[name]; + var childTable = relation.childTable; + applyStrategy(childTable,leg.span,subStrategy); + } + } + + strategyToSpan = toSpan; + return strategyToSpan; +} + +var getMany_1; +var hasRequiredGetMany; + +function requireGetMany () { + if (hasRequiredGetMany) return getMany_1; + hasRequiredGetMany = 1; + let newQuery = requireNewQuery$2(); + let executeQueries = requireExecuteQueries(); + let resultToRows = requireResultToRows(); + let strategyToSpan = requireStrategyToSpan(); + let emptyInnerJoin = requireNewParameterized()(); + let negotiateRawSqlFilter = requireNegotiateRawSqlFilter(); + + function getMany(context,table,filter,strategy) { + return getManyCore(context, table,filter,strategy); + } + + async function getManyCore(context,table,filter,strategy,exclusive) { + let alias = table._dbName; + let noOrderBy; + filter = negotiateRawSqlFilter(context, filter, table); + let span = strategyToSpan(table,strategy); + let queries = newQuery(context, [],table,filter,span,alias,emptyInnerJoin,noOrderBy,exclusive); + let result = await executeQueries(context, queries); + return resultToRows(context, span,result); + } + + getMany.exclusive = function(table,filter,strategy) { + return getManyCore(table,filter,strategy,true); + }; + + getMany_1 = getMany; + return getMany_1; +} + +var tryGetFirstFromDb; +var hasRequiredTryGetFirstFromDb; + +function requireTryGetFirstFromDb () { + if (hasRequiredTryGetFirstFromDb) return tryGetFirstFromDb; + hasRequiredTryGetFirstFromDb = 1; + var getMany = requireGetMany(); + + function tryGet(context, table, filter, strategy) { + strategy = setLimit(strategy); + return getMany(context, table, filter, strategy).then(filterRows); + } + + function filterRows(rows) { + if (rows.length > 0) + return rows[0]; + return null; + } + + tryGet.exclusive = function(context, table, filter, strategy) { + strategy = setLimit(strategy); + return getMany.exclusive(context, table, filter, strategy).then(filterRows); + }; + + function setLimit(strategy) { + return {...strategy, ...{limit: 1}}; + } + + tryGetFirstFromDb = tryGet; + return tryGetFirstFromDb; +} + +var extractStrategy; +var hasRequiredExtractStrategy; + +function requireExtractStrategy () { + if (hasRequiredExtractStrategy) return extractStrategy; + hasRequiredExtractStrategy = 1; + function extract(_context, table) { + var lengthWithStrategy = table._primaryColumns.length + 3; + if (arguments.length === lengthWithStrategy) + return arguments[lengthWithStrategy-1]; + return; + } + + extractStrategy = extract; + return extractStrategy; +} + +var tryGetFromDbById; +var hasRequiredTryGetFromDbById; + +function requireTryGetFromDbById () { + if (hasRequiredTryGetFromDbById) return tryGetFromDbById; + hasRequiredTryGetFromDbById = 1; + var newPrimaryKeyFilter = requireNewPrimaryKeyFilter(); + var tryGetFirstFromDb = requireTryGetFirstFromDb(); + var extractStrategy = requireExtractStrategy(); + + function tryGet(context) { + var filter = newPrimaryKeyFilter.apply(null, arguments); + var table = arguments[1]; + var strategy = extractStrategy.apply(null, arguments); + return tryGetFirstFromDb(context, table, filter, strategy); + } + + tryGet.exclusive = function tryGet(context) { + var filter = newPrimaryKeyFilter.apply(null, arguments); + var table = arguments[1]; + var strategy = extractStrategy.apply(null, arguments); + return tryGetFirstFromDb.exclusive(context, table, filter, strategy); + + + }; + + tryGetFromDbById = tryGet; + return tryGetFromDbById; +} + +var getFromDbById; +var hasRequiredGetFromDbById; + +function requireGetFromDbById () { + if (hasRequiredGetFromDbById) return getFromDbById; + hasRequiredGetFromDbById = 1; + let tryGetFromDbById = requireTryGetFromDbById(); + + function get(_context, table, ...ids) { + return tryGetFromDbById.apply(null, arguments).then((row) => onResult(table, row, ids)); + } + + get.exclusive = function(table, ...ids) { + return tryGetFromDbById.exclusive.apply(null, arguments).then((row) => onResult(table, row, ids)); + }; + + function onResult(table, row, id) { + if (row === null) + throw new Error(`${table._dbName }: Row with id ${id} not found.`); + return row; + } + + getFromDbById = get; + return getFromDbById; +} + +var getById_1; +var hasRequiredGetById; + +function requireGetById () { + if (hasRequiredGetById) return getById_1; + hasRequiredGetById = 1; + let tryGetFromCacheById = requireTryGetFromCacheById(); + let getFromDbById = requireGetFromDbById(); + let resultToPromise = requireResultToPromise(); + let extractStrategy = requireExtractStrategy(); + + async function getById() { + let strategy = extractStrategy.apply(null, arguments); + let cached = tryGetFromCacheById.apply(null,arguments); + if (cached) { + await expand(cached, strategy); + return resultToPromise(cached); + + } + return getFromDbById.apply(null,arguments); + } + + getById.exclusive = getFromDbById.exclusive; + + async function expand(rows, strategy) { + if (!rows) + return; + if (!Array.isArray(rows)) + rows = [rows]; + for(let p in strategy) { + if(!(strategy[p] === null || strategy[p])) + continue; + for (let i = 0; i < rows.length; i++) { + await expand(await rows[i][p], strategy[p]); + } + } + } + + getById_1 = getById; + return getById_1; +} + +var nullPromise; +var hasRequiredNullPromise; + +function requireNullPromise () { + if (hasRequiredNullPromise) return nullPromise; + hasRequiredNullPromise = 1; + nullPromise = requirePromise()(null); + return nullPromise; +} + +var newGetRelated_1; +var hasRequiredNewGetRelated; + +function requireNewGetRelated () { + if (hasRequiredNewGetRelated) return newGetRelated_1; + hasRequiredNewGetRelated = 1; + function newGetRelated(context, parent, relation) { + function getRelated() { + if (getRelated.expanded) + return relation.getFromCache(parent); + if (parent.queryContext) + return relation.getRelatives(context, parent).then(onRelatives); + return relation.getFromDb(context, parent).then(onFromDb); + + function onFromDb(rows) { + getRelated.expanded = true; + return rows; + } + + function onRelatives() { + return relation.getFromCache(parent); + } + } + return getRelated; + } + + newGetRelated_1 = newGetRelated; + return newGetRelated_1; +} + +var negotiateExpandInverse_1; +var hasRequiredNegotiateExpandInverse; + +function requireNegotiateExpandInverse () { + if (hasRequiredNegotiateExpandInverse) return negotiateExpandInverse_1; + hasRequiredNegotiateExpandInverse = 1; + function negotiateExpandInverse(parent, relation, children) { + var joinRelation = relation.joinRelation; + if (!joinRelation || !joinRelation.leftAlias) + return; + var firstChild = children.find(function(child) { + return child.queryContext; + }); + + if (firstChild) + firstChild.queryContext.expand(joinRelation); + } + + negotiateExpandInverse_1 = negotiateExpandInverse; + return negotiateExpandInverse_1; +} + +var getRelatives_1$1; +var hasRequiredGetRelatives$1; + +function requireGetRelatives$1 () { + if (hasRequiredGetRelatives$1) return getRelatives_1$1; + hasRequiredGetRelatives$1 = 1; + var newPrimaryKeyFilter = requireNewPrimaryKeyFilter(); + var emptyFilter = requireEmptyFilter(); + var negotiateExpandInverse = requireNegotiateExpandInverse(); + + function getRelatives(context, parent, relation) { + var queryContext = parent.queryContext; + let strategy = queryContext && queryContext.strategy[relation.leftAlias]; + var filter = emptyFilter; + if (relation.columns.length === 1) + createInFilter(); + else + createCompositeFilter(); + + function createInFilter() { + var ids = []; + var row; + var id; + var alias = relation.columns[0].alias; + for (var i = 0; i < queryContext.rows.length; i++) { + row = queryContext.rows[i]; + id = row[alias]; + if (!isNullOrUndefined(id)) + ids.push(id); + } + + if (ids.length > 0) + filter = relation.childTable._primaryColumns[0].in(context, ids); + } + + function createCompositeFilter() { + var keyFilter; + for (var i = 0; i < queryContext.rows.length; i++) { + keyFilter = rowToPrimaryKeyFilter(context, queryContext.rows[i], relation); + if (keyFilter) + filter = filter.or(context, keyFilter); + } + } + + return relation.childTable.getMany(filter, strategy).then(onRows); + + function onRows(rows) { + queryContext.expand(relation); + negotiateExpandInverse(parent, relation, rows); + return rows; + } + + } + + function rowToPrimaryKeyFilter(context, row, relation) { + var key = relation.columns.map( function(column) { + return row[column.alias]; + }); + if (key.some(isNullOrUndefined)) { + return; + } + var args = [context, relation.childTable].concat(key); + return newPrimaryKeyFilter.apply(null, args); + } + + function isNullOrUndefined(item) { + return item === null || item === undefined; + } + + getRelatives_1$1 = getRelatives; + return getRelatives_1$1; +} + +var fuzzyPromise_1; +var hasRequiredFuzzyPromise; + +function requireFuzzyPromise () { + if (hasRequiredFuzzyPromise) return fuzzyPromise_1; + hasRequiredFuzzyPromise = 1; + function fuzzyPromise(value) { + if (value !== undefined && value !== null) + Object.defineProperty(value, 'then', { + value: then, + writable: true, + enumerable: false, + configurable: true + }); + + return value; + + function then(fn) { + delete value.then; + fn(value); + } + } + + fuzzyPromise_1 = fuzzyPromise; + return fuzzyPromise_1; +} + +var newJoinRelation; +var hasRequiredNewJoinRelation; + +function requireNewJoinRelation () { + if (hasRequiredNewJoinRelation) return newJoinRelation; + hasRequiredNewJoinRelation = 1; + var newLeg = requireNewJoinLeg(), + getById = requireGetById(), + nullPromise = requireNullPromise(), + newGetRelated = requireNewGetRelated(), + getRelatives = requireGetRelatives$1(), + fuzzyPromise = requireFuzzyPromise(); + function _newJoin(parentTable, childTable, columnNames) { + var c = {}; + + c.parentTable = parentTable; + c.childTable = childTable; + c.columns = []; + var columns = parentTable._columns; + addColumns(); + + c.accept = function(visitor) { + visitor.visitJoin(c); + }; + + c.toLeg = function() { + return newLeg(c); + }; + + c.getFromDb = function(parent) { + var key = parentToArrayKey(parent); + if (key.length === 0) { + return nullPromise; + } + var args = [childTable].concat(key); + return getById.apply(null, args); + }; + + c.getFromCache = function(parent) { + var result = c.getRowsSync(parent); + return fuzzyPromise(result); + }; + + c.toGetRelated = function(parent) { + return newGetRelated(parent, c); + }; + + c.getRelatives = function(parent) { + return getRelatives(parent, c); + }; + + c.expand = function(parent) { + parent.expand(c.leftAlias); + }; + + c.getRowsSync = function(parent) { + var key = parentToKey(parent); + let cache = parent._relationCacheMap.get(c); + return cache.tryGet(key); + }; + + c.getInnerCache = function() { + return childTable._cache.getInnerCache(); + }; + + c.notNullExceptInsert = function() { + return c; + }; + + c.notNull = function() { + return c; + }; + + + return c; + + function addColumns() { + var numberOfColumns = columnNames.length; + for (var i = 0; i < columns.length; i++) { + var curColumn = columns[i]; + tryAdd(curColumn); + if (numberOfColumns === c.columns.length) + return; + } + } + + function tryAdd(column) { + for (var i = 0; i < columnNames.length; i++) { + var name = columnNames[i]; + if (column._dbName === name) { + column.default = undefined; + // delete column.lazyDefault; + c.columns.push(column); + return; + } + } + } + + function parentToKey(parent) { + let key = {}; + for (let i = 0; i < c.columns.length; i++) { + let value = parent[c.columns[i].alias]; + if (value === null || value === undefined) + return {}; + key[childTable._primaryColumns[i].alias] = value; + } + return key; + } + + function parentToArrayKey(parent) { + let key = []; + for (let i = 0; i < c.columns.length; i++) { + let value = parent[c.columns[i].alias]; + if (value === null || value === undefined) + return []; + key.push(value); + } + return key; + } + } + + + newJoinRelation = _newJoin; + return newJoinRelation; +} + +var selectSql; +var hasRequiredSelectSql; + +function requireSelectSql () { + if (hasRequiredSelectSql) return selectSql; + hasRequiredSelectSql = 1; + var newParameterized = requireNewParameterized(); + var newBoolean = requireNewBoolean(); + const getSessionSingleton = requireGetSessionSingleton(); + + function newSelectSql(context, table, alias) { + const quote = getSessionSingleton(context, 'quote'); + const quotedAlias = quote(alias); + const colName = quote(table._primaryColumns[0]._dbName); + const sql = 'SELECT ' + quotedAlias + '.' + colName + ' FROM ' + quote(table._dbName) + ' ' + quotedAlias; + const sqlp = newParameterized(sql); + return newBoolean(sqlp); + } + + selectSql = newSelectSql; + return selectSql; +} + +var joinSql; +var hasRequiredJoinSql; + +function requireJoinSql () { + if (hasRequiredJoinSql) return joinSql; + hasRequiredJoinSql = 1; + var newShallowJoinSql = requireNewShallowJoinSql(); + var newParameterized = requireNewParameterized(); + + function newJoinSql(context, relations, depth = 0) { + var leftAlias, + rightAlias; + var relation; + var c = {}; + var sql = newParameterized(''); + + c.visitJoin = function(relation) { + //todo fix discriminators on childTable + sql = newShallowJoinSql(context, relation.parentTable, relation.childTable._primaryColumns, relation.columns, leftAlias, rightAlias).prepend(' INNER').prepend(sql); + }; + + c.visitOne = function(relation) { + innerJoin(relation); + }; + + c.visitMany = c.visitOne; + + function innerJoin(relation) { + var joinRelation = relation.joinRelation; + var table = joinRelation.childTable; + var rightColumns = table._primaryColumns; + var leftColumns = joinRelation.columns; + + sql = newShallowJoinSql(context, table, leftColumns, rightColumns, leftAlias, rightAlias).prepend(' INNER').prepend(sql); + } + + for (let i = relations.length - 1; i > depth; i--) { + leftAlias = 'x' + (i + 1); + rightAlias = 'x' + i; + relation = relations[i]; + relation.accept(c); + } + return sql; + } + + joinSql = newJoinSql; + return joinSql; +} + +var whereSql; +var hasRequiredWhereSql; + +function requireWhereSql () { + if (hasRequiredWhereSql) return whereSql; + hasRequiredWhereSql = 1; + var newShallowJoinSql = requireNewShallowJoinSqlCore(); + + function newWhereSql(context, relations, shallowFilter, depth = 0) { + let relation = relations[depth]; + var c = {}; + var sql; + + c.visitJoin = function(relation) { + var table = relation.childTable; + + //todo fix discriminators + var alias = depth === 0 ? (relation.parentTable._rootAlias || relation.parentTable._dbName) : 'x' + depth; + var leftColumns = relation.columns; + var rightColumns = table._primaryColumns; + where(alias, leftColumns, rightColumns); + }; + + c.visitOne = function(relation) { + var joinRelation = relation.joinRelation; + var rightColumns = joinRelation.columns; + var childTable = joinRelation.childTable; + var leftColumns = childTable._primaryColumns; + //todo fix discriminators + var alias = depth === 0 ? (childTable._rootAlias || childTable._dbName) : 'x' + depth; + where(alias, leftColumns, rightColumns); + }; + + c.visitMany = c.visitOne; + + function where(alias, leftColumns, rightColumns) { + var table = relation.childTable; + var joinCore = newShallowJoinSql(context, table, leftColumns, rightColumns, alias, 'x' + (depth + 1)); + if (shallowFilter && shallowFilter.sql()) { + sql = joinCore.prepend(' WHERE ').append(' AND ').append(shallowFilter); + } + else + sql = joinCore.prepend(' WHERE '); + } + + relation.accept(c); + return sql; + } + + whereSql = newWhereSql; + return whereSql; +} + +var subFilter; +var hasRequiredSubFilter; + +function requireSubFilter () { + if (hasRequiredSubFilter) return subFilter; + hasRequiredSubFilter = 1; + var newSelect = requireSelectSql(); + var newJoin = requireJoinSql(); + var newWhere = requireWhereSql(); + + function newSubFilter(context, relations, shallowFilter, depth) { + var relationCount = relations.length; + var alias = 'x' + relationCount; + var table = relations[relationCount-1].childTable; + var exists = newSelect(context, table,alias).prepend('EXISTS ('); + var join = newJoin(context, relations, depth); + var where = newWhere(context, relations,shallowFilter, depth); + return exists.append(join).append(where).append(')'); + + } + + subFilter = newSubFilter; + return subFilter; +} + +var columnAggregateGroup; +var hasRequiredColumnAggregateGroup; + +function requireColumnAggregateGroup () { + if (hasRequiredColumnAggregateGroup) return columnAggregateGroup; + hasRequiredColumnAggregateGroup = 1; + var newJoin = requireJoinSql(); + var getSessionContext = requireGetSessionContext(); + var newJoinCore = requireNewShallowJoinSqlCore(); + const getSessionSingleton = requireGetSessionSingleton(); + + function columnAggregate(context, operator, column, relations, coalesce = true) { + const quote = getSessionSingleton(context, 'quote'); + const rdb = getSessionContext(context); + const outerAlias = 'y' + rdb.aggregateCount++; + const outerAliasQuoted = quote(outerAlias); + const alias = quote('x' + relations.length); + const foreignKeys = getForeignKeys(relations[0]); + const select = ` LEFT JOIN (SELECT ${foreignKeys},${operator}(${alias}.${quote(column._dbName)}) as amount`; + const innerJoin = relations.length > 1 ? newJoin(context, relations).sql() : ''; + const onClause = createOnClause(context, relations[0], outerAlias); + const from = ` FROM ${quote(relations.at(-1).childTable._dbName)} ${alias} ${innerJoin} GROUP BY ${foreignKeys}) ${outerAliasQuoted} ON (${onClause})`; + const join = select + from; + + return { + expression: (alias) => coalesce ? `COALESCE(${outerAliasQuoted}.amount, 0) as ${quote(alias)}` : `${outerAliasQuoted}.amount as ${alias}`, + joins: [join] + }; + + function getForeignKeys(relation) { + let columns; + let alias = quote('x1'); + if (relation.joinRelation) + columns = relation.joinRelation.columns; + else + columns = relation.childTable._primaryColumns; + return columns.map(x => `${alias}.${quote(x._dbName)}`).join(','); + } + } + + function createOnClause(context, relation, rightAlias) { + var c = {}; + var sql = ''; + let leftAlias = relation.parentTable._rootAlias || relation.parentTable._dbName; + + c.visitJoin = function(relation) { + sql = newJoinCore(context, relation.childTable, relation.columns, relation.childTable._primaryColumns, leftAlias, rightAlias).sql(); + }; + + c.visitOne = function(relation) { + innerJoin(relation); + }; + + c.visitMany = c.visitOne; + + function innerJoin(relation) { + var joinRelation = relation.joinRelation; + var childTable = relation.childTable; + var parentTable = relation.parentTable; + var columns = joinRelation.columns; + + sql = newJoinCore(context, childTable, parentTable._primaryColumns, columns, leftAlias, rightAlias).sql(); + } + + relation.accept(c); + return sql; + } + + + + columnAggregateGroup = columnAggregate; + return columnAggregateGroup; +} + +var joinSqlArray; +var hasRequiredJoinSqlArray; + +function requireJoinSqlArray () { + if (hasRequiredJoinSqlArray) return joinSqlArray; + hasRequiredJoinSqlArray = 1; + const newShallowJoinSql = requireNewShallowJoinSql(); + + function _new(context, relations) { + + let result = []; + let leftAlias = relations[0].parentTable._dbName; + let rightAlias = 'z'; + let sql; + + + let c = {}; + c.visitJoin = function(relation) { + sql = newShallowJoinSql(context, relation.childTable,relation.columns,relation.childTable._primaryColumns,leftAlias,rightAlias).prepend(' LEFT').sql(); + }; + + c.visitOne = function(relation) { + sql = newShallowJoinSql(context, relation.childTable,relation.parentTable._primaryColumns,relation.joinRelation.columns,leftAlias,rightAlias).prepend(' LEFT').sql(); + }; + + c.visitMany = c.visitOne; + + for (let i = 0; i < relations.length; i++) { + rightAlias = rightAlias + relations[i].toLeg().name; + relations[i].accept(c); + result.push(sql); + leftAlias = rightAlias; + } + + return result; + } + + joinSqlArray = _new; + return joinSqlArray; +} + +var columnAggregate_1; +var hasRequiredColumnAggregate; + +function requireColumnAggregate () { + if (hasRequiredColumnAggregate) return columnAggregate_1; + hasRequiredColumnAggregate = 1; + const getSessionSingleton = requireGetSessionSingleton(); + var newJoinArray = requireJoinSqlArray(); + + function columnAggregate(context, operator, column, relations, coalesce = true) { + const quote = getSessionSingleton(context, 'quote'); + + let tableAlias = relations.reduce((prev,relation) => { + return prev + relation.toLeg().name; + }, 'z'); + tableAlias = quote(tableAlias); + const columnName = quote(column._dbName); + + return { + expression: (alias) => coalesce ? `COALESCE(${operator}(${tableAlias}.${columnName}), 0) as ${quote(alias)}` : `${operator}(${tableAlias}.${columnName}) as ${alias}`, + + joins: newJoinArray(context, relations) + }; + } + + columnAggregate_1 = columnAggregate; + return columnAggregate_1; +} + +var childColumn_1; +var hasRequiredChildColumn; + +function requireChildColumn () { + if (hasRequiredChildColumn) return childColumn_1; + hasRequiredChildColumn = 1; + var newJoin = requireJoinSql(); + var getSessionContext = requireGetSessionContext(); + var newJoinCore = requireNewShallowJoinSqlCore(); + const getSessionSingleton = requireGetSessionSingleton(); + const _quote = requireQuote$1(); + + + function childColumn(context, column, relations) { + const quote = getSessionSingleton(context, 'quote'); + const rdb = getSessionContext(context); + const outerAlias = 'y' + rdb.aggregateCount++; + const outerAliasQuoted = quote(outerAlias); + const alias = 'x' + relations.length; + const foreignKeys = getForeignKeys(context, relations[0]); + const select = ` LEFT JOIN (SELECT ${foreignKeys},${alias}.${quote(column._dbName)} as prop`; + const innerJoin = relations.length > 1 ? newJoin(context, relations).sql() : ''; + const onClause = createOnClause(context, relations[0], outerAlias); + const from = ` FROM ${quote(relations.at(-1).childTable._dbName)} ${alias} ${innerJoin}) ${outerAliasQuoted} ON (${onClause})`; + const join = select + from ; + + return { + expression: (alias) => `${outerAliasQuoted}.prop ${quote(alias)}`, + joins: [join], + column, + groupBy: `${outerAliasQuoted}.prop`, + }; + } + + function createOnClause(context, relation, rightAlias) { + var c = {}; + var sql = ''; + let leftAlias = relation.parentTable._rootAlias || relation.parentTable._dbName; + + c.visitJoin = function(relation) { + sql = newJoinCore(context, relation.childTable,relation.columns,relation.childTable._primaryColumns,leftAlias,rightAlias).sql(); + }; + + c.visitOne = function(relation) { + innerJoin(relation); + }; + + c.visitMany = c.visitOne; + + function innerJoin(relation) { + var joinRelation = relation.joinRelation; + var childTable = relation.childTable; + var parentTable = relation.parentTable; + var columns = joinRelation.columns; + + sql = newJoinCore(context, childTable,parentTable._primaryColumns,columns,leftAlias, rightAlias).sql(); + } + relation.accept(c); + return sql; + } + + function getForeignKeys(context, relation) { + let columns; + let alias = 'x1'; + if (relation.joinRelation) + columns = relation.joinRelation.columns; + else + columns = relation.childTable._primaryColumns; + return columns.map(x => `${alias}.${_quote(context, x._dbName)}`).join(','); + } + + childColumn_1 = childColumn; + return childColumn_1; +} + +var relatedColumn; +var hasRequiredRelatedColumn; + +function requireRelatedColumn () { + if (hasRequiredRelatedColumn) return relatedColumn; + hasRequiredRelatedColumn = 1; + var newSubFilter = requireSubFilter(); + var aggregateGroup = requireColumnAggregateGroup(); + var aggregate = requireColumnAggregate(); + var childColumn = requireChildColumn(); + + function newRelatedColumn(column, relations, isShallow, depth) { + var c = {}; + + var alias = 'x' + relations.length; + for (var propName in column) { + var prop = column[propName]; + if (prop instanceof Function) + + c[propName] = wrapFilter(prop); + } + + c.groupSum = (context, ...rest) => aggregateGroup.apply(null, [context, 'sum', column, relations, ...rest]); + c.groupAvg = (context, ...rest) => aggregateGroup.apply(null, [context, 'avg', column, relations, ...rest]); + c.groupMin = (context, ...rest) => aggregateGroup.apply(null, [context, 'min', column, relations, ...rest]); + c.groupMax = (context, ...rest) => aggregateGroup.apply(null, [context, 'max', column, relations, ...rest]); + c.groupCount = (context, ...rest) => aggregateGroup.apply(null, [context, 'count', column, relations, false, ...rest]); + c.sum = (context, ...rest) => aggregate.apply(null, [context, 'sum', column, relations, ...rest]); + c.avg = (context, ...rest) => aggregate.apply(null, [context, 'avg', column, relations, ...rest]); + c.min = (context, ...rest) => aggregate.apply(null, [context, 'min', column, relations, ...rest]); + c.max = (context, ...rest) => aggregate.apply(null, [context, 'max', column, relations, ...rest]); + c.count = (context, ...rest) => aggregate.apply(null, [context, 'count', column, relations, false, ...rest]); + c.self = (context, ...rest) => childColumn.apply(null, [context, column, relations, ...rest]); + + return c; + + function wrapFilter(filter) { + return runFilter; + + function runFilter(context) { + var args = []; + for (var i = 0; i < arguments.length; i++) { + args.push(arguments[i]); + } + args.push(alias); + var shallowFilter = filter.apply(null, args); + if (isShallow) + return shallowFilter; + return newSubFilter(context, relations, shallowFilter, depth); + } + } + + } + + relatedColumn = newRelatedColumn; + return relatedColumn; +} + +var any; +var hasRequiredAny; + +function requireAny () { + if (hasRequiredAny) return any; + hasRequiredAny = 1; + const negotiateRawSqlFilter = requireNegotiateRawSqlFilter(); + let subFilter = requireSubFilter(); + let isShallow = true; + + function newAny(newRelatedTable, relations, depth) { + + function any(context, fn) { + let relatedTable = newRelatedTable(relations, isShallow, depth + 1); + let arg = typeof fn === 'function' ? fn(relatedTable) : fn; + let filter = negotiateRawSqlFilter(context, arg); + let sub = subFilter(context, relations, filter, depth); + return sub; + } + return any; + } + + any = newAny; + + // + // let newRelatedTable = _newRelatedTable; + // let negotiateRawSqlFilter = require('../column/negotiateRawSqlFilter'); + // let newSelect = require('./selectSql'); + // let newJoin = require('./joinSql'); + // let newWhere = require('./whereSql'); + // let subFilter = require('./subFilter'); + // let isShallow = true; + + // function newAny(relations, depth) { + + // function any(fn) { + // let relationCount = relations.length; + // let alias = 'x' + (depth); + // // let alias = 'x' + relationCount; + // let table = relations[relationCount - 1].childTable; + // let exists = newSelect(table, alias).prepend('EXISTS ('); + // let join = newJoin(relations, depth); + + // let relatedTable = newRelatedTable(relations.slice(-1), isShallow, depth+1); + // let arg = typeof fn === 'function' ? fn(relatedTable) : fn; //we need inner joins from here + // let filter = negotiateRawSqlFilter(arg); + // let where = newWhere(relations[0],filter, depth); + // return exists.append(join).append(where).append(')'); + + + // // let innerJoin = newJoinSql(relations); + // // let relatedTable = newRelatedTable(relations.slice(-1), isShallow); + // // //relations is missing anything below any(..) + // // let arg = typeof fn === 'function' ? fn(relatedTable) : fn; //we need inner joins from here + // // let filter = negotiateRawSqlFilter(arg); + // // let sqlFilter = filter.sql(); + // // //_3.id is not null + // // return subFilter(relations.slice(-1), filter); + // } + // return any; + // // db.order.lines.any(x => x.order.deliveryAddress.id.notEqual(null)); + // } + + // function _newRelatedTable() { + // newRelatedTable = require('../newRelatedTable'); + // return newRelatedTable.apply(null, arguments); + // } + + // module.exports = newAny; + return any; +} + +var all; +var hasRequiredAll; + +function requireAll () { + if (hasRequiredAll) return all; + hasRequiredAll = 1; + const negotiateRawSqlFilter = requireNegotiateRawSqlFilter(); + let subFilter = requireSubFilter(); + let isShallow = true; + + function newAll(newRelatedTable, relations, depth) { + + function all(context, fn) { + let relatedTable = newRelatedTable(relations, isShallow, depth + 1); + let arg = typeof fn === 'function' ? fn(relatedTable) : fn; + let anyFilter = negotiateRawSqlFilter(context, arg); + let anySubFilter = subFilter(context, relations, anyFilter, depth); + let notFilter = subFilter(context, relations, anyFilter.not(), depth).not(); + return anySubFilter.and(context, notFilter); + } + return all; + } + + all = newAll; + return all; +} + +var where$1; +var hasRequiredWhere$1; + +function requireWhere$1 () { + if (hasRequiredWhere$1) return where$1; + hasRequiredWhere$1 = 1; + const negotiateRawSqlFilter = requireNegotiateRawSqlFilter(); + let tryGetSessionContext = requireTryGetSessionContext(); + + function newWhere(_relations, _depth) { + + function where(context, fn) { + const includeMany = tryGetSessionContext(context)?.engine === 'mssql'; + let { relations, alias } = extract(includeMany, _relations); + const table = relations[relations.length - 1].childTable; + if (!relations[0].isMany || includeMany) + table._rootAlias = alias; + + try { + let arg = typeof fn === 'function' ? fn(table) : fn; + let anyFilter = negotiateRawSqlFilter(context, arg); + delete table._rootAlias; + return anyFilter; + } + catch (e) { + delete table._rootAlias; + throw e; + } + } + return where; + + function extract(includeMany, relations) { + let alias = relations[0].toLeg().table._dbName; + let result = []; + for (let i = 0; i < relations.length; i++) { + if (relations[i].isMany && !includeMany) { + result = [relations[i]]; + alias = relations[i].toLeg().table._dbName; + } + else { + result.push(relations[i]); + alias += relations[i].toLeg().name; + } + } + return { relations: result, alias }; + } + + } + + where$1 = newWhere; + return where$1; +} + +var aggregate$1; +var hasRequiredAggregate$1; + +function requireAggregate$1 () { + if (hasRequiredAggregate$1) return aggregate$1; + hasRequiredAggregate$1 = 1; + let tryGetSessionContext = requireTryGetSessionContext(); + + function newAggregate(_relations) { + + function aggregate(context, fn) { + const includeMany = tryGetSessionContext(context)?.engine === 'mssql'; + let { relations, alias } = extract(includeMany, _relations); + const table = relations[relations.length - 1].childTable; + if (!relations[0].isMany || includeMany) + table._rootAlias = alias; + + try { + const query = fn(table); + delete table._rootAlias; + return query; + } + catch (e) { + delete table._rootAlias; + throw e; + } + } + return aggregate; + + function extract(includeMany, relations) { + let alias = relations[0].toLeg().table._dbName; + let result = []; + for (let i = 0; i < relations.length; i++) { + if (relations[i].isMany && !includeMany) { + result = [relations[i]]; + alias = relations[i].toLeg().table._dbName; + } + else { + result.push(relations[i]); + alias += relations[i].toLeg().name; + } + } + return { relations: result, alias }; + } + + } + + aggregate$1 = newAggregate; + return aggregate$1; +} + +var none; +var hasRequiredNone; + +function requireNone () { + if (hasRequiredNone) return none; + hasRequiredNone = 1; + const negotiateRawSqlFilter = requireNegotiateRawSqlFilter(); + let subFilter = requireSubFilter(); + let isShallow = true; + + function newNone(newRelatedTable, relations, depth) { + + function none(context, fn) { + let relatedTable = newRelatedTable(relations, isShallow, depth + 1); + let arg = typeof fn === 'function' ? fn(relatedTable) : fn; + let filter = negotiateRawSqlFilter(context, arg); + return subFilter(context, relations, filter, depth).not(); + } + return none; + } + + none = newNone; + return none; +} + +var newRelatedTable_1; +var hasRequiredNewRelatedTable; + +function requireNewRelatedTable () { + if (hasRequiredNewRelatedTable) return newRelatedTable_1; + hasRequiredNewRelatedTable = 1; + var newRelatedColumn = requireRelatedColumn(); + var subFilter = requireSubFilter(); + var any = requireAny(); + var all = requireAll(); + var where = requireWhere$1(); + var aggregate = requireAggregate$1(); + var none = requireNone(); + + function newRelatedTable(relations, isShallow, depth = 0) { + var table = relations[relations.length - 1].childTable; + var columns = table._columns; + + let c; + // if (isShallow) + // c = any(relations.slice(-1), depth); + // else + c = any(newRelatedTable, relations, depth); + // @ts-ignore + c.all = all(newRelatedTable, relations, depth); + // @ts-ignore + c.any = c; + + // @ts-ignore + c.none = none(newRelatedTable, relations, depth); + + // @ts-ignore + c.where = where(relations, depth); + + // @ts-ignore + c._aggregate = aggregate(relations); + + Object.defineProperty(c, '_relation', { + value: relations[relations.length - 1], + writable: false + }); + + for (var i = 0; i < columns.length; i++) { + var col = columns[i]; + if (col.alias === 'name') + c._name = newRelatedColumn(col, relations, isShallow, depth); + else + c[col.alias] = newRelatedColumn(col, relations, isShallow, depth); + } + defineChildren(); + + function defineChildren() { + var childRelations = table._relations; + for (var alias in childRelations) { + defineChild(alias); + } + } + + function defineChild(alias) { + var relation = table._relations[alias]; + var children = relations.slice(0); + children.push(relation); + + Object.defineProperty(c, alias, { + get: function() { + return newRelatedTable(children, false, depth); + } + }); + } + + + // @ts-ignore + c.exists = function(context) { + if (isShallow) + return ''; + return subFilter(context, relations, false, depth); + }; + + let cProxy = new Proxy(c, { + get: function(target, prop) { + if (prop === 'name') { + return target._name !== undefined ? target._name : target.name; + } + return target[prop]; + }, + set: function(target, prop, value) { + if (prop === 'name') { + target._name = value; + } else { + target[prop] = value; + } + return true; + } + }); + + return cProxy; + } + + newRelatedTable_1 = newRelatedTable; + return newRelatedTable_1; +} + +var join; +var hasRequiredJoin; + +function requireJoin () { + if (hasRequiredJoin) return join; + hasRequiredJoin = 1; + var newJoinRelation = requireNewJoinRelation(); + var newRelatedTable = requireNewRelatedTable(); + + function newJoin(parentTable, childTable) { + var c = {}; + var columnNames = []; + var relation; + + c.by = function() { + for (var i = 0; i < arguments.length; i++) { + columnNames.push(getColumnName(arguments[i])); + } + relation = newJoinRelation(parentTable, childTable, columnNames); + relation.as = c.as; + return relation; + }; + + function getColumnName(columnName) { + var columns = parentTable._columns; + for (var i = 0; i < columns.length; i++) { + if (columns[i]._dbName === columnName || columns[i].alias === columnName) + return columns[i]._dbName; + } + throw new Error('Unknown column: ' + columnName); + } + + c.as = function(alias) { + relation.leftAlias = alias; + parentTable._relations[alias] = relation; + + Object.defineProperty(parentTable, alias, { + get: function() { + return newRelatedTable([relation]); + } + }); + + return relation; + }; + + c.notNullExceptInsert = function() { + return c; + }; + + c.notNull = function() { + return c; + }; + + return c; + } + + join = newJoin; + return join; +} + +var newOneLeg; +var hasRequiredNewOneLeg; + +function requireNewOneLeg () { + if (hasRequiredNewOneLeg) return newOneLeg; + hasRequiredNewOneLeg = 1; + var newCollection = requireNewCollection(); + var newQueryContext = requireNewQueryContext(); + + function newLeg(relation) { + + var joinRelation = relation.joinRelation; + var c = {}; + c.name = joinRelation.rightAlias; + var span = {}; + span.queryContext = newQueryContext(); + span.table = joinRelation.parentTable; + span.legs = newCollection(); + c.span = span; + c.table = joinRelation.childTable; + c.columns = joinRelation.columns; + c.expand = relation.expand; + + c.accept = function(visitor) { + visitor.visitOne(c); + }; + + return c; + } + + newOneLeg = newLeg; + return newOneLeg; +} + +var newManyLeg; +var hasRequiredNewManyLeg; + +function requireNewManyLeg () { + if (hasRequiredNewManyLeg) return newManyLeg; + hasRequiredNewManyLeg = 1; + var newOneLeg = requireNewOneLeg(); + + function newLeg(relation) { + var c = newOneLeg(relation); + c.name = relation.joinRelation.rightAlias; + c.accept = function(visitor) { + visitor.visitMany(c); + }; + + c.expand = relation.expand; + + return c; + } + + newManyLeg = newLeg; + return newManyLeg; +} + +var extractParentKey_1; +var hasRequiredExtractParentKey; + +function requireExtractParentKey () { + if (hasRequiredExtractParentKey) return extractParentKey_1; + hasRequiredExtractParentKey = 1; + function extractParentKey(joinRelation, child) { + + var childTable = joinRelation.childTable; + var primaryColumns = childTable._primaryColumns; + var parent = {}; + + joinRelation.columns.forEach(addKeyToParent); + + function addKeyToParent(childPk, index) { + var primaryColumn = primaryColumns[index]; + parent[primaryColumn.alias] = child[childPk.alias]; + } + + return parent; + } + + extractParentKey_1 = extractParentKey; + return extractParentKey_1; +} + +var synchronizeChanged_1; +var hasRequiredSynchronizeChanged; + +function requireSynchronizeChanged () { + if (hasRequiredSynchronizeChanged) return synchronizeChanged_1; + hasRequiredSynchronizeChanged = 1; + var extractParentKey = requireExtractParentKey(); + + function synchronizeChanged(context, manyCache, joinRelation, parent, child) { + var columns = joinRelation.columns; + columns.forEach(subscribeColumn); + child = null; + + function subscribeColumn(column) { + child.subscribeChanged(onChanged, column.alias); + } + + function unsubscribe(child) { + columns.forEach(unsubscribeColumn); + + function unsubscribeColumn(column) { + child.unsubscribeChanged(onChanged, column.alias); + } + } + + function onChanged(child) { + unsubscribe(child); + manyCache.tryRemove(context, parent, child); + var newParent = extractParentKey(joinRelation, child); + manyCache.tryAdd(context, newParent, child); + } + + + + } + + synchronizeChanged_1 = synchronizeChanged; + return synchronizeChanged_1; +} + +var synchronizeAdded_1; +var hasRequiredSynchronizeAdded; + +function requireSynchronizeAdded () { + if (hasRequiredSynchronizeAdded) return synchronizeAdded_1; + hasRequiredSynchronizeAdded = 1; + var extractParentKey = requireExtractParentKey(); + + function synchronizeAdded(context, action, joinRelation) { + var cache = joinRelation.parentTable._cache; + cache.subscribeAdded(context, onAdded); + + function onAdded(child) { + var parent = extractParentKey(joinRelation, child); + action(parent, child); + } + } + + synchronizeAdded_1 = synchronizeAdded; + return synchronizeAdded_1; +} + +var synchronizeRemoved_1; +var hasRequiredSynchronizeRemoved; + +function requireSynchronizeRemoved () { + if (hasRequiredSynchronizeRemoved) return synchronizeRemoved_1; + hasRequiredSynchronizeRemoved = 1; + var extractParentKey = requireExtractParentKey(); + + function synchronizeRemoved(context, action, joinRelation) { + var cache = joinRelation.parentTable._cache; + cache.subscribeRemoved(context, onRemoved); + + function onRemoved(child) { + var parent = extractParentKey(joinRelation, child); + action(parent, child); + } + } + + synchronizeRemoved_1 = synchronizeRemoved; + return synchronizeRemoved_1; +} + +var newCache; +var hasRequiredNewCache; + +function requireNewCache () { + if (hasRequiredNewCache) return newCache; + hasRequiredNewCache = 1; + var newEmitEvent = requireEmitEvent(); + + function cacheCore() { + var emitAdded = newEmitEvent(); + var emitRemoved = newEmitEvent(); + var c = {}; + var cache = {}; + var keyLength; + + c.tryGet = function(key) { + var index = 0; + var keyLength = key.length; + + return tryGetCore(cache, index); + + function tryGetCore(cache, index) { + var keyValue = key[index]; + var cacheValue = cache[keyValue]; + if (typeof cacheValue === 'undefined') + return null; + if (keyLength - 1 === index) + return cacheValue; + return tryGetCore(cache[keyValue], ++index); + } + + }; + + c.tryAdd = function(key, result) { + var index = 0; + keyLength = key.length; + + return addCore(cache, index); + + function addCore(cache, index) { + var keyValue = key[index]; + + if (keyLength - 1 === index) { + if (keyValue in cache) + return cache[keyValue]; + + cache[keyValue] = result; + emitAdded(result); + return result; + } + if (! (keyValue in cache)) + cache[keyValue] = {}; + return addCore(cache[keyValue], ++index); + } + }; + + c.tryRemove = function(key) { + var index = 0; + var keyLength = key.length; + + return tryRemoveCore(cache, index); + + function tryRemoveCore(cache, index) { + var keyValue = key[index]; + if (!(keyValue in cache)) + return null; + var cacheValue = cache[keyValue]; + if (keyLength - 1 === index) { + delete cache[keyValue]; + emitRemoved(cacheValue); + return cacheValue; + } + + return tryRemoveCore(cache[keyValue], ++index); + } + + }; + + c.getAll = function() { + var index = 0; + var result = []; + getAllCore(cache, index); + + function getAllCore(cache, index) { + for (var name in cache) { + var value = cache[name]; + if (index === keyLength - 1) + result.push(value); + else + getAllCore(value, index+1); + } + } + return result; + }; + + c.subscribeAdded = emitAdded.add; + c.subscribeRemoved = emitRemoved.add; + + return c; + } + + newCache = cacheCore; + return newCache; +} + +var newManyCacheCore; +var hasRequiredNewManyCacheCore; + +function requireNewManyCacheCore () { + if (hasRequiredNewManyCacheCore) return newManyCacheCore; + hasRequiredNewManyCacheCore = 1; + var newCacheCore = requireNewCache(); + var newRowArray = requireRowArray(); + + function newManyCache(joinRelation) { + var c = {}; + var cache = newCacheCore(); + var primaryColumns = joinRelation.childTable._primaryColumns; + + c.tryGet = function(parentRow) { + var key = toKey(parentRow); + var rows = cache.tryGet(key); + if (!rows) + return newArray(); + return rows; + }; + + function tryAdd(parentRow, childRow) { + var key = toKey(parentRow); + var existing = cache.tryGet(key); + if(existing) { + existing.push(childRow); + return; + } + var rows = newArray(); + rows.push(childRow); + existing = cache.tryAdd(key, rows); + } + + function newArray() { + return newRowArray(joinRelation.parentTable); + } + + c.tryAdd = tryAdd; + + c.tryRemove = function(parentRow, childRow) { + var key = toKey(parentRow); + var existing = cache.tryGet(key); + var index = existing.indexOf(childRow); + existing.splice(index,1); + }; + + function toKey(row) { + return primaryColumns.map(onColumn); + + function onColumn(column) { + return row[column.alias]; + } + } + + return c; + } + + newManyCacheCore = newManyCache; + return newManyCacheCore; +} + +var newId; +var hasRequiredNewId; + +function requireNewId () { + if (hasRequiredNewId) return newId; + hasRequiredNewId = 1; + const { v4 : uuid} = require$$0$2; + newId = uuid; + return newId; +} + +var newManyCache_1; +var hasRequiredNewManyCache; + +function requireNewManyCache () { + if (hasRequiredNewManyCache) return newManyCache_1; + hasRequiredNewManyCache = 1; + var synchronizeChanged = requireSynchronizeChanged(); + var synchronizeAdded = requireSynchronizeAdded(); + var synchronizeRemoved = requireSynchronizeRemoved(); + var extractParentKey = requireExtractParentKey(); + var newCacheCore = requireNewManyCacheCore(); + var newId = requireNewId(); + var getSessionSingleton = requireGetSessionSingleton(); + var setSessionSingleton = requireSetSessionSingleton(); + + function newManyCache(joinRelation) { + var c = {}; + var key; + + c.tryAdd = function(context, parent, child) { + c.getInnerCache(context).tryAdd(parent, child); + synchronizeChanged(context, c, joinRelation, parent, child); + }; + + c.tryRemove = function(context, parent, child) { + c.getInnerCache(context).tryRemove(parent, child); + }; + + c.tryGet = function(context, parentRow) { + return c.getInnerCache(context).tryGet(parentRow); + }; + + c.getInnerCache = function(context) { + const theKey = negotiateKey(); + var cache = getSessionSingleton(context, theKey); + if (!cache) { + cache = newCacheCore(joinRelation); + setSessionSingleton(context, theKey, cache); + fillCache(context); + synchronizeAdded(context, c.tryAdd.bind(null, context), joinRelation); + synchronizeRemoved(context, c.tryRemove.bind(null, context), joinRelation); + } + return cache; + }; + + + function fillCache(context) { + var childTable = joinRelation.parentTable; + var childCache = childTable._cache; + var children = childCache.getAll(context); + children.forEach(addToCache); + + function addToCache(child) { + var parent = extractParentKey(joinRelation, child); + c.tryAdd(context, parent, child); + } + } + + function negotiateKey() { + if (key) + return key; + key = newId(); + return key; + + } + + + return c; + } + + newManyCache_1 = newManyCache; + return newManyCache_1; +} + +var newForeignKeyFilter_1; +var hasRequiredNewForeignKeyFilter; + +function requireNewForeignKeyFilter () { + if (hasRequiredNewForeignKeyFilter) return newForeignKeyFilter_1; + hasRequiredNewForeignKeyFilter = 1; + function newForeignKeyFilter(context, joinRelation, parentRow) { + var columns = joinRelation.columns; + var rightTable = joinRelation.childTable; + + var filter = getNextFilterPart(0); + + for (var i = 1; i < columns.length; i++) { + + filter = filter.and(getNextFilterPart(i)); + } + + function getNextFilterPart(index) { + var column = columns[index]; + var pk = rightTable._primaryColumns[index]; + return column.eq(context, parentRow[pk.alias]); + } + return filter; + } + + newForeignKeyFilter_1 = newForeignKeyFilter; + return newForeignKeyFilter_1; +} + +var getRelatives_1; +var hasRequiredGetRelatives; + +function requireGetRelatives () { + if (hasRequiredGetRelatives) return getRelatives_1; + hasRequiredGetRelatives = 1; + let emptyFilter = requireEmptyFilter(); + let newForeignKeyFilter = requireNewForeignKeyFilter(); + let negotiateExpandInverse = requireNegotiateExpandInverse(); + + function getRelatives(context, parent, relation) { + let queryContext = parent.queryContext; + let strategy = queryContext && queryContext.strategy[relation.joinRelation.rightAlias]; + + + let filter; + let parentTable = relation.joinRelation.childTable; + + if (parentTable._primaryColumns.length === 1) + filter = createInFilter(); + else + filter = createCompositeFilter(); + + + function createInFilter() { + let parentAlias = parentTable._primaryColumns[0].alias; + let ids = queryContext.rows.map(function(row) { + return row[parentAlias]; + }); + let column = relation.joinRelation.columns[0]; + return column.in(context, ids); + } + + function createCompositeFilter() { + let filters = queryContext.rows.map(function(row) { + return newForeignKeyFilter(context, relation.joinRelation, row); + }); + return emptyFilter.or.apply(emptyFilter, [context, ...filters]); + } + + return relation.childTable.getMany(context, filter, strategy).then(onRows); + + function onRows(rows) { + queryContext.expand(relation); + negotiateExpandInverse(parent, relation, rows); + return rows; + } + + } + + getRelatives_1 = getRelatives; + return getRelatives_1; +} + +var newManyRelation_1; +var hasRequiredNewManyRelation; + +function requireNewManyRelation () { + if (hasRequiredNewManyRelation) return newManyRelation_1; + hasRequiredNewManyRelation = 1; + var newLeg = requireNewManyLeg(); + var newManyCache = requireNewManyCache(); + var newForeignKeyFilter = requireNewForeignKeyFilter(); + var getRelatives = requireGetRelatives(); + var fuzzyPromise = requireFuzzyPromise(); + var newGetRelated = requireNewGetRelated(); + + function newManyRelation(joinRelation) { + var c = {}; + var manyCache = newManyCache(joinRelation); + + c.joinRelation = joinRelation; + c.childTable = joinRelation.parentTable; + c.parentTable = joinRelation.childTable; + c.isMany = true; + + c.accept = function(visitor) { + visitor.visitMany(c); + }; + + c.getFromCache = function(parent) { + var result = c.getRowsSync(parent); + return fuzzyPromise(result); + }; + + c.getFromDb = function(context, parent) { + var filter = newForeignKeyFilter(context, joinRelation, parent); + return c.childTable.getMany(context, filter, null); + }; + + c.getRelatives = function(context, parent) { + return getRelatives(context, parent, c); + }; + + c.toGetRelated = function(context, parent) { + return newGetRelated(context, parent, c); + }; + + c.expand = function(parent) { + return parent.expand(joinRelation.rightAlias); + }; + + c.getRowsSync = function(parent) { + let cache = parent._relationCacheMap.get(c); + if (!cache) + return []; + return cache.tryGet(parent); + }; + + c.toLeg = function() { + return newLeg(c); + }; + + c.getInnerCache = function(context) { + return manyCache.getInnerCache(context); + }; + + return c; + } + + newManyRelation_1 = newManyRelation; + return newManyRelation_1; +} + +var hasMany; +var hasRequiredHasMany; + +function requireHasMany () { + if (hasRequiredHasMany) return hasMany; + hasRequiredHasMany = 1; + var newManyRelation = requireNewManyRelation(); + var newRelatedTable = requireNewRelatedTable(); + + function newOne(joinRelation) { + var c = {}; + var parentTable = joinRelation.childTable; + + c.as = function(alias) { + joinRelation.rightAlias = alias; + var relation = newManyRelation(joinRelation); + parentTable._relations[alias] = relation; + + Object.defineProperty(parentTable, alias, { + get: function() { + return newRelatedTable([relation]); + } + }); + + return relation; + }; + + c.notNullExceptInsert = function() { + return c; + }; + + c.notNull = function() { + return c; + }; + + return c; + } + + hasMany = newOne; + return hasMany; +} + +var newOneCache_1; +var hasRequiredNewOneCache; + +function requireNewOneCache () { + if (hasRequiredNewOneCache) return newOneCache_1; + hasRequiredNewOneCache = 1; + let newManyCache = requireNewManyCache(); + + function newOneCache(joinRelation) { + let c = {}; + let cache = newManyCache(joinRelation); + + c.tryGet = function(context, parent) { + let res = cache.tryGet(context, parent); + if (res.length === 0) + return null; + return res[0]; + }; + + c.getInnerCache = function(context) { + let _cache = cache.getInnerCache(context); + let _c = {}; + _c.tryGet = function(context, parent) { + let res = _cache.tryGet(context, parent); + if (res.length === 0) + return null; + return res[0]; + }; + return _c; + }; + return c; + } + + newOneCache_1 = newOneCache; + return newOneCache_1; +} + +var newOneRelation_1; +var hasRequiredNewOneRelation; + +function requireNewOneRelation () { + if (hasRequiredNewOneRelation) return newOneRelation_1; + hasRequiredNewOneRelation = 1; + var newLeg = requireNewOneLeg(); + var newOneCache = requireNewOneCache(); + var newForeignKeyFilter = requireNewForeignKeyFilter(); + var getRelatives = requireGetRelatives(); + var fuzzyPromise = requireFuzzyPromise(); + var newGetRelated = requireNewGetRelated(); + + function newOneRelation(joinRelation) { + var c = {}; + var oneCache = newOneCache(joinRelation); + + c.joinRelation = joinRelation; + c.childTable = joinRelation.parentTable; + c.parentTable = joinRelation.childTable; + c.isOne = true; + + c.accept = function(visitor) { + visitor.visitOne(c); + }; + + c.getFromCache = function(parent) { + let row = c.getRowsSync(parent); + return fuzzyPromise(row); + }; + + c.getFromDb = function(context, parent) { + var filter = newForeignKeyFilter(context, joinRelation, parent); + return c.childTable.tryGetFirst(context, filter, null); + }; + + c.getRelatives = function(context, parent) { + return getRelatives(context, parent, c); + }; + + c.toGetRelated = function(context, parent) { + return newGetRelated(context, parent, c); + }; + + c.expand = function(parent) { + return parent.expand(joinRelation.rightAlias); + }; + + c.getRowsSync = function(parent) { + let cache = parent._relationCacheMap.get(c); + if (!cache) + return null; + return cache.tryGet(parent); + }; + + c.toLeg = function() { + return newLeg(c); + }; + + c.getInnerCache = function(context) { + return oneCache.getInnerCache(context); + }; + + return c; + } + + newOneRelation_1 = newOneRelation; + return newOneRelation_1; +} + +var hasOne; +var hasRequiredHasOne; + +function requireHasOne () { + if (hasRequiredHasOne) return hasOne; + hasRequiredHasOne = 1; + var newOneRelation = requireNewOneRelation(); + var newRelatedTable = requireNewRelatedTable(); + + function newOne(joinRelation) { + var c = {}; + var parentTable = joinRelation.childTable; + + c.as = function(alias) { + joinRelation.rightAlias = alias; + var relation = newOneRelation(joinRelation); + parentTable._relations[alias] = relation; + + Object.defineProperty(parentTable, alias, { + get: function() { + return newRelatedTable([relation]); + } + }); + return relation; + }; + + c.notNullExceptInsert = function() { + return c; + }; + + c.notNull = function() { + + return c; + }; + + + return c; + } + + hasOne = newOne; + return hasOne; +} + +var count_1; +var hasRequiredCount; + +function requireCount () { + if (hasRequiredCount) return count_1; + hasRequiredCount = 1; + const executeQueries = requireExecuteQueries(); + const negotiateRawSqlFilter = requireNegotiateRawSqlFilter(); + const extractFilter = requireExtractFilter(); + const newWhereSql = requireNewWhereSql(); + const quote = requireQuote$1(); + + async function count(context, table, filter) { + let alias = table._dbName; + filter = negotiateRawSqlFilter(context,filter, table); + let query = newQuery(context, table, filter, alias); + let allResults = await executeQueries(context, [query]); + let count = await allResults[0].then((rows) => { + + const count = Number.parseInt(rows[0]._count); + return count; + }); + return count; + } + + function newQuery(context, table, filter, alias) { + filter = extractFilter(filter); + var name = quote(context, table._dbName); + alias = quote(context, alias); + var whereSql = newWhereSql(context, table, filter, alias); + + return whereSql.prepend('select count(*) "_count" from ' + name + ' ' + alias); + + + } + + count_1 = count; + return count_1; +} + +var newSingleQuery; +var hasRequiredNewSingleQuery; + +function requireNewSingleQuery () { + if (hasRequiredNewSingleQuery) return newSingleQuery; + hasRequiredNewSingleQuery = 1; + var newColumnSql = requireNewColumnSql(); + var newWhereSql = requireNewWhereSql(); + var newJoinSql = requireNewJoinSql(); + var newParameterized = requireNewParameterized(); + var getSessionSingleton = requireGetSessionSingleton(); + + function _new(context,table,filter,span, alias,orderBy,limit,offset) { + var quote = getSessionSingleton(context, 'quote'); + var name = quote(table._dbName); + var columnSql = newColumnSql(context,table,span,alias,true); + var joinSql = newJoinSql(context, span, alias); + var whereSql = newWhereSql(context,table,filter,alias); + if (limit) + limit = limit + ' '; + + return newParameterized('select ' + limit + columnSql + ' from ' + name + ' ' + quote(alias)).append(joinSql).append(whereSql).append(orderBy + offset); + + } + + newSingleQuery = _new; + return newSingleQuery; +} + +var newQuery_1$1; +var hasRequiredNewQuery$1; + +function requireNewQuery$1 () { + if (hasRequiredNewQuery$1) return newQuery_1$1; + hasRequiredNewQuery$1 = 1; + var newSingleQuery = requireNewSingleQuery(); + var extractFilter = requireExtractFilter(); + var extractOrderBy = requireExtractOrderBy(); + var extractLimit = requireExtractLimit(); + var newParameterized = requireNewParameterized(); + var extractOffset = requireExtractOffset(); + + function newQuery(context,table,filter,span,alias) { + filter = extractFilter(filter); + var orderBy = extractOrderBy(context,table,alias,span.orderBy); + var limit = extractLimit(context, span); + var offset = extractOffset(context, span); + + var query = newSingleQuery(context,table,filter,span,alias,orderBy,limit,offset); + return newParameterized(query.sql(), query.parameters); + } + + newQuery_1$1 = newQuery; + return newQuery_1$1; +} + +var getManyDto_1$1; +var hasRequiredGetManyDto$1; + +function requireGetManyDto$1 () { + if (hasRequiredGetManyDto$1) return getManyDto_1$1; + hasRequiredGetManyDto$1 = 1; + const emptyFilter = requireEmptyFilter(); + const newQuery = requireNewQuery$1(); + const negotiateRawSqlFilter = requireNegotiateRawSqlFilter(); + const strategyToSpan = requireStrategyToSpan(); + const executeQueries = requireExecuteQueries(); + const getSessionSingleton = requireGetSessionSingleton(); + + async function getManyDto(context, table, filter, strategy, spanFromParent, updateParent) { + filter = negotiateRawSqlFilter(context, filter, table); + if (strategy && strategy.where) { + let arg = typeof strategy.where === 'function' ? strategy.where(context, table) : strategy.where; + filter = filter.and(context, arg); + } + + let span = spanFromParent || strategyToSpan(table, strategy); + let alias = table._dbName; + + const query = newQuery(context, table, filter, span, alias); + const res = await executeQueries(context, [query]); + return decode(context, strategy, span, await res[0], undefined, updateParent); + } + + function newCreateRow(span) { + let columnsMap = span.columns; + const columns = span.table._columns.filter(column => !columnsMap || columnsMap.get(column)); + const protoRow = createProto(columns, span); + const manyNames = []; + + const c = {}; + c.visitJoin = () => { }; + c.visitOne = () => { }; + c.visitMany = function(leg) { + manyNames.push(leg.name); + }; + + span.legs.forEach(onEachLeg); + return createRow; + + function onEachLeg(leg) { + leg.accept(c); + } + + function createRow() { + const obj = Object.create(protoRow); + for (let i = 0; i < manyNames.length; i++) { + obj[manyNames[i]] = []; + } + return obj; + } + } + + function createProto(columns, span) { + let obj = {}; + for (let i = 0; i < columns.length; i++) { + obj[columns[i].alias] = null; + } + for (let key in span.aggregates) { + obj[key] = null; + } + const c = {}; + + c.visitJoin = function(leg) { + obj[leg.name] = null; + }; + c.visitOne = c.visitJoin; + c.visitMany = function(leg) { + obj[leg.name] = null; + }; + + span.legs.forEach(onEachLeg); + + function onEachLeg(leg) { + leg.accept(c); + } + + return obj; + } + + + // function newCreateRow(span) { + // const columnsMap = span.columns; + // const columns = span.table._columns.filter(column => !columnsMap || columnsMap.get(column)); + // const ProtoRow = createProto(columns, span); + // const manyNames = []; + + // const c = { + // visitJoin: () => { }, + // visitOne: () => { }, + // visitMany: function(leg) { + // manyNames.push(leg.name); + // } + // }; + + // span.legs.forEach(leg => leg.accept(c)); + + // return createRow; + + // function createRow() { + // const obj = new ProtoRow(); + // manyNames.forEach(name => { + // obj[name] = []; + // }); + // return obj; + // } + // } + + // function createProto(columns, span) { + // function ProtoRow() { + // columns.forEach(column => { + // this[column.alias] = null; + // }); + + // for (const key in span.aggregates) { + // this[key] = null; + // } + + // const c = { + // visitJoin: (leg) => { + // this[leg.name] = null; + // }, + // visitOne: (leg) => { + // this[leg.name] = null; + // }, + // visitMany: (leg) => { + // this[leg.name] = null; + // } + // }; + + // span.legs.forEach(leg => leg.accept(c)); + // } + + // return ProtoRow; + // } + + + function hasManyRelations(span) { + let result; + const c = {}; + c.visitJoin = () => { }; + c.visitOne = c.visitJoin; + c.visitMany = function() { + result = true; + }; + + span.legs.forEach(onEachLeg); + return result; + + function onEachLeg(leg) { + leg.accept(c); + } + } + + async function decode(context, strategy, span, rows, keys = rows.length > 0 ? Object.keys(rows[0]) : [], updateParent) { + const table = span.table; + let columnsMap = span.columns; + const columns = table._columns.filter(column => !columnsMap || columnsMap.get(column)); + const rowsLength = rows.length; + const columnsLength = columns.length; + const primaryColumns = table._primaryColumns; + const primaryColumnsLength = primaryColumns.length; + const rowsMap = new Map(); + const fkIds = new Array(rows.length); + const getIds = createGetIds(); + const aggregateKeys = Object.keys(span.aggregates); + + const outRows = new Array(rowsLength); + const createRow = newCreateRow(span); + const shouldCreateMap = hasManyRelations(span); + for (let i = 0; i < rowsLength; i++) { + const row = rows[i]; + let outRow = createRow(); + let pkWithNullCount = 0; + for (let j = 0; j < columnsLength; j++) { + if (j < primaryColumnsLength) { + if (row[keys[j]] === null) + pkWithNullCount++; + if (pkWithNullCount === primaryColumnsLength) { + outRow = null; + break; + } + } + const column = columns[j]; + outRow[column.alias] = column.decode(context, row[keys[j]]); + } + + for (let j = 0; j < aggregateKeys.length; j++) { + const key = aggregateKeys[j]; + const parse = span.aggregates[key].column?.decode || ((context, arg) => Number.parseFloat(arg)); + outRow[key] = parse(context, row[keys[j + columnsLength]]); + } + + outRows[i] = outRow; + if (updateParent) + updateParent(outRow, i); + if (shouldCreateMap) { + fkIds[i] = getIds(outRow); + addToMap(rowsMap, fkIds[i], outRow); + } + } + span._rowsMap = rowsMap; + span._ids = fkIds; + + keys.splice(0, columnsLength + aggregateKeys.length); + if (span.legs.toArray().length === 0) + return outRows; + + const all = []; + + if (shouldCreateMap) { + all.push(decodeManyRelations(context, strategy, span)); + all.push(decodeRelations2(context, strategy, span, rows, outRows, keys)); + } + else + all.push(decodeRelations2(context, strategy, span, rows, outRows, keys)); + + await Promise.all(all); + + return outRows; + + + function createGetIds() { + const primaryColumns = table._primaryColumns; + const length = primaryColumns.length; + if (length === 1) { + const alias = table._primaryColumns[0].alias; + return (row) => row[alias]; + } + else + return (row) => { + const result = new Array(length); + for (let i = 0; i < length; i++) { + result[i] = row[primaryColumns[i].alias]; + } + return result; + }; + } + + } + + async function decodeManyRelations(context, strategy, span) { + const maxParameters = getSessionSingleton(context, 'maxParameters'); + const maxRows = maxParameters + ? maxParameters * span.table._primaryColumns.length + : undefined; + + const promises = []; + const c = {}; + c.visitJoin = () => { }; + c.visitOne = c.visitJoin; + + // Helper function to split an array into chunks + function chunk(array, size) { + const results = []; + for (let i = 0; i < array.length; i += size) { + results.push(array.slice(i, i + size)); + } + return results; + } + + c.visitMany = function(leg) { + const name = leg.name; + const table = span.table; + const relation = table._relations[name]; + const rowsMap = span._rowsMap; + + const extractKey = createExtractKey(leg); + const extractFromMap = createExtractFromMap(rowsMap, table._primaryColumns); + + // If maxRows is defined, chunk the IDs before calling getManyDto + if (maxRows) { + const chunkedIds = chunk(span._ids, maxRows); + for (const idsChunk of chunkedIds) { + const filter = createOneFilter(context, relation, idsChunk); + const p = getManyDto( + context, + relation.childTable, + filter, + strategy[name], + leg.span, + updateParent + ); + promises.push(p); + } + } else { + // Otherwise, do the entire set in one go + const filter = createOneFilter(context, relation, span._ids); + const p = getManyDto( + context, + relation.childTable, + filter, + strategy[name], + leg.span, + updateParent + ); + promises.push(p); + } + + function updateParent(subRow) { + const key = extractKey(subRow); + const parentRow = extractFromMap(key); + parentRow[name].push(subRow); + } + }; + + function createExtractKey(leg) { + if (leg.columns.length === 1) { + const alias = leg.columns[0].alias; + return (row) => row[alias]; + } else { + const aliases = leg.columns.map(column => column.alias); + return (row) => aliases.map(alias => row[alias]); + } + } + + function createExtractFromMap(map, primaryColumns) { + if (primaryColumns.length === 1) { + return (key) => map.get(key); + } else { + return getFromMap.bind(null, map, primaryColumns); + } + } + + // Visit all legs + span.legs.forEach(onEachLeg); + + function onEachLeg(leg) { + leg.accept(c); + } + + // Wait until all promises resolve + await Promise.all(promises); + } + + async function decodeRelations2(context, strategy, span, rawRows, resultRows, keys) { + const c = {}; + c.visitJoin = function(leg) { + const name = leg.name; + return decode(context, strategy[name], leg.span, rawRows, keys, updateParent); + + function updateParent(subRow, i) { + resultRows[i][name] = subRow; + + } + }; + + c.visitOne = c.visitJoin; + c.visitMany = () => { }; + + async function processLegsSequentially(legs) { + for (const leg of legs.toArray()) { + await leg.accept(c); + } + } + + await processLegsSequentially(span.legs); + } + + function createOneFilter(context, relation, ids) { + const columns = relation.joinRelation.columns; + + if (columns.length === 1) + return columns[0].in(context, ids); + + else + return createCompositeFilter(); + + function createCompositeFilter() { + let filter = emptyFilter; + for (let id of ids) { + let nextFilter; + for (let i = 0; i < columns.length; i++) { + if (nextFilter) + nextFilter = nextFilter.and(context, columns[i].eq(context, id[i])); + else + nextFilter = columns[i].eq(context, id[i]); + } + filter = filter.or(context, nextFilter); + } + return filter; + } + } + + function addToMap(map, values, row) { + if (Array.isArray(values)) { + + const lastIndex = values.length - 1; + for (let i = 0; i < lastIndex; i++) { + const id = values[i]; + if (map.has(id)) + map = map.get(id); + else { + const next = new Map(); + map.set(id, next); + map = next; + } + } + map.set(values[lastIndex], row); + } + else + map.set(values, row); + } + + function getFromMap(map, primaryColumns, values) { + if (Array.isArray(values)) { + const length = primaryColumns.length; + for (let i = 0; i < length; i++) { + map = map.get(values[i]); + } + return map; + } + else + return map.get(values); + } + + + getManyDto_1$1 = getManyDto; + return getManyDto_1$1; +} + +var getManyDto_1; +var hasRequiredGetManyDto; + +function requireGetManyDto () { + if (hasRequiredGetManyDto) return getManyDto_1; + hasRequiredGetManyDto = 1; + const getSessionSingleton = requireGetSessionSingleton(); + const getManyDtoCore = requireGetManyDto$1(); + + function getManyDto(context, _table, _filter, _strategy) { + const _getManyDto = getSessionSingleton(context, 'getManyDto') || getManyDtoCore; + return _getManyDto.apply(null, arguments); + } + + getManyDto_1 = getManyDto; + return getManyDto_1; +} + +var tryGetById; +var hasRequiredTryGetById; + +function requireTryGetById () { + if (hasRequiredTryGetById) return tryGetById; + hasRequiredTryGetById = 1; + var tryGetFromCacheById = requireTryGetFromCacheById(); + var tryGetFromDbById = requireTryGetFromDbById(); + var resultToPromise = requireResultToPromise(); + + function get() { + var cached = tryGetFromCacheById.apply(null,arguments); + if (cached) + return resultToPromise(cached); + return tryGetFromDbById.apply(null,arguments); + } + get.exclusive = tryGetFromDbById.exclusive; + + tryGetById = get; + return tryGetById; +} + +var newRowCache_1; +var hasRequiredNewRowCache; + +function requireNewRowCache () { + if (hasRequiredNewRowCache) return newRowCache_1; + hasRequiredNewRowCache = 1; + let newCache = requireNewCache(); + let getSessionSingleton = requireGetSessionSingleton(); + let setSessionSingleton = requireSetSessionSingleton(); + + function newRowCache(table) { + let id = Symbol(); + let c = {}; + + c.tryGet = function(context, row) { + return getCache(context, table, id).tryGet(row); + }; + + c.tryAdd = function(context, row) { + return getCache(context, table, id).tryAdd(row); + }; + + c.tryRemove = function(context, row) { + return getCache(context, table, id).tryRemove(row); + }; + + c.subscribeAdded = function(context, ...rest) { + return getCache(context, table, id).subscribeAdded.apply(null, rest); + }; + + c.subscribeRemoved = function(context, ...rest) { + return getCache(context, table, id).subscribeRemoved.apply(null, rest); + }; + + c.getAll = function(context) { + return getCache(context, table, id).getAll.apply(null, arguments); + }; + + c.getInnerCache = function(context) { + return getCache(context, table, id); + }; + return c; + } + + + function getCache(context, table, id) { + let cache = getSessionSingleton(context, id); + if (cache) + return cache; + cache = _newRowCache(table); + setSessionSingleton(context, id, cache); + return cache; + } + + + function _newRowCache(table) { + let c = {}; + let cache = newCache(); + let pkNames; + let rowToKey = firstRowToKey; + + function getPkNames() { + let names = {}; + let primaryColumns = table._primaryColumns; + let keyLength = primaryColumns.length; + for (let i = 0; i < keyLength; i++) { + let column = primaryColumns[i]; + names[column.alias] = null; + } + return names; + } + + c.tryGet = function(row) { + let key = rowToKey(row); + return cache.tryGet(key); + + }; + + function firstRowToKey(row) { + pkNames = getPkNames(); + rowToKey = nextRowToKey; + table = null; + return rowToKey(row); + } + + function nextRowToKey(row) { + let key = []; + for(let pkName in pkNames) { + key.push(row[pkName]); + } + return key; + } + + c.tryAdd = function(row) { + let key = rowToKey(row); + return cache.tryAdd(key, row); + }; + + c.tryRemove = function(row) { + let key = rowToKey(row); + return cache.tryRemove(key); + }; + + c.subscribeAdded = cache.subscribeAdded; + c.subscribeRemoved = cache.subscribeRemoved; + + c.getAll = cache.getAll; + + return c; + } + + newRowCache_1 = newRowCache; + return newRowCache_1; +} + +var newRow_1; +var hasRequiredNewRow; + +function requireNewRow () { + if (hasRequiredNewRow) return newRow_1; + hasRequiredNewRow = 1; + var decodeDbRow = requireDecodeDbRow(); + var flags = requireFlags(); + + function newRow(context, {table, _options}) { + var dto = {}; + table._columns.forEach(addColumn); + + function addColumn(column) { + var alias = column.alias; + if ('default' in column) { + if (typeof column.default === 'function') + dto[alias] = column.default(); + else if (column.toDto) + dto[alias] = column.toDto(column.default); + else + dto[alias] = column.default; + } + else if (flags.useLazyDefaults && 'lazyDefault' in column && !column.isPrimary) { + if (typeof column.lazyDefault === 'function') + dto[alias] = column.lazyDefault(); + else if (column.toDto) + dto[alias] = column.toDto(column.lazyDefault); + else + dto[alias] = column.lazyDefault; + } + else if (column.dbNull !== null) + dto[alias] = null; + else + dto[alias] = undefined; + } + const arg = arguments[2]; + if (isObject(arg)) + for (let name in arg) { + if (table[name] && table[name].equal) + dto[name] = arg[name]; + } + else + for (var i = 2; i < arguments.length; i++) { + var pkValue = arguments[i]; + var column = table._primaryColumns[i - 1]; + dto[column.alias] = pkValue; + } + + return decodeDbRow(context, table, table, dto, true, true); + } + + function isObject(object) { + return (object === Object(object) && !Array.isArray(object) && !(object instanceof Date)); + } + + newRow_1 = newRow; + return newRow_1; +} + +var insert_1; +var hasRequiredInsert$1; + +function requireInsert$1 () { + if (hasRequiredInsert$1) return insert_1; + hasRequiredInsert$1 = 1; + let getSessionContext = requireGetSessionContext(); + let newRow = requireNewRow(); + + function insert(context, { table, options }, arg) { + if (Array.isArray(arg)) { + let all = []; + for (let i = 0; i < arg.length; i++) { + all.push(insert(context, table, arg[i])); + } + return Promise.all(all); + } + let row = newRow.apply(null, [...arguments]); + let hasPrimary = getHasPrimary(table, row); + if (hasPrimary) { + row = table._cache.tryAdd(context, row); + } + expand(table, row); + Object.defineProperty(row, 'then', { + value: then, + writable: true, + enumerable: false, + configurable: true + }); + const rdb = getSessionContext(context); + const insertP = rdb.insert(context, table, row, options).then(onResult); + + + // } + // else { + // // Non-PG case, use Promise + // result = new Promise((resolve, reject) => { + // ([result]) => { + // row.hydrate(result); + // if (!hasPrimary) { + // row = table._cache.tryAdd(row); + // } + // table._cache.tryAdd(row); + // resolve(row);qq + // }; + // }); + // } + + async function then(fn, efn) { + delete row.then; + return insertP.then(() => fn(row), efn); + } + + return row; + + function onResult([result]) { + row.hydrate(context, result); + // if (!hasPrimary) + // row = table._cache.tryAdd(context, row); + row = table._cache.tryAdd(context, row); + return row; + } + } + + function expand(table, row) { + let relationName; + let visitor = {}; + visitor.visitJoin = function() { }; + + visitor.visitMany = function() { + row.expand(relationName); + }; + + visitor.visitOne = function() { + row.expand(relationName); + }; + + for (relationName in table._relations) { + let relation = table._relations[relationName]; + relation.accept(visitor); + } + } + + function getHasPrimary(table, row) { + for (let i = 0; i < table._primaryColumns.length; i++) { + let column = table._primaryColumns[i]; + if (row[column.alias] === null) { + return false; + } + } + return true; + } + + insert_1 = insert; + return insert_1; +} + +var _delete_1; +var hasRequired_delete; + +function require_delete () { + if (hasRequired_delete) return _delete_1; + hasRequired_delete = 1; + var pushCommand = requirePushCommand(); + var newDeleteCommand = requireNewDeleteCommand(); + var extractDeleteStrategy = requireExtractDeleteStrategy(); + var negotiateRawSqlFilter = requireNegotiateRawSqlFilter(); + var emptyPromise = requireResultToPromise()(); + + function _delete(context, table, filter, strategy) { + filter = negotiateRawSqlFilter(context, filter, table); + strategy = extractDeleteStrategy(strategy); + var relations = []; + var cmds = []; + + cmds = newDeleteCommand(context, cmds, table, filter, strategy, relations); + cmds.forEach(function(cmd) { + pushCommand(context, cmd); + }); + return emptyPromise; + } + + _delete_1 = _delete; + return _delete_1; +} + +var cascadeDelete_1; +var hasRequiredCascadeDelete; + +function requireCascadeDelete () { + if (hasRequiredCascadeDelete) return cascadeDelete_1; + hasRequiredCascadeDelete = 1; + var _delete = require_delete(); + var newObject = requireNewObject(); + var newCascadeDeleteStrategy = requireNewCascadeDeleteStrategy(); + + function cascadeDelete(context, table, filter) { + var empty = newObject(); + var strategy = newCascadeDeleteStrategy(empty, table); + return _delete(context, table, filter, strategy); + } + + cascadeDelete_1 = cascadeDelete; + return cascadeDelete_1; +} + +var where; +var hasRequiredWhere; + +function requireWhere () { + if (hasRequiredWhere) return where; + hasRequiredWhere = 1; + const negotiateRawSqlFilter = requireNegotiateRawSqlFilter(); + + function newWhere(table) { + + function where(context, fn) { + let arg = typeof fn === 'function' ? fn(table) : fn; + return negotiateRawSqlFilter(context, arg); + } + return where; + } + + where = newWhere; + return where; +} + +var aggregate; +var hasRequiredAggregate; + +function requireAggregate () { + if (hasRequiredAggregate) return aggregate; + hasRequiredAggregate = 1; + function newAggregate(table) { + + function aggregate(_context, fn) { + return fn(table); + } + return aggregate; + } + + aggregate = newAggregate; + return aggregate; +} + +var newQuery_1; +var hasRequiredNewQuery; + +function requireNewQuery () { + if (hasRequiredNewQuery) return newQuery_1; + hasRequiredNewQuery = 1; + var newSingleQuery = requireNewSingleQuery(); + var extractFilter = requireExtractFilter(); + var extractLimit = requireExtractLimit(); + var newParameterized = requireNewParameterized(); + var extractOffset = requireExtractOffset(); + + function newQuery(context, table,filter,span,alias) { + filter = extractFilter(filter); + var orderBy = ''; + var limit = extractLimit(context, span); + var offset = extractOffset(context, span); + + var query = newSingleQuery(context, table,filter,span,alias,orderBy,limit,offset); + const groupClause = groupBy(span); + return newParameterized(query.sql(), query.parameters).append(groupClause); + } + + function groupBy(span) { + const keys = Object.keys(span.aggregates).filter(x => span.aggregates[x].column); + if (keys.length === 0) + return ''; + return ' GROUP BY ' + keys.map(key => span.aggregates[key].groupBy).join(','); + } + + newQuery_1 = newQuery; + return newQuery_1; +} + +var groupBy_1; +var hasRequiredGroupBy; + +function requireGroupBy () { + if (hasRequiredGroupBy) return groupBy_1; + hasRequiredGroupBy = 1; + const newQuery = requireNewQuery(); + const negotiateRawSqlFilter = requireNegotiateRawSqlFilter(); + const strategyToSpan = requireStrategyToSpan(); + const executeQueries = requireExecuteQueries(); + + async function groupBy(context, table, filter, strategy) { + filter = negotiateRawSqlFilter(context, filter, table); + if (strategy && strategy.where) { + let arg = typeof strategy.where === 'function' ? strategy.where(table) : strategy.where; + filter = filter.and(context, arg); + } + + let span = strategyToSpan(table, strategy); + span.columns = new Map(); + + let alias = table._dbName; + + const query = newQuery(context, table, filter, span, alias); + const res = await executeQueries(context, [query]); + return decode(context, span, await res[0]); + } + + function newCreateRow(span) { + const protoRow = createProto(span); + + return createRow; + + function createRow() { + return Object.create(protoRow); + } + } + + function createProto(span) { + let obj = {}; + for (let key in span.aggregates) { + obj[key] = null; + } + + return obj; + } + + + async function decode(context, span, rows, keys = rows.length > 0 ? Object.keys(rows[0]) : []) { + const rowsLength = rows.length; + const aggregateKeys = Object.keys(span.aggregates); + + const outRows = new Array(rowsLength); + const createRow = newCreateRow(span); + for (let i = 0; i < rowsLength; i++) { + const row = rows[i]; + let outRow = createRow(); + + for (let j = 0; j < aggregateKeys.length; j++) { + const key = aggregateKeys[j]; + const parse = span.aggregates[key].column?.decode || ((_context, arg) => Number.parseFloat(arg)); + outRow[key] = parse(context, row[keys[j]]); + } + + outRows[i] = outRow; + } + + return outRows; + } + + groupBy_1 = groupBy; + return groupBy_1; +} + +var table; +var hasRequiredTable; + +function requireTable () { + if (hasRequiredTable) return table; + hasRequiredTable = 1; + const newColumn = requireNewColumn(); + const column = requireColumn(); + const join = requireJoin(); + const hasMany = requireHasMany(); + const hasOne = requireHasOne(); + const getMany = requireGetMany(); + const count = requireCount(); + const getManyDto = requireGetManyDto(); + const getById = requireGetById(); + const tryGetById = requireTryGetById(); + const tryGetFirst = requireTryGetFirstFromDb(); + const newCache = requireNewRowCache(); + const newContext = requireNewObject(); + const insert = requireInsert$1(); + const _delete = require_delete(); + const cascadeDelete = requireCascadeDelete(); + const patchTable = requirePatchTable(); + const newEmitEvent = requireEmitEvent(); + const hostLocal = requireHostLocal(); + // const getTSDefinition = require('./getTSDefinition'); //todo: unused ? + const where = requireWhere(); + const aggregate = requireAggregate(); + const groupBy = requireGroupBy(); + + + function _new(tableName) { + var table = newContext(); + table._dbName = tableName; + table._primaryColumns = []; + table._aliases = new Set(); + table._columns = []; + table._columnDiscriminators = []; + table._formulaDiscriminators = []; + table._relations = {}; + table._cache = newCache(table); + table._emitChanged = newEmitEvent(); + + table.primaryColumn = function(columnName) { + var columnDef = newColumn(table, columnName); + columnDef.isPrimary = true; + table._primaryColumns.push(columnDef); + return column(columnDef, table); + }; + + table.column = function(columnName) { + var columnDef = newColumn(table, columnName); + return column(columnDef, table); + }; + + table.join = function(relatedTable) { + return join(table, relatedTable); + }; + + table.hasMany = function(joinRelation) { + return hasMany(joinRelation); + }; + + table.hasOne = function(joinRelation) { + return hasOne(joinRelation); + }; + + table.count = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => count.apply(null, args)); + }; - headers[normalized] = true; - }); + table.getMany = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => getMany.apply(null, args)); + }; + table.getManyDto = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => getManyDto.apply(null, args)); + }; - return this; - } + table.aggregate = function(context, ...rest) { + const args = [context, table, ...rest]; + return groupBy.apply(null, args); + }; - concat(...targets) { - return this.constructor.concat(this, ...targets); - } + table.getMany.exclusive = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => getMany.exclusive.apply(null, args)); + }; - toJSON(asStrings) { - const obj = Object.create(null); + table.tryGetFirst = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => tryGetFirst.apply(null, args)); + }; + table.tryGetFirst.exclusive = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => tryGetFirst.exclusive.apply(null, args)); + }; - utils$1.forEach(this, (value, header) => { - value != null && value !== false && (obj[header] = asStrings && utils$1.isArray(value) ? value.join(', ') : value); - }); + table.getOne = table.tryGetFirst; + table.getOne.exclusive = table.tryGetFirst.exclusive; - return obj; - } + table.getById = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => getById.apply(null, args)); + }; - [Symbol.iterator]() { - return Object.entries(this.toJSON())[Symbol.iterator](); - } + table.getById.exclusive = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => getById.exclusive.apply(null, args)); + }; - toString() { - return Object.entries(this.toJSON()).map(([header, value]) => header + ': ' + value).join('\n'); - } + table.tryGetById = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => tryGetById.apply(null, args)); + }; - get [Symbol.toStringTag]() { - return 'AxiosHeaders'; - } + table.tryGetById.exclusive = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => tryGetById.exclusive.apply(null, args)); + }; - static from(thing) { - return thing instanceof this ? thing : new this(thing); - } - static concat(first, ...targets) { - const computed = new this(first); + table.columnDiscriminators = function() { + for (var i = 0; i < arguments.length; i++) { + table._columnDiscriminators.push(arguments[i]); + } + return table; + }; - targets.forEach((target) => computed.set(target)); - - return computed; - } - - static accessor(header) { - const internals = this[$internals] = (this[$internals] = { - accessors: {} - }); - - const accessors = internals.accessors; - const prototype = this.prototype; - - function defineAccessor(_header) { - const lHeader = normalizeHeader(_header); - - if (!accessors[lHeader]) { - buildAccessors(prototype, _header); - accessors[lHeader] = true; - } - } - - utils$1.isArray(header) ? header.forEach(defineAccessor) : defineAccessor(header); - - return this; - } -} - -AxiosHeaders.accessor(['Content-Type', 'Content-Length', 'Accept', 'Accept-Encoding', 'User-Agent', 'Authorization']); - -// reserved names hotfix -utils$1.reduceDescriptors(AxiosHeaders.prototype, ({value}, key) => { - let mapped = key[0].toUpperCase() + key.slice(1); // map `set` => `Set` - return { - get: () => value, - set(headerValue) { - this[mapped] = headerValue; - } - } -}); - -utils$1.freezeMethods(AxiosHeaders); - -var AxiosHeaders$1 = AxiosHeaders; - -/** - * Transform the data for a request or a response - * - * @param {Array|Function} fns A single function or Array of functions - * @param {?Object} response The response object - * - * @returns {*} The resulting transformed data - */ -function transformData(fns, response) { - const config = this || defaults$1; - const context = response || config; - const headers = AxiosHeaders$1.from(context.headers); - let data = context.data; - - utils$1.forEach(fns, function transform(fn) { - data = fn.call(config, data, headers.normalize(), response ? response.status : undefined); - }); - - headers.normalize(); - - return data; -} - -function isCancel(value) { - return !!(value && value.__CANCEL__); -} - -/** - * A `CanceledError` is an object that is thrown when an operation is canceled. - * - * @param {string=} message The message. - * @param {Object=} config The config. - * @param {Object=} request The request. - * - * @returns {CanceledError} The created error. - */ -function CanceledError(message, config, request) { - // eslint-disable-next-line no-eq-null,eqeqeq - AxiosError.call(this, message == null ? 'canceled' : message, AxiosError.ERR_CANCELED, config, request); - this.name = 'CanceledError'; -} - -utils$1.inherits(CanceledError, AxiosError, { - __CANCEL__: true -}); - -/** - * Resolve or reject a Promise based on response status. - * - * @param {Function} resolve A function that resolves the promise. - * @param {Function} reject A function that rejects the promise. - * @param {object} response The response. - * - * @returns {object} The response. - */ -function settle(resolve, reject, response) { - const validateStatus = response.config.validateStatus; - if (!response.status || !validateStatus || validateStatus(response.status)) { - resolve(response); - } else { - reject(new AxiosError( - 'Request failed with status code ' + response.status, - [AxiosError.ERR_BAD_REQUEST, AxiosError.ERR_BAD_RESPONSE][Math.floor(response.status / 100) - 4], - response.config, - response.request, - response - )); - } -} - -function parseProtocol(url) { - const match = /^([-+\w]{1,25})(:?\/\/|:)/.exec(url); - return match && match[1] || ''; -} - -/** - * Calculate data maxRate - * @param {Number} [samplesCount= 10] - * @param {Number} [min= 1000] - * @returns {Function} - */ -function speedometer(samplesCount, min) { - samplesCount = samplesCount || 10; - const bytes = new Array(samplesCount); - const timestamps = new Array(samplesCount); - let head = 0; - let tail = 0; - let firstSampleTS; - - min = min !== undefined ? min : 1000; - - return function push(chunkLength) { - const now = Date.now(); - - const startedAt = timestamps[tail]; - - if (!firstSampleTS) { - firstSampleTS = now; - } - - bytes[head] = chunkLength; - timestamps[head] = now; - - let i = tail; - let bytesCount = 0; - - while (i !== head) { - bytesCount += bytes[i++]; - i = i % samplesCount; - } - - head = (head + 1) % samplesCount; - - if (head === tail) { - tail = (tail + 1) % samplesCount; - } - - if (now - firstSampleTS < min) { - return; - } - - const passed = startedAt && now - startedAt; - - return passed ? Math.round(bytesCount * 1000 / passed) : undefined; - }; -} - -/** - * Throttle decorator - * @param {Function} fn - * @param {Number} freq - * @return {Function} - */ -function throttle(fn, freq) { - let timestamp = 0; - let threshold = 1000 / freq; - let lastArgs; - let timer; - - const invoke = (args, now = Date.now()) => { - timestamp = now; - lastArgs = null; - if (timer) { - clearTimeout(timer); - timer = null; - } - fn.apply(null, args); - }; - - const throttled = (...args) => { - const now = Date.now(); - const passed = now - timestamp; - if ( passed >= threshold) { - invoke(args, now); - } else { - lastArgs = args; - if (!timer) { - timer = setTimeout(() => { - timer = null; - invoke(lastArgs); - }, threshold - passed); - } - } - }; - - const flush = () => lastArgs && invoke(lastArgs); - - return [throttled, flush]; -} - -const progressEventReducer = (listener, isDownloadStream, freq = 3) => { - let bytesNotified = 0; - const _speedometer = speedometer(50, 250); - - return throttle(e => { - const loaded = e.loaded; - const total = e.lengthComputable ? e.total : undefined; - const progressBytes = loaded - bytesNotified; - const rate = _speedometer(progressBytes); - const inRange = loaded <= total; - - bytesNotified = loaded; - - const data = { - loaded, - total, - progress: total ? (loaded / total) : undefined, - bytes: progressBytes, - rate: rate ? rate : undefined, - estimated: rate && total && inRange ? (total - loaded) / rate : undefined, - event: e, - lengthComputable: total != null, - [isDownloadStream ? 'download' : 'upload']: true - }; + table.formulaDiscriminators = function() { + for (var i = 0; i < arguments.length; i++) { + table._formulaDiscriminators.push(arguments[i]); + } + return table; + }; - listener(data); - }, freq); -}; - -const progressEventDecorator = (total, throttled) => { - const lengthComputable = total != null; - - return [(loaded) => throttled[0]({ - lengthComputable, - total, - loaded - }), throttled[1]]; -}; - -const asyncDecorator = (fn) => (...args) => utils$1.asap(() => fn(...args)); - -var isURLSameOrigin = platform.hasStandardBrowserEnv ? - -// Standard browser envs have full support of the APIs needed to test -// whether the request URL is of the same origin as current location. - (function standardBrowserEnv() { - const msie = platform.navigator && /(msie|trident)/i.test(platform.navigator.userAgent); - const urlParsingNode = document.createElement('a'); - let originURL; - - /** - * Parse a URL to discover its components - * - * @param {String} url The URL to be parsed - * @returns {Object} - */ - function resolveURL(url) { - let href = url; - - if (msie) { - // IE needs attribute set twice to normalize properties - urlParsingNode.setAttribute('href', href); - href = urlParsingNode.href; - } - - urlParsingNode.setAttribute('href', href); - - // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils - return { - href: urlParsingNode.href, - protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '', - host: urlParsingNode.host, - search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '', - hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '', - hostname: urlParsingNode.hostname, - port: urlParsingNode.port, - pathname: (urlParsingNode.pathname.charAt(0) === '/') ? - urlParsingNode.pathname : - '/' + urlParsingNode.pathname - }; - } - - originURL = resolveURL(window.location.href); - - /** - * Determine if a URL shares the same origin as the current location - * - * @param {String} requestURL The URL to test - * @returns {boolean} True if URL shares the same origin, otherwise false - */ - return function isURLSameOrigin(requestURL) { - const parsed = (utils$1.isString(requestURL)) ? resolveURL(requestURL) : requestURL; - return (parsed.protocol === originURL.protocol && - parsed.host === originURL.host); - }; - })() : + table.insert = function(context, ...rest) { + const concurrency = undefined; + let args = [context, {table, concurrency}, ...rest]; + return insert.apply(null, args); + }; - // Non standard browser envs (web workers, react-native) lack needed support. - (function nonStandardBrowserEnv() { - return function isURLSameOrigin() { - return true; - }; - })(); - -var cookies = platform.hasStandardBrowserEnv ? - - // Standard browser envs support document.cookie - { - write(name, value, expires, path, domain, secure) { - const cookie = [name + '=' + encodeURIComponent(value)]; - - utils$1.isNumber(expires) && cookie.push('expires=' + new Date(expires).toGMTString()); - - utils$1.isString(path) && cookie.push('path=' + path); - - utils$1.isString(domain) && cookie.push('domain=' + domain); - - secure === true && cookie.push('secure'); - - document.cookie = cookie.join('; '); - }, - - read(name) { - const match = document.cookie.match(new RegExp('(^|;\\s*)(' + name + ')=([^;]*)')); - return (match ? decodeURIComponent(match[3]) : null); - }, - - remove(name) { - this.write(name, '', Date.now() - 86400000); - } - } - - : - - // Non-standard browser env (web workers, react-native) lack needed support. - { - write() {}, - read() { - return null; - }, - remove() {} - }; - -/** - * Determines whether the specified URL is absolute - * - * @param {string} url The URL to test - * - * @returns {boolean} True if the specified URL is absolute, otherwise false - */ -function isAbsoluteURL(url) { - // A URL is considered absolute if it begins with "://" or "//" (protocol-relative URL). - // RFC 3986 defines scheme name as a sequence of characters beginning with a letter and followed - // by any combination of letters, digits, plus, period, or hyphen. - return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url); -} - -/** - * Creates a new URL by combining the specified URLs - * - * @param {string} baseURL The base URL - * @param {string} relativeURL The relative URL - * - * @returns {string} The combined URL - */ -function combineURLs(baseURL, relativeURL) { - return relativeURL - ? baseURL.replace(/\/?\/$/, '') + '/' + relativeURL.replace(/^\/+/, '') - : baseURL; -} - -/** - * Creates a new URL by combining the baseURL with the requestedURL, - * only when the requestedURL is not already an absolute URL. - * If the requestURL is absolute, this function returns the requestedURL untouched. - * - * @param {string} baseURL The base URL - * @param {string} requestedURL Absolute or relative URL to combine - * - * @returns {string} The combined full path - */ -function buildFullPath(baseURL, requestedURL) { - if (baseURL && !isAbsoluteURL(requestedURL)) { - return combineURLs(baseURL, requestedURL); - } - return requestedURL; -} - -const headersToObject = (thing) => thing instanceof AxiosHeaders$1 ? { ...thing } : thing; - -/** - * Config-specific merge-function which creates a new config-object - * by merging two configuration objects together. - * - * @param {Object} config1 - * @param {Object} config2 - * - * @returns {Object} New object resulting from merging config2 to config1 - */ -function mergeConfig(config1, config2) { - // eslint-disable-next-line no-param-reassign - config2 = config2 || {}; - const config = {}; - - function getMergedValue(target, source, caseless) { - if (utils$1.isPlainObject(target) && utils$1.isPlainObject(source)) { - return utils$1.merge.call({caseless}, target, source); - } else if (utils$1.isPlainObject(source)) { - return utils$1.merge({}, source); - } else if (utils$1.isArray(source)) { - return source.slice(); - } - return source; - } - - // eslint-disable-next-line consistent-return - function mergeDeepProperties(a, b, caseless) { - if (!utils$1.isUndefined(b)) { - return getMergedValue(a, b, caseless); - } else if (!utils$1.isUndefined(a)) { - return getMergedValue(undefined, a, caseless); - } - } - - // eslint-disable-next-line consistent-return - function valueFromConfig2(a, b) { - if (!utils$1.isUndefined(b)) { - return getMergedValue(undefined, b); - } - } - - // eslint-disable-next-line consistent-return - function defaultToConfig2(a, b) { - if (!utils$1.isUndefined(b)) { - return getMergedValue(undefined, b); - } else if (!utils$1.isUndefined(a)) { - return getMergedValue(undefined, a); - } - } - - // eslint-disable-next-line consistent-return - function mergeDirectKeys(a, b, prop) { - if (prop in config2) { - return getMergedValue(a, b); - } else if (prop in config1) { - return getMergedValue(undefined, a); - } - } - - const mergeMap = { - url: valueFromConfig2, - method: valueFromConfig2, - data: valueFromConfig2, - baseURL: defaultToConfig2, - transformRequest: defaultToConfig2, - transformResponse: defaultToConfig2, - paramsSerializer: defaultToConfig2, - timeout: defaultToConfig2, - timeoutMessage: defaultToConfig2, - withCredentials: defaultToConfig2, - withXSRFToken: defaultToConfig2, - adapter: defaultToConfig2, - responseType: defaultToConfig2, - xsrfCookieName: defaultToConfig2, - xsrfHeaderName: defaultToConfig2, - onUploadProgress: defaultToConfig2, - onDownloadProgress: defaultToConfig2, - decompress: defaultToConfig2, - maxContentLength: defaultToConfig2, - maxBodyLength: defaultToConfig2, - beforeRedirect: defaultToConfig2, - transport: defaultToConfig2, - httpAgent: defaultToConfig2, - httpsAgent: defaultToConfig2, - cancelToken: defaultToConfig2, - socketPath: defaultToConfig2, - responseEncoding: defaultToConfig2, - validateStatus: mergeDirectKeys, - headers: (a, b) => mergeDeepProperties(headersToObject(a), headersToObject(b), true) - }; - - utils$1.forEach(Object.keys(Object.assign({}, config1, config2)), function computeConfigValue(prop) { - const merge = mergeMap[prop] || mergeDeepProperties; - const configValue = merge(config1[prop], config2[prop], prop); - (utils$1.isUndefined(configValue) && merge !== mergeDirectKeys) || (config[prop] = configValue); - }); - - return config; -} - -var resolveConfig = (config) => { - const newConfig = mergeConfig({}, config); - - let {data, withXSRFToken, xsrfHeaderName, xsrfCookieName, headers, auth} = newConfig; - - newConfig.headers = headers = AxiosHeaders$1.from(headers); - - newConfig.url = buildURL(buildFullPath(newConfig.baseURL, newConfig.url), config.params, config.paramsSerializer); - - // HTTP basic authentication - if (auth) { - headers.set('Authorization', 'Basic ' + - btoa((auth.username || '') + ':' + (auth.password ? unescape(encodeURIComponent(auth.password)) : '')) - ); - } - - let contentType; - - if (utils$1.isFormData(data)) { - if (platform.hasStandardBrowserEnv || platform.hasStandardBrowserWebWorkerEnv) { - headers.setContentType(undefined); // Let the browser set it - } else if ((contentType = headers.getContentType()) !== false) { - // fix semicolon duplication issue for ReactNative FormData implementation - const [type, ...tokens] = contentType ? contentType.split(';').map(token => token.trim()).filter(Boolean) : []; - headers.setContentType([type || 'multipart/form-data', ...tokens].join('; ')); - } - } - - // Add xsrf header - // This is only done if running in a standard browser environment. - // Specifically not if we're in a web worker, or react-native. - - if (platform.hasStandardBrowserEnv) { - withXSRFToken && utils$1.isFunction(withXSRFToken) && (withXSRFToken = withXSRFToken(newConfig)); - - if (withXSRFToken || (withXSRFToken !== false && isURLSameOrigin(newConfig.url))) { - // Add xsrf header - const xsrfValue = xsrfHeaderName && xsrfCookieName && cookies.read(xsrfCookieName); - - if (xsrfValue) { - headers.set(xsrfHeaderName, xsrfValue); - } - } - } - - return newConfig; -}; - -const isXHRAdapterSupported = typeof XMLHttpRequest !== 'undefined'; - -var xhrAdapter = isXHRAdapterSupported && function (config) { - return new Promise(function dispatchXhrRequest(resolve, reject) { - const _config = resolveConfig(config); - let requestData = _config.data; - const requestHeaders = AxiosHeaders$1.from(_config.headers).normalize(); - let {responseType, onUploadProgress, onDownloadProgress} = _config; - let onCanceled; - let uploadThrottled, downloadThrottled; - let flushUpload, flushDownload; - - function done() { - flushUpload && flushUpload(); // flush events - flushDownload && flushDownload(); // flush events - - _config.cancelToken && _config.cancelToken.unsubscribe(onCanceled); - - _config.signal && _config.signal.removeEventListener('abort', onCanceled); - } - - let request = new XMLHttpRequest(); - - request.open(_config.method.toUpperCase(), _config.url, true); - - // Set the request timeout in MS - request.timeout = _config.timeout; - - function onloadend() { - if (!request) { - return; - } - // Prepare the response - const responseHeaders = AxiosHeaders$1.from( - 'getAllResponseHeaders' in request && request.getAllResponseHeaders() - ); - const responseData = !responseType || responseType === 'text' || responseType === 'json' ? - request.responseText : request.response; - const response = { - data: responseData, - status: request.status, - statusText: request.statusText, - headers: responseHeaders, - config, - request - }; - - settle(function _resolve(value) { - resolve(value); - done(); - }, function _reject(err) { - reject(err); - done(); - }, response); - - // Clean up request - request = null; - } - - if ('onloadend' in request) { - // Use onloadend if available - request.onloadend = onloadend; - } else { - // Listen for ready state to emulate onloadend - request.onreadystatechange = function handleLoad() { - if (!request || request.readyState !== 4) { - return; - } - - // The request errored out and we didn't get a response, this will be - // handled by onerror instead - // With one exception: request that using file: protocol, most browsers - // will return status as 0 even though it's a successful request - if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) { - return; - } - // readystate handler is calling before onerror or ontimeout handlers, - // so we should call onloadend on the next 'tick' - setTimeout(onloadend); - }; - } - - // Handle browser request cancellation (as opposed to a manual cancellation) - request.onabort = function handleAbort() { - if (!request) { - return; - } - - reject(new AxiosError('Request aborted', AxiosError.ECONNABORTED, config, request)); - - // Clean up request - request = null; - }; + table.insertWithConcurrency = function(context, options, ...rows) { + let args = [context, {table, options}].concat([].slice.call(rows)); + return insert.apply(null, args); + }; + + table.delete = _delete.bind(null, table); + table.cascadeDelete = function(context, ...rest) { + const args = [context, table, ...rest]; + return cascadeDelete.apply(null, args); + }; + + table.deleteCascade = table.cascadeDelete; + table.exclusive = function() { + table._exclusive = true; + return table; + }; + table.patch = function(context, ...rest) { + const args = [context, table, ...rest]; + return patchTable.apply(null, args); + }; + + // table.subscribeChanged = table._emitChanged.add; //legacy + // table.unsubscribeChanged = table._emitChanged.remove; //legacy + + table.hostLocal = function(options) { + return hostLocal({table, ...options}); + }; + + // table.ts = function(name) { //unused ? + // return getTSDefinition(table, {name}); + // }; + + table.where = where(table); + table._aggregate = aggregate(table); + + return table; + } + + table = _new; + return table; +} + +var createProviders_1; +var hasRequiredCreateProviders; + +function requireCreateProviders () { + if (hasRequiredCreateProviders) return createProviders_1; + hasRequiredCreateProviders = 1; + const connectionCache = new WeakMap(); + + + function createProviders(index) { + + function dbMap(fn) { + fn = new Proxy(fn, {}); + return (() => negotiateCachedPool(fn, dbMap)); + } + + Object.defineProperty(dbMap, 'pg', { + get: function() { + return createPool.bind(null, 'pg'); + } + }); + Object.defineProperty(dbMap, 'postgres', { + get: function() { + return createPool.bind(null, 'pg'); + } + }); + Object.defineProperty(dbMap, 'mssql', { + get: function() { + return createPool.bind(null, 'mssql'); + } + }); + Object.defineProperty(dbMap, 'mssqlNative', { + get: function() { + return createPool.bind(null, 'mssqlNative'); + } + }); + Object.defineProperty(dbMap, 'mysql', { + get: function() { + return createPool.bind(null, 'mysql'); + } + }); + Object.defineProperty(dbMap, 'sap', { + get: function() { + return createPool.bind(null, 'sap'); + } + }); + Object.defineProperty(dbMap, 'oracle', { + get: function() { + return createPool.bind(null, 'oracle'); + } + }); + Object.defineProperty(dbMap, 'sqlite', { + get: function() { + return createPool.bind(null, 'sqlite'); + } + }); + Object.defineProperty(dbMap, 'd1', { + get: function() { + return createPool.bind(null, 'd1'); + } + }); + Object.defineProperty(dbMap, 'http', { + get: function() { + return createPool.bind(null, 'http'); + } + }); + + dbMap.express = index.express; + + function createPool(providerName, ...args) { + const provider = index[providerName]; + return provider.apply(null, args); + } + + return dbMap; + + } + + function negotiateCachedPool(fn, providers) { + let cache = connectionCache.get(fn); + if (!cache) { + cache = {}; + connectionCache.set(fn, cache); + } + + const dbMap = { + get pg() { + return createPool.bind(null, 'pg'); + }, + get postgres() { + return createPool.bind(null, 'pg'); + }, + get mssql() { + return createPool.bind(null, 'mssql'); + }, + get mssqlNative() { + return createPool.bind(null, 'mssqlNative'); + }, + get mysql() { + return createPool.bind(null, 'mysql'); + }, + get sap() { + return createPool.bind(null, 'sap'); + }, + get oracle() { + return createPool.bind(null, 'oracle'); + }, + get sqlite() { + return createPool.bind(null, 'sqlite'); + }, + get d1() { + return createPool.bind(null, 'd1'); + }, + get http() { + return createPool.bind(null, 'http'); + } + }; + + function createPool(providerName, ...args) { + //todo + if (providerName === 'd1') { + return providers[providerName].apply(null, args); + } + const key = JSON.stringify(args); + if (!cache[providerName]) + cache[providerName] = {}; + let pool = cache[providerName][key]; + if (!pool) { + pool = providers[providerName].apply(null, args); + cache[providerName][key] = pool; + } + return pool; + } + return fn(dbMap); + } + + + + createProviders_1 = createProviders; + return createProviders_1; +} + +var map_1; +var hasRequiredMap; + +function requireMap () { + if (hasRequiredMap) return map_1; + hasRequiredMap = 1; + const _newTable = requireTable(); + const createProviders = requireCreateProviders(); + + function mapRoot(index, fn) { + + const providers = createProviders(index); + + return map(index, context, providers, fn); + + function context(arg) { + + const tables = {}; + for (let name in context) { + if (context[name] && context[name]._dbName) + tables[name] = context[name]; + } + + if (arg && arg.db && typeof arg.db === 'function') { + return index({ + ...arg, + db: providers(arg.db), + tables, providers + }); + } + else + return index({ + ...arg, tables, providers + }); + } + } + + + function map(index, context, providers, fn) { + let next = fn({ table: newTable, ...context }); + + for (let name in next) { + if (next[name] && next[name]._dbName) { + context[name] = next[name]; + context[name].map = mapTable.bind(null, context[name]); + } + } + context.map = map.bind(null, index, context, providers); + context.pg = connect.bind(null, 'pg'); + context.postgres = connect.bind(null, 'pg'); + context.mssql = connect.bind(null, 'mssql'); + context.mssqlNative = connect.bind(null, 'mssqlNative'); + context.mysql = connect.bind(null, 'mysql'); + context.sap = connect.bind(null, 'sap'); + context.oracle = connect.bind(null, 'oracle'); + context.sqlite = connect.bind(null, 'sqlite'); + context.d1 = connect.bind(null, 'd1'); + context.http = function(url) { + return index({ db: url, providers}); + }; + + function connect(name, ...args) { + const provider = index[name]; + const pool = provider.apply(null, args); + + const tables = {}; + for (let name in context) { + if (context[name] && context[name]._dbName) + tables[name] = context[name]; + } + + return index({ db: pool, tables, providers }); + } + + return context; + + function newTable() { + let table = _newTable.apply(null, arguments); + table.map = mapTable.bind(null, table); + return table; + } + } + + function mapTable(table, fn) { + let next = fn({ column: table.column, primaryColumn: table.primaryColumn, references: table.join, hasMany, hasOne }); + for (let name in next) { + if (next[name].as) + next[name] = next[name].as(name); + } + + function hasMany(to) { + if (!to) + throw new Error('Missing \'to\' table'); + return { by }; + + function by() { + const join = to.join(table).by.apply(null, arguments); + return table.hasMany(join); + } + } + + function hasOne(to) { + if (!to) + throw new Error('Missing \'to\' table'); + return { by }; + + function by() { + const join = to.join(table).by.apply(null, arguments); + return table.hasOne(join); + } + } + + return table; + + } + + map_1 = mapRoot; + return map_1; +} + +var commitCommand; +var hasRequiredCommitCommand; + +function requireCommitCommand () { + if (hasRequiredCommitCommand) return commitCommand; + hasRequiredCommitCommand = 1; + var newParameterized = requireNewParameterized(); + + var command = newParameterized('COMMIT'); + function empty() {} + + command.endEdit = empty; + command.matches = empty; + + commitCommand = command; + return commitCommand; +} + +var deleteSessionContext_1; +var hasRequiredDeleteSessionContext; + +function requireDeleteSessionContext () { + if (hasRequiredDeleteSessionContext) return deleteSessionContext_1; + hasRequiredDeleteSessionContext = 1; + function deleteSessionContext(context) { + delete context.rdb; + } + + deleteSessionContext_1 = deleteSessionContext; + return deleteSessionContext_1; +} + +var releaseDbClient; +var hasRequiredReleaseDbClient; + +function requireReleaseDbClient () { + if (hasRequiredReleaseDbClient) return releaseDbClient; + hasRequiredReleaseDbClient = 1; + var getSessionSingleton = requireGetSessionSingleton(); + var deleteSessionContext = requireDeleteSessionContext(); + + function release(context) { + var done = getSessionSingleton(context, 'dbClientDone'); + var pool = getSessionSingleton(context, 'pool'); + deleteSessionContext(context); + if (done) + done(); + if (pool) + return pool.end(); + + } + + releaseDbClient = release; + return releaseDbClient; +} + +var commit_1; +var hasRequiredCommit; + +function requireCommit () { + if (hasRequiredCommit) return commit_1; + hasRequiredCommit = 1; + let commitCommand = requireCommitCommand(); + let pushCommand = requirePushCommand(); + let executeChanges = requireExecuteChanges(); + let releaseDbClient = requireReleaseDbClient(); + let popChanges = requirePopChanges(); + const getSessionSingleton = requireGetSessionSingleton(); + + function _commit(context, result) { + return popAndPushChanges() + .then(releaseDbClient.bind(null, context)) + .then(onReleased); + + function onReleased() { + return result; + } + + async function popAndPushChanges() { + let changes = popChanges(context); + while (changes.length > 0) { + await executeChanges(context, changes); + changes = popChanges(context); + } + if (!getSessionSingleton(context, 'transactionLess')) + pushCommand(context, commitCommand); + return executeChanges(context, popChanges(context)); + } + } + + function commit(context, result) { + return Promise.resolve() + .then(() => _commit(context, result)); + } + + commit_1 = commit; + return commit_1; +} + +var rollbackCommand; +var hasRequiredRollbackCommand; + +function requireRollbackCommand () { + if (hasRequiredRollbackCommand) return rollbackCommand; + hasRequiredRollbackCommand = 1; + var newParameterized = requireNewParameterized(); + + var command = newParameterized('ROLLBACK'); + function empty() {} + + // @ts-ignore + command.endEdit = empty; + // @ts-ignore + command.matches = empty; + + rollbackCommand = command; + return rollbackCommand; +} + +var tryReleaseDbClient_1; +var hasRequiredTryReleaseDbClient; + +function requireTryReleaseDbClient () { + if (hasRequiredTryReleaseDbClient) return tryReleaseDbClient_1; + hasRequiredTryReleaseDbClient = 1; + var release = requireReleaseDbClient(); + + function tryReleaseDbClient(context) { + try { + release(context); + } + // eslint-disable-next-line no-empty + catch (e) { + + } + + } + + tryReleaseDbClient_1 = tryReleaseDbClient; + return tryReleaseDbClient_1; +} + +var newThrow_1; +var hasRequiredNewThrow; + +function requireNewThrow () { + if (hasRequiredNewThrow) return newThrow_1; + hasRequiredNewThrow = 1; + var tryReleaseDbClient = requireTryReleaseDbClient(); + + function newThrow(context, e, previousPromise) { + return previousPromise.then(throwError, throwError); + function throwError() { + tryReleaseDbClient(context); + throw e; + } + } + + newThrow_1 = newThrow; + return newThrow_1; +} + +var rollback_1; +var hasRequiredRollback; + +function requireRollback () { + if (hasRequiredRollback) return rollback_1; + hasRequiredRollback = 1; + const rollbackCommand = requireRollbackCommand(); + const executeQuery = requireExecuteQuery(); + const releaseDbClient = requireReleaseDbClient(); + const popChanges = requirePopChanges(); + const newThrow = requireNewThrow(); + const resultToPromise = requireResultToPromise(); + const conflictId = '12345678-1234-1234-1234-123456789012'; + const getSessionSingleton = requireGetSessionSingleton(); + + function _rollback(context, e) { + var chain = resultToPromise() + .then(() => popChanges(context)) + .then(executeRollback) + .then(() => releaseDbClient(context)); + + + function executeRollback() { + const transactionLess = getSessionSingleton(context, 'transactionLess'); + if (transactionLess) + return Promise.resolve(); + return executeQuery(context, rollbackCommand); + } + + if (e) { + if (e.message?.indexOf('ORA-01476: divisor is equal to zero') > -1) + return newThrow(context, new Error('Conflict when updating a column'), chain); + let errors = e.message && e.message.split(conflictId) || []; + if (errors.length > 1) { + return newThrow(context, new Error(errors[1]), chain); + } + else + return newThrow(context, e, chain); + } + return chain; + } + + function rollback(context, e) { + return Promise.resolve().then(() => _rollback(context, e)); + } + + rollback_1 = rollback; + return rollback_1; +} + +var pools_1; +var hasRequiredPools; + +function requirePools () { + if (hasRequiredPools) return pools_1; + hasRequiredPools = 1; + var pools = requireNewObject()(); + + Object.defineProperty(pools, 'end', { + enumerable: false, + value: end + }); + + function end() { + var all = []; + for (var poolId in pools) { + var endPool = pools[poolId].end(); + all.push(endPool); + } + return Promise.all(all); + } + + pools_1 = pools; + return pools_1; +} + +var log_1; +var hasRequiredLog; + +function requireLog () { + if (hasRequiredLog) return log_1; + hasRequiredLog = 1; + var newEmitEvent = requireEmitEvent(); + + var emitters = { + query: newEmitEvent() + }; + + var logger = function() { + }; + + function log() { + logger.apply(null, arguments); + } + function emitQuery({ sql, parameters }) { + emitters.query.apply(null, arguments); + log(sql); + log('parameters: ' + parameters); + } + + log.emitQuery = emitQuery; + + log.registerLogger = function(cb) { + logger = cb; + }; + + log.on = function(type, cb) { + if (type === 'query') + emitters.query.add(cb); + else + throw new Error('unknown event type: ' + type); + }; + + log.off = function(type, cb) { + if (type === 'query') + emitters.query.tryRemove(cb); + else + throw new Error('unknown event type: ' + type); + }; + + log_1 = log; + return log_1; +} + +var toIntKey_1; +var hasRequiredToIntKey; + +function requireToIntKey () { + if (hasRequiredToIntKey) return toIntKey_1; + hasRequiredToIntKey = 1; + function toIntKey(key) { + if (isInteger()) + return key; + if (isIntegerString()) + return trim(key); + var intKey = ''; + for (var i = 0; i < key.length; ++i) { + var value = key[i].toUpperCase(); + value = parseInt(value, 16); + if (!isNaN(value)) + intKey += value; + } + + return trim(intKey); + + function isIntegerString() { + var pattern = /^-?\d+\.?\d*$/; + var reg = new RegExp(pattern); + return (typeof key === 'string' && reg.test(key)); + } + + function isInteger() { + return (typeof key === 'number') && (Math.floor(key) === key); + } + + function trim(value) { + var maxBigInt = '9223372036854775807'; + value = value.substring(0, 19); + if (value > maxBigInt) + return value.substring(0,18); + return value; + } + } + + toIntKey_1 = toIntKey; + return toIntKey_1; +} + +var lock_1; +var hasRequiredLock; + +function requireLock () { + if (hasRequiredLock) return lock_1; + hasRequiredLock = 1; + var query = requireQuery(); + var toIntKey = requireToIntKey(); + + function lock(key, func) { + key = toIntKey(key); + if(typeof func === 'function') { + return inLock(key, func); + } else { + var sql = 'SELECT pg_advisory_xact_lock(' + key + ')'; + return query(sql); + } + } + + async function inLock(key, func) { + await query('SELECT pg_advisory_lock(' + key + ')'); + try { + let result = await func(); + await query('SELECT pg_advisory_unlock(' + key + ')'); + return result; + } catch(e) { + await query('SELECT pg_advisory_unlock(' + key + ')'); + throw e; + } + } + + lock_1 = lock; + return lock_1; +} + +var schema; +var hasRequiredSchema; - // Handle low level network errors - request.onerror = function handleError() { - // Real errors are hidden from us by the browser - // onerror should only fire if it's a network error - reject(new AxiosError('Network Error', AxiosError.ERR_NETWORK, config, request)); +function requireSchema () { + if (hasRequiredSchema) return schema; + hasRequiredSchema = 1; + var query = requireQuery(); - // Clean up request - request = null; - }; + function executeSchema(context, schema) { + if (!schema) + throw new Error('Missing schema'); + if (!Array.isArray(schema)) + schema = [schema]; + return query(context, 'SET LOCAL search_path TO ' + schema.join(',')); + } - // Handle timeout - request.ontimeout = function handleTimeout() { - let timeoutErrorMessage = _config.timeout ? 'timeout of ' + _config.timeout + 'ms exceeded' : 'timeout exceeded'; - const transitional = _config.transitional || transitionalDefaults; - if (_config.timeoutErrorMessage) { - timeoutErrorMessage = _config.timeoutErrorMessage; - } - reject(new AxiosError( - timeoutErrorMessage, - transitional.clarifyTimeoutError ? AxiosError.ETIMEDOUT : AxiosError.ECONNABORTED, - config, - request)); - - // Clean up request - request = null; - }; + schema = executeSchema; + return schema; +} - // Remove Content-Type if data is undefined - requestData === undefined && requestHeaders.setContentType(null); - - // Add headers to the request - if ('setRequestHeader' in request) { - utils$1.forEach(requestHeaders.toJSON(), function setRequestHeader(val, key) { - request.setRequestHeader(key, val); - }); - } - - // Add withCredentials to request if needed - if (!utils$1.isUndefined(_config.withCredentials)) { - request.withCredentials = !!_config.withCredentials; - } - - // Add responseType to request if needed - if (responseType && responseType !== 'json') { - request.responseType = _config.responseType; - } - - // Handle progress if needed - if (onDownloadProgress) { - ([downloadThrottled, flushDownload] = progressEventReducer(onDownloadProgress, true)); - request.addEventListener('progress', downloadThrottled); - } - - // Not all browsers support upload events - if (onUploadProgress && request.upload) { - ([uploadThrottled, flushUpload] = progressEventReducer(onUploadProgress)); - - request.upload.addEventListener('progress', uploadThrottled); - - request.upload.addEventListener('loadend', flushUpload); - } - - if (_config.cancelToken || _config.signal) { - // Handle cancellation - // eslint-disable-next-line func-names - onCanceled = cancel => { - if (!request) { - return; - } - reject(!cancel || cancel.type ? new CanceledError(null, config, request) : cancel); - request.abort(); - request = null; - }; - - _config.cancelToken && _config.cancelToken.subscribe(onCanceled); - if (_config.signal) { - _config.signal.aborted ? onCanceled() : _config.signal.addEventListener('abort', onCanceled); - } - } - - const protocol = parseProtocol(_config.url); - - if (protocol && platform.protocols.indexOf(protocol) === -1) { - reject(new AxiosError('Unsupported protocol ' + protocol + ':', AxiosError.ERR_BAD_REQUEST, config)); - return; - } - - - // Send the request - request.send(requestData || null); - }); -}; - -const composeSignals = (signals, timeout) => { - const {length} = (signals = signals ? signals.filter(Boolean) : []); - - if (timeout || length) { - let controller = new AbortController(); - - let aborted; - - const onabort = function (reason) { - if (!aborted) { - aborted = true; - unsubscribe(); - const err = reason instanceof Error ? reason : this.reason; - controller.abort(err instanceof AxiosError ? err : new CanceledError(err instanceof Error ? err.message : err)); - } - }; +var createDomain_1; +var hasRequiredCreateDomain; - let timer = timeout && setTimeout(() => { - timer = null; - onabort(new AxiosError(`timeout ${timeout} of ms exceeded`, AxiosError.ETIMEDOUT)); - }, timeout); - - const unsubscribe = () => { - if (signals) { - timer && clearTimeout(timer); - timer = null; - signals.forEach(signal => { - signal.unsubscribe ? signal.unsubscribe(onabort) : signal.removeEventListener('abort', onabort); - }); - signals = null; - } - }; +function requireCreateDomain () { + if (hasRequiredCreateDomain) return createDomain_1; + hasRequiredCreateDomain = 1; + function createDomain() { + let c = {}; + function run(fn) { + return fn(c); + } + c.run = run; + return c; + } - signals.forEach((signal) => signal.addEventListener('abort', onabort)); - - const {signal} = controller; - - signal.unsubscribe = () => utils$1.asap(unsubscribe); - - return signal; - } -}; - -var composeSignals$1 = composeSignals; - -const streamChunk = function* (chunk, chunkSize) { - let len = chunk.byteLength; - - if (!chunkSize || len < chunkSize) { - yield chunk; - return; - } - - let pos = 0; - let end; - - while (pos < len) { - end = pos + chunkSize; - yield chunk.slice(pos, end); - pos = end; - } -}; - -const readBytes = async function* (iterable, chunkSize) { - for await (const chunk of readStream(iterable)) { - yield* streamChunk(chunk, chunkSize); - } -}; - -const readStream = async function* (stream) { - if (stream[Symbol.asyncIterator]) { - yield* stream; - return; - } - - const reader = stream.getReader(); - try { - for (;;) { - const {done, value} = await reader.read(); - if (done) { - break; - } - yield value; - } - } finally { - await reader.cancel(); - } -}; - -const trackStream = (stream, chunkSize, onProgress, onFinish) => { - const iterator = readBytes(stream, chunkSize); - - let bytes = 0; - let done; - let _onFinish = (e) => { - if (!done) { - done = true; - onFinish && onFinish(e); - } - }; - - return new ReadableStream({ - async pull(controller) { - try { - const {done, value} = await iterator.next(); - - if (done) { - _onFinish(); - controller.close(); - return; - } - - let len = value.byteLength; - if (onProgress) { - let loadedBytes = bytes += len; - onProgress(loadedBytes); - } - controller.enqueue(new Uint8Array(value)); - } catch (err) { - _onFinish(err); - throw err; - } - }, - cancel(reason) { - _onFinish(reason); - return iterator.return(); - } - }, { - highWaterMark: 2 - }) -}; - -const isFetchSupported = typeof fetch === 'function' && typeof Request === 'function' && typeof Response === 'function'; -const isReadableStreamSupported = isFetchSupported && typeof ReadableStream === 'function'; - -// used only inside the fetch adapter -const encodeText = isFetchSupported && (typeof TextEncoder === 'function' ? - ((encoder) => (str) => encoder.encode(str))(new TextEncoder()) : - async (str) => new Uint8Array(await new Response(str).arrayBuffer()) -); - -const test = (fn, ...args) => { - try { - return !!fn(...args); - } catch (e) { - return false - } -}; - -const supportsRequestStream = isReadableStreamSupported && test(() => { - let duplexAccessed = false; - - const hasContentType = new Request(platform.origin, { - body: new ReadableStream(), - method: 'POST', - get duplex() { - duplexAccessed = true; - return 'half'; - }, - }).headers.has('Content-Type'); - - return duplexAccessed && !hasContentType; -}); - -const DEFAULT_CHUNK_SIZE = 64 * 1024; - -const supportsResponseStream = isReadableStreamSupported && - test(() => utils$1.isReadableStream(new Response('').body)); - - -const resolvers = { - stream: supportsResponseStream && ((res) => res.body) -}; - -isFetchSupported && (((res) => { - ['text', 'arrayBuffer', 'blob', 'formData', 'stream'].forEach(type => { - !resolvers[type] && (resolvers[type] = utils$1.isFunction(res[type]) ? (res) => res[type]() : - (_, config) => { - throw new AxiosError(`Response type '${type}' is not supported`, AxiosError.ERR_NOT_SUPPORT, config); - }); - }); -})(new Response)); - -const getBodyLength = async (body) => { - if (body == null) { - return 0; - } - - if(utils$1.isBlob(body)) { - return body.size; - } - - if(utils$1.isSpecCompliantForm(body)) { - const _request = new Request(platform.origin, { - method: 'POST', - body, - }); - return (await _request.arrayBuffer()).byteLength; - } - - if(utils$1.isArrayBufferView(body) || utils$1.isArrayBuffer(body)) { - return body.byteLength; - } - - if(utils$1.isURLSearchParams(body)) { - body = body + ''; - } - - if(utils$1.isString(body)) { - return (await encodeText(body)).byteLength; - } -}; - -const resolveBodyLength = async (headers, body) => { - const length = utils$1.toFiniteNumber(headers.getContentLength()); - - return length == null ? getBodyLength(body) : length; -}; - -var fetchAdapter = isFetchSupported && (async (config) => { - let { - url, - method, - data, - signal, - cancelToken, - timeout, - onDownloadProgress, - onUploadProgress, - responseType, - headers, - withCredentials = 'same-origin', - fetchOptions - } = resolveConfig(config); - - responseType = responseType ? (responseType + '').toLowerCase() : 'text'; - - let composedSignal = composeSignals$1([signal, cancelToken && cancelToken.toAbortSignal()], timeout); - - let request; - - const unsubscribe = composedSignal && composedSignal.unsubscribe && (() => { - composedSignal.unsubscribe(); - }); - - let requestContentLength; - - try { - if ( - onUploadProgress && supportsRequestStream && method !== 'get' && method !== 'head' && - (requestContentLength = await resolveBodyLength(headers, data)) !== 0 - ) { - let _request = new Request(url, { - method: 'POST', - body: data, - duplex: "half" - }); - - let contentTypeHeader; - - if (utils$1.isFormData(data) && (contentTypeHeader = _request.headers.get('content-type'))) { - headers.setContentType(contentTypeHeader); - } - - if (_request.body) { - const [onProgress, flush] = progressEventDecorator( - requestContentLength, - progressEventReducer(asyncDecorator(onUploadProgress)) - ); - - data = trackStream(_request.body, DEFAULT_CHUNK_SIZE, onProgress, flush); - } - } - - if (!utils$1.isString(withCredentials)) { - withCredentials = withCredentials ? 'include' : 'omit'; - } - - // Cloudflare Workers throws when credentials are defined - // see https://github.com/cloudflare/workerd/issues/902 - const isCredentialsSupported = "credentials" in Request.prototype; - request = new Request(url, { - ...fetchOptions, - signal: composedSignal, - method: method.toUpperCase(), - headers: headers.normalize().toJSON(), - body: data, - duplex: "half", - credentials: isCredentialsSupported ? withCredentials : undefined - }); - - let response = await fetch(request); - - const isStreamResponse = supportsResponseStream && (responseType === 'stream' || responseType === 'response'); - - if (supportsResponseStream && (onDownloadProgress || (isStreamResponse && unsubscribe))) { - const options = {}; - - ['status', 'statusText', 'headers'].forEach(prop => { - options[prop] = response[prop]; - }); - - const responseContentLength = utils$1.toFiniteNumber(response.headers.get('content-length')); - - const [onProgress, flush] = onDownloadProgress && progressEventDecorator( - responseContentLength, - progressEventReducer(asyncDecorator(onDownloadProgress), true) - ) || []; - - response = new Response( - trackStream(response.body, DEFAULT_CHUNK_SIZE, onProgress, () => { - flush && flush(); - unsubscribe && unsubscribe(); - }), - options - ); - } - - responseType = responseType || 'text'; - - let responseData = await resolvers[utils$1.findKey(resolvers, responseType) || 'text'](response, config); - - !isStreamResponse && unsubscribe && unsubscribe(); - - return await new Promise((resolve, reject) => { - settle(resolve, reject, { - data: responseData, - headers: AxiosHeaders$1.from(response.headers), - status: response.status, - statusText: response.statusText, - config, - request - }); - }) - } catch (err) { - unsubscribe && unsubscribe(); - - if (err && err.name === 'TypeError' && /fetch/i.test(err.message)) { - throw Object.assign( - new AxiosError('Network Error', AxiosError.ERR_NETWORK, config, request), - { - cause: err.cause || err - } - ) - } - - throw AxiosError.from(err, err && err.code, config, request); - } -}); - -const knownAdapters = { - http: httpAdapter$1, - xhr: xhrAdapter, - fetch: fetchAdapter -}; - -utils$1.forEach(knownAdapters, (fn, value) => { - if (fn) { - try { - Object.defineProperty(fn, 'name', {value}); - } catch (e) { - // eslint-disable-next-line no-empty - } - Object.defineProperty(fn, 'adapterName', {value}); - } -}); - -const renderReason = (reason) => `- ${reason}`; - -const isResolvedHandle = (adapter) => utils$1.isFunction(adapter) || adapter === null || adapter === false; - -var adapters = { - getAdapter: (adapters) => { - adapters = utils$1.isArray(adapters) ? adapters : [adapters]; - - const {length} = adapters; - let nameOrAdapter; - let adapter; - - const rejectedReasons = {}; - - for (let i = 0; i < length; i++) { - nameOrAdapter = adapters[i]; - let id; - - adapter = nameOrAdapter; - - if (!isResolvedHandle(nameOrAdapter)) { - adapter = knownAdapters[(id = String(nameOrAdapter)).toLowerCase()]; - - if (adapter === undefined) { - throw new AxiosError(`Unknown adapter '${id}'`); - } - } - - if (adapter) { - break; - } - - rejectedReasons[id || '#' + i] = adapter; - } - - if (!adapter) { - - const reasons = Object.entries(rejectedReasons) - .map(([id, state]) => `adapter ${id} ` + - (state === false ? 'is not supported by the environment' : 'is not available in the build') - ); - - let s = length ? - (reasons.length > 1 ? 'since :\n' + reasons.map(renderReason).join('\n') : ' ' + renderReason(reasons[0])) : - 'as no adapter specified'; - - throw new AxiosError( - `There is no suitable adapter to dispatch the request ` + s, - 'ERR_NOT_SUPPORT' - ); - } - - return adapter; - }, - adapters: knownAdapters -}; - -/** - * Throws a `CanceledError` if cancellation has been requested. - * - * @param {Object} config The config that is to be used for the request - * - * @returns {void} - */ -function throwIfCancellationRequested(config) { - if (config.cancelToken) { - config.cancelToken.throwIfRequested(); - } - - if (config.signal && config.signal.aborted) { - throw new CanceledError(null, config); - } -} - -/** - * Dispatch a request to the server using the configured adapter. - * - * @param {object} config The config that is to be used for the request - * - * @returns {Promise} The Promise to be fulfilled - */ -function dispatchRequest(config) { - throwIfCancellationRequested(config); - - config.headers = AxiosHeaders$1.from(config.headers); - - // Transform request data - config.data = transformData.call( - config, - config.transformRequest - ); - - if (['post', 'put', 'patch'].indexOf(config.method) !== -1) { - config.headers.setContentType('application/x-www-form-urlencoded', false); - } - - const adapter = adapters.getAdapter(config.adapter || defaults$1.adapter); - - return adapter(config).then(function onAdapterResolution(response) { - throwIfCancellationRequested(config); - - // Transform response data - response.data = transformData.call( - config, - config.transformResponse, - response - ); - - response.headers = AxiosHeaders$1.from(response.headers); - - return response; - }, function onAdapterRejection(reason) { - if (!isCancel(reason)) { - throwIfCancellationRequested(config); - - // Transform response data - if (reason && reason.response) { - reason.response.data = transformData.call( - config, - config.transformResponse, - reason.response - ); - reason.response.headers = AxiosHeaders$1.from(reason.response.headers); - } - } - - return Promise.reject(reason); - }); -} - -const VERSION = "1.7.7"; - -const validators$1 = {}; - -// eslint-disable-next-line func-names -['object', 'boolean', 'number', 'function', 'string', 'symbol'].forEach((type, i) => { - validators$1[type] = function validator(thing) { - return typeof thing === type || 'a' + (i < 1 ? 'n ' : ' ') + type; - }; -}); - -const deprecatedWarnings = {}; - -/** - * Transitional option validator - * - * @param {function|boolean?} validator - set to false if the transitional option has been removed - * @param {string?} version - deprecated version / removed since version - * @param {string?} message - some message with additional info - * - * @returns {function} - */ -validators$1.transitional = function transitional(validator, version, message) { - function formatMessage(opt, desc) { - return '[Axios v' + VERSION + '] Transitional option \'' + opt + '\'' + desc + (message ? '. ' + message : ''); - } - - // eslint-disable-next-line func-names - return (value, opt, opts) => { - if (validator === false) { - throw new AxiosError( - formatMessage(opt, ' has been removed' + (version ? ' in ' + version : '')), - AxiosError.ERR_DEPRECATED - ); - } - - if (version && !deprecatedWarnings[opt]) { - deprecatedWarnings[opt] = true; - // eslint-disable-next-line no-console - console.warn( - formatMessage( - opt, - ' has been deprecated since v' + version + ' and will be removed in the near future' - ) - ); - } - - return validator ? validator(value, opt, opts) : true; - }; -}; - -/** - * Assert object's properties type - * - * @param {object} options - * @param {object} schema - * @param {boolean?} allowUnknown - * - * @returns {object} - */ - -function assertOptions(options, schema, allowUnknown) { - if (typeof options !== 'object') { - throw new AxiosError('options must be an object', AxiosError.ERR_BAD_OPTION_VALUE); - } - const keys = Object.keys(options); - let i = keys.length; - while (i-- > 0) { - const opt = keys[i]; - const validator = schema[opt]; - if (validator) { - const value = options[opt]; - const result = value === undefined || validator(value, opt, options); - if (result !== true) { - throw new AxiosError('option ' + opt + ' must be ' + result, AxiosError.ERR_BAD_OPTION_VALUE); - } - continue; - } - if (allowUnknown !== true) { - throw new AxiosError('Unknown option ' + opt, AxiosError.ERR_BAD_OPTION); - } - } -} - -var validator = { - assertOptions, - validators: validators$1 -}; - -const validators = validator.validators; - -/** - * Create a new instance of Axios - * - * @param {Object} instanceConfig The default config for the instance - * - * @return {Axios} A new instance of Axios - */ -class Axios { - constructor(instanceConfig) { - this.defaults = instanceConfig; - this.interceptors = { - request: new InterceptorManager$1(), - response: new InterceptorManager$1() - }; - } - - /** - * Dispatch a request - * - * @param {String|Object} configOrUrl The config specific for this request (merged with this.defaults) - * @param {?Object} config - * - * @returns {Promise} The Promise to be fulfilled - */ - async request(configOrUrl, config) { - try { - return await this._request(configOrUrl, config); - } catch (err) { - if (err instanceof Error) { - let dummy; - - Error.captureStackTrace ? Error.captureStackTrace(dummy = {}) : (dummy = new Error()); - - // slice off the Error: ... line - const stack = dummy.stack ? dummy.stack.replace(/^.+\n/, '') : ''; - try { - if (!err.stack) { - err.stack = stack; - // match without the 2 top stack lines - } else if (stack && !String(err.stack).endsWith(stack.replace(/^.+\n.+\n/, ''))) { - err.stack += '\n' + stack; - } - } catch (e) { - // ignore the case where "stack" is an un-writable property - } - } - - throw err; - } - } - - _request(configOrUrl, config) { - /*eslint no-param-reassign:0*/ - // Allow for axios('example/url'[, config]) a la fetch API - if (typeof configOrUrl === 'string') { - config = config || {}; - config.url = configOrUrl; - } else { - config = configOrUrl || {}; - } - - config = mergeConfig(this.defaults, config); - - const {transitional, paramsSerializer, headers} = config; - - if (transitional !== undefined) { - validator.assertOptions(transitional, { - silentJSONParsing: validators.transitional(validators.boolean), - forcedJSONParsing: validators.transitional(validators.boolean), - clarifyTimeoutError: validators.transitional(validators.boolean) - }, false); - } - - if (paramsSerializer != null) { - if (utils$1.isFunction(paramsSerializer)) { - config.paramsSerializer = { - serialize: paramsSerializer - }; - } else { - validator.assertOptions(paramsSerializer, { - encode: validators.function, - serialize: validators.function - }, true); - } - } - - // Set config.method - config.method = (config.method || this.defaults.method || 'get').toLowerCase(); - - // Flatten headers - let contextHeaders = headers && utils$1.merge( - headers.common, - headers[config.method] - ); - - headers && utils$1.forEach( - ['delete', 'get', 'head', 'post', 'put', 'patch', 'common'], - (method) => { - delete headers[method]; - } - ); - - config.headers = AxiosHeaders$1.concat(contextHeaders, headers); - - // filter out skipped interceptors - const requestInterceptorChain = []; - let synchronousRequestInterceptors = true; - this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) { - if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) { - return; - } - - synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous; - - requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected); - }); - - const responseInterceptorChain = []; - this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) { - responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected); - }); - - let promise; - let i = 0; - let len; - - if (!synchronousRequestInterceptors) { - const chain = [dispatchRequest.bind(this), undefined]; - chain.unshift.apply(chain, requestInterceptorChain); - chain.push.apply(chain, responseInterceptorChain); - len = chain.length; - - promise = Promise.resolve(config); - - while (i < len) { - promise = promise.then(chain[i++], chain[i++]); - } - - return promise; - } - - len = requestInterceptorChain.length; - - let newConfig = config; - - i = 0; - - while (i < len) { - const onFulfilled = requestInterceptorChain[i++]; - const onRejected = requestInterceptorChain[i++]; - try { - newConfig = onFulfilled(newConfig); - } catch (error) { - onRejected.call(this, error); - break; - } - } - - try { - promise = dispatchRequest.call(this, newConfig); - } catch (error) { - return Promise.reject(error); - } - - i = 0; - len = responseInterceptorChain.length; - - while (i < len) { - promise = promise.then(responseInterceptorChain[i++], responseInterceptorChain[i++]); - } - - return promise; - } - - getUri(config) { - config = mergeConfig(this.defaults, config); - const fullPath = buildFullPath(config.baseURL, config.url); - return buildURL(fullPath, config.params, config.paramsSerializer); - } -} - -// Provide aliases for supported request methods -utils$1.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) { - /*eslint func-names:0*/ - Axios.prototype[method] = function(url, config) { - return this.request(mergeConfig(config || {}, { - method, - url, - data: (config || {}).data - })); - }; -}); - -utils$1.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) { - /*eslint func-names:0*/ - - function generateHTTPMethod(isForm) { - return function httpMethod(url, data, config) { - return this.request(mergeConfig(config || {}, { - method, - headers: isForm ? { - 'Content-Type': 'multipart/form-data' - } : {}, - url, - data - })); - }; - } - - Axios.prototype[method] = generateHTTPMethod(); - - Axios.prototype[method + 'Form'] = generateHTTPMethod(true); -}); - -var Axios$1 = Axios; - -/** - * A `CancelToken` is an object that can be used to request cancellation of an operation. - * - * @param {Function} executor The executor function. - * - * @returns {CancelToken} - */ -class CancelToken { - constructor(executor) { - if (typeof executor !== 'function') { - throw new TypeError('executor must be a function.'); - } - - let resolvePromise; - - this.promise = new Promise(function promiseExecutor(resolve) { - resolvePromise = resolve; - }); - - const token = this; - - // eslint-disable-next-line func-names - this.promise.then(cancel => { - if (!token._listeners) return; - - let i = token._listeners.length; - - while (i-- > 0) { - token._listeners[i](cancel); - } - token._listeners = null; - }); - - // eslint-disable-next-line func-names - this.promise.then = onfulfilled => { - let _resolve; - // eslint-disable-next-line func-names - const promise = new Promise(resolve => { - token.subscribe(resolve); - _resolve = resolve; - }).then(onfulfilled); - - promise.cancel = function reject() { - token.unsubscribe(_resolve); - }; - - return promise; - }; + createDomain_1 = createDomain; + return createDomain_1; +} - executor(function cancel(message, config, request) { - if (token.reason) { - // Cancellation has already been requested - return; - } - - token.reason = new CanceledError(message, config, request); - resolvePromise(token.reason); - }); - } - - /** - * Throws a `CanceledError` if cancellation has been requested. - */ - throwIfRequested() { - if (this.reason) { - throw this.reason; - } - } - - /** - * Subscribe to the cancel signal - */ - - subscribe(listener) { - if (this.reason) { - listener(this.reason); - return; - } - - if (this._listeners) { - this._listeners.push(listener); - } else { - this._listeners = [listener]; - } - } - - /** - * Unsubscribe from the cancel signal - */ - - unsubscribe(listener) { - if (!this._listeners) { - return; - } - const index = this._listeners.indexOf(listener); - if (index !== -1) { - this._listeners.splice(index, 1); - } - } - - toAbortSignal() { - const controller = new AbortController(); - - const abort = (err) => { - controller.abort(err); - }; +var wrapQuery_1; +var hasRequiredWrapQuery; - this.subscribe(abort); - - controller.signal.unsubscribe = () => this.unsubscribe(abort); - - return controller.signal; - } - - /** - * Returns an object that contains a new `CancelToken` and a function that, when called, - * cancels the `CancelToken`. - */ - static source() { - let cancel; - const token = new CancelToken(function executor(c) { - cancel = c; - }); - return { - token, - cancel - }; - } -} - -var CancelToken$1 = CancelToken; - -/** - * Syntactic sugar for invoking a function and expanding an array for arguments. - * - * Common use case would be to use `Function.prototype.apply`. - * - * ```js - * function f(x, y, z) {} - * var args = [1, 2, 3]; - * f.apply(null, args); - * ``` - * - * With `spread` this example can be re-written. - * - * ```js - * spread(function(x, y, z) {})([1, 2, 3]); - * ``` - * - * @param {Function} callback - * - * @returns {Function} - */ -function spread(callback) { - return function wrap(arr) { - return callback.apply(null, arr); - }; -} - -/** - * Determines whether the payload is an error thrown by Axios - * - * @param {*} payload The value to test - * - * @returns {boolean} True if the payload is an error thrown by Axios, otherwise false - */ -function isAxiosError(payload) { - return utils$1.isObject(payload) && (payload.isAxiosError === true); -} - -const HttpStatusCode = { - Continue: 100, - SwitchingProtocols: 101, - Processing: 102, - EarlyHints: 103, - Ok: 200, - Created: 201, - Accepted: 202, - NonAuthoritativeInformation: 203, - NoContent: 204, - ResetContent: 205, - PartialContent: 206, - MultiStatus: 207, - AlreadyReported: 208, - ImUsed: 226, - MultipleChoices: 300, - MovedPermanently: 301, - Found: 302, - SeeOther: 303, - NotModified: 304, - UseProxy: 305, - Unused: 306, - TemporaryRedirect: 307, - PermanentRedirect: 308, - BadRequest: 400, - Unauthorized: 401, - PaymentRequired: 402, - Forbidden: 403, - NotFound: 404, - MethodNotAllowed: 405, - NotAcceptable: 406, - ProxyAuthenticationRequired: 407, - RequestTimeout: 408, - Conflict: 409, - Gone: 410, - LengthRequired: 411, - PreconditionFailed: 412, - PayloadTooLarge: 413, - UriTooLong: 414, - UnsupportedMediaType: 415, - RangeNotSatisfiable: 416, - ExpectationFailed: 417, - ImATeapot: 418, - MisdirectedRequest: 421, - UnprocessableEntity: 422, - Locked: 423, - FailedDependency: 424, - TooEarly: 425, - UpgradeRequired: 426, - PreconditionRequired: 428, - TooManyRequests: 429, - RequestHeaderFieldsTooLarge: 431, - UnavailableForLegalReasons: 451, - InternalServerError: 500, - NotImplemented: 501, - BadGateway: 502, - ServiceUnavailable: 503, - GatewayTimeout: 504, - HttpVersionNotSupported: 505, - VariantAlsoNegotiates: 506, - InsufficientStorage: 507, - LoopDetected: 508, - NotExtended: 510, - NetworkAuthenticationRequired: 511, -}; - -Object.entries(HttpStatusCode).forEach(([key, value]) => { - HttpStatusCode[value] = key; -}); - -var HttpStatusCode$1 = HttpStatusCode; - -/** - * Create an instance of Axios - * - * @param {Object} defaultConfig The default config for the instance - * - * @returns {Axios} A new instance of Axios - */ -function createInstance(defaultConfig) { - const context = new Axios$1(defaultConfig); - const instance = bind(Axios$1.prototype.request, context); - - // Copy axios.prototype to instance - utils$1.extend(instance, Axios$1.prototype, context, {allOwnKeys: true}); - - // Copy context to instance - utils$1.extend(instance, context, null, {allOwnKeys: true}); - - // Factory for creating new instances - instance.create = function create(instanceConfig) { - return createInstance(mergeConfig(defaultConfig, instanceConfig)); - }; - - return instance; -} - -// Create the default instance to be exported -const axios = createInstance(defaults$1); - -// Expose Axios class to allow class inheritance -axios.Axios = Axios$1; - -// Expose Cancel & CancelToken -axios.CanceledError = CanceledError; -axios.CancelToken = CancelToken$1; -axios.isCancel = isCancel; -axios.VERSION = VERSION; -axios.toFormData = toFormData; - -// Expose AxiosError class -axios.AxiosError = AxiosError; - -// alias for CanceledError for backward compatibility -axios.Cancel = axios.CanceledError; - -// Expose all/spread -axios.all = function all(promises) { - return Promise.all(promises); -}; - -axios.spread = spread; - -// Expose isAxiosError -axios.isAxiosError = isAxiosError; - -// Expose mergeConfig -axios.mergeConfig = mergeConfig; - -axios.AxiosHeaders = AxiosHeaders$1; - -axios.formToJSON = thing => formDataToJSON(utils$1.isHTMLForm(thing) ? new FormData(thing) : thing); - -axios.getAdapter = adapters.getAdapter; - -axios.HttpStatusCode = HttpStatusCode$1; - -axios.default = axios; - -var axios_1 = axios; - -const _axios = axios_1; - -function httpAdapter(baseURL, path, axiosInterceptor) { - //@ts-ignore - const axios = _axios.default ? _axios.default.create({ baseURL }) : _axios.create({ baseURL }); - axiosInterceptor.applyTo(axios); +function requireWrapQuery () { + if (hasRequiredWrapQuery) return wrapQuery_1; + hasRequiredWrapQuery = 1; + var log = requireLog(); - let c = { - get, - post, - patch, - query, - express - }; + function wrapQuery(client) { - return c; + return runQuery; - async function get() { - try { - const headers = { 'Content-Type': 'application/json', 'Accept': 'application/json' }; - const res = await axios.request(path, { headers, method: 'get' }); - return res.data; - } - catch (e) { - if (typeof e.response?.data === 'string') - throw new Error(e.response.data.replace(/^Error: /, '')); - else - throw e; - } + function runQuery(query, onCompleted) { - } + var params = query.parameters; + var sql = query.sql(); + log.emitQuery({sql, parameters: params}); + client.d1.prepare(sql, params).bind(...params).all().then(onInnerCompleted, onCompleted); - async function patch(body) { - try { + function onInnerCompleted(response) { + onCompleted(null, response.results); + } - const headers = { 'Content-Type': 'application/json' }; - const res = await axios.request(path, { headers, method: 'patch', data: body }); - return res.data; - } - catch (e) { - if (typeof e.response?.data === 'string') - throw new Error(e.response.data.replace(/^Error: /, '')); - else - throw e; } - } - async function post(body) { - try { - const headers = { 'Content-Type': 'application/json' }; - const res = await axios.request(path, { headers, method: 'post', data: body }); - return res.data; - } - catch (e) { - if (typeof e.response?.data === 'string') - throw new Error(e.response.data.replace(/^Error: /, '')); - else throw e; - } - } + wrapQuery_1 = wrapQuery; + return wrapQuery_1; +} +var encodeBoolean_1; +var hasRequiredEncodeBoolean; - function query() { - throw new Error('Queries are not supported through http'); +function requireEncodeBoolean () { + if (hasRequiredEncodeBoolean) return encodeBoolean_1; + hasRequiredEncodeBoolean = 1; + function encodeBoolean(bool) { + if (bool) + return 1; + return 0; } - function express() { - throw new Error('Hosting in express is not supported on the client side'); + encodeBoolean_1 = encodeBoolean; + return encodeBoolean_1; +} + +var format_1; +var hasRequiredFormat; + +function requireFormat () { + if (hasRequiredFormat) return format_1; + hasRequiredFormat = 1; + function format(template, ...values) { + let index = 0; + return template.replace(/%s/g, () => { + // If there aren't enough values, this will insert 'undefined' + // for placeholders that don't have a corresponding array item. + return values[index++]; + }); } + format_1 = format; + return format_1; } -function netAdapter$1(url, tableName, { axios, tableOptions }) { +var quote; +var hasRequiredQuote; - let c = { - get, - post, - patch, - query - }; +function requireQuote () { + if (hasRequiredQuote) return quote; + hasRequiredQuote = 1; + quote = (name) => `"${name}"`; + return quote; +} - return c; +var deleteFromSql_1; +var hasRequiredDeleteFromSql; - async function get() { - const adapter = await getInnerAdapter(); - return adapter.get.apply(null, arguments); - } +function requireDeleteFromSql () { + if (hasRequiredDeleteFromSql) return deleteFromSql_1; + hasRequiredDeleteFromSql = 1; + const format = 'delete from %s where %s.rowId in (SELECT %s.rowId FROM %s %s%s)'; + const formatString = requireFormat(); + const quote = requireQuote(); - async function patch(_body) { - const adapter = await getInnerAdapter(); - return adapter.patch.apply(null, arguments); + function deleteFromSql(table, alias, whereSql) { + const name = quote(table._dbName); + alias = quote(alias); + return formatString(format, name, name, alias, name, alias, whereSql); } + deleteFromSql_1 = deleteFromSql; + return deleteFromSql_1; +} - async function post(_body) { - const adapter = await getInnerAdapter(); - return adapter.post.apply(null, arguments); - } +var selectForUpdateSql; +var hasRequiredSelectForUpdateSql; + +function requireSelectForUpdateSql () { + if (hasRequiredSelectForUpdateSql) return selectForUpdateSql; + hasRequiredSelectForUpdateSql = 1; + const quote = requireQuote$1(); + + selectForUpdateSql = function(alias) { + return ' FOR UPDATE OF ' + quote(alias); + }; + return selectForUpdateSql; +} + +var lastInsertedSql_1; +var hasRequiredLastInsertedSql; + +function requireLastInsertedSql () { + if (hasRequiredLastInsertedSql) return lastInsertedSql_1; + hasRequiredLastInsertedSql = 1; + function lastInsertedSql(context, table, keyValues) { + return keyValues.map((value,i) => { + let column = table._primaryColumns[i]; + if (value === undefined && column.tsType === 'NumberColumn') + return 'rowid IN (select last_insert_rowid())'; + else + return column.eq(context, value); + }); - async function query() { - const adapter = await getInnerAdapter(); - return adapter.query.apply(null, arguments); } - async function getInnerAdapter() { - const db = await getDb(); - if (typeof db === 'string') { - return httpAdapter(db, `?table=${tableName}`, axios); - } - else if (db && db.transaction) { - return db.hostLocal({ ...tableOptions, db, table: url }); - } + lastInsertedSql_1 = lastInsertedSql; + return lastInsertedSql_1; +} + +var limitAndOffset_1; +var hasRequiredLimitAndOffset; + +function requireLimitAndOffset () { + if (hasRequiredLimitAndOffset) return limitAndOffset_1; + hasRequiredLimitAndOffset = 1; + function limitAndOffset(span) { + if (span.offset) + return ` limit ${limit()} offset ${span.offset}`; + else if (span.limit || span.limit === 0) + return ` limit ${span.limit}`; else - throw new Error('Invalid arguments'); - } + return ''; - async function getDb() { - let db = tableOptions.db; - if (db.transaction) - return db; - if (typeof db === 'function') { - let dbPromise = db(); - if (dbPromise.then) - db = await dbPromise; + function limit() { + if (span.limit || span.limit === 0) + return span.limit; else - db = dbPromise; + return '-1'; } - return db; } + limitAndOffset_1 = limitAndOffset; + return limitAndOffset_1; } -var netAdapter_1 = netAdapter$1; +var insertSql_1; +var hasRequiredInsertSql; -const stringify$1 = stringify_1; -const { v4: uuid } = require$$1; +function requireInsertSql () { + if (hasRequiredInsertSql) return insertSql_1; + hasRequiredInsertSql = 1; + const quote = requireQuote(); -function toKeyPositionMap$1(rows, options) { - return rows.reduce((map, element, i) => { - if (options && options.keys && element === Object(element)) { - let key = []; - for (let i = 0; i < options.keys.length; i++) { - let keyName = options.keys[i].name; - key.push(negotiateTempKey(element[keyName])); - } - map[stringify$1(key)] = i; - } - else if ('id' in element) - map[stringify$1(element.id)] = i; - else - map[i] = i; - return map; - }, {}); + function insertSql(_context, table, row, options) { + let columnNames = []; + let conflictColumnUpdateSql = ''; + let values = []; -} + let sql = 'INSERT INTO ' + quote(table._dbName) + ' '; + addDiscriminators(); + addColumns(); -function negotiateTempKey(value) { - if (value === undefined) - return `~${uuid()}`; - else - return value; -} + if (columnNames.length === 0) { + sql += 'DEFAULT VALUES'; + } else { + sql = sql + '(' + columnNames.join(',') + ') ' + 'VALUES (' + values.join(',') + ')' + onConflict(); + } -var toKeyPositionMap_1 = toKeyPositionMap$1; + return sql; -function map$1(index, _fn) { - const handler = { - get(target, prop) { - if (prop === 'map') { - return () => { - return new Proxy(onFinal, handler); - }; - } else if (typeof target[prop] !== 'undefined') { - return target[prop]; + function onConflict() { + if (options.concurrency === 'skipOnConflict' || options.concurrency === 'overwrite') { + const primaryKeys = table._primaryColumns.map(x => quote(x._dbName)).join(','); + return ` ON CONFLICT(${primaryKeys}) ${conflictColumnUpdateSql}`; } else { - return () => { - return new Proxy({}, handler); - }; + return ''; } - }, - apply(target, _thisArg, argumentsList) { - if (target === onFinal) { - return target(...argumentsList); - } else { - return new Proxy({}, handler); + } + + function addDiscriminators() { + let discriminators = table._columnDiscriminators; + for (let i = 0; i < discriminators.length; i++) { + let parts = discriminators[i].split('='); + columnNames.push(quote(parts[0])); + values.push(parts[1]); } - }, - set(target, prop, value) { - target[prop] = value; - return true; - }, - }; + } - function dbMap(fn) { - return fn(dbMap); + function addColumns() { + let conflictColumnUpdates = []; + let columns = table._columns; + for (let i = 0; i < columns.length; i++) { + let column = columns[i]; + const columnName = quote(column._dbName); + if (row['__' + column.alias] !== undefined) { + columnNames.push(columnName); + values.push('%s'); + addConflictUpdate(column); + } + } + if (conflictColumnUpdates.length === 0) + conflictColumnUpdateSql = 'DO NOTHING'; + else + conflictColumnUpdateSql = 'DO UPDATE SET ' + conflictColumnUpdates.join(','); + + function addConflictUpdate(column) { + let concurrency = options[column.alias]?.concurrency || options.concurrency; + const tableName = table._dbName; + const columnName = quote(column._dbName); + if (concurrency === 'overwrite') { + conflictColumnUpdates.push(`${columnName}=excluded.${columnName}`); + } else if (concurrency === 'optimistic') + conflictColumnUpdates.push(`${columnName} = CASE WHEN ${tableName}.${columnName} <> excluded.${columnName} THEN '12345678-1234-1234-1234-123456789012Conflict when updating ${columnName}12345678-1234-1234-1234-123456789012' ELSE ${tableName}.${columnName} END`); + } + } } - dbMap.http = (url) => url; - dbMap.pg = throwDb; - dbMap.postgres = throwDb; - dbMap.mssql = throwDb; - dbMap.mssqlNative = throwDb; - dbMap.mysql = throwDb; - dbMap.sap = throwDb; - dbMap.oracle = throwDb; - dbMap.sqlite = throwDb; + insertSql_1 = insertSql; + return insertSql_1; +} - function throwDb() { - throw new Error('Cannot create pool for database outside node'); - } +var newInsertCommand_1; +var hasRequiredNewInsertCommand; - function onFinal(arg) { - if (arg && arg.db && typeof arg.db === 'function') { - return index({ - ...arg, - db: dbMap(arg.db), - providers: dbMap - }); - } +function requireNewInsertCommand () { + if (hasRequiredNewInsertCommand) return newInsertCommand_1; + hasRequiredNewInsertCommand = 1; + var newImmutable = requireNewImmutable(); + var createPatch = requireCreatePatch(); + var createDto = requireCreateDto(); - return index({ ...arg, providers: dbMap }); - } - - onFinal.http = (url) => index({ db: url, providers: dbMap }); - onFinal.pg = () => index({ db: throwDb, providers: dbMap }); - onFinal.postgres = () => index({ db: throwDb, providers: dbMap }); - onFinal.mssql = () => index({ db: throwDb, providers: dbMap }); - onFinal.mssqlNative = () => index({ db: throwDb, providers: dbMap }); - onFinal.mysql = () => index({ db: throwDb, providers: dbMap }); - onFinal.sap = () => index({ db: throwDb, providers: dbMap }); - onFinal.oracle = () => index({ db: throwDb, providers: dbMap }); - onFinal.sqlite = () => index({ db: throwDb, providers: dbMap }); - - return new Proxy(onFinal, handler); -} - -var clientMap = map$1; - -var rfdc_1 = rfdc; - -function copyBuffer (cur) { - if (cur instanceof Buffer) { - return Buffer.from(cur) - } - - return new cur.constructor(cur.buffer.slice(), cur.byteOffset, cur.length) -} - -function rfdc (opts) { - opts = opts || {}; - if (opts.circles) return rfdcCircles(opts) - - const constructorHandlers = new Map(); - constructorHandlers.set(Date, (o) => new Date(o)); - constructorHandlers.set(Map, (o, fn) => new Map(cloneArray(Array.from(o), fn))); - constructorHandlers.set(Set, (o, fn) => new Set(cloneArray(Array.from(o), fn))); - if (opts.constructorHandlers) { - for (const handler of opts.constructorHandlers) { - constructorHandlers.set(handler[0], handler[1]); - } - } - - let handler = null; - - return opts.proto ? cloneProto : clone - - function cloneArray (a, fn) { - const keys = Object.keys(a); - const a2 = new Array(keys.length); - for (let i = 0; i < keys.length; i++) { - const k = keys[i]; - const cur = a[k]; - if (typeof cur !== 'object' || cur === null) { - a2[k] = cur; - } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) { - a2[k] = handler(cur, fn); - } else if (ArrayBuffer.isView(cur)) { - a2[k] = copyBuffer(cur); - } else { - a2[k] = fn(cur); - } - } - return a2 - } - - function clone (o) { - if (typeof o !== 'object' || o === null) return o - if (Array.isArray(o)) return cloneArray(o, clone) - if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) { - return handler(o, clone) - } - const o2 = {}; - for (const k in o) { - if (Object.hasOwnProperty.call(o, k) === false) continue - const cur = o[k]; - if (typeof cur !== 'object' || cur === null) { - o2[k] = cur; - } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) { - o2[k] = handler(cur, clone); - } else if (ArrayBuffer.isView(cur)) { - o2[k] = copyBuffer(cur); - } else { - o2[k] = clone(cur); - } - } - return o2 - } - - function cloneProto (o) { - if (typeof o !== 'object' || o === null) return o - if (Array.isArray(o)) return cloneArray(o, cloneProto) - if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) { - return handler(o, cloneProto) - } - const o2 = {}; - for (const k in o) { - const cur = o[k]; - if (typeof cur !== 'object' || cur === null) { - o2[k] = cur; - } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) { - o2[k] = handler(cur, cloneProto); - } else if (ArrayBuffer.isView(cur)) { - o2[k] = copyBuffer(cur); - } else { - o2[k] = cloneProto(cur); - } - } - return o2 - } -} - -function rfdcCircles (opts) { - const refs = []; - const refsNew = []; - - const constructorHandlers = new Map(); - constructorHandlers.set(Date, (o) => new Date(o)); - constructorHandlers.set(Map, (o, fn) => new Map(cloneArray(Array.from(o), fn))); - constructorHandlers.set(Set, (o, fn) => new Set(cloneArray(Array.from(o), fn))); - if (opts.constructorHandlers) { - for (const handler of opts.constructorHandlers) { - constructorHandlers.set(handler[0], handler[1]); - } - } - - let handler = null; - return opts.proto ? cloneProto : clone - - function cloneArray (a, fn) { - const keys = Object.keys(a); - const a2 = new Array(keys.length); - for (let i = 0; i < keys.length; i++) { - const k = keys[i]; - const cur = a[k]; - if (typeof cur !== 'object' || cur === null) { - a2[k] = cur; - } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) { - a2[k] = handler(cur, fn); - } else if (ArrayBuffer.isView(cur)) { - a2[k] = copyBuffer(cur); - } else { - const index = refs.indexOf(cur); - if (index !== -1) { - a2[k] = refsNew[index]; - } else { - a2[k] = fn(cur); - } - } - } - return a2 - } - - function clone (o) { - if (typeof o !== 'object' || o === null) return o - if (Array.isArray(o)) return cloneArray(o, clone) - if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) { - return handler(o, clone) - } - const o2 = {}; - refs.push(o); - refsNew.push(o2); - for (const k in o) { - if (Object.hasOwnProperty.call(o, k) === false) continue - const cur = o[k]; - if (typeof cur !== 'object' || cur === null) { - o2[k] = cur; - } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) { - o2[k] = handler(cur, clone); - } else if (ArrayBuffer.isView(cur)) { - o2[k] = copyBuffer(cur); - } else { - const i = refs.indexOf(cur); - if (i !== -1) { - o2[k] = refsNew[i]; - } else { - o2[k] = clone(cur); - } - } - } - refs.pop(); - refsNew.pop(); - return o2 - } - - function cloneProto (o) { - if (typeof o !== 'object' || o === null) return o - if (Array.isArray(o)) return cloneArray(o, cloneProto) - if (o.constructor !== Object && (handler = constructorHandlers.get(o.constructor))) { - return handler(o, cloneProto) - } - const o2 = {}; - refs.push(o); - refsNew.push(o2); - for (const k in o) { - const cur = o[k]; - if (typeof cur !== 'object' || cur === null) { - o2[k] = cur; - } else if (cur.constructor !== Object && (handler = constructorHandlers.get(cur.constructor))) { - o2[k] = handler(cur, cloneProto); - } else if (ArrayBuffer.isView(cur)) { - o2[k] = copyBuffer(cur); - } else { - const i = refs.indexOf(cur); - if (i !== -1) { - o2[k] = refsNew[i]; - } else { - o2[k] = cloneProto(cur); - } - } - } - refs.pop(); - refsNew.pop(); - return o2 - } -} - -var _default = rfdc_1(); - -class InterceptorProxy { - constructor() { - this.requestInterceptors = []; - this.responseInterceptors = []; - } - - get request() { - return { - use: (onFulfilled, onRejected) => { - const id = Math.random().toString(36).substr(2, 9); // unique id - this.requestInterceptors.push({ id, onFulfilled, onRejected }); - return id; - }, - eject: (id) => { - this.requestInterceptors = this.requestInterceptors.filter(interceptor => interceptor.id !== id); - } - }; + function newInsertCommand(newInsertCommandCore, table, row, options) { + return new InsertCommand(newInsertCommandCore, table, row, options); } - get response() { - return { - use: (onFulfilled, onRejected) => { - const id = Math.random().toString(36).substr(2, 9); // unique id - this.responseInterceptors.push({ id, onFulfilled, onRejected }); - return id; - }, - eject: (id) => { - this.responseInterceptors = this.responseInterceptors.filter(interceptor => interceptor.id !== id); - } - }; + function InsertCommand(newInsertCommandCore, table, row, options) { + this.__getCoreCommand = newImmutable(newInsertCommandCore); + this._table = table; + this._row = row; + this._options = options; } - applyTo(axiosInstance) { - for (const { onFulfilled, onRejected } of this.requestInterceptors) { - axiosInstance.interceptors.request.use(onFulfilled, onRejected); + InsertCommand.prototype._getCoreCommand = function() { + return this.__getCoreCommand(this._table, this._row, this._options); + }; + + InsertCommand.prototype.sql = function() { + return this._getCoreCommand().sql(); + }; + + InsertCommand.prototype.matches = function(otherRow) { + return this._row === otherRow; + }; + + + InsertCommand.prototype.endEdit = function() { + this.sql(); + var dto = createDto(this._table, this._row); + if (this._disallowCompress || this._table._emitChanged.callbacks.length > 0) + this._patch = createPatch([], [dto]); + }; + + InsertCommand.prototype.emitChanged = function() { + return this._table._emitChanged({row: this._row, patch: this._patch}); + }; + + Object.defineProperty(InsertCommand.prototype, 'parameters', { + get: function() { + return this._getCoreCommand().parameters; + } + }); - for (const { onFulfilled, onRejected } of this.responseInterceptors) { - axiosInstance.interceptors.response.use(onFulfilled, onRejected); + Object.defineProperty(InsertCommand.prototype, 'disallowCompress', { + get: function() { + return this._disallowCompress || this._table._emitChanged.callbacks.length > 0; + + }, + set: function(value) { + this._disallowCompress = value; } - } + }); + + + newInsertCommand_1 = newInsertCommand; + return newInsertCommand_1; } -var axiosInterceptor = function create() { - return new InterceptorProxy(); -}; +var getSqlTemplate_1; +var hasRequiredGetSqlTemplate; -const createPatch = createPatch$1; -const stringify = stringify_1; -const cloneFromDb = cloneFromDb_1; -const netAdapter = netAdapter_1; -const toKeyPositionMap = toKeyPositionMap_1; -const rootMap = new WeakMap(); -const fetchingStrategyMap = new WeakMap(); -const targetKey = Symbol(); -const map = clientMap; -const clone = _default; -const createAxiosInterceptor = axiosInterceptor; +function requireGetSqlTemplate () { + if (hasRequiredGetSqlTemplate) return getSqlTemplate_1; + hasRequiredGetSqlTemplate = 1; + let getSessionContext = requireGetSessionContext(); + let quote = requireQuote$1(); -function rdbClient(options = {}) { - if (options.pg) - options = { db: options }; - let transaction = options.transaction; - let _reactive = options.reactive; - let providers = options.providers || {}; - let baseUrl = options.db; - if (typeof providers === 'function') - baseUrl = typeof options.db === 'function' ? providers(options.db) : options.db; - const axiosInterceptor = createAxiosInterceptor(); + function getSqlTemplate(context, _table, _row) { + let rdb = getSessionContext(context); + if (rdb.insertSql) + return rdb.insertSql.apply(null, arguments); + else + return getSqlTemplateDefault.apply(null, arguments); - function client(_options = {}) { - if (_options.pg) - _options = { db: _options }; - return rdbClient({ ...options, ..._options }); } - client.reactive = (cb => _reactive = cb); - client.map = map.bind(null, client); - Object.defineProperty(client, 'metaData', { - get: getMetaData, - enumerable: true, - configurable: false - }); - client.interceptors = axiosInterceptor; - client.createPatch = _createPatch; - client.table = table; - client.or = column('or'); - client.and = column('and'); - client.not = column('not'); - client.filter = { - or: client.or, - and: client.and, - not: client.not, - toJSON: function() { - return; - } - }; - client.query = query; - client.transaction = runInTransaction; - client.db = baseUrl; - client.mssql = onProvider.bind(null, 'mssql'); - client.mssqlNative = onProvider.bind(null, 'mssqlNative'); - client.pg = onProvider.bind(null, 'pg'); - client.postgres = onProvider.bind(null, 'postgres'); - client.sqlite = onProvider.bind(null, 'sqlite'); - client.sap = onProvider.bind(null, 'sap'); - client.oracle = onProvider.bind(null, 'oracle'); - client.http = onProvider.bind(null, 'http');//todo - client.mysql = onProvider.bind(null, 'mysql'); - client.express = express; - - function onProvider(name, ...args) { - let db = providers[name].apply(null, args); - return client({ db }); - } - - if (options.tables) { - // for (let name in options.tables) { - // client[name] = table(options.tables[name], name, { ...readonly, ...clone(options[name]) }); - // } - client.tables = options.tables; - // return client; - } - // else { - let handler = { - get(_target, property,) { - if (property in client) - return Reflect.get(...arguments); - else { - const readonly = { readonly: options.readonly, concurrency: options.concurrency }; - return table(options?.tables?.[property] || baseUrl, property, { ...readonly, ...clone(options[property]) }); + function getSqlTemplateDefault(context, table, row) { + let columnNames = []; + let values = []; + let sql = 'INSERT INTO ' + quote(context, table._dbName) + ' '; + addDiscriminators(); + addColumns(); + if (columnNames.length === 0) + sql += `${outputInserted()}${defaultValues()}${lastInserted()}`; + else + sql = sql + '('+ columnNames.join(',') + ') ' + outputInserted() + 'VALUES (' + values.join(',') + ')' + lastInserted() ; + return sql; + + function addDiscriminators() { + let discriminators = table._columnDiscriminators; + for (let i = 0; i < discriminators.length; i++) { + let parts = discriminators[i].split('='); + columnNames.push(quote(context, parts[0])); + values.push(parts[1]); } } - }; - return new Proxy(client, handler); - // } - - function getMetaData() { - const result = { readonly: options.readonly, concurrency: options.concurrency }; - for (let name in options.tables) { - result[name] = getMetaDataTable(options.tables[name], inferOptions(options, name)); + function addColumns() { + let columns = table._columns; + for (let i = 0; i < columns.length; i++) { + let column = columns[i]; + if (row['__' + column.alias] !== undefined) { + columnNames.push(quote(context, column._dbName)); + values.push('%s'); + } + } } - return result; - } - - function inferOptions(defaults, property) { - const parent = {}; - if ('readonly' in defaults) - parent.readonly = defaults.readonly; - if ('concurrency' in defaults) - parent.concurrency = defaults.concurrency; - return { ...parent, ...(defaults[property] || {}) }; - } - - function getMetaDataTable(table, options) { - const result = {}; - for (let i = 0; i < table._columns.length; i++) { - const name = table._columns[i].alias; - result[name] = inferOptions(options, name); + function lastInserted() { + let rdb = getSessionContext(context); + if (!rdb.lastInsertedIsSeparate && rdb.lastInsertedSql) + return ' ' + rdb.lastInsertedSql(table); + return ''; } - for (let name in table._relations) { - if (!isJoinRelation(name, table)) - result[name] = getMetaDataTable(table._relations[name].childTable, inferOptions(options, name)); + + function outputInserted() { + let rdb = getSessionContext(context); + if (!rdb.lastInsertedIsSeparate && rdb.outputInsertedSql) + return ' ' + rdb.outputInsertedSql(table) + ' '; + return ''; } - return result; + function defaultValues() { + let rdb = getSessionContext(context); + let _default = rdb.insertDefault || 'DEFAULT VALUES'; + return `${_default}${lastInserted()}`; - function isJoinRelation(name, table) { - return table[name] && table[name]._relation.columns; } } - async function query() { - return netAdapter(baseUrl, undefined, { tableOptions: { db: baseUrl, transaction } }).query.apply(null, arguments); - } + getSqlTemplate_1 = getSqlTemplate; + return getSqlTemplate_1; +} - function express(arg) { - if (providers.express) { - return providers.express(client, { ...options, ...arg }); +var newInsertCommandCore_1; +var hasRequiredNewInsertCommandCore; + +function requireNewInsertCommandCore () { + if (hasRequiredNewInsertCommandCore) return newInsertCommandCore_1; + hasRequiredNewInsertCommandCore = 1; + const newParameterized = requireNewParameterized(); + const getSqlTemplate = requireGetSqlTemplate(); + const formatString = requireFormat(); + + function newInsertCommandCore(context, table, row, options = {}) { + let parameters = []; + let values = [getSqlTemplate(context, table, row, options)]; + + let columns = table._columns; + for (let i = 0; i < columns.length; i++) { + let column = columns[i]; + let alias = column.alias; + if (row['__' + column.alias] !== undefined) { + let encoded = column.encode(context, row[alias]); + if (encoded.parameters.length > 0) { + values.push('?'); + parameters.push(encoded.parameters[0]); + } else + values.push(encoded.sql()); + } } - else - throw new Error('Cannot host express clientside'); - } + let sql = formatString.apply(null, values); + return newParameterized(sql, parameters); + } + newInsertCommandCore_1 = newInsertCommandCore; + return newInsertCommandCore_1; +} - function _createPatch(original, modified, ...restArgs) { - if (!Array.isArray(original)) { - original = [original]; - modified = [modified]; +var newGetLastInsertedCommandCore_1; +var hasRequiredNewGetLastInsertedCommandCore; + +function requireNewGetLastInsertedCommandCore () { + if (hasRequiredNewGetLastInsertedCommandCore) return newGetLastInsertedCommandCore_1; + hasRequiredNewGetLastInsertedCommandCore = 1; + const newParameterized = requireNewParameterized(); + const getSessionContext = requireGetSessionContext(); + const newDiscriminatorSql = requireNewDiscriminatorSql$1(); + const quote = requireQuote$1(); + + function newGetLastInsertedCommandCore(context, table, row) { + let parameters = []; + let keyValues = table._primaryColumns.map(column => row['__' + column.alias]); + let sql = `SELECT ${columnNames()} FROM ${quote(context, table._dbName)} WHERE ${whereSql()}`; + return newParameterized(sql, parameters); + + function columnNames() { + return table._columns.map(col => quote(context, col._dbName)).join(','); } - let args = [original, modified, ...restArgs]; - return createPatch(...args); - } - async function getDb() { - let db = baseUrl; - if (typeof db === 'function') { - let dbPromise = db(); - if (dbPromise.then) - db = await dbPromise; + function whereSql() { + let parameterized; + let filter = getSessionContext(context).lastInsertedSql(context, table, keyValues); + if (Array.isArray(filter)) { + for (let i = 0; i < filter.length; i++) { + const sep = i === 0 ? '' : ' AND '; + if (!filter[i].sql) { + const sql = filter[i]; + filter[i] = {sql : () => sql}; + } + let next = newParameterized(sep + filter[i].sql(), filter[i].parameters); + if (parameterized) + parameterized = parameterized.append(next); + else + parameterized = next; + } + } else - db = dbPromise; + parameterized = newParameterized(filter); + parameters = parameters.concat(parameterized.parameters); + return [discriminators(), parameterized.sql()].filter(x => x).join(' AND '); } - return db; - } - - async function runInTransaction(fn, _options) { - let db = await getDb(); - if (!db.createTransaction) - throw new Error('Transaction not supported through http'); - const transaction = db.createTransaction(_options); - try { - const nextClient = client({ transaction }); - await fn(nextClient); - await transaction(db.commit); - } - catch (e) { - await transaction(db.rollback.bind(null, e)); + function discriminators() { + return newDiscriminatorSql(context, table, table._dbName); } } - function table(url, tableName, tableOptions) { - tableOptions = tableOptions || {}; - tableOptions = { db: baseUrl, ...tableOptions, transaction }; - let meta; - let c = { - count, - getMany, - aggregate: groupBy, - getAll, - getOne, - getById, - proxify, - update, - replace, - updateChanges, - insert, - insertAndForget, - delete: _delete, - deleteCascade, - patch, - expand, - }; + newGetLastInsertedCommandCore_1 = newGetLastInsertedCommandCore; + return newGetLastInsertedCommandCore_1; +} +var newGetLastInsertedCommand_1; +var hasRequiredNewGetLastInsertedCommand; - let handler = { - get(_target, property,) { - if (property in c) - return Reflect.get(...arguments); - else - return column(property); - } +function requireNewGetLastInsertedCommand () { + if (hasRequiredNewGetLastInsertedCommand) return newGetLastInsertedCommand_1; + hasRequiredNewGetLastInsertedCommand = 1; + var newGetLastInsertedCommandCore = requireNewGetLastInsertedCommandCore(); + var newImmutable = requireNewImmutable(); - }; - let _table = new Proxy(c, handler); - return _table; + function newGetLastInsertedCommand(context, table, row, insertCommand) { + let cmd = new InsertCommand(context, table, row, insertCommand); + insertCommand.endEdit = () => {}; + return cmd; + } - function expand() { - return c; - } + function InsertCommand(context, table, row, insertCommand) { + this._insertCommand = insertCommand; + this.__getCoreCommand = newImmutable(newGetLastInsertedCommandCore.bind(null, context)); + this._table = table; + this._row = row; + } - async function getAll() { - let _getMany = getMany.bind(null, undefined); - return _getMany.apply(null, arguments); - } + InsertCommand.prototype._getCoreCommand = function() { + return this.__getCoreCommand(this._table, this._row); + }; - async function getMany(_, strategy) { - let metaPromise = getMeta(); - strategy = extractFetchingStrategy({}, strategy); - let args = [_, strategy].concat(Array.prototype.slice.call(arguments).slice(2)); - let rows = await getManyCore.apply(null, args); - await metaPromise; - return proxify(rows, strategy, true); - } + InsertCommand.prototype.sql = function() { + return this._getCoreCommand().sql(); + }; - async function groupBy(strategy) { - let args = negotiateGroupBy(null, strategy); - let body = stringify({ - path: 'aggregate', - args - }); - let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); - return adapter.post(body); - } + InsertCommand.prototype.matches = function(otherRow) { + return this._row === otherRow; + }; + + + InsertCommand.prototype.endEdit = function() { + this._insertCommand.endEdit(); + this.sql(); + }; + + Object.defineProperty(InsertCommand.prototype, 'parameters', { + get: function() { + return this._getCoreCommand().parameters; - async function count(_) { - let args = [_].concat(Array.prototype.slice.call(arguments).slice(1)); - let body = stringify({ - path: 'count', - args - }); - let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); - return adapter.post(body); - } - - async function getOne(filter, strategy) { - let metaPromise = getMeta(); - strategy = extractFetchingStrategy({}, strategy); - let _strategy = { ...strategy, ...{ limit: 1 } }; - let args = [filter, _strategy].concat(Array.prototype.slice.call(arguments).slice(2)); - let rows = await getManyCore.apply(null, args); - await metaPromise; - if (rows.length === 0) - return; - return proxify(rows[0], strategy, true); } + }); - async function getById() { - if (arguments.length === 0) - return; - let meta = await getMeta(); - let keyFilter = client.filter; - for (let i = 0; i < meta.keys.length; i++) { - let keyName = meta.keys[i].name; - let keyValue = arguments[i]; - keyFilter = keyFilter.and(_table[keyName].eq(keyValue)); - } - let args = [keyFilter].concat(Array.prototype.slice.call(arguments).slice(meta.keys.length)); - return getOne.apply(null, args); - } - - async function getManyCore() { - let args = negotiateWhere.apply(null, arguments); - let body = stringify({ - path: 'getManyDto', - args - }); - let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); - return adapter.post(body); + Object.defineProperty(InsertCommand.prototype, 'disallowCompress', { + get: function() { + return true; } + }); - function negotiateWhere(_, strategy, ...rest) { - const args = Array.prototype.slice.call(arguments); - if (strategy) - return [_, negotiateWhereSingle(strategy), ...rest]; - else - return args; + newGetLastInsertedCommand_1 = newGetLastInsertedCommand; + return newGetLastInsertedCommand_1; +} - } +var insert; +var hasRequiredInsert; - function negotiateWhereSingle(_strategy, path = '') { - if (typeof _strategy !== 'object' || _strategy === null) - return _strategy; +function requireInsert () { + if (hasRequiredInsert) return insert; + hasRequiredInsert = 1; + let newInsertCommand = requireNewInsertCommand(); + let newInsertCommandCore = requireNewInsertCommandCore(); + let newGetLastInsertedCommand = requireNewGetLastInsertedCommand(); + let executeQueries = requireExecuteQueries(); + let pushCommand = requirePushCommand(); - if (Array.isArray(_strategy)) { - return _strategy.map(item => negotiateWhereSingle(item, path)); - } - const strategy = { ..._strategy }; - for (let name in _strategy) { - if (name === 'where' && typeof strategy[name] === 'function') - strategy.where = column(path + 'where')(strategy.where); // Assuming `column` is defined elsewhere. - else if (typeof strategy[name] === 'function') { - strategy[name] = aggregate(path, strategy[name]); - } - else - strategy[name] = negotiateWhereSingle(_strategy[name], path + name + '.'); - } - return strategy; - } + function insertDefault(context, table, row, options) { + let commands = []; + let insertCmd = newInsertCommand(newInsertCommandCore.bind(null, context), table, row, options); + insertCmd.disallowCompress = true; + pushCommand(context, insertCmd); + let selectCmd = newGetLastInsertedCommand(context, table, row, insertCmd); + commands.push(selectCmd); + return executeQueries(context, commands).then((result) => result[result.length - 1]); - function negotiateGroupBy(_, strategy, ...rest) { - const args = Array.prototype.slice.call(arguments); - if (strategy) - return [_, where(strategy), ...rest]; - else - return args; + } - function where(_strategy, path = '') { - if (typeof _strategy !== 'object' || _strategy === null) - return _strategy; + insert = insertDefault; + return insert; +} - if (Array.isArray(_strategy)) { - return _strategy.map(item => where(item, path)); +var newTransaction; +var hasRequiredNewTransaction; + +function requireNewTransaction () { + if (hasRequiredNewTransaction) return newTransaction; + hasRequiredNewTransaction = 1; + const wrapQuery = requireWrapQuery(); + const encodeBoolean = requireEncodeBoolean(); + const deleteFromSql = requireDeleteFromSql(); + const selectForUpdateSql = requireSelectForUpdateSql(); + const lastInsertedSql = requireLastInsertedSql(); + const limitAndOffset = requireLimitAndOffset(); + const insertSql = requireInsertSql(); + const insert = requireInsert(); + + function newResolveTransaction(domain, pool, { readonly = false } = {}) { + var rdb = {poolFactory: pool}; + if (!pool.connect) { + pool = pool(); + rdb.pool = pool; + } + rdb.engine = 'sqlite'; + rdb.maxParameters = 100; + rdb.encodeBoolean = encodeBoolean; + rdb.decodeJSON = decodeJSON; + rdb.encodeJSON = JSON.stringify; + rdb.deleteFromSql = deleteFromSql; + rdb.selectForUpdateSql = selectForUpdateSql; + rdb.lastInsertedSql = lastInsertedSql; + rdb.insertSql = insertSql; + rdb.insert = insert; + rdb.lastInsertedIsSeparate = true; + rdb.multipleStatements = false; + rdb.limitAndOffset = limitAndOffset; + rdb.accept = function(caller) { + caller.visitSqlite(); + }; + rdb.aggregateCount = 0; + rdb.quote = (name) => `"${name}"`; + + if (readonly) { + rdb.dbClient = { + executeQuery: function(query, callback) { + pool.connect((err, client, done) => { + if (err) { + return callback(err); + } + try { + wrapQuery(client)(query, (err, res) => { + done(); + callback(err, res); + }); + } catch (e) { + done(); + callback(e); + } + }); } + }; + domain.rdb = rdb; + return (onSuccess) => onSuccess(); + } - const strategy = { ..._strategy }; - for (let name in _strategy) { - if (name === 'where' && typeof strategy[name] === 'function') - strategy.where = column(path + 'where')(strategy.where); // Assuming `column` is defined elsewhere. - else if (typeof strategy[name] === 'function') { - strategy[name] = groupByAggregate(path, strategy[name]); + return function(onSuccess, onError) { + pool.connect(onConnected); + + function onConnected(err, client, done) { + try { + if (err) { + onError(err); + return; } - else - strategy[name] = where(_strategy[name], path + name + '.'); + client.executeQuery = wrapQuery(client); + rdb.dbClient = client; + rdb.dbClientDone = done; + domain.rdb = rdb; + onSuccess(); + } catch (e) { + onError(e); } - return strategy; } + }; + } - } - - - - - - async function _delete() { - let args = Array.prototype.slice.call(arguments); - let body = stringify({ - path: 'delete', - args - }); - let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); - return adapter.post(body); - } + function decodeJSON(value) { + return JSON.parse(value); + } - async function deleteCascade() { - let args = Array.prototype.slice.call(arguments); - let body = stringify({ - path: 'deleteCascade', - args - }); - let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); - return adapter.post(body); - } + newTransaction = newResolveTransaction; + return newTransaction; +} - async function update(_row, _where, strategy) { - let args = [_row, negotiateWhereSingle(_where), negotiateWhereSingle(strategy)]; - let body = stringify({ - path: 'update', - args - }); - let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); - const result = await adapter.post(body); - if (strategy) - return proxify(result, strategy); - } +var beginCommand; +var hasRequiredBeginCommand; - async function replace(_row, strategy) { - let args = [_row, negotiateWhereSingle(strategy)]; - let body = stringify({ - path: 'replace', - args - }); - let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); - const result = await adapter.post(body); - if (strategy) - return proxify(result, strategy); - } +function requireBeginCommand () { + if (hasRequiredBeginCommand) return beginCommand; + hasRequiredBeginCommand = 1; + let newParameterized = requireNewParameterized(); + let getSessionContext = requireGetSessionContext(); - async function updateChanges(rows, oldRows, ...rest) { - const concurrency = undefined; - const args = [concurrency].concat(rest); - if (Array.isArray(rows)) { - const proxy = await getMany.apply(null, [rows, ...rest]); - proxy.splice.apply(proxy, [0, proxy.length, ...rows]); - await proxy.saveChanges.apply(proxy, args); - return proxy; - } - else { - let proxy = proxify([oldRows], args[0]); - proxy.splice.apply(proxy, [0, 1, rows]); - await proxy.saveChanges.apply(proxy, args); - return proxify(proxy[0], args[0]); - } - } + beginCommand = function(context) { + let command = newParameterized(getSessionContext(context).begin || 'BEGIN'); + command.endEdit = empty; + command.matches = empty; - async function insert(rows, ...rest) { - const concurrency = undefined; - const args = [concurrency].concat(rest); - if (Array.isArray(rows)) { - let proxy = proxify([], rest[0]); - proxy.splice.apply(proxy, [0, 0, ...rows]); - await proxy.saveChanges.apply(proxy, args); - return proxy; - } - else { - let proxy = proxify([], args[0]); - proxy.splice.apply(proxy, [0, 0, rows]); - await proxy.saveChanges.apply(proxy, args); - return proxify(proxy[0], rest[0]); - } - } + function empty() {} - async function insertAndForget(rows) { - const concurrency = undefined; - let args = [concurrency, { insertAndForget: true }]; - if (Array.isArray(rows)) { - let proxy = proxify([], args[0]); - proxy.splice.apply(proxy, [0, 0, ...rows]); - await proxy.saveChanges.apply(proxy, args); - } - else { - let proxy = proxify([], args[0]); - proxy.splice.apply(proxy, [0, 0, rows]); - await proxy.saveChanges.apply(proxy, args); - } - } + return command; + }; + return beginCommand; +} - function proxify(itemOrArray, strategy, fast) { - if (Array.isArray(itemOrArray)) - return proxifyArray(itemOrArray, strategy, fast); - else - return proxifyRow(itemOrArray, strategy, fast); +var begin_1; +var hasRequiredBegin; + +function requireBegin () { + if (hasRequiredBegin) return begin_1; + hasRequiredBegin = 1; + let beginCommand = requireBeginCommand(); + let executeQuery = requireExecuteQuery(); + let setSessionSingleton = requireSetSessionSingleton(); + + function begin(context, transactionLess) { + setSessionSingleton(context, 'changes', []); + if (transactionLess) { + setSessionSingleton(context, 'transactionLess', true); + return Promise.resolve(); } + return executeQuery(context, beginCommand(context)); + } - function proxifyArray(array, strategy, fast) { - let _array = array; - if (_reactive) - array = _reactive(array); - let handler = { - get(_target, property) { - if (property === 'toJSON') - return () => { - return toJSON(array); - }; - else if (property === 'save' || property === 'saveChanges') - return saveArray.bind(null, array); - else if (property === 'delete') - return deleteArray.bind(null, array); - else if (property === 'refresh') - return refreshArray.bind(null, array); - else if (property === 'clearChanges') - return clearChangesArray.bind(null, array); - else if (property === 'acceptChanges') - return acceptChangesArray.bind(null, array); - else if (property === targetKey) - return _array; - else - return Reflect.get.apply(_array, arguments); - } + begin_1 = begin; + return begin_1; +} - }; +var promisify_1; +var hasRequiredPromisify; - let watcher = onChange(array, () => { - rootMap.set(array, { json: cloneFromDb(array, fast), strategy, originalArray: [...array] }); - }); - let innerProxy = new Proxy(watcher, handler); - if (strategy !== undefined) { - const { limit, ...cleanStrategy } = { ...strategy }; - fetchingStrategyMap.set(array, cleanStrategy); - } - return innerProxy; +function requirePromisify () { + if (hasRequiredPromisify) return promisify_1; + hasRequiredPromisify = 1; + function promisify(original) { + if (typeof original !== 'function') { + throw new TypeError('The "original" argument must be of type Function'); } - function proxifyRow(row, strategy, fast) { - let handler = { - get(_target, property,) { - if (property === 'save' || property === 'saveChanges') //call server then acceptChanges - return saveRow.bind(null, row); - else if (property === 'delete') //call server then remove from json and original - return deleteRow.bind(null, row); - else if (property === 'refresh') //refresh from server then acceptChanges - return refreshRow.bind(null, row); - else if (property === 'clearChanges') //refresh from json, update original if present - return clearChangesRow.bind(null, row); - else if (property === 'acceptChanges') //remove from json - return acceptChangesRow.bind(null, row); - else if (property === 'toJSON') - return () => { - return toJSON(row); - }; - else if (property === targetKey) - return row; - else - return Reflect.get(...arguments); + return function(...args) { + return new Promise((resolve, reject) => { + // Add the callback that Node-style APIs expect + function callback(err, ...values) { + if (err) { + return reject(err); + } + // If there's exactly one success value, return it; + // otherwise, return all values as an array. + return resolve(values.length > 1 ? values : values[0]); } - }; - let watcher = onChange(row, () => { - rootMap.set(row, { json: cloneFromDb(row, fast), strategy }); + // Call the original function, appending our callback + original.call(this, ...args, callback); }); - let innerProxy = new Proxy(watcher, handler); - fetchingStrategyMap.set(row, strategy); - return innerProxy; - } + }; + } - function toJSON(row, _meta = meta) { - if (!row) - return null; - if (!_meta) - return row; - if (Array.isArray(row)) { - return row.map(x => toJSON(x, _meta)); - } - let result = {}; - for (let name in row) { - if (name in _meta.relations) - result[name] = toJSON(row[name], _meta.relations[name]); - else if (name in _meta.columns) { - if (_meta.columns[name].serializable) - result[name] = row[name]; - } - else - result[name] = row[name]; - } - return result; - } + promisify_1 = promisify; + return promisify_1; +} +var end; +var hasRequiredEnd; +function requireEnd () { + if (hasRequiredEnd) return end; + hasRequiredEnd = 1; + var pools = requirePools(); + function endPool(genericPool, id, done) { + genericPool.drain(onDrained); - async function getMeta() { - if (meta) - return meta; - let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); - meta = await adapter.get(); + function onDrained() { + genericPool.destroyAllNow(); + delete pools[id]; + done(); + } + } - while (hasUnresolved(meta)) { - meta = parseMeta(meta); - } - return meta; + end = endPool; + return end; +} - function parseMeta(meta, map = new Map()) { - if (typeof meta === 'number') { - return map.get(meta) || meta; - } - map.set(meta.id, meta); - for (let p in meta.relations) { - meta.relations[p] = parseMeta(meta.relations[p], map); - } - return meta; - } +var poolDefaults; +var hasRequiredPoolDefaults; - function hasUnresolved(meta, set = new WeakSet()) { - if (typeof meta === 'number') - return true; - else if (set.has(meta)) - return false; - else { - set.add(meta); - return Object.values(meta.relations).reduce((prev, current) => { - return prev || hasUnresolved(current, set); - }, false); - } - } +function requirePoolDefaults () { + if (hasRequiredPoolDefaults) return poolDefaults; + hasRequiredPoolDefaults = 1; + poolDefaults = { + //Connection pool options - see https://github.com/coopernurse/node-pool + //number of connections to use in connection pool + //0 will disable connection pooling + poolSize: 0, + //max milliseconds a client can go unused before it is removed + //from the pool and destroyed + poolIdleTimeout: 30000, - } + //frequeny to check for idle clients within the client pool + reapIntervalMillis: 1000, - async function saveArray(array, concurrencyOptions, strategy) { - let deduceStrategy = false; - let json = rootMap.get(array)?.json; - if (!json) - return; - strategy = extractStrategy({ strategy }, array); - strategy = extractFetchingStrategy(array, strategy); + }; + return poolDefaults; +} - let meta = await getMeta(); - const patch = createPatch(json, array, meta); - if (patch.length === 0) - return; - let body = stringify({ patch, options: { strategy, ...tableOptions, ...concurrencyOptions, deduceStrategy } }); - let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); - let p = adapter.patch(body); - if (strategy?.insertAndForget) { - await p; - return; - } +/* eslint-disable @typescript-eslint/no-this-alias */ + +var genericPool; +var hasRequiredGenericPool; + +function requireGenericPool () { + if (hasRequiredGenericPool) return genericPool; + hasRequiredGenericPool = 1; + /* @ts-nocheck */ + + /** + * A helper function to schedule a callback in a cross-platform manner: + * - Uses setImmediate if available (Node). + * - Else uses queueMicrotask if available (Deno, modern browsers). + * - Else falls back to setTimeout(fn, 0). + */ + function queueTask(fn) { + if (typeof setImmediate === 'function') { + setImmediate(fn); + } + else if + (typeof queueMicrotask === 'function') { + queueMicrotask(fn); + } else { + setTimeout(fn, 0); + } + } - let updatedPositions = extractChangedRowsPositions(array, patch, meta); - let insertedPositions = getInsertedRowsPosition(array); - let { changed, strategy: newStrategy } = await p; - copyIntoArray(changed, array, [...insertedPositions, ...updatedPositions]); - rootMap.set(array, { json: cloneFromDb(array), strategy: newStrategy, originalArray: [...array] }); + /** + * @class + * @private + */ + function PriorityQueue(size) { + if (!(this instanceof PriorityQueue)) { + return new PriorityQueue(size); } - async function patch(patch, concurrencyOptions, strategy) { - let deduceStrategy = false; - if (patch.length === 0) - return; - let body = stringify({ patch, options: { strategy, ...tableOptions, ...concurrencyOptions, deduceStrategy } }); - let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); - await adapter.patch(body); - return; + this._size = Math.max(+size | 0, 1); + this._slots = []; + this._total = null; + + // initialize arrays to hold queue elements + for (let i = 0; i < this._size; i += 1) { + this._slots.push([]); } + } - function extractChangedRowsPositions(rows, patch, meta) { - const positions = []; - const originalSet = new Set(rootMap.get(rows).originalArray); - const positionsAdded = {}; - const keyPositionMap = toKeyPositionMap(rows, meta); - for (let i = 0; i < patch.length; i++) { - const element = patch[i]; - const pathArray = element.path.split('/'); - const position = keyPositionMap[pathArray[1]]; - if (position >= 0 && originalSet.has(rows[position]) && !positionsAdded[position]) { - positions.push(position); - positionsAdded[position] = true; - } + PriorityQueue.prototype.size = function size() { + if (this._total === null) { + this._total = 0; + for (let i = 0; i < this._size; i += 1) { + this._total += this._slots[i].length; } - return positions; } + return this._total; + }; - function getInsertedRowsPosition(array) { - const positions = []; - const originalSet = new Set(rootMap.get(array).originalArray); - for (let i = 0; i < array.length; i++) { - if (!originalSet.has(array[i])) - positions.push(i); - } - return positions; + PriorityQueue.prototype.enqueue = function enqueue(obj, priority) { + // Convert to integer with a default value of 0. + priority = priority && +priority | 0 || 0; + this._total = null; + if (priority < 0 || priority >= this._size) { + console.error( + 'invalid priority: ' + priority + ' must be between 0 and ' + (this._size - 1) + ); + priority = this._size - 1; // put obj at the end of the line } + this._slots[priority].push(obj); + }; - function copyInto(from, to) { - for (let i = 0; i < from.length; i++) { - for (let p in from[i]) { - to[i][p] = from[i][p]; - } + PriorityQueue.prototype.dequeue = function dequeue() { + let obj = null; + this._total = null; + for (let i = 0, sl = this._slots.length; i < sl; i += 1) { + if (this._slots[i].length) { + obj = this._slots[i].shift(); + break; } } + return obj; + }; - function copyIntoArray(from, to, positions) { - for (let i = 0; i < from.length; i++) { - to[positions[i]] = from[i]; + function doWhileAsync(conditionFn, iterateFn, callbackFn) { + const next = function() { + if (conditionFn()) { + iterateFn(next); + } else { + callbackFn(); } + }; + next(); + } + + /** + * Generate an Object pool with a specified `factory`. + * + * @class + * @param {Object} factory + * Factory to be used for generating and destroying the items. + * @param {String} factory.name + * @param {Function} factory.create + * @param {Function} factory.destroy + * @param {Function} factory.validate + * @param {Function} factory.validateAsync + * @param {Number} factory.max + * @param {Number} factory.min + * @param {Number} factory.idleTimeoutMillis + * @param {Number} factory.reapIntervalMillis + * @param {Boolean|Function} factory.log + * @param {Number} factory.priorityRange + * @param {Boolean} factory.refreshIdle + * @param {Boolean} [factory.returnToHead=false] + */ + function Pool(factory) { + if (!(this instanceof Pool)) { + return new Pool(factory); + } + if (factory.validate && factory.validateAsync) { + throw new Error('Only one of validate or validateAsync may be specified'); } + // defaults + factory.idleTimeoutMillis = factory.idleTimeoutMillis || 30000; + factory.returnToHead = factory.returnToHead || false; + factory.refreshIdle = ('refreshIdle' in factory) ? factory.refreshIdle : true; + factory.reapInterval = factory.reapIntervalMillis || 1000; + factory.priorityRange = factory.priorityRange || 1; + factory.validate = factory.validate || function() { + return true; + }; + + factory.max = parseInt(factory.max, 10); + factory.min = parseInt(factory.min, 10); + factory.max = Math.max(isNaN(factory.max) ? 1 : factory.max, 1); + factory.min = Math.min(isNaN(factory.min) ? 0 : factory.min, factory.max - 1); + + this._factory = factory; + this._inUseObjects = []; + this._draining = false; + this._waitingClients = new PriorityQueue(factory.priorityRange); + this._availableObjects = []; + this._asyncTestObjects = []; + this._count = 0; + this._removeIdleTimer = null; + this._removeIdleScheduled = false; + + // create initial resources (if factory.min > 0) + this._ensureMinimum(); + } - function extractStrategy(options, obj) { - if (options?.strategy !== undefined) - return options.strategy; - if (obj) { - let context = rootMap.get(obj); - if (context?.strategy !== undefined) { - // @ts-ignore - let { limit, ...strategy } = { ...context.strategy }; - return strategy; - } - } + /** + * logs to console or user-defined log function + * @private + * @param {string} str + * @param {string} level + */ + Pool.prototype._log = function _log(str, level) { + if (typeof this._factory.log === 'function') { + this._factory.log(str, level); + } else if (this._factory.log) { + console.log(level.toUpperCase() + ' pool ' + this._factory.name + ' - ' + str); } + }; - function extractFetchingStrategy(obj, strategy) { - if (strategy !== undefined) - return strategy; - else if (fetchingStrategyMap.get(obj) !== undefined) { - // @ts-ignore - const { limit, ...strategy } = { ...fetchingStrategyMap.get(obj) }; - return strategy; + /** + * Request the client to be destroyed. The factory's destroy handler + * will also be called. + * + * This should be called within an acquire() block as an alternative to release(). + * + * @param {Object} obj + * The acquired item to be destroyed. + * @param {Function} [cb] + * Optional. Callback invoked after client is destroyed + */ + Pool.prototype.destroy = function destroy(obj, cb) { + this._count -= 1; + if (this._count < 0) this._count = 0; + + this._availableObjects = this._availableObjects.filter( + (objWithTimeout) => objWithTimeout.obj !== obj + ); + this._inUseObjects = this._inUseObjects.filter( + (objInUse) => objInUse !== obj + ); + + this._factory.destroy(obj, cb); + + // keep compatibility with old interface + if (this._factory.destroy.length === 1 && cb && typeof cb === 'function') { + cb(); + } + + this._ensureMinimum(); + }; + + /** + * Checks and removes the available (idle) clients that have timed out. + * @private + */ + Pool.prototype._removeIdle = function _removeIdle() { + const now = new Date().getTime(); + const refreshIdle = this._factory.refreshIdle; + const maxRemovable = this._count - this._factory.min; + const toRemove = []; + + this._removeIdleScheduled = false; + + for (let i = 0; i < this._availableObjects.length; i++) { + const objWithTimeout = this._availableObjects[i]; + if ( + now >= objWithTimeout.timeout && + (refreshIdle || toRemove.length < maxRemovable) + ) { + this._log( + 'removeIdle() destroying obj - now:' + + now + + ' timeout:' + + objWithTimeout.timeout, + 'verbose' + ); + toRemove.push(objWithTimeout.obj); } } - function clearChangesArray(array) { - let json = rootMap.get(array)?.json; - if (!json) - return; - let old = cloneFromDb(json); - array.splice(0, old.length, ...old); + toRemove.forEach((obj) => this.destroy(obj)); + + if (this._availableObjects.length > 0) { + this._log( + 'this._availableObjects.length=' + this._availableObjects.length, + 'verbose' + ); + this._scheduleRemoveIdle(); + } else { + this._log('removeIdle() all objects removed', 'verbose'); } + }; - function acceptChangesArray(array) { - const map = rootMap.get(array); - if (!map) - return; - map.json = cloneFromDb(array); - map.originalArray = [...array]; + /** + * Schedule removal of idle items in the pool. + * + * More schedules cannot run concurrently. + */ + Pool.prototype._scheduleRemoveIdle = function _scheduleRemoveIdle() { + if (!this._removeIdleScheduled) { + this._removeIdleScheduled = true; + this._removeIdleTimer = setTimeout(() => { + this._removeIdle(); + }, this._factory.reapInterval); } + }; - async function deleteArray(array, options) { - if (array.length === 0) - return; - let meta = await getMeta(); - let patch = createPatch(array, [], meta); - let body = stringify({ patch, options }); - let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); - let { strategy } = await adapter.patch(body); - array.length = 0; - rootMap.set(array, { json: cloneFromDb(array), strategy }); + /** + * Try to get a new client to work, and clean up pool unused (idle) items. + * + * - If there are available clients waiting, shift the first one out, + * and call its callback. + * - If there are no waiting clients, try to create one if it won't exceed + * the maximum number of clients. + * - If creating a new client would exceed the maximum, add the client to + * the wait list. + * @private + */ + Pool.prototype._dispense = function _dispense() { + const waitingCount = this._waitingClients.size(); + this._log( + 'dispense() clients=' + + waitingCount + + ' available=' + + this._availableObjects.length, + 'info' + ); + + if (waitingCount < 1) { + return; } - function setMapValue(rowsMap, keys, row, index) { - let keyValue = row[keys[0].name]; - if (keys.length > 1) { - let subMap = rowsMap.get(keyValue); - if (!subMap) { - subMap = new Map(); - rowsMap.set(keyValue, subMap); + if (this._factory.validateAsync) { + doWhileAsync( + () => this._availableObjects.length > 0, + this._createAsyncValidator(), + () => { + if (this._count < this._factory.max) { + this._createResource(); + } } - setMapValue(subMap, keys.slice(1), row, index); + ); + return; + } + + while (this._availableObjects.length > 0) { + this._log('dispense() - reusing obj', 'verbose'); + const objWithTimeout = this._availableObjects[0]; + + if (!this._factory.validate(objWithTimeout.obj)) { + this.destroy(objWithTimeout.obj); + continue; } - else - rowsMap.set(keyValue, index); + + this._availableObjects.shift(); + this._inUseObjects.push(objWithTimeout.obj); + const clientCb = this._waitingClients.dequeue(); + return clientCb(null, objWithTimeout.obj); } - function getMapValue(rowsMap, keys, row) { - let keyValue = row[keys[0].name]; - if (keys.length > 1) - return getMapValue(rowsMap.get(keyValue), keys.slice(1)); - else - return rowsMap.get(keyValue); + if (this._count < this._factory.max) { + this._createResource(); } + }; - async function refreshArray(array, strategy) { - clearChangesArray(array); - strategy = extractStrategy({ strategy }, array); - strategy = extractFetchingStrategy(array, strategy); - if (array.length === 0) - return; - let meta = await getMeta(); - let filter = client.filter; - let rowsMap = new Map(); - for (let rowIndex = 0; rowIndex < array.length; rowIndex++) { - let row = array[rowIndex]; - let keyFilter = client.filter; - for (let i = 0; i < meta.keys.length; i++) { - let keyName = meta.keys[i].name; - let keyValue = row[keyName]; - keyFilter = keyFilter.and(_table[keyName].eq(keyValue)); + Pool.prototype._createAsyncValidator = function _createAsyncValidator() { + return (next) => { + this._log('dispense() - reusing obj', 'verbose'); + const objWithTimeout = this._availableObjects.shift(); + this._asyncTestObjects.push(objWithTimeout); + + this._factory.validateAsync(objWithTimeout.obj, (valid) => { + const pos = this._asyncTestObjects.indexOf(objWithTimeout); + this._asyncTestObjects.splice(pos, 1); + + if (!valid) { + this.destroy(objWithTimeout.obj); + return next(); + } + if (this._waitingClients.size() < 1) { + // no longer anyone waiting for a resource + this._addResourceToAvailableObjects(objWithTimeout.obj); + return; } - setMapValue(rowsMap, meta.keys, row, rowIndex); - filter = filter.or(keyFilter); + + this._inUseObjects.push(objWithTimeout.obj); + const clientCb = this._waitingClients.dequeue(); + clientCb(null, objWithTimeout.obj); + }); + }; + }; + + /** + * @private + */ + Pool.prototype._createResource = function _createResource() { + this._count += 1; + this._log( + 'createResource() - creating obj - count=' + + this._count + + ' min=' + + this._factory.min + + ' max=' + + this._factory.max, + 'verbose' + ); + + this._factory.create((...args) => { + let err, obj; + if (args.length > 1) { + [err, obj] = args; + } else { + err = args[0] instanceof Error ? args[0] : null; + obj = args[0] instanceof Error ? null : args[0]; } - let rows = await getManyCore(filter, strategy); - let removedIndexes = new Set(); - if (array.length !== rows.length) - for (var i = 0; i < array.length; i++) { - removedIndexes.add(i); + + const clientCb = this._waitingClients.dequeue(); + + if (err) { + this._count -= 1; + if (this._count < 0) this._count = 0; + if (clientCb) { + clientCb(err, obj); + } + // queueTask to simulate process.nextTick + queueTask(() => { + this._dispense(); + }); + } else { + this._inUseObjects.push(obj); + if (clientCb) { + clientCb(null, obj); + } else { + this._addResourceToAvailableObjects(obj); } - for (let i = 0; i < rows.length; i++) { - let row = rows[i]; - let originalIndex = getMapValue(rowsMap, meta.keys, row); - if (array.length !== rows.length) - removedIndexes.delete(originalIndex); - array[originalIndex] = row; } - let offset = 0; - for (let i of removedIndexes) { - array.splice(i + offset, 1); - offset--; + }); + }; + + Pool.prototype._addResourceToAvailableObjects = function(obj) { + const objWithTimeout = { + obj, + timeout: new Date().getTime() + this._factory.idleTimeoutMillis, + }; + if (this._factory.returnToHead) { + this._availableObjects.unshift(objWithTimeout); + } else { + this._availableObjects.push(objWithTimeout); + } + this._dispense(); + this._scheduleRemoveIdle(); + }; + + /** + * @private + */ + Pool.prototype._ensureMinimum = function _ensureMinimum() { + if (!this._draining && this._count < this._factory.min) { + const diff = this._factory.min - this._count; + for (let i = 0; i < diff; i++) { + this._createResource(); } - rootMap.set(array, { json: cloneFromDb(array), strategy, originalArray: [...array] }); - fetchingStrategyMap.set(array, strategy); } + }; - async function deleteRow(row, options) { - let strategy = extractStrategy(options, row); - let meta = await getMeta(); - let patch = createPatch([row], [], meta); - let body = stringify({ patch, options }); - let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); - await adapter.patch(body); - rootMap.set(row, { strategy }); + /** + * Request a new client. The callback will be called + * when a new client is available. + * + * @param {Function} callback + * @param {Number} [priority] + * @returns {Boolean} true if the pool is not fully utilized, false otherwise + */ + Pool.prototype.acquire = function acquire(callback, priority) { + if (this._draining) { + throw new Error('pool is draining and cannot accept work'); } + this._waitingClients.enqueue(callback, priority); + this._dispense(); + return this._count < this._factory.max; + }; - async function saveRow(row, concurrencyOptions, strategy) { - let deduceStrategy; - if (arguments.length < 3) - deduceStrategy = false; - strategy = extractStrategy({ strategy }, row); - strategy = extractFetchingStrategy(row, strategy); + /** + * @deprecated + */ + Pool.prototype.borrow = function borrow(callback, priority) { + this._log('borrow() is deprecated. use acquire() instead', 'warn'); + return this.acquire(callback, priority); + }; - let json = rootMap.get(row)?.json; - if (!json) - return; - let meta = await getMeta(); + /** + * Return the client to the pool, indicating it is no longer needed. + * + * @param {Object} obj + */ + Pool.prototype.release = function release(obj) { + // Check whether this object has already been released + const alreadyReleased = this._availableObjects.some(o => o.obj === obj); + if (alreadyReleased) { + this._log( + 'release called twice for the same resource: ' + new Error().stack, + 'error' + ); + return; + } - let patch = createPatch([json], [row], meta); - if (patch.length === 0) - return; + // remove from in-use list + const index = this._inUseObjects.indexOf(obj); + if (index < 0) { + this._log( + 'attempt to release an invalid resource: ' + new Error().stack, + 'error' + ); + return; + } - let body = stringify({ patch, options: { ...tableOptions, ...concurrencyOptions, strategy, deduceStrategy } }); + this._inUseObjects.splice(index, 1); + this._addResourceToAvailableObjects(obj); + }; - let adapter = netAdapter(url, tableName, { axios: axiosInterceptor, tableOptions }); - let { changed, strategy: newStrategy } = await adapter.patch(body); - copyInto(changed, [row]); - rootMap.set(row, { json: cloneFromDb(row), strategy: newStrategy }); - } + /** + * @deprecated + */ + Pool.prototype.returnToPool = function returnToPool(obj) { + this._log('returnToPool() is deprecated. use release() instead', 'warn'); + this.release(obj); + }; - async function refreshRow(row, strategy) { - clearChangesRow(row); - strategy = extractStrategy({ strategy }, row); - strategy = extractFetchingStrategy(row, strategy); + function invoke(cb) { + queueTask(cb); + } - let meta = await getMeta(); - let keyFilter = client.filter; - for (let i = 0; i < meta.keys.length; i++) { - let keyName = meta.keys[i].name; - let keyValue = row[keyName]; - keyFilter = keyFilter.and(_table[keyName].eq(keyValue)); + /** + * Disallow any new requests and let the request backlog dissipate. + * + * @param {Function} [callback] + * Callback invoked when all work is done and all clients have been released. + */ + Pool.prototype.drain = function drain(callback) { + this._log('draining', 'info'); + this._draining = true; + + const check = () => { + if (this._waitingClients.size() > 0) { + // wait until all client requests have been satisfied + return setTimeout(check, 100); } - let rows = await getManyCore(keyFilter, strategy); - for (let p in row) { - delete row[p]; + if (this._asyncTestObjects.length > 0) { + // wait until async validations are done + return setTimeout(check, 100); } - if (rows.length === 0) - return; - for (let p in rows[0]) { - row[p] = rows[0][p]; + if (this._availableObjects.length !== this._count) { + // wait until in-use objects have been released + return setTimeout(check, 100); } - rootMap.set(row, { json: cloneFromDb(row), strategy }); - fetchingStrategyMap.set(row, strategy); - } + if (callback) { + invoke(callback); + } + }; + check(); + }; - function acceptChangesRow(row) { - const data = rootMap.get(row); - if (!data) - return; - const { strategy } = data; - rootMap.set(row, { json: cloneFromDb(row), strategy }); + /** + * Forcibly destroys all clients regardless of timeout. + * Does not prevent creation of new clients from subsequent calls to acquire. + * + * If factory.min > 0, the pool will destroy all idle resources + * but replace them with newly created resources up to factory.min. + * If this is not desired, set factory.min to zero before calling. + * + * @param {Function} [callback] + * Invoked after all existing clients are destroyed. + */ + Pool.prototype.destroyAllNow = function destroyAllNow(callback) { + this._log('force destroying all objects', 'info'); + const willDie = this._availableObjects; + this._availableObjects = []; + const todo = willDie.length; + let done = 0; + + this._removeIdleScheduled = false; + clearTimeout(this._removeIdleTimer); + + if (todo === 0 && callback) { + invoke(callback); + return; } - function clearChangesRow(row) { - let json = rootMap.get(row)?.json; - if (!json) - return; - let old = cloneFromDb(json); - for (let p in row) { - delete row[p]; - } - for (let p in old) { - row[p] = old[p]; - } + while (willDie.length > 0) { + const { obj } = willDie.shift(); + this.destroy(obj, () => { + done += 1; + if (done === todo && callback) { + invoke(callback); + } + }); } - } -} + }; -function tableProxy() { - let handler = { - get(_target, property,) { - return column(property); - } + /** + * Decorates a function to use an acquired client from the pool when called. + * + * @param {Function} decorated + * @param {Number} [priority] + */ + Pool.prototype.pooled = function pooled(decorated, priority) { + return (...args) => { + const callerCallback = args[args.length - 1]; + const callerHasCallback = typeof callerCallback === 'function'; + + this.acquire((err, client) => { + if (err) { + if (callerHasCallback) { + callerCallback(err); + } + return; + } + + // We pass everything except the user's final callback + const invokeArgs = [client].concat( + args.slice(0, callerHasCallback ? -1 : undefined) + ); + // then the final callback after we release the resource + invokeArgs.push((...cbArgs) => { + this.release(client); + if (callerHasCallback) { + callerCallback(...cbArgs); + } + }); + decorated(...invokeArgs); + }, priority); + }; }; - return new Proxy({}, handler); -} -function aggregate(path, arg) { + Pool.prototype.getPoolSize = function getPoolSize() { + return this._count; + }; - const c = { - sum, - count, - avg, - max, - min + Pool.prototype.getName = function getName() { + return this._factory.name; }; - let handler = { - get(_target, property,) { - if (property in c) - return Reflect.get(...arguments); - else { - subColumn = column(path + '_aggregate'); - return column(property); - } - } + Pool.prototype.availableObjectsCount = function availableObjectsCount() { + return this._availableObjects.length; + }; + Pool.prototype.inUseObjectsCount = function inUseObjectsCount() { + return this._inUseObjects.length; }; - let subColumn; - const proxy = new Proxy(c, handler); - const result = arg(proxy); + Pool.prototype.waitingClientsCount = function waitingClientsCount() { + return this._waitingClients.size(); + }; - if (subColumn) - return subColumn(result.self()); - else - return result; + Pool.prototype.getMaxPoolSize = function getMaxPoolSize() { + return this._factory.max; + }; + Pool.prototype.getMinPoolSize = function getMinPoolSize() { + return this._factory.min; + }; - function sum(fn) { - return column(path + '_aggregate')(fn(column('')).groupSum()); - } - function avg(fn) { - return column(path + '_aggregate')(fn(column('')).groupAvg()); - } - function max(fn) { - return column(path + '_aggregate')(fn(column('')).groupMax()); - } - function min(fn) { - return column(path + '_aggregate')(fn(column('')).groupMin()); + genericPool = { Pool }; + return genericPool; +} + +/* eslint-disable no-prototype-builtins */ + +var newGenericPool_1; +var hasRequiredNewGenericPool; + +function requireNewGenericPool () { + if (hasRequiredNewGenericPool) return newGenericPool_1; + hasRequiredNewGenericPool = 1; + var defaults = requirePoolDefaults(); + var genericPool = requireGenericPool(); + + function newGenericPool(d1Database, poolOptions) { + poolOptions = poolOptions || {}; + // @ts-ignore + var pool = genericPool.Pool({ + max: 1, + idleTimeoutMillis: poolOptions.idleTimeout || defaults.poolIdleTimeout, + reapIntervalMillis: poolOptions.reapIntervalMillis || defaults.reapIntervalMillis, + log: poolOptions.log || defaults.poolLog, + create: function(cb) { + var client = {d1: d1Database, poolCount: 0}; + + return cb(null, client); + }, + + destroy: function() { + } + }); + //monkey-patch with connect method + pool.connect = function(cb) { + + pool.acquire(function(err, client) { + if(err) return cb(err, null, function() {/*NOOP*/}); + client.poolCount++; + cb(null, client, function(err) { + if(err) { + pool.destroy(client); + } else { + pool.release(client); + } + }); + }); + }; + return pool; } - function count(fn) { - return column(path + '_aggregate')(fn(column('')).groupCount()); + + newGenericPool_1 = newGenericPool; + return newGenericPool_1; +} + +var newPool_1; +var hasRequiredNewPool; + +function requireNewPool () { + if (hasRequiredNewPool) return newPool_1; + hasRequiredNewPool = 1; + const promisify = requirePromisify(); + const pools = requirePools(); + const end = requireEnd(); + const newGenericPool = requireNewGenericPool(); + const newId = requireNewId(); + + function newPool(d1Database, poolOptions) { + var pool = newGenericPool(d1Database, poolOptions); + var id = newId(); + var boundEnd = end.bind(null, pool, id); + var c = {}; + + c.connect = pool.connect; + c.end = promisify(boundEnd); + pools[id] = c; + return c; } + + newPool_1 = newPool; + return newPool_1; } -function groupByAggregate(path, arg) { +var newDatabase_1; +var hasRequiredNewDatabase; + +function requireNewDatabase () { + if (hasRequiredNewDatabase) return newDatabase_1; + hasRequiredNewDatabase = 1; + let createDomain = requireCreateDomain(); + let newTransaction = requireNewTransaction(); + let _begin = requireBegin(); + let commit = requireCommit(); + let rollback = requireRollback(); + let newPool = requireNewPool(); + let express = requireHostExpress(); + let hostLocal = requireHostLocal(); + let doQuery = requireQuery(); + let releaseDbClient = requireReleaseDbClient(); + let setSessionSingleton = requireSetSessionSingleton(); + + function newDatabase(d1Database, poolOptions) { + if (!d1Database) + throw new Error('Missing d1Database'); + var pool; + if (!poolOptions) + pool = newPool.bind(null,d1Database, poolOptions); + else + pool = newPool(d1Database, poolOptions); - const c = { - sum, - count, - avg, - max, - min - }; + let c = {poolFactory: pool, hostLocal, express}; - let handler = { - get(_target, property,) { - if (property in c) - return Reflect.get(...arguments); - else { - subColumn = column(path + '_aggregate'); - return column(property); + c.transaction = function(options, fn) { + if ((arguments.length === 1) && (typeof options === 'function')) { + fn = options; + options = undefined; } - } + let domain = createDomain(); - }; - let subColumn; - const proxy = new Proxy(c, handler); + if (fn) + return domain.run(runInTransaction); + else + return domain.run(run); + + async function runInTransaction() { + let result; + let transaction = newTransaction(domain, pool, options); + await new Promise(transaction) + .then(begin) + .then(() => fn(domain)) + .then((res) => result = res) + .then(() => c.commit(domain)) + .then(null, (e) => c.rollback(domain,e)); + return result; + } - const result = arg(proxy); + function begin() { + const transactionLess = true; + return _begin(domain, transactionLess); + } - if (subColumn) - return subColumn(result.self()); - else - return result; + function run() { + let p; + let transaction = newTransaction(domain, pool, options); + p = new Promise(transaction); + return p.then(begin); + } - function sum(fn) { - return column(path + '_aggregate')(fn(column('')).sum()); - } - function avg(fn) { - return column(path + '_aggregate')(fn(column('')).avg()); - } - function max(fn) { - return column(path + '_aggregate')(fn(column('')).max()); - } - function min(fn) { - return column(path + '_aggregate')(fn(column('')).min()); - } - function count(fn) { - return column(path + '_aggregate')(fn(column('')).count()); - } -} + }; -function column(path, ...previous) { - function c() { - let args = []; - for (let i = 0; i < arguments.length; i++) { - if (typeof arguments[i] === 'function') - args[i] = arguments[i](tableProxy(path.split('.').slice(0, -1).join('.'))); - else - args[i] = arguments[i]; - } - args = previous.concat(Array.prototype.slice.call(args)); - let result = { path, args }; - let handler = { - get(_target, property) { - if (property === 'toJSON') - return result.toJSON; - else if (property === 'then') - return; - if (property in result) - return Reflect.get(...arguments); - else - return column(property, result); + c.createTransaction = function(options) { + let domain = createDomain(); + let transaction = newTransaction(domain, pool, options); + let p = domain.run(() => new Promise(transaction).then(begin)); + function run(fn) { + return p.then(domain.run.bind(domain, fn)); } - }; - return new Proxy(result, handler); - } - let handler = { - get(_target, property) { - if (property === 'toJSON') - return Reflect.get(...arguments); - else if (property === 'then') - return; - else { - const nextPath = path ? path + '.' : ''; - return column(nextPath + property); + + function begin() { + return _begin(domain, options); } - } - }; - return new Proxy(c, handler); + run.rollback = rollback.bind(null, domain); + run.commit = commit.bind(null, domain); -} + return run; -function onChange(target, onChange) { + }; - let notified = false; - const handler = { - get(target, prop, receiver) { - const value = Reflect.get(target, prop, receiver); - if (typeof value === 'object' && value !== null) { - return new Proxy(value, handler); - } - return value; - }, - set(target, prop, value, receiver) { - if (!notified) { - notified = true; - onChange(JSON.stringify(target)); + c.query = function(query) { + let domain = createDomain(); + let transaction = newTransaction(domain, pool); + let p = domain.run(() => new Promise(transaction) + .then(() => setSessionSingleton(domain, 'changes', [])) + .then(() => doQuery(domain, query).then(onResult, onError))); + return p; + + function onResult(result) { + releaseDbClient(domain); + return result; } - return Reflect.set(target, prop, value, receiver); - }, - deleteProperty(target, prop) { - if (!notified) { - notified = true; - onChange(JSON.stringify(target)); + function onError(e) { + releaseDbClient(domain); + throw e; } - return Reflect.deleteProperty(target, prop); - } - }; + }; + + c.rollback = rollback; + c.commit = commit; + + c.end = function() { + if (poolOptions) + return pool.end(); + else + return Promise.resolve(); + }; + + c.accept = function(caller) { + caller.visitSqlite(); + }; + + return c; + } - return new Proxy(target, handler); + newDatabase_1 = newDatabase; + return newDatabase_1; } +var indexBrowser$1; +var hasRequiredIndexBrowser; + +function requireIndexBrowser () { + if (hasRequiredIndexBrowser) return indexBrowser$1; + hasRequiredIndexBrowser = 1; + const hostExpress = requireHostExpress(); + const hostLocal = requireHostLocal(); + const client = requireClient(); + const map = requireMap(); + let _d1; + + var connectViaPool = function() { + return client.apply(null, arguments); + }; + connectViaPool.createPatch = client.createPatch; + connectViaPool.table = requireTable(); + connectViaPool.filter = requireEmptyFilter(); + connectViaPool.commit = requireCommit(); + connectViaPool.rollback = requireRollback(); + connectViaPool.end = requirePools().end; + connectViaPool.log = requireLog().registerLogger; + connectViaPool.on = requireLog().on; + connectViaPool.off = requireLog().off; + connectViaPool.query = requireQuery(); + connectViaPool.lock = requireLock(); + connectViaPool.schema = requireSchema(); + connectViaPool.map = map.bind(null, connectViaPool); + + connectViaPool.http = function(url) { + return url; + }; + + + Object.defineProperty(connectViaPool, 'd1', { + get: function() { + if (!_d1) + _d1 = requireNewDatabase(); + return _d1; + } + }); + + connectViaPool.express = hostExpress.bind(null, hostLocal); + + indexBrowser$1 = connectViaPool; + return indexBrowser$1; +} -var client = rdbClient(); +var indexBrowserExports = requireIndexBrowser(); +var indexBrowser = /*@__PURE__*/getDefaultExportFromCjs(indexBrowserExports); -export { client as default }; +export { indexBrowser as default }; diff --git a/src/client/map.js b/src/client/map.js index c7b59d43..f5d2b18e 100644 --- a/src/client/map.js +++ b/src/client/map.js @@ -48,6 +48,7 @@ function map(index, context, providers, fn) { context.sap = connect.bind(null, 'sap'); context.oracle = connect.bind(null, 'oracle'); context.sqlite = connect.bind(null, 'sqlite'); + context.d1 = connect.bind(null, 'd1'); context.http = function(url) { return index({ db: url, providers}); }; diff --git a/src/client/rollup.config.js b/src/client/rollup.config.js index 074f2294..4421caa1 100644 --- a/src/client/rollup.config.js +++ b/src/client/rollup.config.js @@ -1,12 +1,32 @@ +import json from '@rollup/plugin-json'; import commonjs from '@rollup/plugin-commonjs'; import nodeResolve from '@rollup/plugin-node-resolve'; export default { - input: './src/client/index.js', + input: './src/indexBrowser.js', output: { file: './src/client/index.mjs', - format: 'esm' + format: 'esm', + interop: 'auto' + }, + + // plugins: [json(), commonjs()], + plugins: [json(), nodeResolve({ preferBuiltins: false }), commonjs({ + transformMixedEsModules: true, + esmExternals: true, // Add this + requireReturnsDefault: 'preferred' // Change this + })], + external(id) { + // If it's in node_modules, mark as external + return id.includes('node_modules'); + }, + onwarn: (warning, warn) => { + if (warning.code === 'CIRCULAR_DEPENDENCY') { + // Log the full circular dependency warning message + console.warn(`[CIRCULAR DEPENDENCY] ${warning.message}`); + } else { + // For all other warnings, use Rollup's default handler. + warn(warning); + } }, - plugins: [commonjs(), nodeResolve({browser: true})], - external: ['vue'] }; \ No newline at end of file diff --git a/src/client/stringify.js b/src/client/stringify.js index 0accbd52..e1d6a408 100644 --- a/src/client/stringify.js +++ b/src/client/stringify.js @@ -1,22 +1,15 @@ let dateToISOString = require('../dateToISOString'); -const isNode = (typeof window === 'undefined'); function stringify(value) { return JSON.stringify(value, replacer); } function replacer(key, value) { - if (isNode && isNodeBuffer(value)) - return value.toString('base64'); - // @ts-ignore - else if (value instanceof Date && !isNaN(value)) + // // @ts-ignore + if (value instanceof Date && !isNaN(value)) return dateToISOString(value); else return value; } -function isNodeBuffer(object) { - return Buffer.isBuffer(object); -} - module.exports = stringify; \ No newline at end of file diff --git a/src/clsTest.js b/src/clsTest.js deleted file mode 100644 index 14b0b927..00000000 --- a/src/clsTest.js +++ /dev/null @@ -1,79 +0,0 @@ -let cls = require('node-cls'); -const fs = require('fs'); -const log = (str) => fs.writeSync(1, `${str}\n`); - -function begin(id) { - return new Promise((resolve) => { - let context = cls.get(); - context.id = id; - resolve(); - }); -} - -function getById() { - return new Promise((resolve) => { - let context = cls.get(); - context.id; - resolve(context.id); - }); -} - -async function getFromDb() { - let c = cls.create(); - await c.start(); - await begin(1); - await new Promise((resolve) => { - setTimeout(resolve(), 500); - }); - await getFromDb2(); - - let c3 = cls.create(); - await c3.start(); - await begin(3); - let id3 = await getById(); - if (id3 !== 3) - throw new Error('3 Unexpected context id : ' + id3); - cls.exit(); - - await getFromDb3(); - - let id = await getById(); - if (id !== 1) - throw new Error('1 Unexpected context id : ' + id); - cls.exit(); -} - -function getFromDb2() { - return new Promise((resolve) => { - setTimeout(async () => { - let c2 = cls.create(); - await c2.start(); - await begin(2); - let id2 = await getById(); - if (id2 !== 2) - throw new Error('2 Unexpected context id : ' + id2); - id2 = cls.active.id; - if (id2 !== 2) - throw new Error('2 Unexpected context id : ' + id2); - cls.exit(); - resolve(); - }, 500); - }); -} - -async function getFromDb3() { - let c3 = cls.create(); - await c3.start(); - await begin(3); - let id3 = await getById(); - if (id3 !== 3) - throw new Error('3 Unexpected context id : ' + id3); - cls.exit(); -} - - -async function testStart() { - await getFromDb(); -} - -testStart().then(() => log('done'), (e) => log(e.stack)); diff --git a/src/createDomain.js b/src/createDomain.js index a3594373..ac83fbcf 100644 --- a/src/createDomain.js +++ b/src/createDomain.js @@ -1,31 +1,10 @@ -let useHook = require('./useHook'); -let cls; -var Domain = require('domain'); -var negotiateForwardProperty = require('./createDomain/negotiateForwardProperty'); - function createDomain() { - var oldDomain = Domain.active || {}; - var domain = Domain.create(); - var ownProperties = Object.getOwnPropertyNames(oldDomain); - ownProperties.forEach(function(propName) { - negotiateForwardProperty(oldDomain, domain, propName); - }); - return domain; -} - -function createOnContext() { - if (!cls) - cls = require('node-cls'); - return cls.create('rdb'); -} - - -function _createDomain() { - if (useHook()) - return createOnContext(); - else - return createDomain(); - + let c = {}; + function run(fn) { + return fn(c); + } + c.run = run; + return c; } -module.exports = _createDomain; \ No newline at end of file +module.exports = createDomain; \ No newline at end of file diff --git a/src/createDomain/negotiateForwardProperty.js b/src/createDomain/negotiateForwardProperty.js deleted file mode 100644 index a92203fe..00000000 --- a/src/createDomain/negotiateForwardProperty.js +++ /dev/null @@ -1,23 +0,0 @@ -function negotiateForwardProperty(oldDomain, newDomain, propertyName) { - if(newDomain[propertyName]) return; - if (propertyName === 'rdb') return; - Object.defineProperty(newDomain, propertyName, { - enumerable: true, - get: createGetter(oldDomain, propertyName), - set: createSetter(oldDomain, propertyName) - }); -} - -function createGetter(oldDomain, propName) { - return function() { - return oldDomain[propName]; - }; -} - -function createSetter(oldDomain, propName) { - return function(value) { - oldDomain[propName] = value; - }; -} - -module.exports = negotiateForwardProperty; \ No newline at end of file diff --git a/src/d1/newDatabase.js b/src/d1/newDatabase.js new file mode 100644 index 00000000..29a7a82a --- /dev/null +++ b/src/d1/newDatabase.js @@ -0,0 +1,119 @@ +let createDomain = require('../createDomain'); +let newTransaction = require('./newTransaction'); +let _begin = require('../table/begin'); +let commit = require('../table/commit'); +let rollback = require('../table/rollback'); +let newPool = require('./newPool'); +let express = require('../hostExpress'); +let hostLocal = require('../hostLocal'); +let doQuery = require('../query'); +let releaseDbClient = require('../table/releaseDbClient'); +let setSessionSingleton = require('../table/setSessionSingleton'); + +function newDatabase(d1Database, poolOptions) { + if (!d1Database) + throw new Error('Missing d1Database'); + var pool; + if (!poolOptions) + pool = newPool.bind(null,d1Database, poolOptions); + else + pool = newPool(d1Database, poolOptions); + + let c = {poolFactory: pool, hostLocal, express}; + + c.transaction = function(options, fn) { + if ((arguments.length === 1) && (typeof options === 'function')) { + fn = options; + options = undefined; + } + let domain = createDomain(); + + if (fn) + return domain.run(runInTransaction); + else + return domain.run(run); + + async function runInTransaction() { + let result; + let transaction = newTransaction(domain, pool, options); + await new Promise(transaction) + .then(begin) + .then(() => fn(domain)) + .then((res) => result = res) + .then(() => c.commit(domain)) + .then(null, (e) => c.rollback(domain,e)); + return result; + } + + function begin() { + const transactionLess = true; + return _begin(domain, transactionLess); + } + + function run() { + let p; + let transaction = newTransaction(domain, pool, options); + p = new Promise(transaction); + + return p.then(begin); + } + + }; + + c.createTransaction = function(options) { + let domain = createDomain(); + let transaction = newTransaction(domain, pool, options); + let p = domain.run(() => new Promise(transaction).then(begin)); + + function run(fn) { + return p.then(domain.run.bind(domain, fn)); + } + + function begin() { + return _begin(domain, options); + } + + run.rollback = rollback.bind(null, domain); + run.commit = commit.bind(null, domain); + + return run; + + }; + + c.query = function(query) { + let domain = createDomain(); + let transaction = newTransaction(domain, pool); + let p = domain.run(() => new Promise(transaction) + .then(() => setSessionSingleton(domain, 'changes', [])) + .then(() => doQuery(domain, query).then(onResult, onError))); + return p; + + function onResult(result) { + releaseDbClient(domain); + return result; + } + + function onError(e) { + releaseDbClient(domain); + throw e; + } + }; + + c.rollback = rollback; + c.commit = commit; + + c.end = function() { + if (poolOptions) + return pool.end(); + else + return Promise.resolve(); + }; + + c.accept = function(caller) { + caller.visitSqlite(); + }; + + return c; +} + +module.exports = newDatabase; diff --git a/src/d1/newPool.js b/src/d1/newPool.js new file mode 100644 index 00000000..b07d4456 --- /dev/null +++ b/src/d1/newPool.js @@ -0,0 +1,19 @@ +const promisify = require('../promisify'); +const pools = require('../pools'); +const end = require('./pool/end'); +const newGenericPool = require('./pool/newGenericPool'); +const newId = require('../newId'); + +function newPool(d1Database, poolOptions) { + var pool = newGenericPool(d1Database, poolOptions); + var id = newId(); + var boundEnd = end.bind(null, pool, id); + var c = {}; + + c.connect = pool.connect; + c.end = promisify(boundEnd); + pools[id] = c; + return c; +} + +module.exports = newPool; \ No newline at end of file diff --git a/src/d1/newTransaction.js b/src/d1/newTransaction.js new file mode 100644 index 00000000..dae8fd18 --- /dev/null +++ b/src/d1/newTransaction.js @@ -0,0 +1,83 @@ +const wrapQuery = require('./wrapQuery'); +const encodeBoolean = require('../sqlite/encodeBoolean'); +const deleteFromSql = require('../sqlite/deleteFromSql'); +const selectForUpdateSql = require('../sqlite/selectForUpdateSql'); +const lastInsertedSql = require('../sqlite/lastInsertedSql'); +const limitAndOffset = require('../sqlite/limitAndOffset'); +const insertSql = require('../sqlite/insertSql'); +const insert = require('../sqlite/insert'); + +function newResolveTransaction(domain, pool, { readonly = false } = {}) { + var rdb = {poolFactory: pool}; + if (!pool.connect) { + pool = pool(); + rdb.pool = pool; + } + rdb.engine = 'sqlite'; + rdb.maxParameters = 100; + rdb.encodeBoolean = encodeBoolean; + rdb.decodeJSON = decodeJSON; + rdb.encodeJSON = JSON.stringify; + rdb.deleteFromSql = deleteFromSql; + rdb.selectForUpdateSql = selectForUpdateSql; + rdb.lastInsertedSql = lastInsertedSql; + rdb.insertSql = insertSql; + rdb.insert = insert; + rdb.lastInsertedIsSeparate = true; + rdb.multipleStatements = false; + rdb.limitAndOffset = limitAndOffset; + rdb.accept = function(caller) { + caller.visitSqlite(); + }; + rdb.aggregateCount = 0; + rdb.quote = (name) => `"${name}"`; + + if (readonly) { + rdb.dbClient = { + executeQuery: function(query, callback) { + pool.connect((err, client, done) => { + if (err) { + return callback(err); + } + try { + wrapQuery(client)(query, (err, res) => { + done(); + callback(err, res); + }); + } catch (e) { + done(); + callback(e); + } + }); + } + }; + domain.rdb = rdb; + return (onSuccess) => onSuccess(); + } + + return function(onSuccess, onError) { + pool.connect(onConnected); + + function onConnected(err, client, done) { + try { + if (err) { + onError(err); + return; + } + client.executeQuery = wrapQuery(client); + rdb.dbClient = client; + rdb.dbClientDone = done; + domain.rdb = rdb; + onSuccess(); + } catch (e) { + onError(e); + } + } + }; +} + +function decodeJSON(value) { + return JSON.parse(value); +} + +module.exports = newResolveTransaction; \ No newline at end of file diff --git a/src/d1/pool/end.js b/src/d1/pool/end.js new file mode 100644 index 00000000..7b43fa3e --- /dev/null +++ b/src/d1/pool/end.js @@ -0,0 +1,13 @@ +var pools = require('../../pools'); + +function endPool(genericPool, id, done) { + genericPool.drain(onDrained); + + function onDrained() { + genericPool.destroyAllNow(); + delete pools[id]; + done(); + } +} + +module.exports = endPool; diff --git a/src/d1/pool/newGenericPool.js b/src/d1/pool/newGenericPool.js new file mode 100644 index 00000000..9ab85e9f --- /dev/null +++ b/src/d1/pool/newGenericPool.js @@ -0,0 +1,40 @@ +/* eslint-disable no-prototype-builtins */ +var defaults = require('../../poolDefaults'); +var genericPool = require('../../generic-pool'); + +function newGenericPool(d1Database, poolOptions) { + poolOptions = poolOptions || {}; + // @ts-ignore + var pool = genericPool.Pool({ + max: 1, + idleTimeoutMillis: poolOptions.idleTimeout || defaults.poolIdleTimeout, + reapIntervalMillis: poolOptions.reapIntervalMillis || defaults.reapIntervalMillis, + log: poolOptions.log || defaults.poolLog, + create: function(cb) { + var client = {d1: d1Database, poolCount: 0}; + + return cb(null, client); + }, + + destroy: function() { + } + }); + //monkey-patch with connect method + pool.connect = function(cb) { + + pool.acquire(function(err, client) { + if(err) return cb(err, null, function() {/*NOOP*/}); + client.poolCount++; + cb(null, client, function(err) { + if(err) { + pool.destroy(client); + } else { + pool.release(client); + } + }); + }); + }; + return pool; +} + +module.exports = newGenericPool; \ No newline at end of file diff --git a/src/d1/wrapQuery.js b/src/d1/wrapQuery.js new file mode 100644 index 00000000..9f8197ca --- /dev/null +++ b/src/d1/wrapQuery.js @@ -0,0 +1,22 @@ +var log = require('../table/log'); + +function wrapQuery(client) { + + return runQuery; + + function runQuery(query, onCompleted) { + + var params = query.parameters; + var sql = query.sql(); + log.emitQuery({sql, parameters: params}); + client.d1.prepare(sql, params).bind(...params).all().then(onInnerCompleted, onCompleted); + + function onInnerCompleted(response) { + onCompleted(null, response.results); + } + + } + +} + +module.exports = wrapQuery; \ No newline at end of file diff --git a/src/d1test.js b/src/d1test.js new file mode 100644 index 00000000..fa22aa42 --- /dev/null +++ b/src/d1test.js @@ -0,0 +1,35 @@ +import { connect } from '@cloudflare/d1'; + +const databaseId = process.env.D1_DATABASE_ID; +const accountId = process.env.D1_ACCOUNT_ID; +const apiToken = process.env.D1_API_TOKEN; + +export class Database { + constructor() { + this.db = connect({ + databaseId, + accountId, + apiToken, + }); + } + + async createUser(name, email) { + return await this.db + .prepare('INSERT INTO users (name, email) VALUES (?, ?)') + .bind(name, email) + .run(); + } + + async getUsers() { + return await this.db + .prepare('SELECT * FROM users') + .all(); + } + + async getUserById(id) { + return await this.db + .prepare('SELECT * FROM users WHERE id = ?') + .bind(id) + .first(); + } +} diff --git a/src/emitEvent.js b/src/emitEvent.js index d49e4aab..198e35e5 100644 --- a/src/emitEvent.js +++ b/src/emitEvent.js @@ -6,12 +6,14 @@ function emitEvent() { var result = []; for (var i = 0; i < copy.length; i++) { var callback = copy[i]; - result.push(callback.apply(null,arguments)); + result.push(callback.apply(null, arguments)); } return result; }; emit.add = function(callback) { + if (!callback) + throw new Error('missing callback'); callbacks.push(callback); }; @@ -22,15 +24,15 @@ function emitEvent() { emit.remove = function(callback) { for (var i = 0; i < callbacks.length; i++) { - if(callbacks[i] === callback){ - callbacks.splice(i,1); + if (callbacks[i] === callback) { + callbacks.splice(i, 1); return; } } }; emit.tryRemove = function(callback) { - if(callback) + if (callback) emit.remove(callback); }; diff --git a/src/emptyFilter.js b/src/emptyFilter.js index bcd91a0c..933aec86 100644 --- a/src/emptyFilter.js +++ b/src/emptyFilter.js @@ -7,26 +7,26 @@ function emptyFilter() { emptyFilter.sql = parameterized.sql; emptyFilter.parameters = parameterized.parameters; -emptyFilter.and = function(other) { - other = negotiateRawSqlFilter(other); - for (var i = 1; i < arguments.length; i++) { - other = other.and(arguments[i]); +emptyFilter.and = function(context, other) { + other = negotiateRawSqlFilter(context, other); + for (var i = 2; i < arguments.length; i++) { + other = other.and(context, arguments[i]); } return other; }; -emptyFilter.or = function(other) { - other = negotiateRawSqlFilter(other); - for (var i = 1; i < arguments.length; i++) { - other = other.or(arguments[i]); +emptyFilter.or = function(context, other) { + other = negotiateRawSqlFilter(context, other); + for (var i = 2; i < arguments.length; i++) { + other = other.or(context, arguments[i]); } return other; }; -emptyFilter.not = function(other) { - other = negotiateRawSqlFilter(other).not(); - for (var i = 1; i < arguments.length; i++) { - other = other.and(arguments[i]); +emptyFilter.not = function(context, other) { + other = negotiateRawSqlFilter(context, other).not(context); + for (var i = 2; i < arguments.length; i++) { + other = other.and(context, arguments[i]); } return other; diff --git a/src/format.js b/src/format.js new file mode 100644 index 00000000..436d8ea3 --- /dev/null +++ b/src/format.js @@ -0,0 +1,9 @@ +function format(template, ...values) { + let index = 0; + return template.replace(/%s/g, () => { + // If there aren't enough values, this will insert 'undefined' + // for placeholders that don't have a corresponding array item. + return values[index++]; + }); +} +module.exports = format; \ No newline at end of file diff --git a/src/generic-pool.js b/src/generic-pool.js index d01b940b..66dbd171 100644 --- a/src/generic-pool.js +++ b/src/generic-pool.js @@ -1,27 +1,39 @@ /* eslint-disable @typescript-eslint/no-this-alias */ - -// @ts-nocheck -//Taken from https://raw.githubusercontent.com/coopernurse/node-pool/6c98fa9163bbe35b683ffc2b55ac741d02956096/lib/generic-pool.js -//Version 3 of generic-pool has lots og bugs and node program will never finish. -//So I copied version 2.5.4 below +/* @ts-nocheck */ /** - * @class - * @private + * A helper function to schedule a callback in a cross-platform manner: + * - Uses setImmediate if available (Node). + * - Else uses queueMicrotask if available (Deno, modern browsers). + * - Else falls back to setTimeout(fn, 0). */ +function queueTask(fn) { + if (typeof setImmediate === 'function') { + setImmediate(fn); + } + else if + (typeof queueMicrotask === 'function') { + queueMicrotask(fn); + } else { + setTimeout(fn, 0); + } +} + +/** + * @class + * @private + */ function PriorityQueue(size) { if (!(this instanceof PriorityQueue)) { - return new PriorityQueue(); + return new PriorityQueue(size); } - this._size = size; - this._slots = null; + this._size = Math.max(+size | 0, 1); + this._slots = []; this._total = null; // initialize arrays to hold queue elements - size = Math.max(+size | 0, 1); - this._slots = []; - for (var i = 0; i < size; i += 1) { + for (let i = 0; i < this._size; i += 1) { this._slots.push([]); } } @@ -29,7 +41,7 @@ function PriorityQueue(size) { PriorityQueue.prototype.size = function size() { if (this._total === null) { this._total = 0; - for (var i = 0; i < this._size; i += 1) { + for (let i = 0; i < this._size; i += 1) { this._total += this._slots[i].length; } } @@ -37,30 +49,22 @@ PriorityQueue.prototype.size = function size() { }; PriorityQueue.prototype.enqueue = function enqueue(obj, priority) { - var priorityOrig; - // Convert to integer with a default value of 0. priority = priority && +priority | 0 || 0; - - // Clear cache for total. this._total = null; - if (priority) { - priorityOrig = priority; - if (priority < 0 || priority >= this._size) { - priority = (this._size - 1); - // put obj at the end of the line - console.error('invalid priority: ' + priorityOrig + ' must be between 0 and ' + priority); - } + if (priority < 0 || priority >= this._size) { + console.error( + 'invalid priority: ' + priority + ' must be between 0 and ' + (this._size - 1) + ); + priority = this._size - 1; // put obj at the end of the line } - this._slots[priority].push(obj); }; -PriorityQueue.prototype.dequeue = function dequeue(_callback) { - var obj = null; - // Clear cache for total. +PriorityQueue.prototype.dequeue = function dequeue() { + let obj = null; this._total = null; - for (var i = 0, sl = this._slots.length; i < sl; i += 1) { + for (let i = 0, sl = this._slots.length; i < sl; i += 1) { if (this._slots[i].length) { obj = this._slots[i].shift(); break; @@ -70,7 +74,7 @@ PriorityQueue.prototype.dequeue = function dequeue(_callback) { }; function doWhileAsync(conditionFn, iterateFn, callbackFn) { - var next = function() { + const next = function() { if (conditionFn()) { iterateFn(next); } else { @@ -81,57 +85,29 @@ function doWhileAsync(conditionFn, iterateFn, callbackFn) { } /** - * Generate an Object pool with a specified `factory`. - * - * @class - * @param {Object} factory - * Factory to be used for generating and destorying the items. - * @param {String} factory.name - * Name of the factory. Serves only logging purposes. - * @param {Function} factory.create - * Should create the item to be acquired, - * and call it's first callback argument with the generated item as it's argument. - * @param {Function} factory.destroy - * Should gently close any resources that the item is using. - * Called before the items is destroyed. - * @param {Function} factory.validate - * Should return true if connection is still valid and false - * If it should be removed from pool. Called before item is - * acquired from pool. - * @param {Function} factory.validateAsync - * Asynchronous validate function. Receives a callback function - * as its second argument, that should be called with a single - * boolean argument being true if the item is still valid and false - * if it should be removed from pool. Called before item is - * acquired from pool. Only one of validate/validateAsync may be specified - * @param {Number} factory.max - * Maximum number of items that can exist at the same time. Default: 1. - * Any further acquire requests will be pushed to the waiting list. - * @param {Number} factory.min - * Minimum number of items in pool (including in-use). Default: 0. - * When the pool is created, or a resource destroyed, this minimum will - * be checked. If the pool resource count is below the minimum, a new - * resource will be created and added to the pool. - * @param {Number} factory.idleTimeoutMillis - * Delay in milliseconds after the idle items in the pool will be destroyed. - * And idle item is that is not acquired yet. Waiting items doesn't count here. - * @param {Number} factory.reapIntervalMillis - * Cleanup is scheduled in every `factory.reapIntervalMillis` milliseconds. - * @param {Boolean|Function} factory.log - * Whether the pool should log activity. If function is specified, - * that will be used instead. The function expects the arguments msg, loglevel - * @param {Number} factory.priorityRange - * The range from 1 to be treated as a valid priority - * @param {RefreshIdle} factory.refreshIdle - * Should idle resources at or below the min threshold be destroyed and recreated every idleTimeoutMillis? Default: true. - * @param {Bool} [factory.returnToHead=false] - * Returns released object to head of available objects list - */ + * Generate an Object pool with a specified `factory`. + * + * @class + * @param {Object} factory + * Factory to be used for generating and destroying the items. + * @param {String} factory.name + * @param {Function} factory.create + * @param {Function} factory.destroy + * @param {Function} factory.validate + * @param {Function} factory.validateAsync + * @param {Number} factory.max + * @param {Number} factory.min + * @param {Number} factory.idleTimeoutMillis + * @param {Number} factory.reapIntervalMillis + * @param {Boolean|Function} factory.log + * @param {Number} factory.priorityRange + * @param {Boolean} factory.refreshIdle + * @param {Boolean} [factory.returnToHead=false] + */ function Pool(factory) { if (!(this instanceof Pool)) { return new Pool(factory); } - if (factory.validate && factory.validateAsync) { throw new Error('Only one of validate or validateAsync may be specified'); } @@ -148,7 +124,6 @@ function Pool(factory) { factory.max = parseInt(factory.max, 10); factory.min = parseInt(factory.min, 10); - factory.max = Math.max(isNaN(factory.max) ? 1 : factory.max, 1); factory.min = Math.min(isNaN(factory.min) ? 0 : factory.min, factory.max - 1); @@ -167,12 +142,12 @@ function Pool(factory) { } /** - * logs to console or user defined log function - * @private - * @param {string} str - * @param {string} level - */ -Pool.prototype._log = function log(str, level) { + * logs to console or user-defined log function + * @private + * @param {string} str + * @param {string} level + */ +Pool.prototype._log = function _log(str, level) { if (typeof this._factory.log === 'function') { this._factory.log(str, level); } else if (this._factory.log) { @@ -181,30 +156,30 @@ Pool.prototype._log = function log(str, level) { }; /** - * Request the client to be destroyed. The factory's destroy handler - * will also be called. - * - * This should be called within an acquire() block as an alternative to release(). - * - * @param {Object} obj - * The acquired item to be destoyed. - * @param {Function} callback - * Optional. Callback invoked after client is destroyed - */ + * Request the client to be destroyed. The factory's destroy handler + * will also be called. + * + * This should be called within an acquire() block as an alternative to release(). + * + * @param {Object} obj + * The acquired item to be destroyed. + * @param {Function} [cb] + * Optional. Callback invoked after client is destroyed + */ Pool.prototype.destroy = function destroy(obj, cb) { this._count -= 1; if (this._count < 0) this._count = 0; - this._availableObjects = this._availableObjects.filter(function(objWithTimeout) { - return (objWithTimeout.obj !== obj); - }); - this._inUseObjects = this._inUseObjects.filter(function(objInUse) { - return (objInUse !== obj); - }); + this._availableObjects = this._availableObjects.filter( + (objWithTimeout) => objWithTimeout.obj !== obj + ); + this._inUseObjects = this._inUseObjects.filter( + (objInUse) => objInUse !== obj + ); this._factory.destroy(obj, cb); - // keep compatibily with old interface + // keep compatibility with old interface if (this._factory.destroy.length === 1 && cb && typeof cb === 'function') { cb(); } @@ -213,40 +188,41 @@ Pool.prototype.destroy = function destroy(obj, cb) { }; /** - * Checks and removes the available (idle) clients that have timed out. - * @private - */ -Pool.prototype._removeIdle = function removeIdle() { - var toRemove = []; - var now = new Date().getTime(); - var i; - var al = this._availableObjects.length; - var refreshIdle = this._factory.refreshIdle; - var maxRemovable = this._count - this._factory.min; - var timeout; + * Checks and removes the available (idle) clients that have timed out. + * @private + */ +Pool.prototype._removeIdle = function _removeIdle() { + const now = new Date().getTime(); + const refreshIdle = this._factory.refreshIdle; + const maxRemovable = this._count - this._factory.min; + const toRemove = []; this._removeIdleScheduled = false; - // Go through the available (idle) items, - // check if they have timed out - for (i = 0; i < al && (refreshIdle || (maxRemovable > toRemove.length)); i++) { - timeout = this._availableObjects[i].timeout; - if (now >= timeout) { - // Client timed out, so destroy it. - this._log('removeIdle() destroying obj - now:' + now + ' timeout:' + timeout, 'verbose'); - toRemove.push(this._availableObjects[i].obj); + for (let i = 0; i < this._availableObjects.length; i++) { + const objWithTimeout = this._availableObjects[i]; + if ( + now >= objWithTimeout.timeout && + (refreshIdle || toRemove.length < maxRemovable) + ) { + this._log( + 'removeIdle() destroying obj - now:' + + now + + ' timeout:' + + objWithTimeout.timeout, + 'verbose' + ); + toRemove.push(objWithTimeout.obj); } } - toRemove.forEach(this.destroy, this); - - // NOTE: we are re-calcing this value because it may have changed - // after destroying items above - // Replace the available items with the ones to keep. - al = this._availableObjects.length; + toRemove.forEach((obj) => this.destroy(obj)); - if (al > 0) { - this._log('this._availableObjects.length=' + al, 'verbose'); + if (this._availableObjects.length > 0) { + this._log( + 'this._availableObjects.length=' + this._availableObjects.length, + 'verbose' + ); this._scheduleRemoveIdle(); } else { this._log('removeIdle() all objects removed', 'verbose'); @@ -254,60 +230,61 @@ Pool.prototype._removeIdle = function removeIdle() { }; /** - * Schedule removal of idle items in the pool. - * - * More schedules cannot run concurrently. - */ -Pool.prototype._scheduleRemoveIdle = function scheduleRemoveIdle() { - var self = this; + * Schedule removal of idle items in the pool. + * + * More schedules cannot run concurrently. + */ +Pool.prototype._scheduleRemoveIdle = function _scheduleRemoveIdle() { if (!this._removeIdleScheduled) { this._removeIdleScheduled = true; - this._removeIdleTimer = setTimeout(function() { - self._removeIdle(); + this._removeIdleTimer = setTimeout(() => { + this._removeIdle(); }, this._factory.reapInterval); } }; /** - * Try to get a new client to work, and clean up pool unused (idle) items. - * - * - If there are available clients waiting, shift the first one out (LIFO), - * and call its callback. - * - If there are no waiting clients, try to create one if it won't exceed - * the maximum number of clients. - * - If creating a new client would exceed the maximum, add the client to - * the wait list. - * @private - */ -Pool.prototype._dispense = function dispense() { - var self = this; - var objWithTimeout = null; - var clientCb = null; - var waitingCount = this._waitingClients.size(); - - this._log('dispense() clients=' + waitingCount + ' available=' + this._availableObjects.length, 'info'); + * Try to get a new client to work, and clean up pool unused (idle) items. + * + * - If there are available clients waiting, shift the first one out, + * and call its callback. + * - If there are no waiting clients, try to create one if it won't exceed + * the maximum number of clients. + * - If creating a new client would exceed the maximum, add the client to + * the wait list. + * @private + */ +Pool.prototype._dispense = function _dispense() { + const waitingCount = this._waitingClients.size(); + this._log( + 'dispense() clients=' + + waitingCount + + ' available=' + + this._availableObjects.length, + 'info' + ); if (waitingCount < 1) { return; } if (this._factory.validateAsync) { - doWhileAsync(function() { - return self._availableObjects.length > 0; - }, - this._createAsyncValidator(), - function() { - if (self._count < self._factory.max) { - self._createResource(); + doWhileAsync( + () => this._availableObjects.length > 0, + this._createAsyncValidator(), + () => { + if (this._count < this._factory.max) { + this._createResource(); + } } - }); - + ); return; } while (this._availableObjects.length > 0) { this._log('dispense() - reusing obj', 'verbose'); - objWithTimeout = this._availableObjects[0]; + const objWithTimeout = this._availableObjects[0]; + if (!this._factory.validate(objWithTimeout.obj)) { this.destroy(objWithTimeout.obj); continue; @@ -315,7 +292,7 @@ Pool.prototype._dispense = function dispense() { this._availableObjects.shift(); this._inUseObjects.push(objWithTimeout.obj); - clientCb = this._waitingClients.dequeue(); + const clientCb = this._waitingClients.dequeue(); return clientCb(null, objWithTimeout.obj); } @@ -325,203 +302,193 @@ Pool.prototype._dispense = function dispense() { }; Pool.prototype._createAsyncValidator = function _createAsyncValidator() { - var self = this; - return function asyncValidate(next) { - self._log('dispense() - reusing obj', 'verbose'); - - var objWithTimeout = self._availableObjects.shift(); - self._asyncTestObjects.push(objWithTimeout); + return (next) => { + this._log('dispense() - reusing obj', 'verbose'); + const objWithTimeout = this._availableObjects.shift(); + this._asyncTestObjects.push(objWithTimeout); - self._factory.validateAsync(objWithTimeout.obj, function(valid) { - var pos = self._asyncTestObjects.indexOf(objWithTimeout); - self._asyncTestObjects.splice(pos, 1); + this._factory.validateAsync(objWithTimeout.obj, (valid) => { + const pos = this._asyncTestObjects.indexOf(objWithTimeout); + this._asyncTestObjects.splice(pos, 1); if (!valid) { - self.destroy(objWithTimeout.obj); + this.destroy(objWithTimeout.obj); return next(); } - if (self._waitingClients.size() < 1) { - // there is no longer anyone waiting for a resource - self._addResourceToAvailableObjects(objWithTimeout.obj); + if (this._waitingClients.size() < 1) { + // no longer anyone waiting for a resource + this._addResourceToAvailableObjects(objWithTimeout.obj); return; } - self._inUseObjects.push(objWithTimeout.obj); - var clientCb = self._waitingClients.dequeue(); + this._inUseObjects.push(objWithTimeout.obj); + const clientCb = this._waitingClients.dequeue(); clientCb(null, objWithTimeout.obj); }); }; }; /** - * @private - */ + * @private + */ Pool.prototype._createResource = function _createResource() { this._count += 1; - this._log('createResource() - creating obj - count=' + this._count + ' min=' + this._factory.min + ' max=' + this._factory.max, 'verbose'); - var self = this; - this._factory.create(function() { - var err, obj; - var clientCb = self._waitingClients.dequeue(); - if (arguments.length > 1) { - err = arguments[0]; - obj = arguments[1]; + this._log( + 'createResource() - creating obj - count=' + + this._count + + ' min=' + + this._factory.min + + ' max=' + + this._factory.max, + 'verbose' + ); + + this._factory.create((...args) => { + let err, obj; + if (args.length > 1) { + [err, obj] = args; } else { - err = (arguments[0] instanceof Error) ? arguments[0] : null; - obj = (arguments[0] instanceof Error) ? null : arguments[0]; + err = args[0] instanceof Error ? args[0] : null; + obj = args[0] instanceof Error ? null : args[0]; } + + const clientCb = this._waitingClients.dequeue(); + if (err) { - self._count -= 1; - if (self._count < 0) self._count = 0; + this._count -= 1; + if (this._count < 0) this._count = 0; if (clientCb) { clientCb(err, obj); } - process.nextTick(function() { - self._dispense(); + // queueTask to simulate process.nextTick + queueTask(() => { + this._dispense(); }); } else { - self._inUseObjects.push(obj); + this._inUseObjects.push(obj); if (clientCb) { - clientCb(err, obj); + clientCb(null, obj); } else { - self._addResourceToAvailableObjects(obj); + this._addResourceToAvailableObjects(obj); } } }); }; Pool.prototype._addResourceToAvailableObjects = function(obj) { - var objWithTimeout = { - obj: obj, - timeout: (new Date().getTime() + this._factory.idleTimeoutMillis) + const objWithTimeout = { + obj, + timeout: new Date().getTime() + this._factory.idleTimeoutMillis, }; - if (this._factory.returnToHead) { - this._availableObjects.splice(0, 0, objWithTimeout); + this._availableObjects.unshift(objWithTimeout); } else { this._availableObjects.push(objWithTimeout); } - this._dispense(); this._scheduleRemoveIdle(); }; /** - * @private - */ + * @private + */ Pool.prototype._ensureMinimum = function _ensureMinimum() { - var i, diff; - if (!this._draining && (this._count < this._factory.min)) { - diff = this._factory.min - this._count; - for (i = 0; i < diff; i++) { + if (!this._draining && this._count < this._factory.min) { + const diff = this._factory.min - this._count; + for (let i = 0; i < diff; i++) { this._createResource(); } } }; /** - * Request a new client. The callback will be called, - * when a new client will be availabe, passing the client to it. - * - * @param {Function} callback - * Callback function to be called after the acquire is successful. - * The function will receive the acquired item as the first parameter. - * - * @param {Number} priority - * Optional. Integer between 0 and (priorityRange - 1). Specifies the priority - * of the caller if there are no available resources. Lower numbers mean higher - * priority. - * - * @returns {boolean} `true` if the pool is not fully utilized, `false` otherwise. - */ + * Request a new client. The callback will be called + * when a new client is available. + * + * @param {Function} callback + * @param {Number} [priority] + * @returns {Boolean} true if the pool is not fully utilized, false otherwise + */ Pool.prototype.acquire = function acquire(callback, priority) { if (this._draining) { throw new Error('pool is draining and cannot accept work'); } - if (process.domain) { - callback = process.domain.bind(callback); - } this._waitingClients.enqueue(callback, priority); this._dispense(); - return (this._count < this._factory.max); + return this._count < this._factory.max; }; /** - * @deprecated - */ + * @deprecated + */ Pool.prototype.borrow = function borrow(callback, priority) { this._log('borrow() is deprecated. use acquire() instead', 'warn'); - this.acquire(callback, priority); + return this.acquire(callback, priority); }; /** - * Return the client to the pool, in case it is no longer required. - * - * @param {Object} obj - * The acquired object to be put back to the pool. - */ + * Return the client to the pool, indicating it is no longer needed. + * + * @param {Object} obj + */ Pool.prototype.release = function release(obj) { - // check to see if this object has already been released (i.e., is back in the pool of this._availableObjects) - if (this._availableObjects.some(function(objWithTimeout) { - return (objWithTimeout.obj === obj); - })) { - this._log('release called twice for the same resource: ' + (new Error().stack), 'error'); + // Check whether this object has already been released + const alreadyReleased = this._availableObjects.some(o => o.obj === obj); + if (alreadyReleased) { + this._log( + 'release called twice for the same resource: ' + new Error().stack, + 'error' + ); return; } - // check to see if this object exists in the `in use` list and remove it - var index = this._inUseObjects.indexOf(obj); + // remove from in-use list + const index = this._inUseObjects.indexOf(obj); if (index < 0) { - this._log('attempt to release an invalid resource: ' + (new Error().stack), 'error'); + this._log( + 'attempt to release an invalid resource: ' + new Error().stack, + 'error' + ); return; } - // this._log("return to pool") this._inUseObjects.splice(index, 1); this._addResourceToAvailableObjects(obj); }; /** - * @deprecated - */ + * @deprecated + */ Pool.prototype.returnToPool = function returnToPool(obj) { this._log('returnToPool() is deprecated. use release() instead', 'warn'); this.release(obj); }; function invoke(cb) { - if (typeof setImmediate === 'function') { - setImmediate(cb); - } else { - setTimeout(cb, 0); - } + queueTask(cb); } /** - * Disallow any new requests and let the request backlog dissapate. - * - * @param {Function} callback - * Optional. Callback invoked when all work is done and all clients have been - * released. - */ + * Disallow any new requests and let the request backlog dissipate. + * + * @param {Function} [callback] + * Callback invoked when all work is done and all clients have been released. + */ Pool.prototype.drain = function drain(callback) { this._log('draining', 'info'); - - // disable the ability to put more work on the queue. this._draining = true; - var self = this; - var check = function() { - if (self._waitingClients.size() > 0) { - // wait until all client requests have been satisfied. + const check = () => { + if (this._waitingClients.size() > 0) { + // wait until all client requests have been satisfied return setTimeout(check, 100); } - if (self._asyncTestObjects.length > 0) { - // wait until any async tests have finished + if (this._asyncTestObjects.length > 0) { + // wait until async validations are done return setTimeout(check, 100); } - if (self._availableObjects.length !== self._count) { - // wait until in use object have been released. + if (this._availableObjects.length !== this._count) { + // wait until in-use objects have been released return setTimeout(check, 100); } if (callback) { @@ -532,25 +499,22 @@ Pool.prototype.drain = function drain(callback) { }; /** - * Forcibly destroys all clients regardless of timeout. Intended to be - * invoked as part of a drain. Does not prevent the creation of new - * clients as a result of subsequent calls to acquire. - * - * Note that if factory.min > 0, the pool will destroy all idle resources - * in the pool, but replace them with newly created resources up to the - * specified factory.min value. If this is not desired, set factory.min - * to zero before calling destroyAllNow() - * - * @param {Function} callback - * Optional. Callback invoked after all existing clients are destroyed. - */ + * Forcibly destroys all clients regardless of timeout. + * Does not prevent creation of new clients from subsequent calls to acquire. + * + * If factory.min > 0, the pool will destroy all idle resources + * but replace them with newly created resources up to factory.min. + * If this is not desired, set factory.min to zero before calling. + * + * @param {Function} [callback] + * Invoked after all existing clients are destroyed. + */ Pool.prototype.destroyAllNow = function destroyAllNow(callback) { this._log('force destroying all objects', 'info'); - var willDie = this._availableObjects; + const willDie = this._availableObjects; this._availableObjects = []; - var todo = willDie.length; - var done = 0; - var obj = willDie.shift(); + const todo = willDie.length; + let done = 0; this._removeIdleScheduled = false; clearTimeout(this._removeIdleTimer); @@ -559,37 +523,30 @@ Pool.prototype.destroyAllNow = function destroyAllNow(callback) { invoke(callback); return; } - while (obj !== null && obj !== undefined) { - this.destroy(obj.obj, function() { - ++done; + + while (willDie.length > 0) { + const { obj } = willDie.shift(); + this.destroy(obj, () => { + done += 1; if (done === todo && callback) { invoke(callback); - return; } }); - obj = willDie.shift(); } }; /** - * Decorates a function to use a acquired client from the object pool when called. - * - * @param {Function} decorated - * The decorated function, accepting a client as the first argument and - * (optionally) a callback as the final argument. - * - * @param {Number} priority - * Optional. Integer between 0 and (priorityRange - 1). Specifies the priority - * of the caller if there are no available resources. Lower numbers mean higher - * priority. - */ + * Decorates a function to use an acquired client from the pool when called. + * + * @param {Function} decorated + * @param {Number} [priority] + */ Pool.prototype.pooled = function pooled(decorated, priority) { - var self = this; - return function() { - var callerArgs = arguments; - var callerCallback = callerArgs[callerArgs.length - 1]; - var callerHasCallback = typeof callerCallback === 'function'; - self.acquire(function(err, client) { + return (...args) => { + const callerCallback = args[args.length - 1]; + const callerHasCallback = typeof callerCallback === 'function'; + + this.acquire((err, client) => { if (err) { if (callerHasCallback) { callerCallback(err); @@ -597,15 +554,19 @@ Pool.prototype.pooled = function pooled(decorated, priority) { return; } - var args = [client].concat(Array.prototype.slice.call(callerArgs, 0, callerHasCallback ? -1 : undefined)); - args.push(function() { - self.release(client); + // We pass everything except the user's final callback + const invokeArgs = [client].concat( + args.slice(0, callerHasCallback ? -1 : undefined) + ); + // then the final callback after we release the resource + invokeArgs.push((...cbArgs) => { + this.release(client); if (callerHasCallback) { - callerCallback.apply(null, arguments); + callerCallback(...cbArgs); } }); - decorated.apply(null, args); + decorated(...invokeArgs); }, priority); }; }; @@ -638,4 +599,4 @@ Pool.prototype.getMinPoolSize = function getMinPoolSize() { return this._factory.min; }; -exports.Pool = Pool; \ No newline at end of file +module.exports = { Pool }; diff --git a/src/getManyDto.js b/src/getManyDto.js index bfb69461..08fe728e 100644 --- a/src/getManyDto.js +++ b/src/getManyDto.js @@ -3,20 +3,21 @@ const newQuery = require('./getManyDto/newQuery'); const negotiateRawSqlFilter = require('./table/column/negotiateRawSqlFilter'); const strategyToSpan = require('./table/strategyToSpan'); const executeQueries = require('./table/executeQueries'); +const getSessionSingleton = require('./table/getSessionSingleton'); -async function getManyDto(table, filter, strategy, spanFromParent, updateParent) { - filter = negotiateRawSqlFilter(filter, table); +async function getManyDto(context, table, filter, strategy, spanFromParent, updateParent) { + filter = negotiateRawSqlFilter(context, filter, table); if (strategy && strategy.where) { - let arg = typeof strategy.where === 'function' ? strategy.where(table) : strategy.where; - filter = filter.and(arg); + let arg = typeof strategy.where === 'function' ? strategy.where(context, table) : strategy.where; + filter = filter.and(context, arg); } let span = spanFromParent || strategyToSpan(table, strategy); let alias = table._dbName; - const query = newQuery(table, filter, span, alias); - const res = await executeQueries([query]); - return decode(strategy, span, await res[0], undefined, updateParent); + const query = newQuery(context, table, filter, span, alias); + const res = await executeQueries(context, [query]); + return decode(context, strategy, span, await res[0], undefined, updateParent); } function newCreateRow(span) { @@ -149,7 +150,7 @@ function hasManyRelations(span) { } } -async function decode(strategy, span, rows, keys = rows.length > 0 ? Object.keys(rows[0]) : [], updateParent) { +async function decode(context, strategy, span, rows, keys = rows.length > 0 ? Object.keys(rows[0]) : [], updateParent) { const table = span.table; let columnsMap = span.columns; const columns = table._columns.filter(column => !columnsMap || columnsMap.get(column)); @@ -179,18 +180,16 @@ async function decode(strategy, span, rows, keys = rows.length > 0 ? Object.keys } } const column = columns[j]; - outRow[column.alias] = column.decode(row[keys[j]]); + outRow[column.alias] = column.decode(context, row[keys[j]]); } for (let j = 0; j < aggregateKeys.length; j++) { const key = aggregateKeys[j]; - const parse = span.aggregates[key].column?.decode || Number.parseFloat; - outRow[key] = parse(row[keys[j + columnsLength]]); + const parse = span.aggregates[key].column?.decode || ((context, arg) => Number.parseFloat(arg)); + outRow[key] = parse(context, row[keys[j + columnsLength]]); } outRows[i] = outRow; - // if (parentRows) - // parentRows[i][parentProp] = outRow; if (updateParent) updateParent(outRow, i); if (shouldCreateMap) { @@ -208,13 +207,11 @@ async function decode(strategy, span, rows, keys = rows.length > 0 ? Object.keys const all = []; if (shouldCreateMap) { - all.push(decodeManyRelations(strategy, span)); - all.push(decodeRelations2(strategy, span, rows, outRows, keys)); + all.push(decodeManyRelations(context, strategy, span)); + all.push(decodeRelations2(context, strategy, span, rows, outRows, keys)); } - // decodeRelations2(strategy, span, rows, outRows, keys); - // } else - all.push(decodeRelations2(strategy, span, rows, outRows, keys)); + all.push(decodeRelations2(context, strategy, span, rows, outRows, keys)); await Promise.all(all); @@ -240,70 +237,105 @@ async function decode(strategy, span, rows, keys = rows.length > 0 ? Object.keys } -async function decodeManyRelations(strategy, span) { +async function decodeManyRelations(context, strategy, span) { + const maxParameters = getSessionSingleton(context, 'maxParameters'); + const maxRows = maxParameters + ? maxParameters * span.table._primaryColumns.length + : undefined; + const promises = []; const c = {}; c.visitJoin = () => { }; c.visitOne = c.visitJoin; + // Helper function to split an array into chunks + function chunk(array, size) { + const results = []; + for (let i = 0; i < array.length; i += size) { + results.push(array.slice(i, i + size)); + } + return results; + } + c.visitMany = function(leg) { const name = leg.name; const table = span.table; const relation = table._relations[name]; const rowsMap = span._rowsMap; - const filter = createOneFilter(relation, span._ids); const extractKey = createExtractKey(leg); const extractFromMap = createExtractFromMap(rowsMap, table._primaryColumns); - const p = getManyDto(relation.childTable, filter, strategy[name], leg.span, updateParent); - // .then(subRows => { - // for (let i = 0; i < subRows.length; i++) { - // const key = extractKey(subRows[i]); - // const parentRow = extractFromMap(key); - // parentRow[name].push(subRows[i]); - // } - // }); + // If maxRows is defined, chunk the IDs before calling getManyDto + if (maxRows) { + const chunkedIds = chunk(span._ids, maxRows); + for (const idsChunk of chunkedIds) { + const filter = createOneFilter(context, relation, idsChunk); + const p = getManyDto( + context, + relation.childTable, + filter, + strategy[name], + leg.span, + updateParent + ); + promises.push(p); + } + } else { + // Otherwise, do the entire set in one go + const filter = createOneFilter(context, relation, span._ids); + const p = getManyDto( + context, + relation.childTable, + filter, + strategy[name], + leg.span, + updateParent + ); + promises.push(p); + } function updateParent(subRow) { const key = extractKey(subRow); const parentRow = extractFromMap(key); parentRow[name].push(subRow); } - - promises.push(p); }; function createExtractKey(leg) { if (leg.columns.length === 1) { const alias = leg.columns[0].alias; return (row) => row[alias]; - } - else { + } else { const aliases = leg.columns.map(column => column.alias); return (row) => aliases.map(alias => row[alias]); } } + function createExtractFromMap(map, primaryColumns) { - if (primaryColumns.length === 1) + if (primaryColumns.length === 1) { return (key) => map.get(key); - else + } else { return getFromMap.bind(null, map, primaryColumns); + } } + // Visit all legs span.legs.forEach(onEachLeg); function onEachLeg(leg) { leg.accept(c); } + // Wait until all promises resolve await Promise.all(promises); } -async function decodeRelations2(strategy, span, rawRows, resultRows, keys) { + +async function decodeRelations2(context, strategy, span, rawRows, resultRows, keys) { const c = {}; c.visitJoin = function(leg) { const name = leg.name; - return decode(strategy[name], leg.span, rawRows, keys, updateParent); + return decode(context, strategy[name], leg.span, rawRows, keys, updateParent); function updateParent(subRow, i) { resultRows[i][name] = subRow; @@ -323,11 +355,11 @@ async function decodeRelations2(strategy, span, rawRows, resultRows, keys) { await processLegsSequentially(span.legs); } -function createOneFilter(relation, ids) { +function createOneFilter(context, relation, ids) { const columns = relation.joinRelation.columns; if (columns.length === 1) - return columns[0].in(ids); + return columns[0].in(context, ids); else return createCompositeFilter(); @@ -338,11 +370,11 @@ function createOneFilter(relation, ids) { let nextFilter; for (let i = 0; i < columns.length; i++) { if (nextFilter) - nextFilter = nextFilter.and(columns[i].eq(id[i])); + nextFilter = nextFilter.and(context, columns[i].eq(context, id[i])); else - nextFilter = columns[i].eq(id[i]); + nextFilter = columns[i].eq(context, id[i]); } - filter = filter.or(nextFilter); + filter = filter.or(context, nextFilter); } return filter; } diff --git a/src/getManyDto/newQuery.js b/src/getManyDto/newQuery.js index 8722c188..ec4e3769 100644 --- a/src/getManyDto/newQuery.js +++ b/src/getManyDto/newQuery.js @@ -5,13 +5,13 @@ var extractLimit = require('../table/query/extractLimit'); var newParameterized = require('../table/query/newParameterized'); var extractOffset = require('../table/query/extractOffset'); -function newQuery(table,filter,span,alias) { +function newQuery(context,table,filter,span,alias) { filter = extractFilter(filter); - var orderBy = extractOrderBy(table,alias,span.orderBy); - var limit = extractLimit(span); - var offset = extractOffset(span); + var orderBy = extractOrderBy(context,table,alias,span.orderBy); + var limit = extractLimit(context, span); + var offset = extractOffset(context, span); - var query = newSingleQuery(table,filter,span,alias,orderBy,limit,offset); + var query = newSingleQuery(context,table,filter,span,alias,orderBy,limit,offset); return newParameterized(query.sql(), query.parameters); } diff --git a/src/getManyDto/query/newSingleQuery.js b/src/getManyDto/query/newSingleQuery.js index 96f682ed..872e3d54 100644 --- a/src/getManyDto/query/newSingleQuery.js +++ b/src/getManyDto/query/newSingleQuery.js @@ -4,12 +4,12 @@ var newJoinSql = require('../../table/query/singleQuery/newJoinSql'); var newParameterized = require('../../table/query/newParameterized'); var getSessionSingleton = require('../../table/getSessionSingleton'); -function _new(table,filter,span, alias,orderBy,limit,offset) { - var quote = getSessionSingleton('quote'); +function _new(context,table,filter,span, alias,orderBy,limit,offset) { + var quote = getSessionSingleton(context, 'quote'); var name = quote(table._dbName); - var columnSql = newColumnSql(table,span,alias,true); - var joinSql = newJoinSql(span, alias); - var whereSql = newWhereSql(table,filter,alias); + var columnSql = newColumnSql(context,table,span,alias,true); + var joinSql = newJoinSql(context, span, alias); + var whereSql = newWhereSql(context,table,filter,alias); if (limit) limit = limit + ' '; diff --git a/src/hostExpress.js b/src/hostExpress.js index 228ee4fa..683a830b 100644 --- a/src/hostExpress.js +++ b/src/hostExpress.js @@ -1,8 +1,8 @@ const getTSDefinition = require('./getTSDefinition'); -let hostLocal = _hostLocal; +// let hostLocal = _hostLocal; const getMeta = require('./hostExpress/getMeta'); -function hostExpress(client, options = {}) { +function hostExpress(hostLocal, client, options = {}) { if ('db' in options && (options.db ?? undefined) === undefined || !client.db) throw new Error('No db specified'); const dbOptions = { db: options.db || client.db }; @@ -117,9 +117,4 @@ function hostExpress(client, options = {}) { return handler; } -function _hostLocal() { - hostLocal = require('./hostLocal'); - return hostLocal.apply(null, arguments); -} - module.exports = hostExpress; \ No newline at end of file diff --git a/src/hostExpress/cycle.ts b/src/hostExpress/cycle.ts new file mode 100644 index 00000000..c5f6abbf --- /dev/null +++ b/src/hostExpress/cycle.ts @@ -0,0 +1,211 @@ +// Utility to decrement recursion depth +type DecrementDepth = D extends [any, ...infer Rest] ? Rest : never; + +// Define the structure of each node's definition within NodeTypeMap +// NodeKey is a string (or a type union of strings) that identifies a node. +type NodeDefinition = { + base: {}; // Base type of the node + children?: Record; // childPropName -> childNodeKey + parent?: { prop: string; node: string }; // parentPropName, parentNodeKey +}; + +// A map of node keys to their definitions +type NodeTypeMap = { + [NodeKey: string]: NodeDefinition; +}; + +// The RecursiveNode type: +// D: depth array +// M: the NodeTypeMap +// K: the NodeKey for the current node +// +// If D is empty, we return just the base type. +// If not empty, we return the base type plus recursively expanded children and parent. +type RecursiveNode< + D extends any[], + M extends Record, + K extends keyof M +> = D extends [] + ? // At zero depth, just return the base type of this node + M[K]['base'] + : // Non-zero depth: + // Start with the base type + M[K]['base'] + // Add recursively expanded children, if any + & (M[K]['children'] extends Record + ? { [ChildProp in keyof M[K]['children']]: + RecursiveNode, M, M[K]['children'][ChildProp]> } + : {}) + // Add recursively expanded parent, if defined + & (M[K]['parent'] extends { prop: string; node: string } + ? { [P in M[K]['parent']['prop']]: + RecursiveNode, M, M[K]['parent']['node']> } + : {}); + +// ================== EXAMPLE USAGE ================== + +// Define your base types (clean, no recursion) +type ABase = { name: string; foo: number }; +type BBase = { title: string; bar: number }; +type CBase = { label: string; baz: boolean }; +type DBase = { tag: string; qux: string }; + +// Now define a NodeTypeMap describing the structure: +// Let's say we have a graph like before, but arbitrary children. +// A has three children: bChild -> B, cChild -> C, dChild -> D +// B, C, D each have a parent going back to A +// D also has a cLink -> C + +type MyNodeTypeMap = { + A: { + base: ABase; + children: { + bChild: 'B'; + cChild: 'C'; + dChild: 'D'; + }; + // No parent defined for A (root) + }; + B: { + base: BBase; + children: { + fooLink: 'C'; // D links to C as well + }; + parent: { prop: 'aParent'; node: 'A' }; + }; + C: { + base: CBase; + // C has no children defined here + parent: { prop: 'aParent'; node: 'A' }; + }; + D: { + base: DBase; + children: { + cLink: 'C'; // D links to C as well + }; + parent: { prop: 'aParent'; node: 'A' }; + }; +}; + +// Limit recursion to depth 2 +type Depth2 = [unknown, unknown, unknown, unknown]; + +// Now we can create a type for each node expanded to Depth2: +type MyA = RecursiveNode; +type MyB = RecursiveNode; +type MyC = RecursiveNode; +type MyD = RecursiveNode; + +// Create an instance of MyA: +const aInstance: MyA = { + name: "Root A", + foo: 1, + bChild: { + title: "B Node", + bar: 100, + aParent: { + name: "A Level 2", + foo: 2, + bChild: { title: "B2", bar: 200, aParent: { name: "A Terminal", foo: 3 } }, + cChild: { label: "C2", baz: true, aParent: { name: "A Terminal", foo: 4 } }, + dChild: { + tag: "D2", + qux: "XYZ", + aParent: { name: "A Terminal", foo: 5 }, + cLink: { label: "C-Terminal", baz: false } + } + } + }, + cChild: { + label: "C Node", + baz: true, + aParent: { + name: "A Level 2C", + foo: 10, + bChild: { title: "B3", bar: 300, aParent: { name: "A Terminal", foo: 6 } }, + cChild: { label: "C3", baz: false, aParent: { name: "A Terminal", foo: 7 } }, + dChild: { + tag: "D3", + qux: "ABC", + aParent: { name: "A Terminal", foo: 8 }, + cLink: { label: "C-Terminal2", baz: true } + } + } + }, + dChild: { + tag: "D Node", + qux: "QWE", + aParent: { + name: "A Level 2D", + foo: 20, + bChild: { title: "B4", bar: 400, aParent: { name: "A Terminal", foo: 9 } }, + cChild: { label: "C4", baz: true, aParent: { name: "A Terminal", foo: 11 } }, + dChild: { + tag: "D4", + qux: "DEF", + aParent: { name: "A Terminal", foo: 12 }, + cLink: { label: "C-Terminal3", baz: false } + } + }, + cLink: { + label: "C Link Node", + baz: false + } + } +}; + +console.log(aInstance.name); // "Root A" +console.log(aInstance.bChild.title); // "B Node" +console.log(aInstance.bChild.aParent.cChild.label); // "C2" +console.log(aInstance.dChild.aParent.dChild.cLink.baz); // true + +// interface HasChild { +// child: C; +// } + +// interface HasParent

{ +// parent: P; +// } + +// interface AType extends HasChild { +// name: string; +// } + +// interface BType

extends HasParent

{ +// title: string; +// } + +// // Here is the key part: By using a circular type definition, we create a +// // specific pair (CyclicA, CyclicB) that point to each other generically. +// // 'CyclicA' extends 'AType' and expects a child of type 'CyclicB'. +// // 'CyclicB' extends 'BType' and expects a parent of type 'CyclicA'. + +// // Note: TypeScript allows this pattern as long as the interfaces are defined first. +// // The cycle is established by the subsequent type definitions. + +// type CyclicA = AType; +// type CyclicB = BType; + +// // Now 'CyclicA' and 'CyclicB' are fully defined, with a cyclical reference: +// // CyclicA -> child: CyclicB +// // CyclicB -> parent: CyclicA + +// // Example usage: +// const aInstance: CyclicA ; + + +// // Establish the cycle at runtime. + + +// // We can now traverse back and forth: +// console.log(aInstance.name); // "Node A" +// console.log(aInstance.child.title); // "Node B" +// console.log(aInstance.child.parent.name); // "Node A" (cycle complete) + +// // This pattern is generic. If you want another pair of cyclical types, +// // say X and Y, you can do: + +// type CyclicX = XType; // define similarly using HasChild/HasParent +// type CyclicY = YType; +// // ...and so forth, using the same building blocks. + \ No newline at end of file diff --git a/src/hostExpress/executePath.js b/src/hostExpress/executePath.js index cd8587c8..e053281b 100644 --- a/src/hostExpress/executePath.js +++ b/src/hostExpress/executePath.js @@ -3,14 +3,6 @@ const emptyFilter = require('../emptyFilter'); const negotiateRawSqlFilter = require('../table/column/negotiateRawSqlFilter'); let getMeta = require('./getMeta'); let isSafe = Symbol(); -let _ops = { - and: emptyFilter.and, - or: emptyFilter.or, - not: emptyFilter.not, - AND: emptyFilter.and, - OR: emptyFilter.or, - NOT: emptyFilter.not -}; let _allowedOps = { and: true, @@ -69,431 +61,443 @@ let _allowedOps = { self: true, }; -async function executePath({ table, JSONFilter, baseFilter, customFilters = {}, request, response, readonly, disableBulkDeletes, isHttp, client }) { - let allowedOps = { ..._allowedOps, insert: !readonly, ...extractRelations(getMeta(table)) }; - let ops = { ..._ops, ...getCustomFilterPaths(customFilters), getManyDto, getMany, aggregate, count, delete: _delete, cascadeDelete, update, replace }; - - let res = await parseFilter(JSONFilter, table); - if (res === undefined) - return {}; - else - return res; - - function parseFilter(json, table) { - if (isFilter(json)) { - let subFilters = []; - - let anyAllNone = tryGetAnyAllNone(json.path, table); - if (anyAllNone) { - if (isHttp) - validateArgs(json.args[0]); - const f = anyAllNone(x => parseFilter(json.args[0], x)); - f.isSafe = isSafe; - return f; +function _executePath(context, ...rest) { + + const _ops = { + and: emptyFilter.and.bind(null, context), + or: emptyFilter.or.bind(null, context), + not: emptyFilter.not.bind(null, context), + AND: emptyFilter.and.bind(null, context), + OR: emptyFilter.or.bind(null, context), + NOT: emptyFilter.not.bind(null, context), + }; + + return executePath(...rest); + + async function executePath({ table, JSONFilter, baseFilter, customFilters = {}, request, response, readonly, disableBulkDeletes, isHttp, client }) { + let allowedOps = { ..._allowedOps, insert: !readonly, ...extractRelations(getMeta(table)) }; + let ops = { ..._ops, ...getCustomFilterPaths(customFilters), getManyDto, getMany, aggregate, count, delete: _delete, cascadeDelete, update, replace }; + + let res = await parseFilter(JSONFilter, table); + if (res === undefined) + return {}; + else + return res; + + function parseFilter(json, table) { + if (isFilter(json)) { + let subFilters = []; + + let anyAllNone = tryGetAnyAllNone(json.path, table); + if (anyAllNone) { + if (isHttp) + validateArgs(json.args[0]); + const f = anyAllNone(context, x => parseFilter(json.args[0], x)); + if(!('isSafe' in f)) + f.isSafe = isSafe; + return f; + } + else { + for (let i = 0; i < json.args.length; i++) { + subFilters.push(parseFilter(json.args[i], nextTable(json.path, table))); + } + } + return executePath(json.path, subFilters); } - else { - for (let i = 0; i < json.args.length; i++) { - subFilters.push(parseFilter(json.args[i], nextTable(json.path, table))); + else if (Array.isArray(json)) { + const result = []; + for (let i = 0; i < json.length; i++) { + result.push(parseFilter(json[i], table)); + } + return result; + } + return json; + + function tryGetAnyAllNone(path, table) { + path = path.split('.'); + for (let i = 0; i < path.length; i++) { + table = table[path[i]]; + } + + let ops = new Set(['all', 'any', 'none', 'where', '_aggregate']); + // let ops = new Set(['all', 'any', 'none', 'where']); + let last = path.slice(-1)[0]; + if (ops.has(last) || (table && (table._primaryColumns || (table.any && table.all)))) + return table; + } + + function executePath(path, args) { + if (path in ops) { + if (isHttp) + validateArgs(args); + let op = ops[path].apply(null, args); + if (op.then) + return op.then((o) => { + setSafe(o); + return o; + }); + setSafe(op); + return op; + } + let pathArray = path.split('.'); + let target = table; + let op = pathArray[pathArray.length - 1]; + if (!allowedOps[op] && isHttp) { + + let e = new Error('Disallowed operator ' + op); + // @ts-ignore + e.status = 403; + throw e; + + } + for (let i = 0; i < pathArray.length; i++) { + target = target[pathArray[i]]; } + + if (!target) + throw new Error(`Method '${path}' does not exist`); + let res = target.apply(null, [context, ...args]); + setSafe(res); + return res; } - return executePath(json.path, subFilters); } - else if (Array.isArray(json)) { - const result = []; - for (let i = 0; i < json.length; i++) { - result.push(parseFilter(json[i], table)); + + async function invokeBaseFilter() { + if (typeof baseFilter === 'function') { + const res = await baseFilter.apply(null, [bindDb(client), request, response]); + if (!res) + return; + const JSONFilter = JSON.parse(JSON.stringify(res)); + //@ts-ignore + return executePath({ table, JSONFilter, request, response }); } - return result; + else + return; } - return json; - function tryGetAnyAllNone(path, table) { - path = path.split('.'); - for (let i = 0; i < path.length; i++) { - table = table[path[i]]; + function getCustomFilterPaths(customFilters) { + return getLeafNames(customFilters); + + function getLeafNames(obj, result = {}, current = 'customFilters.') { + for (let p in obj) { + if (typeof obj[p] === 'object' && obj[p] !== null) + getLeafNames(obj[p], result, current + p + '.'); + else + result[current + p] = resolveFilter.bind(null, obj[p]); + } + return result; + } + + async function resolveFilter(fn, ...args) { + const context = { db: bindDb(client), request, response }; + let res = fn.apply(null, [context, ...args]); + if (res.then) + res = await res; + const JSONFilter = JSON.parse(JSON.stringify(res)); + //@ts-ignore + return executePath({ table, JSONFilter, request, response }); } + } - let ops = new Set(['all', 'any', 'none', 'where', '_aggregate']); - // let ops = new Set(['all', 'any', 'none', 'where']); + function nextTable(path, table) { + path = path.split('.'); + let ops = new Set(['all', 'any', 'none']); let last = path.slice(-1)[0]; - if (ops.has(last) || (table && (table._primaryColumns || (table.any && table.all)))) + if (ops.has(last)) { + for (let i = 0; i < path.length - 1; i++) { + table = table[path[i]]; + } return table; + } + else { + let lastObj = table; + for (let i = 0; i < path.length; i++) { + if (lastObj) + lastObj = lastObj[path[i]]; + } + if (lastObj?._shallow) + return lastObj._shallow; + else return table; + } } - function executePath(path, args) { - if (path in ops) { - if (isHttp) - validateArgs(args); - let op = ops[path].apply(null, args); - if (op.then) - return op.then((o) => { - setSafe(o); - return o; - }); - setSafe(op); - return op; + async function _delete(filter) { + if (readonly || disableBulkDeletes) { + let e = new Error('Bulk deletes are not allowed. Parameter "disableBulkDeletes" must be true.'); + // @ts-ignore + e.status = 403; + throw e; } - let pathArray = path.split('.'); - let target = table; - let op = pathArray[pathArray.length - 1]; - if (!allowedOps[op] && isHttp) { + filter = negotiateFilter(filter); + const _baseFilter = await invokeBaseFilter(); + if (_baseFilter) + filter = filter.and(context, _baseFilter); + let args = [context, filter].concat(Array.prototype.slice.call(arguments).slice(1)); + return table.delete.apply(null, args); + } - let e = new Error('Disallowed operator ' + op); + async function cascadeDelete(filter) { + if (readonly || disableBulkDeletes) { + const e = new Error('Bulk deletes are not allowed. Parameter "disableBulkDeletes" must be true.'); // @ts-ignore e.status = 403; throw e; } - for (let i = 0; i < pathArray.length; i++) { - target = target[pathArray[i]]; - } - - if (!target) - throw new Error(`Method '${path}' does not exist`); - let res = target.apply(null, args); - setSafe(res); - return res; + filter = negotiateFilter(filter); + const _baseFilter = await invokeBaseFilter(); + if (_baseFilter) + filter = filter.and(context, _baseFilter); + let args = [context, filter].concat(Array.prototype.slice.call(arguments).slice(1)); + return table.cascadeDelete.apply(null, args); } - } - - - async function invokeBaseFilter() { - if (typeof baseFilter === 'function') { - const res = await baseFilter.apply(null, [bindDb(client), request, response]); - if (!res) - return; - const JSONFilter = JSON.parse(JSON.stringify(res)); - //@ts-ignore - return executePath({ table, JSONFilter, request, response }); + function negotiateFilter(filter) { + if (filter) + return negotiateRawSqlFilter(context, filter, table, true); + else + return emptyFilter; } - else - return; - } - - function getCustomFilterPaths(customFilters) { - return getLeafNames(customFilters); - function getLeafNames(obj, result = {}, current = 'customFilters.') { - for (let p in obj) { - if (typeof obj[p] === 'object' && obj[p] !== null) - getLeafNames(obj[p], result, current + p + '.'); - else - result[current + p] = resolveFilter.bind(null, obj[p]); - } - return result; + async function count(filter, strategy) { + validateStrategy(table, strategy); + filter = negotiateFilter(filter); + const _baseFilter = await invokeBaseFilter(); + if (_baseFilter) + filter = filter.and(context, _baseFilter); + let args = [context, filter].concat(Array.prototype.slice.call(arguments).slice(1)); + return table.count.apply(null, args); } - async function resolveFilter(fn, ...args) { - const context = { db: bindDb(client), request, response }; - let res = fn.apply(null, [context, ...args]); - if (res.then) - res = await res; - const JSONFilter = JSON.parse(JSON.stringify(res)); - //@ts-ignore - return executePath({ table, JSONFilter, request, response }); + async function getManyDto(filter, strategy) { + validateStrategy(table, strategy); + filter = negotiateFilter(filter); + const _baseFilter = await invokeBaseFilter(); + if (_baseFilter) + filter = filter.and(context, _baseFilter); + let args = [context, filter].concat(Array.prototype.slice.call(arguments).slice(1)); + await negotiateWhereAndAggregate(strategy); + return table.getManyDto.apply(null, args); } - } - function nextTable(path, table) { - path = path.split('.'); - let ops = new Set(['all', 'any', 'none']); - let last = path.slice(-1)[0]; - if (ops.has(last)) { - for (let i = 0; i < path.length - 1; i++) { - table = table[path[i]]; - } - return table; + async function replace(subject, strategy = { insertAndForget: true }) { + validateStrategy(table, strategy); + const refinedStrategy = objectToStrategy(subject, {}, table); + const JSONFilter2 = { + path: 'getManyDto', + args: [subject, refinedStrategy] + }; + const originals = await executePath({ table, JSONFilter: JSONFilter2, baseFilter, customFilters, request, response, readonly, disableBulkDeletes, isHttp, client }); + const meta = getMeta(table); + const patch = createPatch(originals, Array.isArray(subject) ? subject : [subject], meta); + const { changed } = await table.patch(context, patch, { strategy }); + if (Array.isArray(subject)) + return changed; + else + return changed[0]; } - else { - let lastObj = table; - for (let i = 0; i < path.length; i++) { - if (lastObj) - lastObj = lastObj[path[i]]; + + async function update(subject, whereStrategy, strategy = { insertAndForget: true }) { + validateStrategy(table, strategy); + const refinedWhereStrategy = objectToStrategy(subject, whereStrategy, table); + const JSONFilter2 = { + path: 'getManyDto', + args: [null, refinedWhereStrategy] + }; + const rows = await executePath({ table, JSONFilter: JSONFilter2, baseFilter, customFilters, request, response, readonly, disableBulkDeletes, isHttp, client }); + const originals = new Array(rows.length); + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + originals[i] = { ...row }; + for (let p in subject) { + row[p] = subject[p]; + } } - if (lastObj?._shallow) - return lastObj._shallow; - else return table; + const meta = getMeta(table); + const patch = createPatch(originals, rows, meta); + const { changed } = await table.patch(context, patch, { strategy }); + return changed; } - } - async function _delete(filter) { - if (readonly || disableBulkDeletes) { - let e = new Error('Bulk deletes are not allowed. Parameter "disableBulkDeletes" must be true.'); - // @ts-ignore - e.status = 403; - throw e; + function objectToStrategy(object, whereStrategy, table, strategy = {}) { + strategy = { ...whereStrategy, ...strategy }; + if (Array.isArray(object)) { + for (let i = 0; i < object.length; i++) { + objectToStrategy(object[i], table, strategy); + } + return; + } + for (let name in object) { + const relation = table[name]?._relation; + if (relation && !relation.columns) {//notJoin, that is one or many + strategy[name] = {}; + objectToStrategy(object[name], whereStrategy?.[name], table[name], strategy[name]); + } + else + strategy[name] = true; + } + return strategy; } - filter = negotiateFilter(filter); - const _baseFilter = await invokeBaseFilter(); - if (_baseFilter) - filter = filter.and(_baseFilter); - let args = [filter].concat(Array.prototype.slice.call(arguments).slice(1)); - return table.delete.apply(null, args); - } - async function cascadeDelete(filter) { - if (readonly || disableBulkDeletes) { - const e = new Error('Bulk deletes are not allowed. Parameter "disableBulkDeletes" must be true.'); - // @ts-ignore - e.status = 403; - throw e; + async function aggregate(filter, strategy) { + validateStrategy(table, strategy); + filter = negotiateFilter(filter); + const _baseFilter = await invokeBaseFilter(); + if (_baseFilter) + filter = filter.and(context, _baseFilter); + let args = [context, filter].concat(Array.prototype.slice.call(arguments).slice(1)); + await negotiateWhereAndAggregate(strategy); + return table.aggregate.apply(null, args); } - filter = negotiateFilter(filter); - const _baseFilter = await invokeBaseFilter(); - if (_baseFilter) - filter = filter.and(_baseFilter); - let args = [filter].concat(Array.prototype.slice.call(arguments).slice(1)); - return table.cascadeDelete.apply(null, args); - } - - function negotiateFilter(filter) { - if (filter) - return negotiateRawSqlFilter(filter, table, true); - else - return emptyFilter; - } - async function count(filter, strategy) { - validateStrategy(table, strategy); - filter = negotiateFilter(filter); - const _baseFilter = await invokeBaseFilter(); - if (_baseFilter) - filter = filter.and(_baseFilter); - let args = [filter].concat(Array.prototype.slice.call(arguments).slice(1)); - return table.count.apply(null, args); - } - async function getManyDto(filter, strategy) { - validateStrategy(table, strategy); - filter = negotiateFilter(filter); - const _baseFilter = await invokeBaseFilter(); - if (_baseFilter) - filter = filter.and(_baseFilter); - let args = [filter].concat(Array.prototype.slice.call(arguments).slice(1)); - await negotiateWhereAndAggregate(strategy); - return table.getManyDto.apply(null, args); - } - async function replace(subject, strategy = { insertAndForget: true }) { - validateStrategy(table, strategy); - const refinedStrategy = objectToStrategy(subject, {}, table); - const JSONFilter2 = { - path: 'getManyDto', - args: [subject, refinedStrategy] - }; - const originals = await executePath({ table, JSONFilter: JSONFilter2, baseFilter, customFilters, request, response, readonly, disableBulkDeletes, isHttp, client }); - const meta = getMeta(table); - const patch = createPatch(originals, Array.isArray(subject) ? subject : [subject], meta); - const { changed } = await table.patch(patch, { strategy }); - if (Array.isArray(subject)) - return changed; - else - return changed[0]; - } + async function negotiateWhereAndAggregate(strategy) { + if (typeof strategy !== 'object') + return; - async function update(subject, whereStrategy, strategy = { insertAndForget: true }) { - validateStrategy(table, strategy); - const refinedWhereStrategy = objectToStrategy(subject, whereStrategy, table); - const JSONFilter2 = { - path: 'getManyDto', - args: [null, refinedWhereStrategy] - }; - const rows = await executePath({ table, JSONFilter: JSONFilter2, baseFilter, customFilters, request, response, readonly, disableBulkDeletes, isHttp, client }); - const originals = new Array(rows.length); - for (let i = 0; i < rows.length; i++) { - const row = rows[i]; - originals[i] = { ...row }; - for (let p in subject) { - row[p] = subject[p]; + for (let name in strategy) { + const target = strategy[name]; + if (isFilter(target)) + strategy[name] = await parseFilter(strategy[name], table); + else + await negotiateWhereAndAggregate(strategy[name]); } - } - const meta = getMeta(table); - const patch = createPatch(originals, rows, meta); - const { changed } = await table.patch(patch, { strategy }); - return changed; - } - function objectToStrategy(object, whereStrategy, table, strategy = {}) { - strategy = {...whereStrategy, ...strategy}; - if (Array.isArray(object)) { - for (let i = 0; i < object.length; i++) { - objectToStrategy(object[i], table, strategy); - } - return; - } - for (let name in object) { - const relation = table[name]?._relation; - if (relation && !relation.columns) {//notJoin, that is one or many - strategy[name] = {}; - objectToStrategy(object[name], whereStrategy?.[name], table[name], strategy[name]); - } - else - strategy[name] = true; } - return strategy; - } + async function getMany(filter, strategy) { + validateStrategy(table, strategy); + filter = negotiateFilter(filter); + const _baseFilter = await invokeBaseFilter(); + if (_baseFilter) + filter = filter.and(context, _baseFilter); + let args = [context, filter].concat(Array.prototype.slice.call(arguments).slice(1)); + await negotiateWhereAndAggregate(strategy); + return table.getMany.apply(null, args); + } - async function aggregate(filter, strategy) { - validateStrategy(table, strategy); - filter = negotiateFilter(filter); - const _baseFilter = await invokeBaseFilter(); - if (_baseFilter) - filter = filter.and(_baseFilter); - let args = [filter].concat(Array.prototype.slice.call(arguments).slice(1)); - await negotiateWhereAndAggregate(strategy); - return table.aggregate.apply(null, args); } - - - async function negotiateWhereAndAggregate(strategy) { - if (typeof strategy !== 'object') + function validateStrategy(table, strategy) { + if (!strategy || !table) return; - for (let name in strategy) { - const target = strategy[name]; - if (isFilter(target)) - strategy[name] = await parseFilter(strategy[name], table); - else - await negotiateWhereAndAggregate(strategy[name]); + for (let p in strategy) { + validateOffset(strategy); + validateLimit(strategy); + validateOrderBy(table, strategy); + validateStrategy(table[p], strategy[p]); } - } - async function getMany(filter, strategy) { - validateStrategy(table, strategy); - filter = negotiateFilter(filter); - const _baseFilter = await invokeBaseFilter(); - if (_baseFilter) - filter = filter.and(_baseFilter); - let args = [filter].concat(Array.prototype.slice.call(arguments).slice(1)); - await negotiateWhereAndAggregate(strategy); - return table.getMany.apply(null, args); + function validateLimit(strategy) { + if (!('limit' in strategy) || Number.isInteger(strategy.limit)) + return; + const e = new Error('Invalid limit: ' + strategy.limit); + // @ts-ignore + e.status = 400; } -} - -function validateStrategy(table, strategy) { - if (!strategy || !table) - return; - - for (let p in strategy) { - validateOffset(strategy); - validateLimit(strategy); - validateOrderBy(table, strategy); - validateStrategy(table[p], strategy[p]); + function validateOffset(strategy) { + if (!('offset' in strategy) || Number.isInteger(strategy.offset)) + return; + const e = new Error('Invalid offset: ' + strategy.offset); + // @ts-ignore + e.status = 400; + throw e; } -} -function validateLimit(strategy) { - if (!('limit' in strategy) || Number.isInteger(strategy.limit)) - return; - const e = new Error('Invalid limit: ' + strategy.limit); - // @ts-ignore - e.status = 400; -} - -function validateOffset(strategy) { - if (!('offset' in strategy) || Number.isInteger(strategy.offset)) - return; - const e = new Error('Invalid offset: ' + strategy.offset); - // @ts-ignore - e.status = 400; - throw e; -} + function validateOrderBy(table, strategy) { + if (!('orderBy' in strategy) || !table) + return; + let orderBy = strategy.orderBy; + if (!Array.isArray(orderBy)) + orderBy = [orderBy]; + orderBy.reduce(validate, []); + + function validate(_, element) { + let parts = element.split(' ').filter(x => { + x = x.toLowerCase(); + return (!(x === '' || x === 'asc' || x === 'desc')); + }); + for (let p of parts) { + let col = table[p]; + if (!(col && col.equal)) { + const e = new Error('Unknown column: ' + p); + // @ts-ignore + e.status = 400; + throw e; + } + } + } + } -function validateOrderBy(table, strategy) { - if (!('orderBy' in strategy) || !table) - return; - let orderBy = strategy.orderBy; - if (!Array.isArray(orderBy)) - orderBy = [orderBy]; - orderBy.reduce(validate, []); - - function validate(_, element) { - let parts = element.split(' ').filter(x => { - x = x.toLowerCase(); - return (!(x === '' || x === 'asc' || x === 'desc')); - }); - for (let p of parts) { - let col = table[p]; - if (!(col && col.equal)) { - const e = new Error('Unknown column: ' + p); + function validateArgs() { + for (let i = 0; i < arguments.length; i++) { + const filter = arguments[i]; + if (!filter) + continue; + if (filter && filter.isSafe === isSafe) + continue; + if (filter.sql || typeof (filter) === 'string') { + const e = new Error('Raw filters are disallowed'); // @ts-ignore - e.status = 400; + e.status = 403; throw e; } - } - } -} + if (Array.isArray(filter)) + for (let i = 0; i < filter.length; i++) { -function validateArgs() { - for (let i = 0; i < arguments.length; i++) { - const filter = arguments[i]; - if (!filter) - continue; - if (filter && filter.isSafe === isSafe) - continue; - if (filter.sql || typeof (filter) === 'string') { - const e = new Error('Raw filters are disallowed'); - // @ts-ignore - e.status = 403; - throw e; + validateArgs(filter[i]); + } } - if (Array.isArray(filter)) - for (let i = 0; i < filter.length; i++) { - validateArgs(filter[i]); - } } -} + function isFilter(json) { + return json instanceof Object && 'path' in json && 'args' in json; + } -function isFilter(json) { - return json instanceof Object && 'path' in json && 'args' in json; -} + function setSafe(o) { + if (o instanceof Object) + Object.defineProperty(o, 'isSafe', { + value: isSafe, + enumerable: false -function setSafe(o) { - if (o instanceof Object) - Object.defineProperty(o, 'isSafe', { - value: isSafe, - enumerable: false + }); + } - }); -} + function extractRelations(obj) { + let flattened = {}; -function extractRelations(obj) { - let flattened = {}; + function helper(relations) { + Object.keys(relations).forEach(key => { - function helper(relations) { - Object.keys(relations).forEach(key => { + flattened[key] = true; - flattened[key] = true; + if (typeof relations[key] === 'object' && Object.keys(relations[key]?.relations)?.length > 0) { + helper(relations[key].relations); + } + }); + } - if (typeof relations[key] === 'object' && Object.keys(relations[key]?.relations)?.length > 0) { - helper(relations[key].relations); - } - }); + helper(obj.relations); + + return flattened; } - helper(obj.relations); + function bindDb(client) { + var domain = context; + let p = domain.run(() => true); - return flattened; -} + function run(fn) { + return p.then(domain.run.bind(domain, fn)); + } -function bindDb(client) { - // @ts-ignore - var domain = process.domain; - let p = domain.run(() => true); + return client({ transaction: run }); - function run(fn) { - return p.then(domain.run.bind(domain, fn)); } - - return client({ transaction: run }); - } -module.exports = executePath; \ No newline at end of file +module.exports = _executePath; \ No newline at end of file diff --git a/src/hostLocal.js b/src/hostLocal.js index ce9f1202..3e537cf5 100644 --- a/src/hostLocal.js +++ b/src/hostLocal.js @@ -44,10 +44,10 @@ function hostLocal() { } return result; - async function fn() { - setSessionSingleton('ignoreSerializable', true); + async function fn(context) { + setSessionSingleton(context, 'ignoreSerializable', true); let patch = body.patch; - result = await table.patch(patch, { ..._options, ...body.options, isHttp }); + result = await table.patch(context, patch, { ..._options, ...body.options, isHttp }); } } @@ -72,10 +72,10 @@ function hostLocal() { } return result; - async function fn() { - setSessionSingleton('ignoreSerializable', true); + async function fn(context) { + setSessionSingleton(context, 'ignoreSerializable', true); const options = { ..._options, ...body.options, JSONFilter: body, request, response, isHttp }; - result = await executePath(options); + result = await executePath(context, options); } } async function query() { @@ -97,14 +97,14 @@ function hostLocal() { return result; - async function fn() { - result = await executeQuery.apply(null, args); + async function fn(...args1) { + result = await executeQuery.apply(null, [...args1, ...args]); } } function express(client, options) { - return hostExpress(client, options); + return hostExpress(hostLocal, client, options); } return c; diff --git a/src/index.d.ts b/src/index.d.ts index 3ec64ab2..80b316eb 100644 --- a/src/index.d.ts +++ b/src/index.d.ts @@ -1,5 +1,6 @@ import type { Options } from './ajv'; import type { RequestHandler } from 'express'; +import type { D1Database } from '@cloudflare/workers-types'; import type { ConnectionConfiguration } from 'tedious'; import type { PoolAttributes } from 'oracledb'; import type { AllowedDbMap, DbMapper, MappedDbDef } from './map'; @@ -10,6 +11,7 @@ declare namespace r { function table(name: string): Table; function end(): Promise; + function d1(database: D1Database, options?: PoolOptions): Pool; function postgres(connectionString: string, options?: PoolOptions): Pool; function sqlite(connectionString: string, options?: PoolOptions): Pool; function sap(connectionString: string, options?: PoolOptions): Pool; diff --git a/src/index.js b/src/index.js index 3d12d0f6..186a9d4e 100644 --- a/src/index.js +++ b/src/index.js @@ -1,14 +1,15 @@ -var hostExpress = require('./hostExpress'); -var client = require('./client/index.js'); -var _mySql; -var _pg; -var _sqlite; -var _mssqlNative; -var _sap; -var _mssql; -var _oracle; -var flags = require('./flags'); -var map = require('./client/map'); +const hostExpress = require('./hostExpress'); +const hostLocal = require('./hostLocal'); +const client = require('./client/index.js'); +const map = require('./client/map'); +let _mySql; +let _pg; +let _sqlite; +let _mssqlNative; +let _sap; +let _mssql; +let _oracle; +let _d1; var connectViaPool = function(connectionString) { if (connectionString.indexOf && connectionString.indexOf('mysql') === 0) @@ -51,7 +52,6 @@ Object.defineProperty(connectViaPool, 'mySql', { return _mySql; } }); - Object.defineProperty(connectViaPool, 'postgres', { get: function() { if (!_pg) @@ -76,6 +76,14 @@ Object.defineProperty(connectViaPool, 'sqlite', { } }); +Object.defineProperty(connectViaPool, 'd1', { + get: function() { + if (!_d1) + _d1 = require('./d1/newDatabase'); + return _d1; + } +}); + Object.defineProperty(connectViaPool, 'mssqlNative', { get: function() { if (!_mssqlNative) @@ -108,9 +116,6 @@ Object.defineProperty(connectViaPool, 'oracle', { } }); -connectViaPool.express = hostExpress; -connectViaPool.useHook = function(bool) { - flags.useHook = bool; -}; +connectViaPool.express = hostExpress.bind(null, hostLocal); module.exports = connectViaPool; \ No newline at end of file diff --git a/src/indexBrowser.js b/src/indexBrowser.js new file mode 100644 index 00000000..bfb60af7 --- /dev/null +++ b/src/indexBrowser.js @@ -0,0 +1,39 @@ +const hostExpress = require('./hostExpress'); +const hostLocal = require('./hostLocal'); +const client = require('./client/index.js'); +const map = require('./client/map'); +let _d1; + +var connectViaPool = function() { + return client.apply(null, arguments); +}; +connectViaPool.createPatch = client.createPatch; +connectViaPool.table = require('./table'); +connectViaPool.filter = require('./emptyFilter'); +connectViaPool.commit = require('./table/commit'); +connectViaPool.rollback = require('./table/rollback'); +connectViaPool.end = require('./pools').end; +connectViaPool.log = require('./table/log').registerLogger; +connectViaPool.on = require('./table/log').on; +connectViaPool.off = require('./table/log').off; +connectViaPool.query = require('./query'); +connectViaPool.lock = require('./lock'); +connectViaPool.schema = require('./pg/schema'); +connectViaPool.map = map.bind(null, connectViaPool); + +connectViaPool.http = function(url) { + return url; +}; + + +Object.defineProperty(connectViaPool, 'd1', { + get: function() { + if (!_d1) + _d1 = require('./d1/newDatabase'); + return _d1; + } +}); + +connectViaPool.express = hostExpress.bind(null, hostLocal); + +module.exports = connectViaPool; \ No newline at end of file diff --git a/src/map.d.ts b/src/map.d.ts index 1aa7db0e..cf1b6c46 100644 --- a/src/map.d.ts +++ b/src/map.d.ts @@ -1,5 +1,6 @@ import type { Options } from './ajv'; import type { ConnectionConfiguration } from 'tedious'; +import type { D1Database } from '@cloudflare/workers-types'; import type { PoolAttributes } from 'oracledb'; import type { AxiosInterceptorManager, InternalAxiosRequestConfig, AxiosResponse } from 'axios'; @@ -29,6 +30,7 @@ type MappedDb = { type DbConnectable = { http(url: string): MappedDbInstance; + d1(database: D1Database): MappedDbInstance; postgres(connectionString: string, options?: PoolOptions): MappedDbInstance; sqlite(connectionString: string, options?: PoolOptions): MappedDbInstance; sap(connectionString: string, options?: PoolOptions): MappedDbInstance; @@ -59,6 +61,7 @@ type DbOptions = { interface Connectors { http(url: string): Pool; + d1(database: D1Database): Pool; postgres(connectionString: string, options?: PoolOptions): Pool; sqlite(connectionString: string, options?: PoolOptions): Pool; sap(connectionString: string, options?: PoolOptions): Pool; diff --git a/src/mssql/newDatabase.js b/src/mssql/newDatabase.js index 540fa9fc..2fd9163c 100644 --- a/src/mssql/newDatabase.js +++ b/src/mssql/newDatabase.js @@ -4,10 +4,6 @@ let _begin = require('../table/begin'); let commit = require('../table/commit'); let rollback = require('../table/rollback'); let newPool = require('./newPool'); -let useHook = require('../useHook'); -let promise = require('promise/domains'); -let versionArray = process.version.replace('v', '').split('.'); -let major = parseInt(versionArray[0]); let express = require('../hostExpress'); let hostLocal = require('../hostLocal'); let doQuery = require('../query'); @@ -34,10 +30,6 @@ function newDatabase(connectionString, poolOptions) { if (fn) return domain.run(runInTransaction); - else if ((major >= 12) && useHook()) { - domain.exitContext = true; - return domain.start().then(run); - } else return domain.run(run); @@ -46,67 +38,63 @@ function newDatabase(connectionString, poolOptions) { let transaction = newTransaction(domain, pool, options); await new Promise(transaction) .then(begin) - .then(fn) + .then(() => fn(domain)) .then((res) => result = res) - .then(c.commit) - .then(null, c.rollback); + .then(() => c.commit(domain)) + .then(null, (e) => c.rollback(domain, e)); return result; } function begin() { - return _begin(options?.readonly); + return _begin(domain, options); } function run() { let p; let transaction = newTransaction(domain, pool, options); - if (useHook()) - p = new Promise(transaction); - else - p = new promise(transaction); + p = new Promise(transaction); return p.then(begin); } }; - c.createTransaction = function() { + c.createTransaction = function(options) { let domain = createDomain(); let transaction = newTransaction(domain, pool); - let p = domain.run(() => new Promise(transaction).then(_begin)); + let p = domain.run(() => new Promise(transaction).then(begin)); function run(fn) { return p.then(domain.run.bind(domain, fn)); } - return run; - }; - c.bindTransaction = function() { - // @ts-ignore - var domain = process.domain; - let p = domain.run(() => true); - - function run(fn) { - return p.then(domain.run.bind(domain, fn)); + function begin() { + return _begin(domain, options); } + + run.rollback = rollback.bind(null, domain); + run.commit = commit.bind(null, domain); + return run; + + }; c.query = function(query) { let domain = createDomain(); let transaction = newTransaction(domain, pool); let p = domain.run(() => new Promise(transaction) - .then(() => setSessionSingleton('changes', [])) - .then(() => doQuery(query).then(onResult, onError))); + .then(() => setSessionSingleton(domain, 'changes', [])) + .then(() => doQuery(domain, query).then(onResult, onError))); return p; function onResult(result) { - releaseDbClient(); + releaseDbClient(domain); return result; } function onError(e) { - releaseDbClient(); + releaseDbClient(domain); throw e; } }; diff --git a/src/mssql/newPool.js b/src/mssql/newPool.js index 8ea1295a..3ffcf687 100644 --- a/src/mssql/newPool.js +++ b/src/mssql/newPool.js @@ -1,5 +1,5 @@ +const promisify = require('../promisify'); var pools = require('../pools'); -var promise = require('../table/promise'); var end = require('./pool/end'); var newGenericPool = require('./pool/newGenericPool'); var newId = require('../newId'); @@ -11,7 +11,7 @@ function newPool(connectionString, poolOptions) { var c = {}; c.connect = pool.connect; - c.end = promise.denodeify(boundEnd); + c.end = promisify(boundEnd); pools[id] = c; return c; } diff --git a/src/mssql/newTransaction.js b/src/mssql/newTransaction.js index eb225955..7822b749 100644 --- a/src/mssql/newTransaction.js +++ b/src/mssql/newTransaction.js @@ -2,13 +2,14 @@ var wrapQuery = require('./wrapQuery'); var encodeBoolean = require('../tedious/encodeBoolean'); var deleteFromSql = require('../tedious/deleteFromSql'); var selectForUpdateSql = require('../tedious/selectForUpdateSql'); -var outputInsertedSql = require('../tedious/outputInsertedSql'); const limitAndOffset = require('../tedious/limitAndOffset'); const formatDateOut = require('../tedious/formatDateOut'); +const formatJSONOut = require('../tedious/formatJSONOut'); const insertSql = require('../tedious/insertSql'); const insert = require('../tedious/insert'); +const quote = require('../tedious/quote'); -function newResolveTransaction(domain, pool, { readonly } = {}) { +function newResolveTransaction(domain, pool, { readonly = false } = {}) { var rdb = {poolFactory: pool}; if (!pool.connect) { pool = pool(); @@ -19,9 +20,9 @@ function newResolveTransaction(domain, pool, { readonly } = {}) { rdb.decodeJSON = decodeJSON; rdb.encodeJSON = JSON.stringify; rdb.formatDateOut = formatDateOut; + rdb.formatJSONOut = formatJSONOut; rdb.deleteFromSql = deleteFromSql; rdb.selectForUpdateSql = selectForUpdateSql; - rdb.outputInsertedSql = outputInsertedSql; rdb.insertSql = insertSql; rdb.insert = insert; rdb.lastInsertedIsSeparate = false; @@ -40,7 +41,7 @@ function newResolveTransaction(domain, pool, { readonly } = {}) { caller.visitSqlite(); }; rdb.aggregateCount = 0; - rdb.quote = (name) => `[${name}]`; + rdb.quote = quote; if (readonly) { rdb.dbClient = { diff --git a/src/mssql/pool/defaults.js b/src/mssql/pool/defaults.js deleted file mode 100644 index f21f834a..00000000 --- a/src/mssql/pool/defaults.js +++ /dev/null @@ -1,45 +0,0 @@ -module.exports = { - // database host defaults to localhost - host: 'localhost', - - //database user's name - user: process.platform === 'win32' ? process.env.USERNAME : process.env.USER, - - //name of database to connect - database: process.platform === 'win32' ? process.env.USERNAME : process.env.USER, - - //database user's password - password: null, - - //database port - port: 5432, - - //number of rows to return at a time from a prepared statement's - //portal. 0 will return all rows at once - rows: 0, - - // binary result mode - binary: false, - - //Connection pool options - see https://github.com/coopernurse/node-pool - //number of connections to use in connection pool - //0 will disable connection pooling - poolSize: 0, - - //max milliseconds a client can go unused before it is removed - //from the pool and destroyed - poolIdleTimeout: 30000, - - //frequeny to check for idle clients within the client pool - reapIntervalMillis: 1000, - - //pool log function / boolean - poolLog: false, - - client_encoding: '', - - ssl: false, - - application_name : undefined, - fallback_application_name: undefined -}; \ No newline at end of file diff --git a/src/mssql/pool/newGenericPool.js b/src/mssql/pool/newGenericPool.js index ffef3d67..b18f5cce 100644 --- a/src/mssql/pool/newGenericPool.js +++ b/src/mssql/pool/newGenericPool.js @@ -1,8 +1,7 @@ // @ts-nocheck /* eslint-disable no-prototype-builtins */ -var EventEmitter = require('events').EventEmitter; -var defaults = require('./defaults'); +var defaults = require('../../poolDefaults'); var genericPool = require('../../generic-pool'); var mssql = require('msnodesqlv8'); @@ -31,20 +30,9 @@ function newGenericPool(connectionString, poolOptions) { client.close(); } }); - //mixin EventEmitter to pool - EventEmitter.call(pool); - for(var key in EventEmitter.prototype) { - if(EventEmitter.prototype.hasOwnProperty(key)) { - pool[key] = EventEmitter.prototype[key]; - } - } //monkey-patch with connect method pool.connect = function(cb) { - var domain = process.domain; pool.acquire(function(err, client) { - if(domain) { - cb = domain.bind(cb); - } if(err) return cb(err, null, function() {/*NOOP*/}); client.poolCount++; cb(null, client, function(err) { diff --git a/src/mySql/deleteFromSql.js b/src/mySql/deleteFromSql.js index ed87d37e..e78dbfec 100644 --- a/src/mySql/deleteFromSql.js +++ b/src/mySql/deleteFromSql.js @@ -1,10 +1,10 @@ -var format = 'delete %s from %s as %s%s'; -var util = require('util'); -const quote = require('../table/quote'); +const format = 'delete %s from %s as %s%s'; +const formatString = require('../format'); +const quote = require('./quote'); function deleteFromSql(table, alias, whereSql) { - var name = quote(table._dbName); + const name = quote(table._dbName); alias = quote(alias); - return util.format(format, alias, name, alias, whereSql); + return formatString(format, alias, name, alias, whereSql); } module.exports = deleteFromSql; diff --git a/src/mySql/insert.js b/src/mySql/insert.js index c6571f6a..cee90558 100644 --- a/src/mySql/insert.js +++ b/src/mySql/insert.js @@ -5,16 +5,16 @@ let executeQueries = require('../table/executeQueries'); let pushCommand = require('../table/commands/pushCommand'); -function insertDefault(table, row, options) { +function insertDefault(context, table, row, options) { let commands = []; - let insertCmd = newInsertCommand(newInsertCommandCore, table, row, options); + let insertCmd = newInsertCommand(newInsertCommandCore.bind(null, context), table, row, options); insertCmd.disallowCompress = true; - pushCommand(insertCmd); + pushCommand(context, insertCmd); - let selectCmd = newGetLastInsertedCommand(table, row, insertCmd); + let selectCmd = newGetLastInsertedCommand(context, table, row, insertCmd); commands.push(selectCmd); - return executeQueries(commands).then((result) => result[result.length - 1]); + return executeQueries(context, commands).then((result) => result[result.length - 1]); } diff --git a/src/mySql/insertSql.js b/src/mySql/insertSql.js index b5096ce4..7a312b64 100644 --- a/src/mySql/insertSql.js +++ b/src/mySql/insertSql.js @@ -1,7 +1,6 @@ -const getSessionSingleton = require('../table/getSessionSingleton'); +const quote = require('./quote'); -function insertSql(table, row, options) { - const quote = getSessionSingleton('quote'); +function insertSql(_context, table, row, options) { let columnNames = []; let regularColumnNames = []; let conflictColumnUpdateSql = ''; diff --git a/src/mySql/lastInsertedSql.js b/src/mySql/lastInsertedSql.js index bbfac1fb..07e95c6d 100644 --- a/src/mySql/lastInsertedSql.js +++ b/src/mySql/lastInsertedSql.js @@ -1,13 +1,12 @@ -const getSessionSingleton = require('../table/getSessionSingleton'); +const quote = require('./quote'); -function lastInsertedSql(table, keyValues) { - const quote = getSessionSingleton('quote'); +function lastInsertedSql(context,table, keyValues) { return keyValues.map((value,i) => { let column = table._primaryColumns[i]; if (value === undefined && column.tsType === 'NumberColumn') return `${quote(column._dbName)}=LAST_INSERT_ID()`; else - return column.eq(value); + return column.eq(context, value); }); } diff --git a/src/mySql/newDatabase.js b/src/mySql/newDatabase.js index 417a0738..623db35b 100644 --- a/src/mySql/newDatabase.js +++ b/src/mySql/newDatabase.js @@ -4,10 +4,6 @@ let _begin = require('../table/begin'); let commit = require('../table/commit'); let rollback = require('../table/rollback'); let newPool = require('./newPool'); -let useHook = require('../useHook'); -let promise = require('promise/domains'); -let versionArray = process.version.replace('v', '').split('.'); -let major = parseInt(versionArray[0]); let express = require('../hostExpress'); let hostLocal = require('../hostLocal'); let doQuery = require('../query'); @@ -19,11 +15,11 @@ function newDatabase(connectionString, poolOptions) { throw new Error('Connection string cannot be empty'); var pool; if (!poolOptions) - pool = newPool.bind(null,connectionString, poolOptions); + pool = newPool.bind(null, connectionString, poolOptions); else pool = newPool(connectionString, poolOptions); - let c = {poolFactory: pool, hostLocal, express}; + let c = { poolFactory: pool, hostLocal, express }; c.transaction = function(options, fn) { if ((arguments.length === 1) && (typeof options === 'function')) { @@ -34,10 +30,7 @@ function newDatabase(connectionString, poolOptions) { if (fn) return domain.run(runInTransaction); - else if ((major >= 12) && useHook()) { - domain.exitContext = true; - return domain.start().then(run); - } else + else return domain.run(run); async function runInTransaction() { @@ -45,67 +38,60 @@ function newDatabase(connectionString, poolOptions) { let transaction = newTransaction(domain, pool, options); await new Promise(transaction) .then(begin) - .then(fn) + .then(() => fn(domain)) .then((res) => result = res) - .then(c.commit) - .then(null, c.rollback); + .then(() => commit(domain)) + .then(null, (e) => rollback(domain, e)); return result; } function begin() { - return _begin(options?.readonly); + return _begin(domain, options); } function run() { let p; let transaction = newTransaction(domain, pool, options); - if (useHook()) - p = new Promise(transaction); - else - p = new promise(transaction); + p = new Promise(transaction); return p.then(begin); } }; - c.createTransaction = function() { + c.createTransaction = function(options) { let domain = createDomain(); let transaction = newTransaction(domain, pool); - let p = domain.run(() => new Promise(transaction).then(_begin)); + let p = domain.run(() => new Promise(transaction).then(begin)); function run(fn) { - return p.then(domain.run.bind(domain, fn)); + return p.then(() => fn(domain)); } + run.rollback = rollback.bind(null, domain); + run.commit = commit.bind(null, domain); return run; - }; - c.bindTransaction = function() { - // @ts-ignore - var domain = process.domain; - let p = domain.run(() => true); - - function run(fn) { - return p.then(domain.run.bind(domain, fn)); + function begin() { + return _begin(domain, options); } - return run; }; + c.query = function(query) { let domain = createDomain(); let transaction = newTransaction(domain, pool); let p = domain.run(() => new Promise(transaction) - .then(() => setSessionSingleton('changes', [])) - .then(() => doQuery(query).then(onResult, onError))); + .then(() => setSessionSingleton(domain, 'changes', [])) + .then(() => doQuery(domain, query).then(onResult, onError))); return p; function onResult(result) { - releaseDbClient(); + releaseDbClient(domain); return result; } function onError(e) { - releaseDbClient(); + releaseDbClient(domain); throw e; } }; diff --git a/src/mySql/newPool.js b/src/mySql/newPool.js index 8ea1295a..3d9a8d8c 100644 --- a/src/mySql/newPool.js +++ b/src/mySql/newPool.js @@ -1,17 +1,17 @@ -var pools = require('../pools'); -var promise = require('../table/promise'); -var end = require('./pool/end'); -var newGenericPool = require('./pool/newGenericPool'); -var newId = require('../newId'); +const promisify = require('../promisify'); +const pools = require('../pools'); +const end = require('./pool/end'); +const newGenericPool = require('./pool/newGenericPool'); +const newId = require('../newId'); function newPool(connectionString, poolOptions) { - var pool = newGenericPool(connectionString, poolOptions); - var id = newId(); - var boundEnd = end.bind(null, pool, id); - var c = {}; + let pool = newGenericPool(connectionString, poolOptions); + let id = newId(); + let boundEnd = end.bind(null, pool, id); + let c = {}; c.connect = pool.connect; - c.end = promise.denodeify(boundEnd); + c.end = promisify(boundEnd); pools[id] = c; return c; } diff --git a/src/mySql/newTransaction.js b/src/mySql/newTransaction.js index 851e26f1..37a6c730 100644 --- a/src/mySql/newTransaction.js +++ b/src/mySql/newTransaction.js @@ -6,8 +6,9 @@ const lastInsertedSql = require('./lastInsertedSql'); const limitAndOffset = require('./limitAndOffset'); const insertSql = require('./insertSql'); const insert = require('./insert'); +const quote = require('./quote'); -function newResolveTransaction(domain, pool, { readonly } = {}) { +function newResolveTransaction(domain, pool, { readonly = false } = {}) { var rdb = {poolFactory: pool}; if (!pool.connect) { pool = pool(); @@ -28,8 +29,7 @@ function newResolveTransaction(domain, pool, { readonly } = {}) { caller.visitMySql(); }; rdb.aggregateCount = 0; - rdb.quote = (name) => `\`${name}\``; - + rdb.quote = quote; if (readonly) { rdb.dbClient = { diff --git a/src/mySql/pool/newGenericPool.js b/src/mySql/pool/newGenericPool.js index 8397e61c..3394ae85 100644 --- a/src/mySql/pool/newGenericPool.js +++ b/src/mySql/pool/newGenericPool.js @@ -1,8 +1,6 @@ // @ts-nocheck /* eslint-disable no-prototype-builtins */ -var EventEmitter = require('events').EventEmitter; - -var defaults = require('./defaults'); +var defaults = require('../../poolDefaults'); var genericPool = require('../../generic-pool'); var mysql = require('mysql2'); @@ -16,7 +14,7 @@ function newGenericPool(connectionString, poolOptions) { max: poolOptions.size || poolOptions.poolSize || defaults.poolSize, idleTimeoutMillis: poolOptions.idleTimeout || defaults.poolIdleTimeout, reapIntervalMillis: poolOptions.reapIntervalMillis || defaults.reapIntervalMillis, - log: poolOptions.log || defaults.poolLog, + log: poolOptions.log, create: function(cb) { var innerPool = mysql.createPool(connectionString); return cb(null, innerPool); @@ -36,20 +34,9 @@ function newGenericPool(connectionString, poolOptions) { client.end(); } }); - //mixin EventEmitter to pool - EventEmitter.call(pool); - for(var key in EventEmitter.prototype) { - if(EventEmitter.prototype.hasOwnProperty(key)) { - pool[key] = EventEmitter.prototype[key]; - } - } //monkey-patch with connect method pool.connect = function(cb) { - var domain = process.domain; pool.acquire(function(err, client) { - if(domain) { - cb = domain.bind(cb); - } if(err) return cb(err, null, function() {/*NOOP*/}); client.poolCount++; cb(null, client, function(err) { diff --git a/src/mySql/quote.js b/src/mySql/quote.js new file mode 100644 index 00000000..1e3e33e9 --- /dev/null +++ b/src/mySql/quote.js @@ -0,0 +1 @@ +module.exports = (name) => `\`${name}\``; \ No newline at end of file diff --git a/src/mySql/wrapQueryStream.js b/src/mySql/wrapQueryStream.js deleted file mode 100644 index 0a56ca14..00000000 --- a/src/mySql/wrapQueryStream.js +++ /dev/null @@ -1,9 +0,0 @@ -function wrapQueryStream(connection) { - return runQuery; - - function runQuery(query, options) { - return connection.executeQuery(query).stream(options); - } -} - -module.exports = wrapQueryStream; \ No newline at end of file diff --git a/src/newId.js b/src/newId.js index a9d6205c..0b521fcb 100644 --- a/src/newId.js +++ b/src/newId.js @@ -1 +1,2 @@ -module.exports = require('uuid').v4; \ No newline at end of file +const { v4 : uuid} = require('uuid'); +module.exports = uuid; \ No newline at end of file diff --git a/src/newImmutable.js b/src/newImmutable.js index b27adcad..76f0a3ec 100644 --- a/src/newImmutable.js +++ b/src/newImmutable.js @@ -4,8 +4,7 @@ function newImmutable(fn) { return run; function run() { - var args = [].slice.call(arguments); - return _run(args); + return _run([...arguments]); } function runFirst(args) { diff --git a/src/oracle/deleteFromSql.js b/src/oracle/deleteFromSql.js index 3e1f5e84..3abec910 100644 --- a/src/oracle/deleteFromSql.js +++ b/src/oracle/deleteFromSql.js @@ -1,10 +1,10 @@ -var format = 'delete from %s where %s.rowId in (SELECT %s.rowId FROM %s %s%s)'; -var util = require('util'); -const quote = require('../table/quote'); +const format = 'delete from %s where %s.rowId in (SELECT %s.rowId FROM %s %s%s)'; +const formatString = require('../format'); +const quote = require('./quote'); function deleteFromSql(table, alias, whereSql) { - var name = quote(table._dbName); + const name = quote(table._dbName); alias = quote(alias); - return util.format(format, name, name, alias, name, alias, whereSql); + return formatString(format, name, name, alias, name, alias, whereSql); } module.exports = deleteFromSql; diff --git a/src/oracle/formatDateOut.js b/src/oracle/formatDateOut.js index f3a287c4..fef57a16 100644 --- a/src/oracle/formatDateOut.js +++ b/src/oracle/formatDateOut.js @@ -1,4 +1,4 @@ -const quote = require('../table/quote'); +const quote = require('./quote'); function formatDateColumn(column, alias) { return `TO_CHAR(${alias}.${quote(column._dbName)}, 'YYYY-MM-DD"T"HH24:MI:SS.FF3')`; diff --git a/src/oracle/insert.js b/src/oracle/insert.js index 8b16ed33..15e7de1d 100644 --- a/src/oracle/insert.js +++ b/src/oracle/insert.js @@ -4,17 +4,17 @@ const setSessionSingleton = require('../table/setSessionSingleton'); const newGetLastInsertedCommand = require('../table/commands/newGetLastInsertedCommand'); const executeQueries = require('../table/executeQueries'); -function insert(table, row, options) { +function insert(context, table, row, options) { return new Promise((res, rej) => { - const cmd = newInsertCommand(newInsertCommandCore, table, row, options); + const cmd = newInsertCommand(newInsertCommandCore.bind(null, context), table, row, options); cmd.disallowCompress = true; - executeQueries([cmd]).then((result) => result[0]).then(onResult).then(res, rej); + executeQueries(context, [cmd]).then((result) => result[0]).then(onResult).then(res, rej); function onResult([result]) { - setSessionSingleton('lastRowid', result.lastRowid); - const selectCmd = newGetLastInsertedCommand(table, row, cmd); - return executeQueries([selectCmd]).then((result) => res(result[0])); + setSessionSingleton(context, 'lastRowid', result.lastRowid); + const selectCmd = newGetLastInsertedCommand(context, table, row, cmd); + return executeQueries(context, [selectCmd]).then((result) => res(result[0])); } }); diff --git a/src/oracle/insertSql.js b/src/oracle/insertSql.js index 634b99a2..b6ca0167 100644 --- a/src/oracle/insertSql.js +++ b/src/oracle/insertSql.js @@ -1,12 +1,11 @@ -let outputInsertedSql = require('./outputInsertedSql'); let mergeSql = require('./mergeSql'); -const getSessionSingleton = require('../table/getSessionSingleton'); +const quote = require('./quote'); -function getSqlTemplate(_table, _row, options) { +function getSqlTemplate(_context, _table, _row, options) { if (hasConcurrency(_table, options) && hasColumns()) - return mergeSql.apply(null, arguments); + return mergeSql.apply(null, [...arguments].slice(1)); else - return insertSql.apply(null, arguments); + return insertSql.apply(null, [...arguments].slice(1)); function hasColumns() { for(let p in _row) { @@ -27,7 +26,6 @@ function hasConcurrency(table,options) { } function insertSql(table, row) { - const quote = getSessionSingleton('quote'); let columnNames = []; let regularColumnNames = []; let values = []; @@ -35,9 +33,9 @@ function insertSql(table, row) { addDiscriminators(); addColumns(); if (columnNames.length === 0) - sql += `${outputInserted()} (${quote(table._primaryColumns[0]._dbName)}) VALUES(DEFAULT)`; + sql += ` (${quote(table._primaryColumns[0]._dbName)}) VALUES(DEFAULT)`; else - sql = sql + '('+ columnNames.join(',') + ')' + outputInserted() + 'VALUES (' + values.join(',') + ')'; + sql = sql + '('+ columnNames.join(',') + ')' + ' VALUES (' + values.join(',') + ')'; return sql; function addDiscriminators() { @@ -65,12 +63,6 @@ function insertSql(table, row) { } } - - function outputInserted() { - - return ' ' + outputInsertedSql(table) + ' '; - } - } module.exports = getSqlTemplate; \ No newline at end of file diff --git a/src/oracle/lastInsertedSql.js b/src/oracle/lastInsertedSql.js index ccf3883e..8f9b96f0 100644 --- a/src/oracle/lastInsertedSql.js +++ b/src/oracle/lastInsertedSql.js @@ -1,12 +1,12 @@ let getSessionSingleton = require('../table/getSessionSingleton'); -function lastInsertedSql(table, keyValues) { +function lastInsertedSql(context,table, keyValues) { return keyValues.map((value,i) => { let column = table._primaryColumns[i]; if (value === undefined) - return `ROWID='${getSessionSingleton('lastRowid')}'`; + return `ROWID='${getSessionSingleton(context, 'lastRowid')}'`; else - return column.eq(value); + return column.eq(context, value); }); } diff --git a/src/oracle/mergeSql.js b/src/oracle/mergeSql.js index 83fe8bfa..ab992922 100644 --- a/src/oracle/mergeSql.js +++ b/src/oracle/mergeSql.js @@ -1,8 +1,6 @@ -const outputInsertedSql = require('./outputInsertedSql'); -const getSessionSingleton = require('../table/getSessionSingleton'); +const quote = require('./quote'); function insertSql(table, row, options) { - const quote = getSessionSingleton('quote'); let columnNames = []; let regularColumnNames = []; let conflictColumnUpdateSql = ''; @@ -13,9 +11,9 @@ function insertSql(table, row, options) { const matched = whenMatched(); let sql; if (matched) - sql = `MERGE INTO ${quote(table._dbName)} target USING (SELECT ${values.join(',')} FROM DUAL) source ON (${join()}) WHEN MATCHED THEN ${matched} WHEN NOT MATCHED THEN ${whenNotMatched()} ${outputInsertedSql(table)}`; + sql = `MERGE INTO ${quote(table._dbName)} target USING (SELECT ${values.join(',')} FROM DUAL) source ON (${join()}) WHEN MATCHED THEN ${matched} WHEN NOT MATCHED THEN ${whenNotMatched()}`; else - sql = `MERGE INTO ${quote(table._dbName)} target USING (SELECT ${values.join(',')} FROM DUAL) source ON (${join()}) WHEN NOT MATCHED THEN ${whenNotMatched()} ${outputInsertedSql(table)}`; + sql = `MERGE INTO ${quote(table._dbName)} target USING (SELECT ${values.join(',')} FROM DUAL) source ON (${join()}) WHEN NOT MATCHED THEN ${whenNotMatched()}`; return sql; function join() { @@ -72,7 +70,6 @@ function insertSql(table, row, options) { if (concurrency === 'overwrite') conflictColumnUpdates.push(`target.${columnName}=source.${columnName}`); else if (concurrency === 'optimistic') - // conflictColumnUpdates.push(`target.${column._dbName} = CASE WHEN target.${column._dbName} <> source.${column._dbName} THEN RAISE_APPLICATION_ERROR(-20001, 'Conflict when updating ${column._dbName}') ELSE target.${column._dbName} END`); conflictColumnUpdates.push(`target.${columnName} = CASE WHEN target.${columnName} <> source.${columnName} THEN 1/0 ELSE target.${columnName} END`); } diff --git a/src/oracle/newDatabase.js b/src/oracle/newDatabase.js index c81c18bb..4699e32f 100644 --- a/src/oracle/newDatabase.js +++ b/src/oracle/newDatabase.js @@ -4,10 +4,6 @@ let _begin = require('../table/begin'); let commit = require('../table/commit'); let rollback = require('../table/rollback'); let newPool = require('./newPool'); -let useHook = require('../useHook'); -let promise = require('promise/domains'); -let versionArray = process.version.replace('v', '').split('.'); -let major = parseInt(versionArray[0]); let express = require('../hostExpress'); let hostLocal = require('../hostLocal'); let doQuery = require('../query'); @@ -34,15 +30,12 @@ function newDatabase(connectionString, poolOptions) { if (fn) return domain.run(runInTransaction); - else if ((major >= 12) && useHook()) { - domain.exitContext = true; - return domain.start().then(run); - } else return domain.run(run); + function begin() { - return _begin(options?.readonly); + return _begin(domain, options); } async function runInTransaction() { @@ -50,68 +43,60 @@ function newDatabase(connectionString, poolOptions) { let transaction = newTransaction(domain, pool, options); await new Promise(transaction) .then(begin) - .then(fn) + .then(() => fn(domain)) .then((res) => result = res) - .then(c.commit) - .then(null, c.rollback); + .then(() => commit(domain)) + .then(null, (e) => rollback(domain, e)); return result; + } function run() { let p; let transaction = newTransaction(domain, pool, options); - if (useHook()) - p = new Promise(transaction); - else - p = new promise(transaction); + p = new Promise(transaction); return p.then(begin); } }; - c.createTransaction = function() { + c.createTransaction = function(options) { let domain = createDomain(); let transaction = newTransaction(domain, pool); - let p = domain.run(() => new Promise(transaction).then(_begin)); + let p = domain.run(() => new Promise(transaction).then(begin)); function run(fn) { - return p.then(domain.run.bind(domain, fn)); + return p.then(() => fn(domain)); } + run.rollback = rollback.bind(null, domain); + run.commit = commit.bind(null, domain); return run; - }; - - c.bindTransaction = function() { - // @ts-ignore - var domain = process.domain; - let p = domain.run(() => true); - function run(fn) { - return p.then(domain.run.bind(domain, fn)); + function begin() { + return _begin(domain, options); } - return run; }; c.query = function(query) { let domain = createDomain(); let transaction = newTransaction(domain, pool); let p = domain.run(() => new Promise(transaction) - .then(() => setSessionSingleton('changes', [])) - .then(() => doQuery(query).then(onResult, onError))); + .then(() => setSessionSingleton(domain, 'changes', [])) + .then(() => doQuery(domain, query).then(onResult, onError))); return p; function onResult(result) { - releaseDbClient(); + releaseDbClient(domain); return result; } function onError(e) { - releaseDbClient(); + releaseDbClient(domain); throw e; } }; - c.rollback = rollback; c.commit = commit; diff --git a/src/oracle/newInsertCommandCore.js b/src/oracle/newInsertCommandCore.js index b68bf4c5..23148006 100644 --- a/src/oracle/newInsertCommandCore.js +++ b/src/oracle/newInsertCommandCore.js @@ -1,17 +1,17 @@ var newParameterized = require('../table/query/newParameterized'); var insertSql = require('./insertSql'); -var util = require('util'); +const formatString = require('../format'); -function newInsertCommandCore(table, row, options = {}) { +function newInsertCommandCore(context,table, row, options = {}) { var parameters = []; - var values = [insertSql(table, row, options)]; + var values = [insertSql(context,table, row, options)]; var columns = table._columns; for (var i = 0; i < columns.length; i++) { var column = columns[i]; var alias = column.alias; if (row['__' + column.alias] !== undefined) { - var encoded = column.encode(row[alias]); + var encoded = column.encode(context, row[alias]); if (encoded.parameters.length > 0) { values.push('?'); parameters.push(encoded.parameters[0]); @@ -20,7 +20,7 @@ function newInsertCommandCore(table, row, options = {}) { } } - var sql = util.format.apply(null, values); + var sql = formatString.apply(null, values); return newParameterized(sql, parameters); } diff --git a/src/oracle/newPool.js b/src/oracle/newPool.js index 8ea1295a..3d9a8d8c 100644 --- a/src/oracle/newPool.js +++ b/src/oracle/newPool.js @@ -1,17 +1,17 @@ -var pools = require('../pools'); -var promise = require('../table/promise'); -var end = require('./pool/end'); -var newGenericPool = require('./pool/newGenericPool'); -var newId = require('../newId'); +const promisify = require('../promisify'); +const pools = require('../pools'); +const end = require('./pool/end'); +const newGenericPool = require('./pool/newGenericPool'); +const newId = require('../newId'); function newPool(connectionString, poolOptions) { - var pool = newGenericPool(connectionString, poolOptions); - var id = newId(); - var boundEnd = end.bind(null, pool, id); - var c = {}; + let pool = newGenericPool(connectionString, poolOptions); + let id = newId(); + let boundEnd = end.bind(null, pool, id); + let c = {}; c.connect = pool.connect; - c.end = promise.denodeify(boundEnd); + c.end = promisify(boundEnd); pools[id] = c; return c; } diff --git a/src/oracle/newTransaction.js b/src/oracle/newTransaction.js index e0b699e3..f70a357a 100644 --- a/src/oracle/newTransaction.js +++ b/src/oracle/newTransaction.js @@ -8,8 +8,9 @@ const insertSql = require('./insertSql'); const insert = require('./insert'); const formatDateOut = require('./formatDateOut'); const formatDateIn = require('./formatDateIn'); +const quote = require('./quote'); -function newResolveTransaction(domain, pool, { readonly } = {}) { +function newResolveTransaction(domain, pool, { readonly = false } = {}) { var rdb = {poolFactory: pool}; if (!pool.connect) { pool = pool(); @@ -35,7 +36,7 @@ function newResolveTransaction(domain, pool, { readonly } = {}) { caller.visitSqlite(); }; rdb.aggregateCount = 0; - rdb.quote = (name) => `"${name}"`; + rdb.quote = quote; if (readonly) { rdb.dbClient = { diff --git a/src/oracle/pool/defaults.js b/src/oracle/pool/defaults.js deleted file mode 100644 index f21f834a..00000000 --- a/src/oracle/pool/defaults.js +++ /dev/null @@ -1,45 +0,0 @@ -module.exports = { - // database host defaults to localhost - host: 'localhost', - - //database user's name - user: process.platform === 'win32' ? process.env.USERNAME : process.env.USER, - - //name of database to connect - database: process.platform === 'win32' ? process.env.USERNAME : process.env.USER, - - //database user's password - password: null, - - //database port - port: 5432, - - //number of rows to return at a time from a prepared statement's - //portal. 0 will return all rows at once - rows: 0, - - // binary result mode - binary: false, - - //Connection pool options - see https://github.com/coopernurse/node-pool - //number of connections to use in connection pool - //0 will disable connection pooling - poolSize: 0, - - //max milliseconds a client can go unused before it is removed - //from the pool and destroyed - poolIdleTimeout: 30000, - - //frequeny to check for idle clients within the client pool - reapIntervalMillis: 1000, - - //pool log function / boolean - poolLog: false, - - client_encoding: '', - - ssl: false, - - application_name : undefined, - fallback_application_name: undefined -}; \ No newline at end of file diff --git a/src/oracle/pool/newGenericPool.js b/src/oracle/pool/newGenericPool.js index 575c5bb5..829d2d88 100644 --- a/src/oracle/pool/newGenericPool.js +++ b/src/oracle/pool/newGenericPool.js @@ -1,8 +1,7 @@ // @ts-nocheck /* eslint-disable no-prototype-builtins */ -var EventEmitter = require('events').EventEmitter; -var defaults = require('./defaults'); +var defaults = require('../../poolDefaults'); var genericPool = require('../../generic-pool'); var oracle = require('oracledb'); @@ -15,7 +14,7 @@ function newGenericPool(connectionString, poolOptions) { max: poolOptions.size || poolOptions.poolSize || defaults.poolSize, idleTimeoutMillis: poolOptions.idleTimeout || defaults.poolIdleTimeout, reapIntervalMillis: poolOptions.reapIntervalMillis || defaults.reapIntervalMillis, - log: poolOptions.log || defaults.poolLog, + log: poolOptions.log, create: function(cb) { var client; oracle.getConnection(connectionString, onConnected); @@ -33,20 +32,9 @@ function newGenericPool(connectionString, poolOptions) { client.close(); } }); - //mixin EventEmitter to pool - EventEmitter.call(pool); - for (var key in EventEmitter.prototype) { - if (EventEmitter.prototype.hasOwnProperty(key)) { - pool[key] = EventEmitter.prototype[key]; - } - } //monkey-patch with connect method pool.connect = function(cb) { - var domain = process.domain; pool.acquire(function(err, client) { - if (domain) { - cb = domain.bind(cb); - } if (err) return cb(err, null, function() {/*NOOP*/ }); client.poolCount++; cb(null, client, function(err) { diff --git a/src/oracle/quote.js b/src/oracle/quote.js new file mode 100644 index 00000000..495b1a43 --- /dev/null +++ b/src/oracle/quote.js @@ -0,0 +1 @@ +module.exports = (name) => `"${name}"`; \ No newline at end of file diff --git a/src/oracle/wrapQuery.js b/src/oracle/wrapQuery.js index 950deeac..d9dadca3 100644 --- a/src/oracle/wrapQuery.js +++ b/src/oracle/wrapQuery.js @@ -10,9 +10,6 @@ function wrapQuery(connection) { var sql = replaceParamChar(query, params); log.emitQuery({ sql, parameters: params }); - - - runOriginalQuery.call(connection, sql, params, { fetchTypeHandler: function(metaData) { // Tells the database to return column names in lowercase diff --git a/src/package.json b/src/package.json new file mode 100644 index 00000000..fb1f66ac --- /dev/null +++ b/src/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "uuid": "^11.0.5" + } +} diff --git a/src/patchRow.js b/src/patchRow.js index f0c90afc..d40d5224 100644 --- a/src/patchRow.js +++ b/src/patchRow.js @@ -1,13 +1,13 @@ let patchTable = require('./patchTable'); -function patchRow(table, row, patches, options) { +function patchRow(context, table, row, patches, options) { patches = JSON.parse(JSON.stringify(patches)); let pkName = table._primaryColumns[0].alias; let id = row[pkName]; for (let i = 0; i < patches.length; i++) { patches[i].path = '/' + id + patches[i].path; } - return patchTable(table, patches, options); + return patchTable(context, table, patches, options); } module.exports = patchRow; \ No newline at end of file diff --git a/src/patchTable.js b/src/patchTable.js index a3f4d447..f5c10001 100644 --- a/src/patchTable.js +++ b/src/patchTable.js @@ -12,7 +12,7 @@ async function patchTable() { return patchTableCore.apply(null, arguments); } -async function patchTableCore(table, patches, { strategy = undefined, deduceStrategy = false, ...options } = {}, dryrun) { +async function patchTableCore(context, table, patches, { strategy = undefined, deduceStrategy = false, ...options } = {}, dryrun) { options = cleanOptions(options); strategy = JSON.parse(JSON.stringify(strategy || {})); let changed = new Set(); @@ -41,7 +41,8 @@ async function patchTableCore(table, patches, { strategy = undefined, deduceStra async function toDtos(set) { set = [...set]; - return table.getManyDto(set, strategy); + const result = await table.getManyDto(context, set, strategy); + return result; } function toKey(property) { @@ -56,7 +57,7 @@ async function patchTableCore(table, patches, { strategy = undefined, deduceStra path = path.slice(1); if (!row && path.length > 0) { const key = toKey(property); - row = await table.tryGetById.apply(null, toKey(property), strategy); + row = await table.tryGetById.apply(null, [context, ...key, strategy]); if (!row) throw new Error(`Row ${table._dbName} with id ${key} was not found.`); } @@ -98,7 +99,7 @@ async function patchTableCore(table, patches, { strategy = undefined, deduceStra } } } - let row = table.insertWithConcurrency.apply(null, [options, value]); + let row = table.insertWithConcurrency.apply(null, [context, options, value]); row = await row; for (let i = 0; i < childInserts.length; i++) { @@ -212,7 +213,7 @@ async function patchTableCore(table, patches, { strategy = undefined, deduceStra async function remove({ path, op, oldValue, options }, table, row) { let property = path[0]; path = path.slice(1); - row = row || await table.getById.apply(null, toKey(property)); + row = row || await table.getById.apply(null, [context, ...toKey(property)]); if (path.length === 0) { await validateDeleteAllowed({ row, options, table }); if (await validateDeleteConflict({ row, oldValue, options, table })) diff --git a/src/pg/deleteFromSql.js b/src/pg/deleteFromSql.js index 947d638c..69c51e5b 100644 --- a/src/pg/deleteFromSql.js +++ b/src/pg/deleteFromSql.js @@ -1,10 +1,10 @@ -var format = 'delete from %s %s%s'; -var util = require('util'); -const quote = require('../table/quote'); +const format = 'delete from %s %s%s'; +const formatString = require('../format'); +const quote = require('./quote'); function deleteFromSql(table, alias, whereSql) { - var name = quote(table._dbName); + const name = quote(table._dbName); alias = quote(alias); - return util.format(format, name, alias, whereSql); + return formatString(format, name, alias, whereSql); } module.exports = deleteFromSql; \ No newline at end of file diff --git a/src/pg/formatDateOut.js b/src/pg/formatDateOut.js index b251c8c3..c2588c7c 100644 --- a/src/pg/formatDateOut.js +++ b/src/pg/formatDateOut.js @@ -1,7 +1,6 @@ -const quote = require('../table/quote'); function formatDateOut(column, alias) { - return `${alias}.${quote(column._dbName)}::text`; + return `${alias}."${(column._dbName)}"::text`; } module.exports = formatDateOut; \ No newline at end of file diff --git a/src/pg/insert.js b/src/pg/insert.js index ae0b1031..7bf676be 100644 --- a/src/pg/insert.js +++ b/src/pg/insert.js @@ -3,11 +3,11 @@ let newInsertCommandCore = require('../table/commands/newInsertCommandCore'); let executeQueries = require('../table/executeQueries'); -function insertDefault(table, row, options) { - let insertCmd = newInsertCommand(newInsertCommandCore, table, row, options); +function insertDefault(context, table, row, options) { + let insertCmd = newInsertCommand(newInsertCommandCore.bind(null, context), table, row, options); insertCmd.disallowCompress = true; - return executeQueries([insertCmd]).then((result) => result[result.length - 1]); + return executeQueries(context, [insertCmd]).then((result) => result[result.length - 1]); } diff --git a/src/pg/insertSql.js b/src/pg/insertSql.js index 2d42f642..9af30ada 100644 --- a/src/pg/insertSql.js +++ b/src/pg/insertSql.js @@ -1,9 +1,7 @@ let lastInsertedSql = require('./lastInsertedSql'); -let getSessionContext = require('../table/getSessionContext'); -const getSessionSingleton = require('../table/getSessionSingleton'); +const quote = require('./quote'); -function insertSql(table, row, options) { - const quote = getSessionSingleton('quote'); +function insertSql(_context, table, row, options) { let columnNames = []; let regularColumnNames = []; let conflictColumnUpdateSql = ''; @@ -65,9 +63,6 @@ function insertSql(table, row, options) { function outputInserted() { - let context = getSessionContext(); - if (!context.lastInsertedIsSeparate && context.outputInsertedSql) - return context.outputInsertedSql(table) + ' '; return ''; } } diff --git a/src/pg/lastInsertedSql.js b/src/pg/lastInsertedSql.js index f27d4e93..6ec91456 100644 --- a/src/pg/lastInsertedSql.js +++ b/src/pg/lastInsertedSql.js @@ -1,7 +1,6 @@ -const getSessionSingleton = require('../table/getSessionSingleton'); +const quote = require('./quote'); function lastInsertedSql(table) { - const quote = getSessionSingleton('quote'); let separator = ''; let result = 'RETURNING '; for (let i = 0; i < table._columns.length; i++) { diff --git a/src/pg/newDatabase.js b/src/pg/newDatabase.js index 36a73054..21835ea9 100644 --- a/src/pg/newDatabase.js +++ b/src/pg/newDatabase.js @@ -6,10 +6,6 @@ let rollback = require('../table/rollback'); let newPool = require('./newPool'); let lock = require('../lock'); let executeSchema = require('./schema'); -let useHook = require('../useHook'); -let promise = require('promise/domains'); -let versionArray = process.version.replace('v', '').split('.'); -let major = parseInt(versionArray[0]); let express = require('../hostExpress'); let hostLocal = require('../hostLocal'); let doQuery = require('../query'); @@ -41,39 +37,30 @@ function newDatabase(connectionString, poolOptions) { if (fn) return domain.run(runInTransaction); - else if ((major >= 12) && useHook()) { - domain.exitContext = true; - return domain.start().then(run); - } else return domain.run(run); - - async function runInTransaction() { let result; let transaction = newTransaction(domain, pool, options); await new Promise(transaction) .then(begin) .then(negotiateSchema) - .then(fn) + .then(() => fn(domain)) .then((res) => result = res) - .then(c.commit) - .then(null, c.rollback); + .then(() => commit(domain)) + .then(null, (e) => rollback(domain,e)); return result; } function begin() { - return _begin(options?.readonly); + return _begin(domain, options); } function run() { let p; let transaction = newTransaction(domain, pool, options); - if (useHook()) - p = new Promise(transaction); - else - p = new promise(transaction); + p = new Promise(transaction); return p.then(begin) .then(negotiateSchema); @@ -83,37 +70,34 @@ function newDatabase(connectionString, poolOptions) { let schema = options && options.schema; if (!schema) return previous; - return executeSchema(schema); + return executeSchema(domain, schema); } }; c.createTransaction = function(options) { let domain = createDomain(); - let transaction = newTransaction(domain, pool); - let p = domain.run(() => new Promise(transaction).then(_begin).then(negotiateSchema)); + let transaction = newTransaction(domain, pool, options); + let p = domain.run(() => new Promise(transaction) + .then(begin).then(negotiateSchema)); function run(fn) { return p.then(domain.run.bind(domain, fn)); } + function begin() { + return _begin(domain, options); + } + function negotiateSchema(previous) { let schema = options && options.schema; if (!schema) return previous; - return executeSchema(schema); + return executeSchema(domain,schema); } - return run; - }; + run.rollback = rollback.bind(null, domain); + run.commit = commit.bind(null, domain); - c.bindTransaction = function() { - // @ts-ignore - var domain = process.domain; - let p = domain.run(() => true); - - function run(fn) { - return p.then(domain.run.bind(domain, fn)); - } return run; }; @@ -121,22 +105,21 @@ function newDatabase(connectionString, poolOptions) { let domain = createDomain(); let transaction = newTransaction(domain, pool); let p = domain.run(() => new Promise(transaction) - .then(() => setSessionSingleton('changes', [])) - .then(() => doQuery(query).then(onResult, onError))); + .then(() => setSessionSingleton(domain, 'changes', [])) + .then(() => doQuery(domain, query).then(onResult, onError))); return p; function onResult(result) { - releaseDbClient(); + releaseDbClient(domain); return result; } function onError(e) { - releaseDbClient(); + releaseDbClient(domain); throw e; } }; - c.rollback = rollback; c.commit = commit; c.lock = lock; diff --git a/src/pg/newPool.js b/src/pg/newPool.js index 781f4f77..12c8bfd3 100644 --- a/src/pg/newPool.js +++ b/src/pg/newPool.js @@ -1,17 +1,17 @@ -var pools = require('../pools'); -var promise = require('../table/promise'); -var end = require('./pool/end'); -var newPgPool = require('./pool/newPgPool'); -var newId = require('../newId'); +const promisify = require('../promisify'); +const pools = require('../pools'); +const end = require('./pool/end'); +const newPgPool = require('./pool/newPgPool'); +const newId = require('../newId'); function newPool(connectionString, poolOptions) { - var pool = newPgPool(connectionString, poolOptions); - var id = newId(); - var boundEnd = end.bind(null, pool, id); - var c = {}; + let pool = newPgPool(connectionString, poolOptions); + let id = newId(); + let boundEnd = end.bind(null, pool, id); + let c = {}; c.connect = pool.connect; - c.end = promise.denodeify(boundEnd); + c.end = promisify(boundEnd); pools[id] = c; return c; } diff --git a/src/pg/newStreamableQuery.js b/src/pg/newStreamableQuery.js deleted file mode 100644 index 3899c275..00000000 --- a/src/pg/newStreamableQuery.js +++ /dev/null @@ -1,7 +0,0 @@ -var QueryStream; - -module.exports = function(sql, params) { - if (!QueryStream) - QueryStream = require('pg-query-stream'); - return new QueryStream(sql, params); -}; \ No newline at end of file diff --git a/src/pg/newTransaction.js b/src/pg/newTransaction.js index ab7ae463..c1595d76 100644 --- a/src/pg/newTransaction.js +++ b/src/pg/newTransaction.js @@ -8,8 +8,9 @@ var formatDateOut = require('./formatDateOut'); var encodeJSON = require('./encodeJSON'); var insertSql = require('./insertSql'); var insert = require('./insert'); +var quote = require('./quote'); -function newResolveTransaction(domain, pool, { readonly } = {}) { +function newResolveTransaction(domain, pool, { readonly = false } = {}) { var rdb = { poolFactory: pool }; if (!pool.connect) { pool = pool(); @@ -32,7 +33,7 @@ function newResolveTransaction(domain, pool, { readonly } = {}) { caller.visitPg(); }; rdb.aggregateCount = 0; - rdb.quote = (name) => `"${name}"`; + rdb.quote = quote; if (readonly) { rdb.dbClient = { diff --git a/src/pg/pool/defaults.js b/src/pg/pool/defaults.js deleted file mode 100644 index f21f834a..00000000 --- a/src/pg/pool/defaults.js +++ /dev/null @@ -1,45 +0,0 @@ -module.exports = { - // database host defaults to localhost - host: 'localhost', - - //database user's name - user: process.platform === 'win32' ? process.env.USERNAME : process.env.USER, - - //name of database to connect - database: process.platform === 'win32' ? process.env.USERNAME : process.env.USER, - - //database user's password - password: null, - - //database port - port: 5432, - - //number of rows to return at a time from a prepared statement's - //portal. 0 will return all rows at once - rows: 0, - - // binary result mode - binary: false, - - //Connection pool options - see https://github.com/coopernurse/node-pool - //number of connections to use in connection pool - //0 will disable connection pooling - poolSize: 0, - - //max milliseconds a client can go unused before it is removed - //from the pool and destroyed - poolIdleTimeout: 30000, - - //frequeny to check for idle clients within the client pool - reapIntervalMillis: 1000, - - //pool log function / boolean - poolLog: false, - - client_encoding: '', - - ssl: false, - - application_name : undefined, - fallback_application_name: undefined -}; \ No newline at end of file diff --git a/src/pg/pool/newPgPool.js b/src/pg/pool/newPgPool.js index 0b96492e..10ae4317 100644 --- a/src/pg/pool/newPgPool.js +++ b/src/pg/pool/newPgPool.js @@ -1,9 +1,8 @@ /* eslint-disable no-prototype-builtins */ //slightly modified code from github.com/brianc/node-postgres var log = require('../../table/log'); -var EventEmitter = require('events').EventEmitter; -var defaults = require('./defaults'); +var defaults = require('../../poolDefaults'); var genericPool = require('../../generic-pool'); var _pg = require('pg'); var parseSearchPathParam = require('./parseSearchPathParam'); @@ -17,7 +16,7 @@ function newPgPool(connectionString, poolOptions) { max: poolOptions.size || poolOptions.poolSize || defaults.poolSize, idleTimeoutMillis: poolOptions.idleTimeout || defaults.poolIdleTimeout, reapIntervalMillis: poolOptions.reapIntervalMillis || defaults.reapIntervalMillis, - log: poolOptions.log || defaults.poolLog, + log: poolOptions.log, create: function(cb) { var client = new pg.Client(connectionString); client.connect(function(err) { @@ -55,20 +54,9 @@ function newPgPool(connectionString, poolOptions) { client.end(); } }); - //mixin EventEmitter to pool - EventEmitter.call(pool); - for (var key in EventEmitter.prototype) { - if (EventEmitter.prototype.hasOwnProperty(key)) { - pool[key] = EventEmitter.prototype[key]; - } - } //monkey-patch with connect method pool.connect = function(cb) { - var domain = process.domain; pool.acquire(function(err, client) { - if (domain) { - cb = domain.bind(cb); - } if (err) return cb(err, null, function() { /*NOOP*/ }); diff --git a/src/pg/quote.js b/src/pg/quote.js new file mode 100644 index 00000000..9813301a --- /dev/null +++ b/src/pg/quote.js @@ -0,0 +1,2 @@ + +module.exports = (name) => `"${name}"`; \ No newline at end of file diff --git a/src/pg/schema.js b/src/pg/schema.js index 25b46dec..9c3b4f7c 100644 --- a/src/pg/schema.js +++ b/src/pg/schema.js @@ -1,11 +1,11 @@ var query = require('../query'); -function executeSchema(schema) { +function executeSchema(context, schema) { if (!schema) throw new Error('Missing schema'); if (!Array.isArray(schema)) schema = [schema]; - return query('SET LOCAL search_path TO ' + schema.join(',')); + return query(context, 'SET LOCAL search_path TO ' + schema.join(',')); } module.exports = executeSchema; \ No newline at end of file diff --git a/src/pg/wrapQueryStream.js b/src/pg/wrapQueryStream.js deleted file mode 100644 index 3bd34d14..00000000 --- a/src/pg/wrapQueryStream.js +++ /dev/null @@ -1,20 +0,0 @@ -var log = require('../table/log'); -var replaceParamChar = require('./replaceParamChar'); -var newStreamableQuery = require('./newStreamableQuery'); - -function wrapQueryStream(connection) { - var runOriginalQuery = connection.query; - return runQuery; - - function runQuery(query, options) { - var params = query.parameters; - var sql = replaceParamChar(query, params); - log.emitQuery({sql, parameters: params}); - query = newStreamableQuery(sql, params, options); - - return runOriginalQuery.call(connection, query); - } - -} - -module.exports = wrapQueryStream; \ No newline at end of file diff --git a/src/mySql/pool/defaults.js b/src/poolDefaults.js similarity index 89% rename from src/mySql/pool/defaults.js rename to src/poolDefaults.js index 47d3be87..5bfd0683 100644 --- a/src/mySql/pool/defaults.js +++ b/src/poolDefaults.js @@ -11,6 +11,4 @@ module.exports = { //frequeny to check for idle clients within the client pool reapIntervalMillis: 1000, - //pool log function / boolean - poolLog: false, }; \ No newline at end of file diff --git a/src/promisify.js b/src/promisify.js new file mode 100644 index 00000000..76556a12 --- /dev/null +++ b/src/promisify.js @@ -0,0 +1,24 @@ +function promisify(original) { + if (typeof original !== 'function') { + throw new TypeError('The "original" argument must be of type Function'); + } + + return function(...args) { + return new Promise((resolve, reject) => { + // Add the callback that Node-style APIs expect + function callback(err, ...values) { + if (err) { + return reject(err); + } + // If there's exactly one success value, return it; + // otherwise, return all values as an array. + return resolve(values.length > 1 ? values : values[0]); + } + + // Call the original function, appending our callback + original.call(this, ...args, callback); + }); + }; +} + +module.exports = promisify; \ No newline at end of file diff --git a/src/query.js b/src/query.js index 9e288ffd..e7cea4db 100644 --- a/src/query.js +++ b/src/query.js @@ -1,9 +1,9 @@ var executeQueries = require('./table/executeQueries'); var wrapQuery = require('./query/wrapQuery'); -function doQuery(query) { +function doQuery(context, query) { var wrappedQuery = wrapQuery(query); - return executeQueries([wrappedQuery]).then(unwrapResult); + return executeQueries(context, [wrappedQuery]).then(unwrapResult); } function unwrapResult(results) { diff --git a/src/sap/deleteFromSql.js b/src/sap/deleteFromSql.js index 0a2d1114..129968db 100644 --- a/src/sap/deleteFromSql.js +++ b/src/sap/deleteFromSql.js @@ -1,10 +1,10 @@ var format = 'delete from %s from %s as %s %s'; -var util = require('util'); -const quote = require('../table/quote'); +const formatString = require('../format'); +const quote = require('./quote'); function deleteFromSql(table, alias, whereSql) { var name = quote(table._dbName); alias = quote(alias) ; - return util.format(format, name, name, alias, whereSql); + return formatString(format, name, name, alias, whereSql); } module.exports = deleteFromSql; \ No newline at end of file diff --git a/src/sap/formatDateOut.js b/src/sap/formatDateOut.js index bb60b052..20f76f1a 100644 --- a/src/sap/formatDateOut.js +++ b/src/sap/formatDateOut.js @@ -1,4 +1,4 @@ -const quote = require('../table/quote'); +const quote = require('./quote'); function formatDateOut(column, alias) { return `CONVERT(VARCHAR, ${alias}.${quote(column._dbName)}, 23)`; diff --git a/src/sap/insert.js b/src/sap/insert.js index c6571f6a..cee90558 100644 --- a/src/sap/insert.js +++ b/src/sap/insert.js @@ -5,16 +5,16 @@ let executeQueries = require('../table/executeQueries'); let pushCommand = require('../table/commands/pushCommand'); -function insertDefault(table, row, options) { +function insertDefault(context, table, row, options) { let commands = []; - let insertCmd = newInsertCommand(newInsertCommandCore, table, row, options); + let insertCmd = newInsertCommand(newInsertCommandCore.bind(null, context), table, row, options); insertCmd.disallowCompress = true; - pushCommand(insertCmd); + pushCommand(context, insertCmd); - let selectCmd = newGetLastInsertedCommand(table, row, insertCmd); + let selectCmd = newGetLastInsertedCommand(context, table, row, insertCmd); commands.push(selectCmd); - return executeQueries(commands).then((result) => result[result.length - 1]); + return executeQueries(context, commands).then((result) => result[result.length - 1]); } diff --git a/src/sap/insertSql.js b/src/sap/insertSql.js index 06dee1d8..2bf7c9c7 100644 --- a/src/sap/insertSql.js +++ b/src/sap/insertSql.js @@ -1,12 +1,12 @@ -const getSessionSingleton = require('../table/getSessionSingleton'); const mergeSql = require('./mergeSql'); +const quote = require('./quote'); -function getSqlTemplate(_table, _row, options) { +function getSqlTemplate(_context, _table, _row, options) { if (hasConcurrency(_table, options) && hasColumns()) - return mergeSql.apply(null, arguments); + return mergeSql.apply(null, [...arguments].slice(1)); else - return insertSql.apply(null, arguments); + return insertSql.apply(null, [...arguments].slice(1)); function hasColumns() { for(let p in _row) { @@ -27,7 +27,6 @@ function hasConcurrency(table,options) { } function insertSql(table, row) { - const quote = getSessionSingleton('quote'); let columnNames = []; let regularColumnNames = []; let values = []; diff --git a/src/sap/lastInsertedSql.js b/src/sap/lastInsertedSql.js index 8934f396..f2f00305 100644 --- a/src/sap/lastInsertedSql.js +++ b/src/sap/lastInsertedSql.js @@ -1,10 +1,10 @@ -function lastInsertedSql(table, keyValues) { - return keyValues.map((value,i) => { +function lastInsertedSql(context, table, keyValues) { + return keyValues.map((value, i) => { let column = table._primaryColumns[i]; if (value === undefined && column.tsType === 'NumberColumn') return `${column._dbName}=@@identity`; else - return column.eq(value); + return column.eq(context, value); }); } diff --git a/src/sap/mergeSql.js b/src/sap/mergeSql.js index 1056b0f1..19239309 100644 --- a/src/sap/mergeSql.js +++ b/src/sap/mergeSql.js @@ -1,7 +1,6 @@ -const getSessionSingleton = require('../table/getSessionSingleton'); +const quote = require('./quote'); function insertSql(table, row, options) { - const quote = getSessionSingleton('quote'); let columnNames = []; let conflictColumnUpdateSql = ''; let values = []; diff --git a/src/sap/newDatabase.js b/src/sap/newDatabase.js index 46db23dd..4735baa6 100644 --- a/src/sap/newDatabase.js +++ b/src/sap/newDatabase.js @@ -4,10 +4,6 @@ let _begin = require('../table/begin'); let commit = require('../table/commit'); let rollback = require('../table/rollback'); let newPool = require('./newPool'); -let useHook = require('../useHook'); -let promise = require('promise/domains'); -let versionArray = process.version.replace('v', '').split('.'); -let major = parseInt(versionArray[0]); let express = require('../hostExpress'); let hostLocal = require('../hostLocal'); let doQuery = require('../query'); @@ -34,15 +30,12 @@ function newDatabase(connectionString, poolOptions) { if (fn) return domain.run(runInTransaction); - else if ((major >= 12) && useHook()) { - domain.exitContext = true; - return domain.start().then(run); - } else return domain.run(run); + function begin() { - return _begin(options?.readonly); + return _begin(domain, options); } async function runInTransaction() { @@ -50,69 +43,65 @@ function newDatabase(connectionString, poolOptions) { let transaction = newTransaction(domain, pool, options); await new Promise(transaction) .then(begin) - .then(fn) + .then(() => fn(domain)) .then((res) => result = res) - .then(c.commit) - .then(null, c.rollback); + .then(() => commit(domain)) + .then(null, (e) => rollback(domain, e)); return result; + } function run() { let p; let transaction = newTransaction(domain, pool, options); - if (useHook()) - p = new Promise(transaction); - else - p = new promise(transaction); + p = new Promise(transaction); return p.then(begin); } }; - c.createTransaction = function() { + c.createTransaction = function(options) { let domain = createDomain(); let transaction = newTransaction(domain, pool); - let p = domain.run(() => new Promise(transaction).then(_begin)); + let p = domain.run(() => new Promise(transaction).then(begin)); function run(fn) { - return p.then(domain.run.bind(domain, fn)); + return p.then(() => fn(domain)); } - return run; - }; - - c.bindTransaction = function() { - // @ts-ignore - var domain = process.domain; - let p = domain.run(() => true); - function run(fn) { - return p.then(domain.run.bind(domain, fn)); + function begin() { + return _begin(domain, options); } + + run.rollback = rollback.bind(null, domain); + run.commit = commit.bind(null, domain); + return run; + }; + + c.query = function(query) { let domain = createDomain(); let transaction = newTransaction(domain, pool); let p = domain.run(() => new Promise(transaction) - .then(() => setSessionSingleton('changes', [])) - .then(() => doQuery(query).then(onResult, onError))); + .then(() => setSessionSingleton(domain, 'changes', [])) + .then(() => doQuery(domain, query).then(onResult, onError))); return p; function onResult(result) { - releaseDbClient(); + releaseDbClient(domain); return result; } function onError(e) { - releaseDbClient(); + releaseDbClient(domain); throw e; } }; - - c.rollback = rollback; c.commit = commit; diff --git a/src/sap/newPool.js b/src/sap/newPool.js index 6124c9c5..22acd785 100644 --- a/src/sap/newPool.js +++ b/src/sap/newPool.js @@ -1,5 +1,5 @@ +const promisify = require('../promisify'); var pools = require('../pools'); -var promise = require('../table/promise'); var end = require('./pool/end'); var newGenericPool = require('../mssql/pool/newGenericPool'); var newId = require('../newId'); @@ -11,7 +11,7 @@ function newPool(connectionString, poolOptions) { var c = {}; c.connect = pool.connect; - c.end = promise.denodeify(boundEnd); + c.end = promisify(boundEnd); pools[id] = c; return c; } diff --git a/src/sap/newTransaction.js b/src/sap/newTransaction.js index ae1ef85c..2370a239 100644 --- a/src/sap/newTransaction.js +++ b/src/sap/newTransaction.js @@ -7,8 +7,9 @@ const formatDateOut = require('./formatDateOut'); const insertSql = require('./insertSql'); const insert = require('./insert'); const limitAndOffset = require('./limitAndOffset'); +const quote = require('./quote'); -function newResolveTransaction(domain, pool, { readonly } = {}) { +function newResolveTransaction(domain, pool, { readonly = false } = {}) { var rdb = {poolFactory: pool}; if (!pool.connect) { pool = pool(); @@ -40,7 +41,7 @@ function newResolveTransaction(domain, pool, { readonly } = {}) { caller.visitSap(); }; rdb.aggregateCount = 0; - rdb.quote = (name) => `[${name}]`; + rdb.quote = quote; if (readonly) { rdb.dbClient = { diff --git a/src/sap/quote.js b/src/sap/quote.js new file mode 100644 index 00000000..6e67a495 --- /dev/null +++ b/src/sap/quote.js @@ -0,0 +1 @@ +module.exports = (name) => `[${name}]`; \ No newline at end of file diff --git a/src/sqlite/deleteFromSql.js b/src/sqlite/deleteFromSql.js index 3e1f5e84..3abec910 100644 --- a/src/sqlite/deleteFromSql.js +++ b/src/sqlite/deleteFromSql.js @@ -1,10 +1,10 @@ -var format = 'delete from %s where %s.rowId in (SELECT %s.rowId FROM %s %s%s)'; -var util = require('util'); -const quote = require('../table/quote'); +const format = 'delete from %s where %s.rowId in (SELECT %s.rowId FROM %s %s%s)'; +const formatString = require('../format'); +const quote = require('./quote'); function deleteFromSql(table, alias, whereSql) { - var name = quote(table._dbName); + const name = quote(table._dbName); alias = quote(alias); - return util.format(format, name, name, alias, name, alias, whereSql); + return formatString(format, name, name, alias, name, alias, whereSql); } module.exports = deleteFromSql; diff --git a/src/sqlite/insert.js b/src/sqlite/insert.js index c6571f6a..cee90558 100644 --- a/src/sqlite/insert.js +++ b/src/sqlite/insert.js @@ -5,16 +5,16 @@ let executeQueries = require('../table/executeQueries'); let pushCommand = require('../table/commands/pushCommand'); -function insertDefault(table, row, options) { +function insertDefault(context, table, row, options) { let commands = []; - let insertCmd = newInsertCommand(newInsertCommandCore, table, row, options); + let insertCmd = newInsertCommand(newInsertCommandCore.bind(null, context), table, row, options); insertCmd.disallowCompress = true; - pushCommand(insertCmd); + pushCommand(context, insertCmd); - let selectCmd = newGetLastInsertedCommand(table, row, insertCmd); + let selectCmd = newGetLastInsertedCommand(context, table, row, insertCmd); commands.push(selectCmd); - return executeQueries(commands).then((result) => result[result.length - 1]); + return executeQueries(context, commands).then((result) => result[result.length - 1]); } diff --git a/src/sqlite/insertSql.js b/src/sqlite/insertSql.js index 84b2592d..03de4881 100644 --- a/src/sqlite/insertSql.js +++ b/src/sqlite/insertSql.js @@ -1,6 +1,6 @@ -const quote = require('../table/quote'); +const quote = require('./quote'); -function insertSql(table, row, options) { +function insertSql(_context, table, row, options) { let columnNames = []; let conflictColumnUpdateSql = ''; let values = []; diff --git a/src/sqlite/lastInsertedSql.js b/src/sqlite/lastInsertedSql.js index f7256f57..4a785ac5 100644 --- a/src/sqlite/lastInsertedSql.js +++ b/src/sqlite/lastInsertedSql.js @@ -1,10 +1,10 @@ -function lastInsertedSql(table, keyValues) { +function lastInsertedSql(context, table, keyValues) { return keyValues.map((value,i) => { let column = table._primaryColumns[i]; if (value === undefined && column.tsType === 'NumberColumn') return 'rowid IN (select last_insert_rowid())'; else - return column.eq(value); + return column.eq(context, value); }); } diff --git a/src/sqlite/newDatabase.js b/src/sqlite/newDatabase.js index a7127cb5..95ef2d8e 100644 --- a/src/sqlite/newDatabase.js +++ b/src/sqlite/newDatabase.js @@ -4,10 +4,6 @@ let _begin = require('../table/begin'); let commit = require('../table/commit'); let rollback = require('../table/rollback'); let newPool = require('./newPool'); -let useHook = require('../useHook'); -let promise = require('promise/domains'); -let versionArray = process.version.replace('v', '').split('.'); -let major = parseInt(versionArray[0]); let express = require('../hostExpress'); let hostLocal = require('../hostLocal'); let doQuery = require('../query'); @@ -34,15 +30,11 @@ function newDatabase(connectionString, poolOptions) { if (fn) return domain.run(runInTransaction); - else if ((major >= 12) && useHook()) { - domain.exitContext = true; - return domain.start().then(run); - } else return domain.run(run); function begin() { - return _begin(options?.readonly); + return _begin(domain, options); } async function runInTransaction() { @@ -50,63 +42,55 @@ function newDatabase(connectionString, poolOptions) { let transaction = newTransaction(domain, pool, options); await new Promise(transaction) .then(begin) - .then(fn) + .then(() => fn(domain)) .then((res) => result = res) - .then(c.commit) - .then(null, c.rollback); + .then(() => commit(domain)) + .then(null, (e) => rollback(domain, e)); return result; } function run() { let p; let transaction = newTransaction(domain, pool, options); - if (useHook()) - p = new Promise(transaction); - else - p = new promise(transaction); + p = new Promise(transaction); return p.then(begin); } }; - c.createTransaction = function() { + c.createTransaction = function(options) { let domain = createDomain(); let transaction = newTransaction(domain, pool); - let p = domain.run(() => new Promise(transaction).then(_begin)); + let p = domain.run(() => new Promise(transaction).then(begin)); function run(fn) { - return p.then(domain.run.bind(domain, fn)); + return p.then(() => fn(domain)); } + run.rollback = rollback.bind(null, domain); + run.commit = commit.bind(null, domain); return run; - }; - - c.bindTransaction = function() { - // @ts-ignore - var domain = process.domain; - let p = domain.run(() => true); - function run(fn) { - return p.then(domain.run.bind(domain, fn)); + function begin() { + return _begin(domain, options); } - return run; }; c.query = function(query) { let domain = createDomain(); let transaction = newTransaction(domain, pool); let p = domain.run(() => new Promise(transaction) - .then(() => setSessionSingleton('changes', [])) - .then(() => doQuery(query).then(onResult, onError))); + .then(() => setSessionSingleton(domain, 'changes', [])) + .then(() => doQuery(domain, query).then(onResult, onError))); return p; function onResult(result) { - releaseDbClient(); + releaseDbClient(domain); return result; } function onError(e) { - releaseDbClient(); + releaseDbClient(domain); throw e; } }; diff --git a/src/sqlite/newPool.js b/src/sqlite/newPool.js index 8ea1295a..3d9a8d8c 100644 --- a/src/sqlite/newPool.js +++ b/src/sqlite/newPool.js @@ -1,17 +1,17 @@ -var pools = require('../pools'); -var promise = require('../table/promise'); -var end = require('./pool/end'); -var newGenericPool = require('./pool/newGenericPool'); -var newId = require('../newId'); +const promisify = require('../promisify'); +const pools = require('../pools'); +const end = require('./pool/end'); +const newGenericPool = require('./pool/newGenericPool'); +const newId = require('../newId'); function newPool(connectionString, poolOptions) { - var pool = newGenericPool(connectionString, poolOptions); - var id = newId(); - var boundEnd = end.bind(null, pool, id); - var c = {}; + let pool = newGenericPool(connectionString, poolOptions); + let id = newId(); + let boundEnd = end.bind(null, pool, id); + let c = {}; c.connect = pool.connect; - c.end = promise.denodeify(boundEnd); + c.end = promisify(boundEnd); pools[id] = c; return c; } diff --git a/src/sqlite/newTransaction.js b/src/sqlite/newTransaction.js index 831610c6..3e980ca6 100644 --- a/src/sqlite/newTransaction.js +++ b/src/sqlite/newTransaction.js @@ -6,8 +6,9 @@ const lastInsertedSql = require('./lastInsertedSql'); const limitAndOffset = require('./limitAndOffset'); const insertSql = require('./insertSql'); const insert = require('./insert'); +const quote = require('./quote'); -function newResolveTransaction(domain, pool, { readonly } = {}) { +function newResolveTransaction(domain, pool, { readonly = false } = {}) { var rdb = {poolFactory: pool}; if (!pool.connect) { pool = pool(); @@ -29,7 +30,7 @@ function newResolveTransaction(domain, pool, { readonly } = {}) { caller.visitSqlite(); }; rdb.aggregateCount = 0; - rdb.quote = (name) => `"${name}"`; + rdb.quote = quote; if (readonly) { rdb.dbClient = { diff --git a/src/sqlite/pool/defaults.js b/src/sqlite/pool/defaults.js deleted file mode 100644 index f21f834a..00000000 --- a/src/sqlite/pool/defaults.js +++ /dev/null @@ -1,45 +0,0 @@ -module.exports = { - // database host defaults to localhost - host: 'localhost', - - //database user's name - user: process.platform === 'win32' ? process.env.USERNAME : process.env.USER, - - //name of database to connect - database: process.platform === 'win32' ? process.env.USERNAME : process.env.USER, - - //database user's password - password: null, - - //database port - port: 5432, - - //number of rows to return at a time from a prepared statement's - //portal. 0 will return all rows at once - rows: 0, - - // binary result mode - binary: false, - - //Connection pool options - see https://github.com/coopernurse/node-pool - //number of connections to use in connection pool - //0 will disable connection pooling - poolSize: 0, - - //max milliseconds a client can go unused before it is removed - //from the pool and destroyed - poolIdleTimeout: 30000, - - //frequeny to check for idle clients within the client pool - reapIntervalMillis: 1000, - - //pool log function / boolean - poolLog: false, - - client_encoding: '', - - ssl: false, - - application_name : undefined, - fallback_application_name: undefined -}; \ No newline at end of file diff --git a/src/sqlite/pool/newGenericPool.js b/src/sqlite/pool/newGenericPool.js index dc1af9bf..f34d71f6 100644 --- a/src/sqlite/pool/newGenericPool.js +++ b/src/sqlite/pool/newGenericPool.js @@ -1,7 +1,6 @@ /* eslint-disable no-prototype-builtins */ -var EventEmitter = require('events').EventEmitter; +var defaults = require('../../poolDefaults'); -var defaults = require('./defaults'); var genericPool = require('../../generic-pool'); var sqlite = require('sqlite3'); @@ -28,20 +27,9 @@ function newGenericPool(connectionString, poolOptions) { client.close(); } }); - //mixin EventEmitter to pool - EventEmitter.call(pool); - for(var key in EventEmitter.prototype) { - if(EventEmitter.prototype.hasOwnProperty(key)) { - pool[key] = EventEmitter.prototype[key]; - } - } //monkey-patch with connect method pool.connect = function(cb) { - var domain = process.domain; pool.acquire(function(err, client) { - if(domain) { - cb = domain.bind(cb); - } if(err) return cb(err, null, function() {/*NOOP*/}); client.poolCount++; cb(null, client, function(err) { diff --git a/src/sqlite/quote.js b/src/sqlite/quote.js new file mode 100644 index 00000000..495b1a43 --- /dev/null +++ b/src/sqlite/quote.js @@ -0,0 +1 @@ +module.exports = (name) => `"${name}"`; \ No newline at end of file diff --git a/src/table.js b/src/table.js index b4cc3430..dfed4dd0 100644 --- a/src/table.js +++ b/src/table.js @@ -14,13 +14,10 @@ const newContext = require('./newObject'); const insert = require('./table/insert'); const _delete = require('./table/delete'); const cascadeDelete = require('./table/cascadeDelete'); -const createReadStream = require('./table/createReadStream'); -const createJSONReadStream = require('./table/createJSONReadStream'); -const getIdArgs = require('./table/getIdArgs'); const patchTable = require('./patchTable'); const newEmitEvent = require('./emitEvent'); const hostLocal = require('./hostLocal'); -const getTSDefinition = require('./getTSDefinition'); +// const getTSDefinition = require('./getTSDefinition'); //todo: unused ? const where = require('./table/where'); const aggregate = require('./table/aggregate'); const groupBy = require('./table/groupBy'); @@ -62,63 +59,63 @@ function _new(tableName) { return hasOne(joinRelation); }; - table.count = function(filter) { - return Promise.resolve().then(() => count(table, filter)); + table.count = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => count.apply(null, args)); }; - table.getMany = function(filter, strategy) { - return Promise.resolve().then(() => getMany(table, filter, strategy)); + table.getMany = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => getMany.apply(null, args)); }; - table.getManyDto = function(filter, strategy) { - return Promise.resolve().then(() => getManyDto(table, filter, strategy)); + table.getManyDto = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => getManyDto.apply(null, args)); }; - table.aggregate = function(filter, strategy) { - return groupBy(table, filter, strategy); + table.aggregate = function(context, ...rest) { + const args = [context, table, ...rest]; + return groupBy.apply(null, args); }; - table.getMany.exclusive = function(filter, strategy) { - return Promise.resolve().then(() => getMany.exclusive(table, filter, strategy)); + table.getMany.exclusive = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => getMany.exclusive.apply(null, args)); }; - table.tryGetFirst = function(filter, strategy) { - return Promise.resolve().then(() => tryGetFirst(table, filter, strategy)); + table.tryGetFirst = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => tryGetFirst.apply(null, args)); }; - table.tryGetFirst.exclusive = function(filter, strategy) { - return Promise.resolve().then(() => tryGetFirst.exclusive(table, filter, strategy)); + table.tryGetFirst.exclusive = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => tryGetFirst.exclusive.apply(null, args)); }; + table.getOne = table.tryGetFirst; table.getOne.exclusive = table.tryGetFirst.exclusive; - function callAsync(func, args) { - return Promise.resolve().then(() => call(func, args)); - } - - function call(func, args) { - var mergedArgs = [table]; - for (var i = 0; i < args.length; i++) { - mergedArgs.push(args[i]); - } - return func.apply(null, mergedArgs); - } - - table.getById = function() { - return callAsync(getById, getIdArgs(table, arguments)); + table.getById = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => getById.apply(null, args)); }; - table.getById.exclusive = function() { - - return callAsync(getById.exclusive, getIdArgs(table, arguments)); + table.getById.exclusive = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => getById.exclusive.apply(null, args)); }; - table.tryGetById = function() { - return callAsync(tryGetById, getIdArgs(table, arguments)); + table.tryGetById = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => tryGetById.apply(null, args)); }; - table.tryGetById.exclusive = function() { - return callAsync(tryGetById.exclusive, getIdArgs(table, arguments)); + table.tryGetById.exclusive = function(context, ...rest) { + const args = [context, table, ...rest]; + return Promise.resolve().then(() => tryGetById.exclusive.apply(null, args)); }; + table.columnDiscriminators = function() { for (var i = 0; i < arguments.length; i++) { table._columnDiscriminators.push(arguments[i]); @@ -133,37 +130,43 @@ function _new(tableName) { return table; }; - table.insert = function() { + table.insert = function(context, ...rest) { const concurrency = undefined; - let args = [{table, concurrency}].concat([].slice.call(arguments)); + let args = [context, {table, concurrency}, ...rest]; return insert.apply(null, args); }; - table.insertWithConcurrency = function(options, ...rows) { - let args = [{table, options}].concat([].slice.call(rows)); + table.insertWithConcurrency = function(context, options, ...rows) { + let args = [context, {table, options}].concat([].slice.call(rows)); return insert.apply(null, args); }; table.delete = _delete.bind(null, table); - table.cascadeDelete = cascadeDelete.bind(null, table); - table.deleteCascade = cascadeDelete.bind(null, table); - table.createReadStream = createReadStream.bind(null, table); - table.createJSONReadStream = createJSONReadStream.bind(null, table); + table.cascadeDelete = function(context, ...rest) { + const args = [context, table, ...rest]; + return cascadeDelete.apply(null, args); + }; + + table.deleteCascade = table.cascadeDelete; table.exclusive = function() { table._exclusive = true; return table; }; - table.patch = patchTable.bind(null, table); - table.subscribeChanged = table._emitChanged.add; - table.unsubscribeChanged = table._emitChanged.remove; + table.patch = function(context, ...rest) { + const args = [context, table, ...rest]; + return patchTable.apply(null, args); + }; + + // table.subscribeChanged = table._emitChanged.add; //legacy + // table.unsubscribeChanged = table._emitChanged.remove; //legacy table.hostLocal = function(options) { return hostLocal({table, ...options}); }; - table.ts = function(name) { - return getTSDefinition(table, {name}); - }; + // table.ts = function(name) { //unused ? + // return getTSDefinition(table, {name}); + // }; table.where = where(table); table._aggregate = aggregate(table); diff --git a/src/table/aggregate.js b/src/table/aggregate.js index a5f5a7d5..5bf59d1c 100644 --- a/src/table/aggregate.js +++ b/src/table/aggregate.js @@ -1,6 +1,6 @@ function newAggregate(table) { - function aggregate(fn) { + function aggregate(_context, fn) { return fn(table); } return aggregate; diff --git a/src/table/begin.js b/src/table/begin.js index c1ead460..7f737d12 100644 --- a/src/table/begin.js +++ b/src/table/begin.js @@ -2,13 +2,13 @@ let beginCommand = require('./commands/beginCommand'); let executeQuery = require('./executeQueries/executeQuery'); let setSessionSingleton = require('./setSessionSingleton'); -function begin(readonly) { - setSessionSingleton('changes', []); - if (readonly) { - setSessionSingleton('readonly', true); +function begin(context, transactionLess) { + setSessionSingleton(context, 'changes', []); + if (transactionLess) { + setSessionSingleton(context, 'transactionLess', true); return Promise.resolve(); } - return executeQuery(beginCommand()); + return executeQuery(context, beginCommand(context)); } module.exports = begin; \ No newline at end of file diff --git a/src/table/cascadeDelete.js b/src/table/cascadeDelete.js index 675b5f8c..e9acd84a 100644 --- a/src/table/cascadeDelete.js +++ b/src/table/cascadeDelete.js @@ -2,10 +2,10 @@ var _delete = require('./delete'); var newObject = require('../newObject'); var newCascadeDeleteStrategy = require('./newCascadeDeleteStrategy'); -function cascadeDelete(table, filter) { +function cascadeDelete(context, table, filter) { var empty = newObject(); var strategy = newCascadeDeleteStrategy(empty, table); - return _delete(table, filter, strategy); + return _delete(context, table, filter, strategy); } module.exports = cascadeDelete; \ No newline at end of file diff --git a/src/table/column.js b/src/table/column.js index 831d2b7a..4cbd8d6e 100644 --- a/src/table/column.js +++ b/src/table/column.js @@ -1,5 +1,4 @@ const Ajv = require('ajv'); -const inspect = require('util').inspect; function defineColumn(column, table) { var c = {}; @@ -139,7 +138,7 @@ function defineColumn(column, table) { previousValidate.apply(null, arguments); let valid = validate.apply(null, arguments); if (!valid) { - let e = new Error(`Column ${table._dbName}.${column._dbName} violates JSON Schema: ${inspect(validate.errors, false, 10)}`); + let e = new Error(`Column ${table._dbName}.${column._dbName} violates JSON Schema: ${inspect(validate.errors)}`); e.errors = validate.errors; e.status = 400; throw e; @@ -151,4 +150,9 @@ function defineColumn(column, table) { return c; } +function inspect(obj) { + return JSON.stringify(obj, null, 2); +} + + module.exports = defineColumn; \ No newline at end of file diff --git a/src/table/column/binary/newDecode.js b/src/table/column/binary/newDecode.js index 39face22..aa4c628f 100644 --- a/src/table/column/binary/newDecode.js +++ b/src/table/column/binary/newDecode.js @@ -3,8 +3,8 @@ var newDecodeCore = require('../newDecodeCore'); function _new(column) { var decodeCore = newDecodeCore(column); - return function(value) { - value = decodeCore(value); + return function(context, value) { + value = decodeCore(context, value); if (value === null) return value; else diff --git a/src/table/column/binary/newEncode.js b/src/table/column/binary/newEncode.js index 63426e21..a64bd7da 100644 --- a/src/table/column/binary/newEncode.js +++ b/src/table/column/binary/newEncode.js @@ -3,21 +3,20 @@ var newParam = require('../../query/newParameterized'); function _new(_column) { - - function encode(value) { + function encode(_context, value) { value = purify(value); if (value === null) return newParam('null'); return newParam('?', [Buffer.from(value, 'base64')]); } - encode.unsafe = function(value) { + encode.unsafe = function(_context, value) { value = purify(value); if (value === null) return 'null'; return Buffer.from(value, 'base64'); }; - encode.direct = function(value) { + encode.direct = function(_context, value) { return Buffer.from(value, 'base64'); }; diff --git a/src/table/column/boolean/newDecode.js b/src/table/column/boolean/newDecode.js index 7e6ac39f..c5390246 100644 --- a/src/table/column/boolean/newDecode.js +++ b/src/table/column/boolean/newDecode.js @@ -2,7 +2,7 @@ var purify = require('./purify'); function _new(column) { - return function(value) { + return function(context, value) { if (value == column.dbNull) return null; return purify(value); diff --git a/src/table/column/boolean/newEncode.js b/src/table/column/boolean/newEncode.js index 5538736b..b9463e99 100644 --- a/src/table/column/boolean/newEncode.js +++ b/src/table/column/boolean/newEncode.js @@ -4,34 +4,34 @@ var getSessionSingleton = require('../../getSessionSingleton'); function _new(column) { - function encode(value) { + function encode(context, value) { value = purify(value); if (value === null) { if (column.dbNull === null) return newParam('null'); return newParam('\'' + column.dbNull + '\''); } - var encodeCore = getSessionSingleton('encodeBoolean'); + var encodeCore = getSessionSingleton(context, 'encodeBoolean'); return newParam('?', [encodeCore(value)]); } - encode.unsafe = function(value) { + encode.unsafe = function(context, value) { value = purify(value); if (value === null) { if (column.dbNull === null) return 'null'; return '\'' + column.dbNull + '\''; } - var encodeCore = getSessionSingleton('encodeBoolean'); + var encodeCore = getSessionSingleton(context, 'encodeBoolean'); return encodeCore(value); }; - encode.direct = function(value) { - var encodeCore = getSessionSingleton('encodeBoolean'); + encode.direct = function(context, value) { + var encodeCore = getSessionSingleton(context, 'encodeBoolean'); return encodeCore(value); }; diff --git a/src/table/column/date.js b/src/table/column/date.js index db5d7e30..ea0c0e3c 100644 --- a/src/table/column/date.js +++ b/src/table/column/date.js @@ -8,7 +8,7 @@ function _new(column) { column.purify = purify; column.encode = newEncode(column); column.decode = newDecode(column); - column.formatOut = formatOut.bind(null, column); + column.formatOut = (context, ...rest) => formatOut.apply(null, [context, column, ...rest]); } module.exports = _new; \ No newline at end of file diff --git a/src/table/column/date/formatOut.js b/src/table/column/date/formatOut.js index 17abb55a..6f073524 100644 --- a/src/table/column/date/formatOut.js +++ b/src/table/column/date/formatOut.js @@ -1,14 +1,12 @@ var getSessionSingleton = require('../../getSessionSingleton'); const quote = require('../../quote'); -//todo fix - -function formatOut(column, alias) { - var formatColumn = getSessionSingleton('formatDateOut'); +function formatOut(context, column, alias) { + var formatColumn = getSessionSingleton(context, 'formatDateOut'); if (formatColumn) return formatColumn(column, alias); else - return `${alias}.${quote(column._dbName)}`; + return `${alias}.${quote(context, column._dbName)}`; } module.exports = formatOut; diff --git a/src/table/column/date/newDecode.js b/src/table/column/date/newDecode.js index 3cba4609..33d3241d 100644 --- a/src/table/column/date/newDecode.js +++ b/src/table/column/date/newDecode.js @@ -4,8 +4,8 @@ var dateToISOString = require('../../../dateToISOString'); function _new(column) { var decodeCore = newDecodeCore(column); - return function(value) { - value = decodeCore(value); + return function(context, value) { + value = decodeCore(context, value); if (value === null) return value; else if (typeof value === 'string') diff --git a/src/table/column/date/newEncode.js b/src/table/column/date/newEncode.js index d969333c..2966d271 100644 --- a/src/table/column/date/newEncode.js +++ b/src/table/column/date/newEncode.js @@ -4,32 +4,32 @@ var getSessionContext = require('../../getSessionContext'); var getSessionSingleton = require('../../getSessionSingleton'); function _new(column) { - var encode = function(value) { + var encode = function(context, value) { value = purify(value); if (value == null) { if (column.dbNull === null) return newPara('null'); return newPara('\'' + column.dbNull + '\''); } - var context = getSessionContext(); - var encodeCore = context.encodeDate || encodeDate; - var formatIn = context.formatDateIn; + var ctx = getSessionContext(context); + var encodeCore = ctx.encodeDate || encodeDate; + var formatIn = ctx.formatDateIn; return newPara(formatIn ? formatIn('?') : '?', [encodeCore(value)]); }; - encode.unsafe = function(value) { + encode.unsafe = function(context, value) { value = purify(value); if (value == null) { if (column.dbNull === null) 'null'; return '\'' + column.dbNull + '\''; } - var encodeCore = getSessionSingleton('encodeDate') || encodeDate; + var encodeCore = getSessionSingleton(context, 'encodeDate') || encodeDate; return encodeCore(value); }; - encode.direct = function(value) { - var encodeCore = getSessionSingleton('encodeDate') || encodeDate; + encode.direct = function(context, value) { + var encodeCore = getSessionSingleton(context, 'encodeDate') || encodeDate; return encodeCore(value); }; diff --git a/src/table/column/dateWithTimeZone.js b/src/table/column/dateWithTimeZone.js index 75142bf0..dfed2f86 100644 --- a/src/table/column/dateWithTimeZone.js +++ b/src/table/column/dateWithTimeZone.js @@ -8,7 +8,7 @@ function _new(column) { column.purify = purify; column.encode = newEncode(column); column.decode = newDecode(column); - column.formatOut = formatOut.bind(null, column); + column.formatOut = (context, ...rest) => formatOut.apply(null, [context, column, ...rest]); } module.exports = _new; \ No newline at end of file diff --git a/src/table/column/dateWithTimeZone/newEncode.js b/src/table/column/dateWithTimeZone/newEncode.js index 2f2fe69d..55f134fb 100644 --- a/src/table/column/dateWithTimeZone/newEncode.js +++ b/src/table/column/dateWithTimeZone/newEncode.js @@ -1,9 +1,8 @@ var newPara = require('../../query/newParameterized'); var purify = require('../date/purify'); -// var getSessionSingleton = require('../../getSessionSingleton'); function _new(column) { - var encode = function(value) { + var encode = function(_context, value) { value = purify(value); if (value == null) { if (column.dbNull === null) @@ -13,7 +12,7 @@ function _new(column) { return newPara('?', [encodeDate(value)]); }; - encode.unsafe = function(value) { + encode.unsafe = function(_context, value) { value = purify(value); if (value == null) { if (column.dbNull === null) @@ -23,7 +22,7 @@ function _new(column) { return encodeDate(value); }; - encode.direct = function(value) { + encode.direct = function(_context, value) { return encodeDate(value); }; diff --git a/src/table/column/encodeFilterArg.js b/src/table/column/encodeFilterArg.js index fe9e96af..32859e14 100644 --- a/src/table/column/encodeFilterArg.js +++ b/src/table/column/encodeFilterArg.js @@ -1,8 +1,8 @@ -function encodeFilterArg(column, arg) { +function encodeFilterArg(context, column, arg) { if (column.encode.safe) - return column.encode.safe(arg); + return column.encode.safe(context, arg); else - return column.encode(arg); + return column.encode(context, arg); } module.exports = encodeFilterArg; \ No newline at end of file diff --git a/src/table/column/equal.js b/src/table/column/equal.js index 987a6722..d45f8e03 100644 --- a/src/table/column/equal.js +++ b/src/table/column/equal.js @@ -3,12 +3,12 @@ var nullOperator = ' is '; var encodeFilterArg = require('./encodeFilterArg'); var quote = require('../quote'); -function equal(column,arg,alias) { +function equal(context, column,arg,alias) { var operator = '='; - var encoded = encodeFilterArg(column, arg); + var encoded = encodeFilterArg(context, column, arg); if (encoded.sql() == 'null') operator = nullOperator; - var firstPart = quote(alias) + '.' + quote(column._dbName) + operator; + var firstPart = quote(context, alias) + '.' + quote(context, column._dbName) + operator; var filter = encoded.prepend(firstPart); return newBoolean(filter); } diff --git a/src/table/column/extractAlias.js b/src/table/column/extractAlias.js index f2932cf2..a4f3f9ce 100644 --- a/src/table/column/extractAlias.js +++ b/src/table/column/extractAlias.js @@ -1,8 +1,6 @@ function extract(table, optionalAlias) { - if (optionalAlias) return optionalAlias; - // return table._rootAlias || quote(table._dbName); return table._rootAlias || table._dbName; } diff --git a/src/table/column/greaterThan.js b/src/table/column/greaterThan.js index d2bd7915..ebf96b46 100644 --- a/src/table/column/greaterThan.js +++ b/src/table/column/greaterThan.js @@ -2,10 +2,10 @@ var newBoolean = require('./newBoolean'); var encodeFilterArg = require('./encodeFilterArg'); var quote = require('../quote'); -function greaterThan(column,arg,alias) { +function greaterThan(context, column,arg,alias) { var operator = '>'; - var encoded = encodeFilterArg(column, arg); - var firstPart = quote(alias) + '.' + quote(column._dbName) + operator; + var encoded = encodeFilterArg(context, column, arg); + var firstPart = quote(context, alias) + '.' + quote(context, column._dbName) + operator; var filter = encoded.prepend(firstPart); return newBoolean(filter); } diff --git a/src/table/column/greaterThanOrEqual.js b/src/table/column/greaterThanOrEqual.js index 50688776..abad0733 100644 --- a/src/table/column/greaterThanOrEqual.js +++ b/src/table/column/greaterThanOrEqual.js @@ -2,10 +2,10 @@ var newBoolean = require('./newBoolean'); var encodeFilterArg = require('./encodeFilterArg'); var quote = require('../quote'); -function greaterThanOrEqual(column,arg,alias) { +function greaterThanOrEqual(context, column,arg,alias) { var operator = '>='; - var encoded = encodeFilterArg(column, arg); - var firstPart = quote(alias) + '.' + quote(column._dbName) + operator; + var encoded = encodeFilterArg(context, column, arg); + var firstPart = quote(context, alias) + '.' + quote(context, column._dbName) + operator; var filter = encoded.prepend(firstPart); return newBoolean(filter); } diff --git a/src/table/column/guid/newDecode.js b/src/table/column/guid/newDecode.js index 163766fe..e6b51d69 100644 --- a/src/table/column/guid/newDecode.js +++ b/src/table/column/guid/newDecode.js @@ -1,6 +1,6 @@ function _new(column) { - return function(value) { + return function(_context, value) { if (value == column.dbNull) return null; return value.toLowerCase(); diff --git a/src/table/column/guid/newEncode.js b/src/table/column/guid/newEncode.js index c71a0cf9..88ca61db 100644 --- a/src/table/column/guid/newEncode.js +++ b/src/table/column/guid/newEncode.js @@ -3,7 +3,7 @@ var purify = require('./purify'); function _new(column) { - const encode = function(candidate) { + const encode = function(_context, candidate) { var value = purify(candidate); if (value == null) { if (column.dbNull === null) @@ -13,7 +13,7 @@ function _new(column) { return newPara('\'' + value + '\''); }; - encode.unsafe = function(candidate) { + encode.unsafe = function(_context, candidate) { var value = purify(candidate); if (value == null) { if (column.dbNull === null) @@ -23,7 +23,7 @@ function _new(column) { return '\'' + value + '\''; }; - encode.direct = function(value) { + encode.direct = function(_context, value) { return value ; }; diff --git a/src/table/column/in.js b/src/table/column/in.js index 06b710fc..e8bf3dfa 100644 --- a/src/table/column/in.js +++ b/src/table/column/in.js @@ -2,18 +2,18 @@ const newParameterized = require('../query/newParameterized'); const newBoolean = require('./newBoolean'); const quote = require('../quote'); -function _in(column,values,alias) { +function _in(context, column,values,alias) { let filter; if (values.length === 0) { filter = newParameterized('1=2'); return newBoolean(filter); } - const firstPart = `${quote(alias)}.${quote(column._dbName)} in (`; + const firstPart = `${quote(context, alias)}.${quote(context, column._dbName)} in (`; const encode = column.encode.direct; const params = new Array(values.length); for (let i = 0; i < values.length; i++) { - params[i] = encode(values[i]); + params[i] = encode(context, values[i]); } const sql = `${firstPart + new Array(values.length).fill('?').join(',')})`; return newBoolean(newParameterized(sql, params)); diff --git a/src/table/column/json.js b/src/table/column/json.js index 972594da..a90a7b83 100644 --- a/src/table/column/json.js +++ b/src/table/column/json.js @@ -10,7 +10,8 @@ function _new(column) { column.purify = purify; column.encode = newEncode(column); column.decode = newDecode(column); - column.formatOut = formatOut.bind(null, column); + column.formatOut = (context, ...rest) => formatOut.apply(null, [context, column, ...rest]); + column.onChange = onChange; column.toDto = toDto; } diff --git a/src/table/column/json/formatOut.js b/src/table/column/json/formatOut.js index 586e0bff..45f7ac8c 100644 --- a/src/table/column/json/formatOut.js +++ b/src/table/column/json/formatOut.js @@ -1,12 +1,12 @@ var getSessionSingleton = require('../../getSessionSingleton'); const quote = require('../../quote'); -function formatOut(column, alias) { - var formatColumn = getSessionSingleton('formatJSONOut'); +function formatOut(context, column, alias) { + var formatColumn = getSessionSingleton(context, 'formatJSONOut'); if (formatColumn) return formatColumn(column, alias); else - return `${alias}.${quote(column._dbName)}`; + return `${alias}.${quote(context, column._dbName)}`; } module.exports = formatOut; diff --git a/src/table/column/json/newDecode.js b/src/table/column/json/newDecode.js index 6b1feb60..e8b1f33c 100644 --- a/src/table/column/json/newDecode.js +++ b/src/table/column/json/newDecode.js @@ -4,12 +4,12 @@ let getSessionContext = require('../../getSessionContext'); function _new(column) { let decodeCore = newDecodeCore(column); - return function(value) { - value = decodeCore(value); + return function(context, value) { + value = decodeCore(context, value); if (value === null) return value; if (typeof value !== 'object') { - let decode = getSessionContext().decodeJSON; + let decode = getSessionContext(context).decodeJSON; if (decode) return decode(value); return value; diff --git a/src/table/column/json/newEncode.js b/src/table/column/json/newEncode.js index a97af943..7a5f493a 100644 --- a/src/table/column/json/newEncode.js +++ b/src/table/column/json/newEncode.js @@ -4,14 +4,14 @@ var getSessionSingleton = require('../../getSessionSingleton'); function _new(column) { - const encode = function(candidate) { + const encode = function(context, candidate) { var value = purify(candidate); if (value == null) { if(column.dbNull === null) return newPara('null'); return newPara('\'' + column.dbNull + '\''); } - var encodeCore = getSessionSingleton('encodeJSON'); + var encodeCore = getSessionSingleton(context, 'encodeJSON'); if (encodeCore) { value = encodeCore(value); @@ -20,14 +20,14 @@ function _new(column) { }; - encode.unsafe = function(candidate) { + encode.unsafe = function(context, candidate) { var value = purify(candidate); if (value == null) { if(column.dbNull === null) return 'null'; return '\'' + column.dbNull + '\''; } - var encodeCore = getSessionSingleton('encodeJSON'); + var encodeCore = getSessionSingleton(context, 'encodeJSON'); if (encodeCore) { value = encodeCore(value); @@ -35,8 +35,8 @@ function _new(column) { return value; }; - encode.direct = function(value) { - var encodeCore = getSessionSingleton('encodeJSON'); + encode.direct = function(context, value) { + var encodeCore = getSessionSingleton(context, 'encodeJSON'); if (encodeCore) { value = encodeCore(value); diff --git a/src/table/column/lessThan.js b/src/table/column/lessThan.js index d3b4732c..7cc781d0 100644 --- a/src/table/column/lessThan.js +++ b/src/table/column/lessThan.js @@ -2,10 +2,10 @@ var newBoolean = require('./newBoolean'); var encodeFilterArg = require('./encodeFilterArg'); var quote = require('../quote'); -function lessThanOrEqual(column,arg,alias) { +function lessThanOrEqual(context, column,arg,alias) { var operator = '<'; - var encoded = encodeFilterArg(column, arg); - var firstPart = quote(alias) + '.' + quote(column._dbName) + operator; + var encoded = encodeFilterArg(context, column, arg); + var firstPart = quote(context, alias) + '.' + quote(context, column._dbName) + operator; var filter = encoded.prepend(firstPart); return newBoolean(filter); } diff --git a/src/table/column/lessThanOrEqual.js b/src/table/column/lessThanOrEqual.js index 9ce08c85..5e0edcde 100644 --- a/src/table/column/lessThanOrEqual.js +++ b/src/table/column/lessThanOrEqual.js @@ -2,11 +2,11 @@ var newBoolean = require('./newBoolean'); var encodeFilterArg = require('./encodeFilterArg'); const getSessionSingleton = require('../getSessionSingleton'); -function lessThanOrEqual(column,arg,alias) { - const quote = getSessionSingleton('quote'); +function lessThanOrEqual(context, column,arg,alias) { + const quote = getSessionSingleton(context, 'quote'); var operator = '<='; - var encoded = encodeFilterArg(column, arg); - var firstPart = quote(alias) + '.' + quote(column._dbName) + operator; + var encoded = encodeFilterArg(context, column, arg); + var firstPart = quote(context, alias) + '.' + quote(context, column._dbName) + operator; var filter = encoded.prepend(firstPart); return newBoolean(filter); } diff --git a/src/table/column/negotiateRawSqlFilter.js b/src/table/column/negotiateRawSqlFilter.js index 5724c564..2053c820 100644 --- a/src/table/column/negotiateRawSqlFilter.js +++ b/src/table/column/negotiateRawSqlFilter.js @@ -1,74 +1,3 @@ -let newParameterized = function() { - newParameterized = require('../query/newParameterized'); - return newParameterized.apply(null, arguments); -}; - -let newBoolean = function() { - newBoolean = require('./newBoolean'); - return newBoolean.apply(null, arguments); -}; - -function negotiateRawSqlFilter(filter, optionalTable, emptyArrayMeansFalse) { - if (Array.isArray(filter) && filter.length === 0) { - const sql = emptyArrayMeansFalse ? '1 = 2' : '1 = 1'; - return newBoolean(newParameterized(sql)); - } - else if (Array.isArray(filter)) { - let curFilter; - let curObjectFilter; - for (let i = 0; i < filter.length; i++) { - let nextFilter = negotiateRawSqlFilter(filter[i], optionalTable); - if (nextFilter.isObjectFilter) - curObjectFilter = curObjectFilter ? curObjectFilter.or(nextFilter) : nextFilter; - else - curFilter = curFilter ? curFilter.and(nextFilter) : nextFilter; - } - if (curFilter && curObjectFilter) - return curFilter.and(curObjectFilter); - else if (curFilter) - return curFilter; - else - return curObjectFilter; - } - else { - let params = []; - if (filter) { - if (filter.and) - return filter; - if (filter.sql) { - let sql = filter.sql; - if (typeof filter.sql === 'function') { - sql = filter.sql(); - } - params.push(sql, filter.parameters); - } - else if (isObjectFilter(filter, optionalTable)) - return newObjectFilter(filter, optionalTable); - else - params = [filter]; - } else { - params = [filter]; - } - - let parameterized = newParameterized.apply(null, params); - return newBoolean(parameterized); - } -} - -function isObjectFilter(object, optionalTable) { - return optionalTable && object; -} - -function newObjectFilter(object, table) { - let primaryColumns = table._primaryColumns; - let filter; - for (let i = 0; i < primaryColumns.length; i++) { - let column = primaryColumns[i]; - let colFilter = column.equal(object[column.alias]); - filter = filter ? filter.and(colFilter) : colFilter ; - } - filter.isObjectFilter = true; - return filter; -} +const { negotiateRawSqlFilter } = require('./utils'); module.exports = negotiateRawSqlFilter; \ No newline at end of file diff --git a/src/table/column/newBoolean.js b/src/table/column/newBoolean.js index 72a51d82..bc10a409 100644 --- a/src/table/column/newBoolean.js +++ b/src/table/column/newBoolean.js @@ -1,54 +1,3 @@ -var nextNewBoolean = _nextNewBoolean; -var negotiateRawSqlFilter = require('./negotiateRawSqlFilter'); -var negotiateNextAndFilter = require('./negotiateNextAndFilter'); -var negotiateNextOrFilter = require('./negotiateNextOrFilter'); +const { newBoolean } = require('./utils'); -function newBoolean(filter) { - var c = {}; - c.sql = filter.sql.bind(filter); - c.parameters = filter.parameters; - - c.append = function(other) { - var nextFilter = filter.append(other); - return nextNewBoolean(nextFilter); - }; - - c.prepend = function(other) { - var nextFilter = filter.prepend(other); - return nextNewBoolean(nextFilter); - }; - - c.and = function(other) { - other = negotiateRawSqlFilter(other); - var nextFilter = negotiateNextAndFilter(filter, other); - var next = nextNewBoolean(nextFilter); - for (var i = 1; i < arguments.length; i++) { - next = next.and(arguments[i]); - } - return next; - }; - - c.or = function(other) { - other = negotiateRawSqlFilter(other); - var nextFilter = negotiateNextOrFilter(filter, other); - var next = nextNewBoolean(nextFilter); - for (var i = 1; i < arguments.length; i++) { - next = next.or(arguments[i]); - } - return next; - }; - - c.not = function() { - var nextFilter = filter.prepend('NOT (').append(')'); - return nextNewBoolean(nextFilter); - }; - - return c; -} - -function _nextNewBoolean(filter) { - nextNewBoolean = require('./newBoolean'); - return nextNewBoolean(filter); -} - -module.exports = newBoolean; +module.exports = newBoolean; \ No newline at end of file diff --git a/src/table/column/newColumn.js b/src/table/column/newColumn.js index b7c9b89f..3b1a6da9 100644 --- a/src/table/column/newColumn.js +++ b/src/table/column/newColumn.js @@ -19,46 +19,46 @@ module.exports = function(table, name) { table._columns.push(c); table[name] = c; - c.equal = function(arg, alias) { + c.equal = function(context, arg, alias) { alias = extractAlias(alias); - return equal(c, arg, alias); + return equal(context, c, arg, alias); }; - c.notEqual = function(arg, alias) { + c.notEqual = function(context, arg, alias) { alias = extractAlias(alias); - return notEqual(c, arg, alias); + return notEqual(context, c, arg, alias); }; - c.lessThan = function(arg, alias) { + c.lessThan = function(context, arg, alias) { alias = extractAlias(alias); - return lessThan(c, arg, alias); + return lessThan(context, c, arg, alias); }; - c.lessThanOrEqual = function(arg, alias) { + c.lessThanOrEqual = function(context, arg, alias) { alias = extractAlias(alias); - return lessThanOrEqual(c, arg, alias); + return lessThanOrEqual(context, c, arg, alias); }; - c.greaterThan = function(arg, alias) { + c.greaterThan = function(context, arg, alias) { alias = extractAlias(alias); - return greaterThan(c, arg, alias); + return greaterThan(context, c, arg, alias); }; - c.greaterThanOrEqual = function(arg, alias) { + c.greaterThanOrEqual = function(context, arg, alias) { alias = extractAlias(alias); - return greaterThanOrEqual(c, arg, alias); + return greaterThanOrEqual(context, c, arg, alias); }; - c.between = function(from, to, alias) { + c.between = function(context, from, to, alias) { alias = extractAlias(alias); - from = c.greaterThanOrEqual(from, alias); - to = c.lessThanOrEqual(to, alias); + from = c.greaterThanOrEqual(context, from, alias); + to = c.lessThanOrEqual(context, to, alias); return from.and(to); }; - c.in = function(arg, alias) { + c.in = function(context, arg, alias) { alias = extractAlias(alias); - return _in(c, arg, alias); + return _in(context, c, arg, alias); }; c.eq = c.equal; @@ -76,12 +76,12 @@ module.exports = function(table, name) { c.IN = c.in; c.self = self; - function self() { - const tableAlias = quote(table._rootAlias || table._dbName); - const columnName = quote(c._dbName); + function self(context) { + const tableAlias = quote(context,table._rootAlias || table._dbName); + const columnName = quote(context, c._dbName); return { - expression: (alias) => `${tableAlias}.${columnName} ${quote(alias)}`, + expression: (alias) => `${tableAlias}.${columnName} ${quote(context, alias)}`, joins: [''], column: c, groupBy: `${tableAlias}.${columnName}` diff --git a/src/table/column/newDecodeCore.js b/src/table/column/newDecodeCore.js index 302d016e..aba9cc1f 100644 --- a/src/table/column/newDecodeCore.js +++ b/src/table/column/newDecodeCore.js @@ -1,6 +1,6 @@ function _new(column) { - return function(value) { + return function(_context, value) { if (value == column.dbNull) return null; return value; diff --git a/src/table/column/notEqual.js b/src/table/column/notEqual.js index 8e4695fd..14e433ab 100644 --- a/src/table/column/notEqual.js +++ b/src/table/column/notEqual.js @@ -3,12 +3,12 @@ var encodeFilterArg = require('./encodeFilterArg'); var nullOperator = ' is not '; var quote = require('../quote'); -function notEqual(column,arg,alias) { +function notEqual(context, column,arg,alias) { var operator = '<>'; - var encoded = encodeFilterArg(column, arg); + var encoded = encodeFilterArg(context, column, arg); if (encoded.sql() == 'null') operator = nullOperator; - var firstPart = quote(alias) + '.' + quote(column._dbName) + operator; + var firstPart = quote(context, alias) + '.' + quote(context, column._dbName) + operator; var filter = encoded.prepend(firstPart); return newBoolean(filter); } diff --git a/src/table/column/numeric/newDecode.js b/src/table/column/numeric/newDecode.js index f16d4f10..ea99c4bc 100644 --- a/src/table/column/numeric/newDecode.js +++ b/src/table/column/numeric/newDecode.js @@ -3,8 +3,8 @@ var newDecodeCore = require('../newDecodeCore'); function _new(column) { var decodeCore = newDecodeCore(column); - return function(value) { - value = decodeCore(value); + return function(context, value) { + value = decodeCore(context, value); if (value === null) return value; if (typeof(value) !== 'number') diff --git a/src/table/column/numeric/newEncode.js b/src/table/column/numeric/newEncode.js index d87a8d25..afe89f2d 100644 --- a/src/table/column/numeric/newEncode.js +++ b/src/table/column/numeric/newEncode.js @@ -3,7 +3,7 @@ var newParam = require('../../query/newParameterized'); module.exports = function(column) { - function encode(value) { + function encode(_context, value) { value = purify(value); if (value == null) { var dbNull = column.dbNull; @@ -12,7 +12,7 @@ module.exports = function(column) { return newParam('' + value); } - encode.unsafe = function(value) { + encode.unsafe = function(_context, value) { value = purify(value); if (value == null) { var dbNull = column.dbNull; @@ -21,7 +21,7 @@ module.exports = function(column) { return '' + value; }; - encode.direct = function(value) { + encode.direct = function(_context, value) { return value ; }; diff --git a/src/table/column/string.js b/src/table/column/string.js index 7845b492..a3357d4a 100644 --- a/src/table/column/string.js +++ b/src/table/column/string.js @@ -17,34 +17,34 @@ function _new(table, column) { column.decode = newDecode(column); var extractAlias = _extractAlias.bind(null, table); - column.startsWith = function(arg, alias) { + column.startsWith = function(context, arg, alias) { alias = extractAlias(alias); - return startsWith(column, arg, alias); + return startsWith(context, column, arg, alias); }; - column.endsWith = function(arg, alias) { + column.endsWith = function(context, arg, alias) { alias = extractAlias(alias); - return endsWith(column, arg, alias); + return endsWith(context, column, arg, alias); }; - column.contains = function(arg, alias) { + column.contains = function(context, arg, alias) { alias = extractAlias(alias); - return contains(column, arg, alias); + return contains(context, column, arg, alias); }; - column.iStartsWith = function(arg, alias) { + column.iStartsWith = function(context, arg, alias) { alias = extractAlias(alias); - return iStartsWith(column, arg, alias); + return iStartsWith(context, column, arg, alias); }; - column.iEndsWith = function(arg, alias) { + column.iEndsWith = function(context, arg, alias) { alias = extractAlias(alias); - return iEndsWith(column, arg, alias); + return iEndsWith(context, column, arg, alias); }; - column.iContains = function(arg, alias) { + column.iContains = function(context, arg, alias) { alias = extractAlias(alias); - return iContains(column, arg, alias); + return iContains(context, column, arg, alias); }; - column.iEqual = function(arg, alias) { + column.iEqual = function(context, arg, alias) { alias = extractAlias(alias); - return iEqual(column, arg, alias); + return iEqual(context, column, arg, alias); }; column.iEq = column.iEqual; diff --git a/src/table/column/string/contains.js b/src/table/column/string/contains.js index 37185e6a..30985a3f 100644 --- a/src/table/column/string/contains.js +++ b/src/table/column/string/contains.js @@ -1,3 +1,4 @@ var containsCore = require('./containsCore'); -module.exports = containsCore.bind(null, 'LIKE'); +module.exports = (context, ...rest) => containsCore.apply(null, [context, 'LIKE', ...rest]); + diff --git a/src/table/column/string/containsCore.js b/src/table/column/string/containsCore.js index f2299101..d92d6bd2 100644 --- a/src/table/column/string/containsCore.js +++ b/src/table/column/string/containsCore.js @@ -2,15 +2,15 @@ const quote = require('../../quote'); var newBoolean = require('../newBoolean'); var nullOperator = ' is '; -function endsWithCore(operator, column,arg,alias) { - alias = quote(alias); +function endsWithCore(context, operator, column,arg,alias) { + alias = quote(context, alias); operator = ' ' + operator + ' '; - var encoded = column.encode(arg); + var encoded = column.encode(context, arg); if (encoded.sql() == 'null') operator = nullOperator; else - encoded = column.encode('%' + arg + '%'); - var firstPart = alias + '.' + quote(column._dbName) + operator; + encoded = column.encode(context, '%' + arg + '%'); + var firstPart = alias + '.' + quote(context, column._dbName) + operator; var filter = encoded.prepend(firstPart); return newBoolean(filter); } diff --git a/src/table/column/string/endsWith.js b/src/table/column/string/endsWith.js index 45bc4600..740e77de 100644 --- a/src/table/column/string/endsWith.js +++ b/src/table/column/string/endsWith.js @@ -1,3 +1,3 @@ var endsWithCore = require('./endsWithCore'); -module.exports = endsWithCore.bind(null, 'LIKE'); +module.exports = (context, ...rest) => endsWithCore.apply(null, [context, 'LIKE', ...rest]); diff --git a/src/table/column/string/endsWithCore.js b/src/table/column/string/endsWithCore.js index a28a040a..a52757be 100644 --- a/src/table/column/string/endsWithCore.js +++ b/src/table/column/string/endsWithCore.js @@ -2,15 +2,15 @@ const quote = require('../../quote'); var newBoolean = require('../newBoolean'); var nullOperator = ' is '; -function endsWithCore(operator, column,arg,alias) { +function endsWithCore(context, operator, column,arg,alias) { alias = quote(alias); operator = ' ' + operator + ' '; - var encoded = column.encode(arg); + var encoded = column.encode(context, arg); if (encoded.sql() == 'null') operator = nullOperator; else - encoded = column.encode('%' + arg); - var firstPart = alias + '.' + quote(column._dbName) + operator; + encoded = column.encode(context, '%' + arg); + var firstPart = alias + '.' + quote(context, column._dbName) + operator; var filter = encoded.prepend(firstPart); return newBoolean(filter); } diff --git a/src/table/column/string/iContains.js b/src/table/column/string/iContains.js index 788843a7..812c7413 100644 --- a/src/table/column/string/iContains.js +++ b/src/table/column/string/iContains.js @@ -1,3 +1,4 @@ var containsCore = require('./containsCore'); -module.exports = containsCore.bind(null, 'ILIKE'); +module.exports = (context, ...rest) => containsCore.apply(null, [context, 'ILIKE', ...rest]); + diff --git a/src/table/column/string/iEndsWith.js b/src/table/column/string/iEndsWith.js index 995e796a..2088a38a 100644 --- a/src/table/column/string/iEndsWith.js +++ b/src/table/column/string/iEndsWith.js @@ -1,3 +1,3 @@ var endsWithCore = require('./endsWithCore'); -module.exports = endsWithCore.bind(null, 'ILIKE'); +module.exports = (context, ...rest) => endsWithCore.apply(null, [context, 'ILIKE', ...rest]); diff --git a/src/table/column/string/iEqual.js b/src/table/column/string/iEqual.js index 752af635..46470506 100644 --- a/src/table/column/string/iEqual.js +++ b/src/table/column/string/iEqual.js @@ -3,12 +3,12 @@ var nullOperator = ' is '; var encodeFilterArg = require('../encodeFilterArg'); const quote = require('../../quote'); -function iEqual(column,arg,alias) { +function iEqual(context, column,arg,alias) { var operator = ' ILIKE '; - var encoded = encodeFilterArg(column, arg); + var encoded = encodeFilterArg(context, column, arg); if (encoded.sql() == 'null') operator = nullOperator; - var firstPart = alias + '.' + quote(column._dbName) + operator; + var firstPart = alias + '.' + quote(context, column._dbName) + operator; var filter = encoded.prepend(firstPart); return newBoolean(filter); } diff --git a/src/table/column/string/iStartsWith.js b/src/table/column/string/iStartsWith.js index dbea4ee4..fb7d24d3 100644 --- a/src/table/column/string/iStartsWith.js +++ b/src/table/column/string/iStartsWith.js @@ -1,3 +1,3 @@ var startsWithCore = require('./startsWithCore'); -module.exports = startsWithCore.bind(null, 'ILIKE'); \ No newline at end of file +module.exports = (context, ...rest) => startsWithCore.apply(null, [context, 'ILIKE', ...rest]); \ No newline at end of file diff --git a/src/table/column/string/newEncode.js b/src/table/column/string/newEncode.js index eb6d48bf..3febe073 100644 --- a/src/table/column/string/newEncode.js +++ b/src/table/column/string/newEncode.js @@ -3,7 +3,7 @@ var purify = require('./purify'); function _new(column) { - var encode = function(value) { + var encode = function(_context, value) { value = purify(value); if (value == null) { if (column.dbNull === null) @@ -13,7 +13,7 @@ function _new(column) { return newPara('?', [value]); }; - encode.unsafe = function(value) { + encode.unsafe = function(_context, value) { value = purify(value); if (value == null) { if (column.dbNull === null) @@ -23,7 +23,7 @@ function _new(column) { return '\'' + value + '\''; }; - encode.direct = function(value) { + encode.direct = function(_context, value) { return value ; }; diff --git a/src/table/column/string/startsWith.js b/src/table/column/string/startsWith.js index 1a427b19..b8819c69 100644 --- a/src/table/column/string/startsWith.js +++ b/src/table/column/string/startsWith.js @@ -1,3 +1,3 @@ var startsWithCore = require('./startsWithCore'); -module.exports = startsWithCore.bind(null, 'LIKE'); \ No newline at end of file +module.exports = (context, ...rest) => startsWithCore.apply(null, [context, 'LIKE', ...rest]); \ No newline at end of file diff --git a/src/table/column/string/startsWithCore.js b/src/table/column/string/startsWithCore.js index 23994dc1..c057cb5d 100644 --- a/src/table/column/string/startsWithCore.js +++ b/src/table/column/string/startsWithCore.js @@ -2,14 +2,14 @@ var newBoolean = require('../newBoolean'); var nullOperator = ' is '; var quote = require('../../quote'); -function startsWithCore(operator, column,arg,alias) { +function startsWithCore(context, operator, column,arg,alias) { operator = ' ' + operator + ' '; - var encoded = column.encode(arg); + var encoded = column.encode(context, arg); if (encoded.sql() == 'null') operator = nullOperator; else - encoded = column.encode(arg + '%'); - var firstPart = quote(alias) + '.' + quote(column._dbName) + operator; + encoded = column.encode(context, arg + '%'); + var firstPart = quote(context, alias) + '.' + quote(context, column._dbName) + operator; var filter = encoded.prepend(firstPart); return newBoolean(filter); } diff --git a/src/table/column/utils.js b/src/table/column/utils.js new file mode 100644 index 00000000..b95707d1 --- /dev/null +++ b/src/table/column/utils.js @@ -0,0 +1,113 @@ +const newParameterized = require('../query/newParameterized'); +const negotiateNextAndFilter = require('./negotiateNextAndFilter'); +const negotiateNextOrFilter = require('./negotiateNextOrFilter'); + +function newBoolean(filter) { + var c = {}; + c.sql = filter.sql.bind(filter); + c.parameters = filter.parameters; + + c.append = function(other) { + var nextFilter = filter.append(other); + return newBoolean(nextFilter); + }; + + c.prepend = function(other) { + var nextFilter = filter.prepend(other); + return newBoolean(nextFilter); + }; + + c.and = function(context, other) { + other = negotiateRawSqlFilter(context, other); + var nextFilter = negotiateNextAndFilter(filter, other); + var next = newBoolean(nextFilter); + for (var i = 2; i < arguments.length; i++) { + next = next.and(context, arguments[i]); + } + return next; + }; + + c.or = function(context, other) { + other = negotiateRawSqlFilter(context, other); + var nextFilter = negotiateNextOrFilter(filter, other); + var next = newBoolean(nextFilter); + for (var i = 2; i < arguments.length; i++) { + next = next.or(context, arguments[i]); + } + return next; + }; + + c.not = function(_context) { + var nextFilter = filter.prepend('NOT (').append(')'); + return newBoolean(nextFilter); + }; + + return c; +} + + +function negotiateRawSqlFilter(context, filter, optionalTable, emptyArrayMeansFalse) { + if (Array.isArray(filter) && filter.length === 0) { + const sql = emptyArrayMeansFalse ? '1 = 2' : '1 = 1'; + return newBoolean(newParameterized(sql)); + } + else if (Array.isArray(filter)) { + let curFilter; + let curObjectFilter; + for (let i = 0; i < filter.length; i++) { + let nextFilter = negotiateRawSqlFilter(context,filter[i], optionalTable); + if (nextFilter.isObjectFilter) + curObjectFilter = curObjectFilter ? curObjectFilter.or(context, nextFilter) : nextFilter; + else + curFilter = curFilter ? curFilter.and(context, nextFilter) : nextFilter; + } + if (curFilter && curObjectFilter) + return curFilter.and(context, curObjectFilter); + else if (curFilter) + return curFilter; + else + return curObjectFilter; + } + else { + let params = []; + if (filter) { + if (filter.and) + return filter; + if (filter.sql) { + let sql = filter.sql; + if (typeof filter.sql === 'function') { + sql = filter.sql(); + } + params.push(sql, filter.parameters); + } + else if (isObjectFilter(filter, optionalTable)) + return newObjectFilter(context, filter, optionalTable); + else + params = [filter]; + } else { + params = [filter]; + } + + let parameterized = newParameterized.apply(null, params); + return newBoolean(parameterized); + } +} + +function isObjectFilter(object, optionalTable) { + return optionalTable && object; +} + +function newObjectFilter(context, object, table) { + let primaryColumns = table._primaryColumns; + let filter; + for (let i = 0; i < primaryColumns.length; i++) { + let column = primaryColumns[i]; + let colFilter = column.equal(context, object[column.alias]); + filter = filter ? filter.and(context, colFilter) : colFilter ; + } + filter.isObjectFilter = true; + return filter; +} + + +module.exports = { negotiateRawSqlFilter, newBoolean}; \ No newline at end of file diff --git a/src/table/commands/beginCommand.js b/src/table/commands/beginCommand.js index 620c7afc..82856d3a 100644 --- a/src/table/commands/beginCommand.js +++ b/src/table/commands/beginCommand.js @@ -1,8 +1,8 @@ let newParameterized = require('../query/newParameterized'); let getSessionContext = require('../getSessionContext'); -module.exports = function() { - let command = newParameterized(getSessionContext().begin || 'BEGIN'); +module.exports = function(context) { + let command = newParameterized(getSessionContext(context).begin || 'BEGIN'); command.endEdit = empty; command.matches = empty; diff --git a/src/table/commands/compressChanges.js b/src/table/commands/compressChanges.js index 576a1380..3c6d07ce 100644 --- a/src/table/commands/compressChanges.js +++ b/src/table/commands/compressChanges.js @@ -1,8 +1,8 @@ var newParameterized = require('../query/newParameterized'); var getSessionSingleton = require('../getSessionSingleton'); -function compress(queries) { - var multipleStatements = getSessionSingleton('multipleStatements'); +function compress(context, queries) { + var multipleStatements = getSessionSingleton(context, 'multipleStatements'); var compressed = []; var queryCount = queries.length; diff --git a/src/table/commands/delete/newSingleCommand.js b/src/table/commands/delete/newSingleCommand.js index f37191de..18b8b1ad 100644 --- a/src/table/commands/delete/newSingleCommand.js +++ b/src/table/commands/delete/newSingleCommand.js @@ -4,14 +4,14 @@ var extractFilter = require('../../query/extractFilter'); var newSingleCommandCore = require('./singleCommand/newSingleCommandCore'); var createAlias = require('./createAlias'); -function _new(table,filter,relations) { +function _new(context, table, filter, relations) { var alias = createAlias(table, relations.length); filter = extractFilter(filter); - filter = newSubFilter(relations, filter); - var discriminator = newDiscriminatorSql(table, alias); + filter = newSubFilter(context, relations, filter); + var discriminator = newDiscriminatorSql(context, table, alias); if (discriminator !== '') - filter = filter.and(discriminator); - return newSingleCommandCore(table, filter, alias); + filter = filter.and(context, discriminator); + return newSingleCommandCore(context, table, filter, alias); } module.exports = _new; \ No newline at end of file diff --git a/src/table/commands/delete/singleCommand/joinSql.js b/src/table/commands/delete/singleCommand/joinSql.js index 23fa1aa9..9c1b2af2 100644 --- a/src/table/commands/delete/singleCommand/joinSql.js +++ b/src/table/commands/delete/singleCommand/joinSql.js @@ -1,21 +1,21 @@ -var newShallowJoinSql = require('../../../query/singleQuery/joinSql/newShallowJoinSql'); -var createAlias = require('../createAlias'); +const newShallowJoinSql = require('../../../query/singleQuery/joinSql/newShallowJoinSql'); +const createAlias = require('../createAlias'); -function newJoinSql(relations) { - var length = relations.length; - var leftAlias, +function newJoinSql(context, relations) { + const length = relations.length; + let leftAlias, rightAlias; - var sql = ''; + let sql = ''; function addSql(relation) { - var rightColumns = relation.childTable._primaryColumns; - var leftColumns = relation.columns; - sql += ' INNER' + newShallowJoinSql(relation.childTable,leftColumns,rightColumns,leftAlias,rightAlias).sql(); + const rightColumns = relation.childTable._primaryColumns; + const leftColumns = relation.columns; + sql += ' INNER' + newShallowJoinSql(context, relation.childTable, leftColumns, rightColumns, leftAlias, rightAlias).sql(); } - relations.forEach(function(relation, i){ - leftAlias = 'x' + (length-i); - rightAlias = createAlias(relation.childTable, length-i-1); + relations.forEach(function(relation, i) { + leftAlias = 'x' + (length - i); + rightAlias = createAlias(relation.childTable, length - i - 1); addSql(relation); }); diff --git a/src/table/commands/delete/singleCommand/newSingleCommandCore.js b/src/table/commands/delete/singleCommand/newSingleCommandCore.js index 40e9c34a..3f070eab 100644 --- a/src/table/commands/delete/singleCommand/newSingleCommandCore.js +++ b/src/table/commands/delete/singleCommand/newSingleCommandCore.js @@ -1,13 +1,13 @@ var getSessionSingleton = require('../../../getSessionSingleton'); -function newSingleCommandCore(table,filter,alias) { +function newSingleCommandCore(context, table, filter, alias) { var c = {}; c.sql = function() { var whereSql = filter.sql(); if (whereSql) whereSql = ' where ' + whereSql; - var deleteFromSql = getSessionSingleton('deleteFromSql'); + var deleteFromSql = getSessionSingleton(context, 'deleteFromSql'); return deleteFromSql(table, alias, whereSql); }; diff --git a/src/table/commands/delete/singleCommand/selectSql.js b/src/table/commands/delete/singleCommand/selectSql.js index 6ca76248..d269d7fc 100644 --- a/src/table/commands/delete/singleCommand/selectSql.js +++ b/src/table/commands/delete/singleCommand/selectSql.js @@ -1,11 +1,11 @@ -var newParameterized = require('../../../query/newParameterized'); -var newBoolean = require('../../../column/newBoolean'); +const newParameterized = require('../../../query/newParameterized'); +const newBoolean = require('../../../column/newBoolean'); const quote = require('../../../quote'); -function newSelectSql(table, alias) { - var colName = quote(table._primaryColumns[0]._dbName); - alias = quote(alias); - var sql = 'SELECT ' + alias + '.' + colName + ' FROM ' + quote(table._dbName) + ' ' + alias; +function newSelectSql(context, table, alias) { + const colName = quote(context, table._primaryColumns[0]._dbName); + alias = quote(context, alias); + let sql = 'SELECT ' + alias + '.' + colName + ' FROM ' + quote(context, table._dbName) + ' ' + alias; sql = newParameterized(sql); return newBoolean(sql); } diff --git a/src/table/commands/delete/singleCommand/subFilter.js b/src/table/commands/delete/singleCommand/subFilter.js index c6ac95c4..95456a25 100644 --- a/src/table/commands/delete/singleCommand/subFilter.js +++ b/src/table/commands/delete/singleCommand/subFilter.js @@ -1,17 +1,17 @@ -var newSelect = require('./selectSql'); -var newJoin = require('./joinSql'); -var newWhere = require('./whereSql'); -var createAlias = require('../createAlias'); +const newSelect = require('./selectSql'); +const newJoin = require('./joinSql'); +const newWhere = require('./whereSql'); +const createAlias = require('../createAlias'); -function newSubFilter(relations, shallowFilter) { - var relationCount = relations.length; +function newSubFilter(context,relations, shallowFilter) { + const relationCount = relations.length; if (relationCount === 0) return shallowFilter; - var table = relations[0].childTable; - var alias = createAlias(table, relationCount -1); - var filter = newSelect(table,alias).prepend('EXISTS ('); - var join = newJoin(relations.slice(1)); - var where = newWhere(relations,shallowFilter,alias); + const table = relations[0].childTable; + const alias = createAlias(table, relationCount -1); + const filter = newSelect(context,table,alias).prepend('EXISTS ('); + const join = newJoin(context, relations.slice(1)); + const where = newWhere(context,relations,shallowFilter,alias); return filter.append(join).append(where).append(')'); } diff --git a/src/table/commands/delete/singleCommand/whereSql.js b/src/table/commands/delete/singleCommand/whereSql.js index c442f956..0935f03c 100644 --- a/src/table/commands/delete/singleCommand/whereSql.js +++ b/src/table/commands/delete/singleCommand/whereSql.js @@ -1,6 +1,6 @@ var newShallowJoinSql = require('../../../query/singleQuery/joinSql/newShallowJoinSqlCore'); -function newWhereSql(relations, shallowFilter, rightAlias) { +function newWhereSql(context, relations, shallowFilter, rightAlias) { var sql; var relationCount = relations.length; var relation = relations[0]; @@ -12,7 +12,7 @@ function newWhereSql(relations, shallowFilter, rightAlias) { function where() { var table = relation.childTable; - var joinCore = newShallowJoinSql(table, leftColumns, rightColumns, leftAlias, rightAlias); + var joinCore = newShallowJoinSql(context, table, leftColumns, rightColumns, leftAlias, rightAlias); if (shallowFilter.sql()) sql = shallowFilter.prepend(' AND ').prepend(joinCore).prepend(' WHERE '); else diff --git a/src/table/commands/getChangeSet.js b/src/table/commands/getChangeSet.js index 9e70d6f9..3fb04e20 100644 --- a/src/table/commands/getChangeSet.js +++ b/src/table/commands/getChangeSet.js @@ -1,6 +1,6 @@ var getSessionSingleton = require('../getSessionSingleton'); -function getChangeSet() { - return getSessionSingleton('changes'); +function getChangeSet(context) { + return getSessionSingleton(context, 'changes'); } module.exports = getChangeSet; \ No newline at end of file diff --git a/src/table/commands/insert/getSqlTemplate.js b/src/table/commands/insert/getSqlTemplate.js index a0b05deb..31759fe2 100644 --- a/src/table/commands/insert/getSqlTemplate.js +++ b/src/table/commands/insert/getSqlTemplate.js @@ -1,19 +1,19 @@ let getSessionContext = require('../../getSessionContext'); let quote = require('../../quote'); -function getSqlTemplate(_table, _row) { - let context = getSessionContext(); - if (context.insertSql) - return context.insertSql.apply(null, arguments); +function getSqlTemplate(context, _table, _row) { + let rdb = getSessionContext(context); + if (rdb.insertSql) + return rdb.insertSql.apply(null, arguments); else return getSqlTemplateDefault.apply(null, arguments); } -function getSqlTemplateDefault(table, row) { +function getSqlTemplateDefault(context, table, row) { let columnNames = []; let values = []; - let sql = 'INSERT INTO ' + quote(table._dbName) + ' '; + let sql = 'INSERT INTO ' + quote(context, table._dbName) + ' '; addDiscriminators(); addColumns(); if (columnNames.length === 0) @@ -26,7 +26,7 @@ function getSqlTemplateDefault(table, row) { let discriminators = table._columnDiscriminators; for (let i = 0; i < discriminators.length; i++) { let parts = discriminators[i].split('='); - columnNames.push(quote(parts[0])); + columnNames.push(quote(context, parts[0])); values.push(parts[1]); } } @@ -36,29 +36,29 @@ function getSqlTemplateDefault(table, row) { for (let i = 0; i < columns.length; i++) { let column = columns[i]; if (row['__' + column.alias] !== undefined) { - columnNames.push(quote(column._dbName)); + columnNames.push(quote(context, column._dbName)); values.push('%s'); } } } function lastInserted() { - let context = getSessionContext(); - if (!context.lastInsertedIsSeparate && context.lastInsertedSql) - return ' ' + context.lastInsertedSql(table); + let rdb = getSessionContext(context); + if (!rdb.lastInsertedIsSeparate && rdb.lastInsertedSql) + return ' ' + rdb.lastInsertedSql(table); return ''; } function outputInserted() { - let context = getSessionContext(); - if (!context.lastInsertedIsSeparate && context.outputInsertedSql) - return ' ' + context.outputInsertedSql(table) + ' '; + let rdb = getSessionContext(context); + if (!rdb.lastInsertedIsSeparate && rdb.outputInsertedSql) + return ' ' + rdb.outputInsertedSql(table) + ' '; return ''; } function defaultValues() { - let context = getSessionContext(); - let _default = context.insertDefault || 'DEFAULT VALUES'; + let rdb = getSessionContext(context); + let _default = rdb.insertDefault || 'DEFAULT VALUES'; return `${_default}${lastInserted()}`; } diff --git a/src/table/commands/lastCommandMatches.js b/src/table/commands/lastCommandMatches.js index 83a5daa3..f24ab3f0 100644 --- a/src/table/commands/lastCommandMatches.js +++ b/src/table/commands/lastCommandMatches.js @@ -1,7 +1,7 @@ var getChangeSet = require('./getChangeSet'); -function lastCommandMatches(row) { - var changeSet = getChangeSet(); +function lastCommandMatches(context, row) { + var changeSet = getChangeSet(context); var lastIndex = changeSet.length-1; if (lastIndex >= 0 && changeSet[lastIndex].matches) return changeSet[lastIndex].matches(row); diff --git a/src/table/commands/newDeleteCommand.js b/src/table/commands/newDeleteCommand.js index c3331990..40837f65 100644 --- a/src/table/commands/newDeleteCommand.js +++ b/src/table/commands/newDeleteCommand.js @@ -1,20 +1,15 @@ var newSingleCommand = require('./delete/newSingleCommand'); -var nextCommand = function() { - nextCommand = require('./newDeleteCommand'); - nextCommand.apply(null, arguments); -}; - -function newCommand(queries,table,filter,strategy,relations) { - var singleCommand = newSingleCommand(table,filter,relations); - for(var name in strategy) { +function newCommand(context, queries, table, filter, strategy, relations) { + var singleCommand = newSingleCommand(context, table, filter, relations); + for (var name in strategy) { if (!(strategy[name] === null || strategy[name])) continue; var childStrategy = strategy[name]; var childRelation = table._relations[name]; var joinRelation = childRelation.joinRelation; - var childRelations = [joinRelation].concat(relations); - nextCommand(queries,childRelation.childTable,filter,childStrategy,childRelations); + var childRelations = [joinRelation].concat(relations); + newCommand(context, queries, childRelation.childTable, filter, childStrategy, childRelations); } queries.push(singleCommand); return queries; diff --git a/src/table/commands/newGetLastInsertedCommand.js b/src/table/commands/newGetLastInsertedCommand.js index b88f952c..c02d4ff4 100644 --- a/src/table/commands/newGetLastInsertedCommand.js +++ b/src/table/commands/newGetLastInsertedCommand.js @@ -1,15 +1,15 @@ var newGetLastInsertedCommandCore = require('./newGetLastInsertedCommandCore'); var newImmutable = require('../../newImmutable'); -function newGetLastInsertedCommand(table, row, insertCommand) { - let cmd = new InsertCommand(table, row, insertCommand); +function newGetLastInsertedCommand(context, table, row, insertCommand) { + let cmd = new InsertCommand(context, table, row, insertCommand); insertCommand.endEdit = () => {}; return cmd; } -function InsertCommand(table, row, insertCommand) { +function InsertCommand(context, table, row, insertCommand) { this._insertCommand = insertCommand; - this.__getCoreCommand = newImmutable(newGetLastInsertedCommandCore); + this.__getCoreCommand = newImmutable(newGetLastInsertedCommandCore.bind(null, context)); this._table = table; this._row = row; } diff --git a/src/table/commands/newGetLastInsertedCommandCore.js b/src/table/commands/newGetLastInsertedCommandCore.js index b84a069a..27e5fc88 100644 --- a/src/table/commands/newGetLastInsertedCommandCore.js +++ b/src/table/commands/newGetLastInsertedCommandCore.js @@ -3,19 +3,19 @@ const getSessionContext = require('../getSessionContext'); const newDiscriminatorSql = require('../query/singleQuery/newDiscriminatorSql'); const quote = require('../quote'); -function newGetLastInsertedCommandCore(table, row) { +function newGetLastInsertedCommandCore(context, table, row) { let parameters = []; let keyValues = table._primaryColumns.map(column => row['__' + column.alias]); - let sql = `SELECT ${columnNames()} FROM ${quote(table._dbName)} WHERE ${whereSql()}`; + let sql = `SELECT ${columnNames()} FROM ${quote(context, table._dbName)} WHERE ${whereSql()}`; return newParameterized(sql, parameters); function columnNames() { - return table._columns.map(col => quote(col._dbName)).join(','); + return table._columns.map(col => quote(context, col._dbName)).join(','); } function whereSql() { let parameterized; - let filter = getSessionContext().lastInsertedSql(table, keyValues); + let filter = getSessionContext(context).lastInsertedSql(context, table, keyValues); if (Array.isArray(filter)) { for (let i = 0; i < filter.length; i++) { const sep = i === 0 ? '' : ' AND '; @@ -37,7 +37,7 @@ function newGetLastInsertedCommandCore(table, row) { } function discriminators() { - return newDiscriminatorSql(table, table._dbName); + return newDiscriminatorSql(context, table, table._dbName); } } diff --git a/src/table/commands/newInsertCommand.js b/src/table/commands/newInsertCommand.js index af8900cf..8e61af81 100644 --- a/src/table/commands/newInsertCommand.js +++ b/src/table/commands/newInsertCommand.js @@ -1,4 +1,3 @@ -// var newInsertCommandCore = require('./newInsertCommandCore'); var newImmutable = require('../../newImmutable'); var createPatch = require('../../client/createPatch'); var createDto = require('../resultToRows/toDto/createDto'); @@ -30,7 +29,7 @@ InsertCommand.prototype.matches = function(otherRow) { InsertCommand.prototype.endEdit = function() { this.sql(); var dto = createDto(this._table, this._row); - if (this._table._emitChanged.callbacks.length > 0) + if (this._disallowCompress || this._table._emitChanged.callbacks.length > 0) this._patch = createPatch([], [dto]); }; @@ -47,8 +46,11 @@ Object.defineProperty(InsertCommand.prototype, 'parameters', { Object.defineProperty(InsertCommand.prototype, 'disallowCompress', { get: function() { - return this._table._emitChanged.callbacks.length > 0; + return this._disallowCompress || this._table._emitChanged.callbacks.length > 0; + }, + set: function(value) { + this._disallowCompress = value; } }); diff --git a/src/table/commands/newInsertCommandCore.js b/src/table/commands/newInsertCommandCore.js index cc3fb5a3..e992a2bd 100644 --- a/src/table/commands/newInsertCommandCore.js +++ b/src/table/commands/newInsertCommandCore.js @@ -1,17 +1,17 @@ -var newParameterized = require('../query/newParameterized'); -var getSqlTemplate = require('./insert/getSqlTemplate'); -var util = require('util'); +const newParameterized = require('../query/newParameterized'); +const getSqlTemplate = require('./insert/getSqlTemplate'); +const formatString = require('../../format'); -function newInsertCommandCore(table, row, options = {}) { - var parameters = []; - var values = [getSqlTemplate(table, row, options)]; +function newInsertCommandCore(context, table, row, options = {}) { + let parameters = []; + let values = [getSqlTemplate(context, table, row, options)]; - var columns = table._columns; - for (var i = 0; i < columns.length; i++) { - var column = columns[i]; - var alias = column.alias; + let columns = table._columns; + for (let i = 0; i < columns.length; i++) { + let column = columns[i]; + let alias = column.alias; if (row['__' + column.alias] !== undefined) { - var encoded = column.encode(row[alias]); + let encoded = column.encode(context, row[alias]); if (encoded.parameters.length > 0) { values.push('?'); parameters.push(encoded.parameters[0]); @@ -20,7 +20,7 @@ function newInsertCommandCore(table, row, options = {}) { } } - var sql = util.format.apply(null, values); + let sql = formatString.apply(null, values); return newParameterized(sql, parameters); } diff --git a/src/table/commands/newRow.js b/src/table/commands/newRow.js index a5fe3d35..4bb5446a 100644 --- a/src/table/commands/newRow.js +++ b/src/table/commands/newRow.js @@ -1,7 +1,7 @@ var decodeDbRow = require('../resultToRows/decodeDbRow'); var flags = require('../../flags'); -function newRow({table, _options}) { +function newRow(context, {table, _options}) { var dto = {}; table._columns.forEach(addColumn); @@ -28,20 +28,20 @@ function newRow({table, _options}) { else dto[alias] = undefined; } - const arg = arguments[1]; + const arg = arguments[2]; if (isObject(arg)) for (let name in arg) { if (table[name] && table[name].equal) dto[name] = arg[name]; } else - for (var i = 1; i < arguments.length; i++) { + for (var i = 2; i < arguments.length; i++) { var pkValue = arguments[i]; var column = table._primaryColumns[i - 1]; dto[column.alias] = pkValue; } - return decodeDbRow(table, table, dto, true, true); + return decodeDbRow(context, table, table, dto, true, true); } function isObject(object) { diff --git a/src/table/commands/newUpdateCommand.js b/src/table/commands/newUpdateCommand.js index af271696..121d4460 100644 --- a/src/table/commands/newUpdateCommand.js +++ b/src/table/commands/newUpdateCommand.js @@ -4,14 +4,14 @@ let newColumnList = require('../../newObject'); var createPatch = require('../../client/createPatch'); let createDto = require('../resultToRows/toDto/createDto'); -function newUpdateCommand(table, column, row) { - return new UpdateCommand(table, column, row); +function newUpdateCommand(context, table, column, row) { + return new UpdateCommand(context, table, column, row); } -function UpdateCommand(table, column, row) { +function UpdateCommand(context, table, column, row) { this._table = table; this._row = row; - this.__getCoreCommand = newImmutable(newUpdateCommandCore); + this.__getCoreCommand = newImmutable(newUpdateCommandCore.bind(null, context)); this._columnList = newColumnList(); this._columnList[column.alias] = column; this.onFieldChanged = this.onFieldChanged.bind(this); diff --git a/src/table/commands/newUpdateCommandCore.js b/src/table/commands/newUpdateCommandCore.js index dd571c4a..9049e1fa 100644 --- a/src/table/commands/newUpdateCommandCore.js +++ b/src/table/commands/newUpdateCommandCore.js @@ -1,8 +1,8 @@ const getSessionSingleton = require('../getSessionSingleton'); var newParameterized = require('../query/newParameterized'); -function newUpdateCommandCore(table, columns, row) { - const quote = getSessionSingleton('quote'); +function newUpdateCommandCore(context, table, columns, row) { + const quote = getSessionSingleton(context, 'quote'); var command = newParameterized('UPDATE ' + quote(table._dbName) + ' SET'); var separator = ' '; @@ -13,7 +13,7 @@ function newUpdateCommandCore(table, columns, row) { function addColumns() { for (var alias in columns) { var column = columns[alias]; - var encoded = column.encode(row[alias]); + var encoded = column.encode(context, row[alias]); command = command.append(separator + quote(column._dbName) + '=').append(encoded); separator = ','; } @@ -25,7 +25,7 @@ function newUpdateCommandCore(table, columns, row) { for (var i = 0; i < columns.length; i++) { var column = columns[i]; var value = row[column.alias]; - var encoded = column.encode(value); + var encoded = column.encode(context, value); command = command.append(separator + quote(column._dbName) + '=').append(encoded); separator = ' AND '; } diff --git a/src/table/commands/pushCommand.js b/src/table/commands/pushCommand.js index b35e9471..516cc5a0 100644 --- a/src/table/commands/pushCommand.js +++ b/src/table/commands/pushCommand.js @@ -1,8 +1,8 @@ var getChangeSet = require('./getChangeSet'); var negotiateEndEdit = require('./negotiateEndEdit'); -function pushCommand(command) { - var changes = getChangeSet(); +function pushCommand(context, command) { + var changes = getChangeSet(context); negotiateEndEdit(changes); changes.push(command); } diff --git a/src/table/commit.js b/src/table/commit.js index ef84b69f..4bdbbc60 100644 --- a/src/table/commit.js +++ b/src/table/commit.js @@ -5,9 +5,9 @@ let releaseDbClient = require('./releaseDbClient'); let popChanges = require('./popChanges'); const getSessionSingleton = require('./getSessionSingleton'); -function commit(result) { +function _commit(context, result) { return popAndPushChanges() - .then(releaseDbClient) + .then(releaseDbClient.bind(null, context)) .then(onReleased); function onReleased() { @@ -15,18 +15,20 @@ function commit(result) { } async function popAndPushChanges() { - let changes = popChanges(); + let changes = popChanges(context); while (changes.length > 0) { - await executeChanges(changes); - changes = popChanges(); + await executeChanges(context, changes); + changes = popChanges(context); } - if (!getSessionSingleton('readonly')) - pushCommand(commitCommand); - return executeChanges(popChanges()); + if (!getSessionSingleton(context, 'transactionLess')) + pushCommand(context, commitCommand); + return executeChanges(context, popChanges(context)); } } -module.exports = function(result) { +function commit(context, result) { return Promise.resolve() - .then(() => commit(result)); -}; + .then(() => _commit(context, result)); +} + +module.exports = commit; diff --git a/src/table/count.js b/src/table/count.js index b5e61057..7b7bbafc 100644 --- a/src/table/count.js +++ b/src/table/count.js @@ -4,11 +4,11 @@ const extractFilter = require('./query/extractFilter'); const newWhereSql = require('./query/singleQuery/newWhereSql'); const quote = require('./quote'); -async function count(table, filter) { +async function count(context, table, filter) { let alias = table._dbName; - filter = negotiateRawSqlFilter(filter, table); - let query = newQuery(table, filter, alias); - let allResults = await executeQueries([query]); + filter = negotiateRawSqlFilter(context,filter, table); + let query = newQuery(context, table, filter, alias); + let allResults = await executeQueries(context, [query]); let count = await allResults[0].then((rows) => { const count = Number.parseInt(rows[0]._count); @@ -17,11 +17,11 @@ async function count(table, filter) { return count; } -function newQuery(table, filter, alias) { +function newQuery(context, table, filter, alias) { filter = extractFilter(filter); - var name = quote(table._dbName); - alias = quote(alias); - var whereSql = newWhereSql(table, filter, alias); + var name = quote(context, table._dbName); + alias = quote(context, alias); + var whereSql = newWhereSql(context, table, filter, alias); return whereSql.prepend('select count(*) "_count" from ' + name + ' ' + alias); diff --git a/src/table/createJSONReadStream.js b/src/table/createJSONReadStream.js deleted file mode 100644 index 8138ff55..00000000 --- a/src/table/createJSONReadStream.js +++ /dev/null @@ -1,7 +0,0 @@ -var createJSONReadStreamDefault = require('./createJSONReadStreamDefault'); - -function createJSONReadStream(table, db, filter, strategy, streamOptions) { - return createJSONReadStreamDefault(table, db, filter, strategy, streamOptions); -} - -module.exports = createJSONReadStream; diff --git a/src/table/createJSONReadStreamDefault.js b/src/table/createJSONReadStreamDefault.js deleted file mode 100644 index e5ae92fb..00000000 --- a/src/table/createJSONReadStreamDefault.js +++ /dev/null @@ -1,33 +0,0 @@ -var createReadStreamCore = require('./createReadStreamDefault'); -var Stream = require('stream'); - -function createJSONReadStream(table, db, filter, strategy, streamOptions) { - var transformer = Stream.Transform({ objectMode: true }); - var started; - transformer._transform = function(obj, enc, cb) { - var data = JSON.stringify(obj); - if (started) - transformer.push(',' + data); - else { - transformer.push('['); - transformer.push(data); - started = true; - } - cb(); - }; - - transformer._flush = function(cb) { - transformer.push(']'); - cb(); - }; - - var objectStream = createReadStreamCore(table, db, filter, strategy, streamOptions); - objectStream.on('error', onError); - return objectStream.pipe(transformer); - - function onError(e) { - transformer.emit('error', e); - } -} - -module.exports = createJSONReadStream; diff --git a/src/table/createJSONReadStreamNative.js b/src/table/createJSONReadStreamNative.js deleted file mode 100644 index 6ebf32fd..00000000 --- a/src/table/createJSONReadStreamNative.js +++ /dev/null @@ -1,31 +0,0 @@ -var createReadStreamCore = require('./createReadStreamCoreNative'); -var Stream = require('stream'); - -function createJSONReadStream(table, db, filter, strategy, streamOptions) { - var transformer = Stream.Transform({ - objectMode: true - }); - var started; - transformer._transform = function(chunk, enc, cb) { - if (started) - transformer.push(',' + chunk.result); - else { - transformer.push('['); - let result = chunk.result; - if (typeof result === 'object') - result = JSON.stringify(result); - transformer.push(result); - started = true; - } - cb(); - }; - - transformer._flush = function(cb) { - transformer.push(']'); - cb(); - }; - - return createReadStreamCore(table, db, filter, strategy, transformer, streamOptions); -} - -module.exports = createJSONReadStream; \ No newline at end of file diff --git a/src/table/createReadStream.js b/src/table/createReadStream.js deleted file mode 100644 index 9cb6dff1..00000000 --- a/src/table/createReadStream.js +++ /dev/null @@ -1,24 +0,0 @@ -var createReadStreamNative = require('./createReadStreamNative'); -var createReadStreamDefault = require('./createReadStreamDefault'); - -function createReadStream(table, db, filter, strategy, streamOptions) { - var create; - var c = {}; - - c.visitPg = function() { - create = createReadStreamNative; - }; - - c.visitMySql = c.visitPg; - - c.visitSqlite = function() { - create = createReadStreamDefault; - }; - c.visitSap = c.visitSqlite; - - db.accept(c); - - return create(table, db, filter, strategy, streamOptions); -} - -module.exports = createReadStream; \ No newline at end of file diff --git a/src/table/createReadStreamCoreNative.js b/src/table/createReadStreamCoreNative.js deleted file mode 100644 index adf548d0..00000000 --- a/src/table/createReadStreamCoreNative.js +++ /dev/null @@ -1,40 +0,0 @@ -var newQuery = require('./readStream/newQuery'); -var strategyToSpan = require('./strategyToSpan'); -var negotiateRawSqlFilter = require('./column/negotiateRawSqlFilter'); -var newQueryStream = require('./readStream/newQueryStream'); - -function createReadStreamCoreNative(table, db, filter, strategy, transformer, streamOptions) { - var alias = table._dbName; - filter = negotiateRawSqlFilter(filter, table); - var span = strategyToSpan(table, strategy); - - if (process.domain) - process.domain.add(transformer); - - db.transaction(async () => { - await start(); - }).then(null, onError); - - function start() { - return new Promise((resolve, reject) => { - var query = newQuery(db, table, filter, span, alias); - var queryStream = newQueryStream(query, streamOptions); - queryStream.on('end', resolve); - queryStream.on('error', onStreamError); - queryStream.pipe(transformer); - - function onStreamError(e) { - reject(e); - } - }); - - } - - function onError(e) { - transformer.emit('error', e); - } - - return transformer; -} - -module.exports = createReadStreamCoreNative; \ No newline at end of file diff --git a/src/table/createReadStreamDefault.js b/src/table/createReadStreamDefault.js deleted file mode 100644 index 2c256cda..00000000 --- a/src/table/createReadStreamDefault.js +++ /dev/null @@ -1,102 +0,0 @@ -var extractFilter = require('./query/extractFilter'); -var cloneStrategy = require('./cloneStrategy'); -var defaultBatchSize = 200; -var Readable = require('stream').Readable; -var createBatchFilter = require('./readStreamDefault/createBatchFilter'); - -function createReadStream(table, db, filter, strategy, streamOptions) { - filter = extractFilter(filter); - var batchFilter; - strategy = cloneStrategy(strategy); - calculateOrderBy(); - streamOptions = streamOptions || {}; - var batchSize = streamOptions.batchSize || defaultBatchSize; - batchSize = (batchSize + 1) / 2 >> 0; - var maxRows = strategy.limit; - var currentRowCount = 0; - var busy; - var waitingforMore; - var dtos = []; - var lastDto; - var done; - - var stream = Readable({ objectMode: true }); - stream._read = function() { - waitingforMore = true; - if (!busy) { - if (dtos.length > 0) - negotiatePushStream(); - else - getDtos(); - } - }; - if (process.domain) - process.domain.add(stream); - - function getDtos() { - busy = true; - return db.transaction(async () => { - await getBatch() - .then(onDtos); - }) - .then(negotiatePushStream, onError); - } - - function onDtos(result) { - busy = false; - currentRowCount += result.length; - lastDto = result[result.length - 1]; - dtos = dtos.concat(result); - if (currentRowCount >= maxRows || result.length < batchSize) { - dtos.push(null); - done = true; - } - } - - function negotiatePushStream() { - if (dtos.length <= batchSize && !done) - getDtos(); - if (!waitingforMore) - return; - waitingforMore = false; - stream.push(dtos.shift()); - } - - function getBatch() { - calculateLimit(); - calculateBatchFilter(); - return table.getMany(batchFilter, strategy); - } - - function calculateLimit() { - if (maxRows === undefined || maxRows === null) - strategy.limit = batchSize; - else { - var rowsLeft = maxRows - currentRowCount; - strategy.limit = Math.min(rowsLeft, batchSize); - } - } - - function calculateOrderBy() { - strategy.orderBy = strategy.orderBy || []; - if (typeof strategy.orderBy === 'string') { - strategy.orderBy = [strategy.orderBy]; - } - var primaryColumns = table._primaryColumns; - for (var i = 0; i < primaryColumns.length; i++) { - strategy.orderBy.push(primaryColumns[i].alias); - } - } - - function calculateBatchFilter() { - batchFilter = createBatchFilter(table, filter, strategy, lastDto); - } - - function onError(e) { - stream.emit('error', e); - } - - return stream; -} - -module.exports = createReadStream; diff --git a/src/table/createReadStreamNative.js b/src/table/createReadStreamNative.js deleted file mode 100644 index b880e9ac..00000000 --- a/src/table/createReadStreamNative.js +++ /dev/null @@ -1,17 +0,0 @@ -var createReadStreamCore = require('./createReadStreamCoreNative'); -var Stream = require('stream'); - -function createReadStreamNative(table, db, filter, strategy, streamOptions) { - var transformer = Stream.Transform({ objectMode: true }); - transformer._transform = function(chunk, _enc, cb) { - let result = chunk.result; - if (typeof result === 'string') - result = JSON.parse(result); - transformer.push(result); - cb(); - }; - - return createReadStreamCore(table, db, filter, strategy, transformer, streamOptions); -} - -module.exports = createReadStreamNative; \ No newline at end of file diff --git a/src/table/delete.js b/src/table/delete.js index d2211e8f..46806331 100644 --- a/src/table/delete.js +++ b/src/table/delete.js @@ -4,15 +4,15 @@ var extractDeleteStrategy = require('./extractDeleteStrategy'); var negotiateRawSqlFilter = require('./column/negotiateRawSqlFilter'); var emptyPromise = require('./resultToPromise')(); -function _delete(table, filter, strategy) { - filter = negotiateRawSqlFilter(filter, table); +function _delete(context, table, filter, strategy) { + filter = negotiateRawSqlFilter(context, filter, table); strategy = extractDeleteStrategy(strategy); var relations = []; var cmds = []; - cmds = newDeleteCommand(cmds, table, filter, strategy, relations); + cmds = newDeleteCommand(context, cmds, table, filter, strategy, relations); cmds.forEach(function(cmd) { - pushCommand(cmd); + pushCommand(context, cmd); }); return emptyPromise; } diff --git a/src/table/deleteSessionContext.js b/src/table/deleteSessionContext.js index b00bd392..24dca134 100644 --- a/src/table/deleteSessionContext.js +++ b/src/table/deleteSessionContext.js @@ -1,17 +1,5 @@ -let useHook = require('../useHook'); -let cls; - -function deleteSessionContext() { - if (useHook()) { - if (!cls) - cls = require('node-cls'); - let context = cls.get('rdb'); - delete context.rdb; - if (context.exit) - cls.exit('rdb'); - } - else - delete process.domain.rdb; +function deleteSessionContext(context) { + delete context.rdb; } module.exports = deleteSessionContext; \ No newline at end of file diff --git a/src/table/executeQueries.js b/src/table/executeQueries.js index 79feadfe..376abc43 100644 --- a/src/table/executeQueries.js +++ b/src/table/executeQueries.js @@ -2,13 +2,13 @@ var executeChanges = require('./executeQueries/executeChanges'); var popChanges = require('./popChanges'); var executeQueriesCore = require('./executeQueries/executeQueriesCore'); -function executeQueries(queries) { - var changes = popChanges(); +function executeQueries(context, queries) { + var changes = popChanges(context); - return executeChanges(changes).then(onDoneChanges); + return executeChanges(context, changes).then(onDoneChanges); function onDoneChanges() { - return executeQueriesCore(queries); + return executeQueriesCore(context, queries); } } diff --git a/src/table/executeQueries/executeChanges.js b/src/table/executeQueries/executeChanges.js index 520081b9..39b20713 100644 --- a/src/table/executeQueries/executeChanges.js +++ b/src/table/executeQueries/executeChanges.js @@ -1,7 +1,7 @@ var executeQuery = require('./executeQuery'); var newPromise = require('../promise'); -function executeChanges(queries) { +function executeChanges(context, queries) { if (queries.length === 0) return newPromise(); var i = -1; @@ -11,9 +11,9 @@ function executeChanges(queries) { function execute() { i++; if (i + 1 === queries.length) - return executeQuery(queries[i]).then(notifyListener); + return executeQuery(context, queries[i]).then(notifyListener); else { - return executeQuery(queries[i]).then(notifyListener).then(execute); + return executeQuery(context, queries[i]).then(notifyListener).then(execute); } } diff --git a/src/table/executeQueries/executeQueriesCore.js b/src/table/executeQueries/executeQueriesCore.js index b573f5fe..94888588 100644 --- a/src/table/executeQueries/executeQueriesCore.js +++ b/src/table/executeQueries/executeQueriesCore.js @@ -1,9 +1,9 @@ var executeQuery = require('./executeQuery'); -function executeQueriesCore(queries) { +function executeQueriesCore(context, queries) { var promises = []; for (var i = 0; i < queries.length; i++) { - var q = executeQuery(queries[i]); + var q = executeQuery(context, queries[i]); promises.push(q); } return promises; diff --git a/src/table/executeQueries/executeQuery.js b/src/table/executeQueries/executeQuery.js index 109155bb..23ea4960 100644 --- a/src/table/executeQueries/executeQuery.js +++ b/src/table/executeQueries/executeQuery.js @@ -1,7 +1,7 @@ var newResolver = require('./resolveExecuteQuery'); -function executeQuery(query) { - var resolver = newResolver(query); +function executeQuery(context, query) { + var resolver = newResolver(context, query); return new Promise(resolver); } diff --git a/src/table/executeQueries/resolveExecuteQuery.js b/src/table/executeQueries/resolveExecuteQuery.js index 53984cb2..47892bea 100644 --- a/src/table/executeQueries/resolveExecuteQuery.js +++ b/src/table/executeQueries/resolveExecuteQuery.js @@ -1,18 +1,11 @@ -var getSessionSingleton = require('../getSessionSingleton'); +const getSessionSingleton = require('../getSessionSingleton'); -function resolveExecuteQuery(query) { +function resolveExecuteQuery(context, query) { return resolve; function resolve(success, failed) { try { - - var domain = process.domain; - if (domain) { - success = process.domain.bind(success); - failed = process.domain.bind(failed); - } - - var client = getSessionSingleton('dbClient'); + var client = getSessionSingleton(context, 'dbClient'); query = negotiateNullParams(query); client.executeQuery(query, onCompleted); } catch (e) { diff --git a/src/table/getFromDbById.js b/src/table/getFromDbById.js index 8c9852ba..c0299ee3 100644 --- a/src/table/getFromDbById.js +++ b/src/table/getFromDbById.js @@ -1,6 +1,6 @@ let tryGetFromDbById = require('./tryGetFromDbById'); -function get(table, ...ids) { +function get(_context, table, ...ids) { return tryGetFromDbById.apply(null, arguments).then((row) => onResult(table, row, ids)); } diff --git a/src/table/getMany.js b/src/table/getMany.js index c52acd9f..444b00f3 100644 --- a/src/table/getMany.js +++ b/src/table/getMany.js @@ -5,18 +5,18 @@ let strategyToSpan = require('./strategyToSpan'); let emptyInnerJoin = require('./query/newParameterized')(); let negotiateRawSqlFilter = require('./column/negotiateRawSqlFilter'); -function getMany(table,filter,strategy) { - return getManyCore(table,filter,strategy); +function getMany(context,table,filter,strategy) { + return getManyCore(context, table,filter,strategy); } -async function getManyCore(table,filter,strategy,exclusive) { +async function getManyCore(context,table,filter,strategy,exclusive) { let alias = table._dbName; let noOrderBy; - filter = negotiateRawSqlFilter(filter, table); + filter = negotiateRawSqlFilter(context, filter, table); let span = strategyToSpan(table,strategy); - let queries = newQuery([],table,filter,span,alias,emptyInnerJoin,noOrderBy,exclusive); - let result = await executeQueries(queries); - return resultToRows(span,result); + let queries = newQuery(context, [],table,filter,span,alias,emptyInnerJoin,noOrderBy,exclusive); + let result = await executeQueries(context, queries); + return resultToRows(context, span,result); } getMany.exclusive = function(table,filter,strategy) { diff --git a/src/table/getManyDto.js b/src/table/getManyDto.js index ee5ee55e..f008a1ed 100644 --- a/src/table/getManyDto.js +++ b/src/table/getManyDto.js @@ -1,9 +1,8 @@ -const tryGetSessionContext = require('../table/tryGetSessionContext'); +const getSessionSingleton = require('../table/getSessionSingleton'); const getManyDtoCore = require('../getManyDto'); - -function getManyDto(_table, _filter, _strategy) { - const _getManyDto = tryGetSessionContext().getManyDto || getManyDtoCore; +function getManyDto(context, _table, _filter, _strategy) { + const _getManyDto = getSessionSingleton(context, 'getManyDto') || getManyDtoCore; return _getManyDto.apply(null, arguments); } diff --git a/src/table/getManyDto/pg/newQuery.js b/src/table/getManyDto/pg/newQuery.js deleted file mode 100644 index 94b1a7ee..00000000 --- a/src/table/getManyDto/pg/newQuery.js +++ /dev/null @@ -1,8 +0,0 @@ -var newQueryCore = require('../../readStream/pg/newQueryCore'); - -function newQuery() { - var query = newQueryCore.apply(null, arguments); - return query.prepend('select json_strip_nulls(coalesce(json_agg(row_to_json(r)), \'[]\')) as result from (').append(') r'); -} - -module.exports = newQuery; \ No newline at end of file diff --git a/src/table/getSessionContext.js b/src/table/getSessionContext.js index 7f80ead4..272bb70a 100644 --- a/src/table/getSessionContext.js +++ b/src/table/getSessionContext.js @@ -1,10 +1,10 @@ let tryGetSessionContext = require('./tryGetSessionContext'); -function getSessionContext() { - let context = tryGetSessionContext(); - if (!context) +function getSessionContext(context) { + const rdb = tryGetSessionContext(context); + if (!rdb) throw new Error('Rdb transaction is no longer available. Is promise chain broken ?'); - return context; + return rdb; } module.exports = getSessionContext; \ No newline at end of file diff --git a/src/table/getSessionSingleton.js b/src/table/getSessionSingleton.js index d199c935..f350202b 100644 --- a/src/table/getSessionSingleton.js +++ b/src/table/getSessionSingleton.js @@ -1,5 +1,6 @@ var getSessionContext = require('./getSessionContext'); -module.exports = function(name) { - return getSessionContext()[name]; +module.exports = function(context, name) { + const rdb = getSessionContext(context); + return rdb[name]; }; \ No newline at end of file diff --git a/src/table/groupBy.js b/src/table/groupBy.js index c2fbd40b..c9cc252a 100644 --- a/src/table/groupBy.js +++ b/src/table/groupBy.js @@ -3,11 +3,11 @@ const negotiateRawSqlFilter = require('./column/negotiateRawSqlFilter'); const strategyToSpan = require('./strategyToSpan'); const executeQueries = require('./executeQueries'); -async function groupBy(table, filter, strategy) { - filter = negotiateRawSqlFilter(filter, table); +async function groupBy(context, table, filter, strategy) { + filter = negotiateRawSqlFilter(context, filter, table); if (strategy && strategy.where) { let arg = typeof strategy.where === 'function' ? strategy.where(table) : strategy.where; - filter = filter.and(arg); + filter = filter.and(context, arg); } let span = strategyToSpan(table, strategy); @@ -15,9 +15,9 @@ async function groupBy(table, filter, strategy) { let alias = table._dbName; - const query = newQuery(table, filter, span, alias); - const res = await executeQueries([query]); - return decode(span, await res[0]); + const query = newQuery(context, table, filter, span, alias); + const res = await executeQueries(context, [query]); + return decode(context, span, await res[0]); } function newCreateRow(span) { @@ -40,7 +40,7 @@ function createProto(span) { } -async function decode(span, rows, keys = rows.length > 0 ? Object.keys(rows[0]) : []) { +async function decode(context, span, rows, keys = rows.length > 0 ? Object.keys(rows[0]) : []) { const rowsLength = rows.length; const aggregateKeys = Object.keys(span.aggregates); @@ -52,8 +52,8 @@ async function decode(span, rows, keys = rows.length > 0 ? Object.keys(rows[0]) for (let j = 0; j < aggregateKeys.length; j++) { const key = aggregateKeys[j]; - const parse = span.aggregates[key].column?.decode || Number.parseFloat; - outRow[key] = parse(row[keys[j]]); + const parse = span.aggregates[key].column?.decode || ((_context, arg) => Number.parseFloat(arg)); + outRow[key] = parse(context, row[keys[j]]); } outRows[i] = outRow; diff --git a/src/table/groupBy/newQuery.js b/src/table/groupBy/newQuery.js index a79ec11a..2caabb2c 100644 --- a/src/table/groupBy/newQuery.js +++ b/src/table/groupBy/newQuery.js @@ -4,13 +4,13 @@ var extractLimit = require('../query/extractLimit'); var newParameterized = require('../query/newParameterized'); var extractOffset = require('../query/extractOffset'); -function newQuery(table,filter,span,alias) { +function newQuery(context, table,filter,span,alias) { filter = extractFilter(filter); var orderBy = ''; - var limit = extractLimit(span); - var offset = extractOffset(span); + var limit = extractLimit(context, span); + var offset = extractOffset(context, span); - var query = newSingleQuery(table,filter,span,alias,orderBy,limit,offset); + var query = newSingleQuery(context, table,filter,span,alias,orderBy,limit,offset); const groupClause = groupBy(span); return newParameterized(query.sql(), query.parameters).append(groupClause); } diff --git a/src/table/insert.js b/src/table/insert.js index 13a380e9..9b509320 100644 --- a/src/table/insert.js +++ b/src/table/insert.js @@ -1,21 +1,18 @@ let getSessionContext = require('./getSessionContext'); let newRow = require('./commands/newRow'); -let insertDefault = require('./insertDefault'); -function insert({ table, options }, arg) { - // return insertDefault.apply(null, arguments); +function insert(context, { table, options }, arg) { if (Array.isArray(arg)) { let all = []; for (let i = 0; i < arg.length; i++) { - all.push(insert(table, arg[i])); + all.push(insert(context, table, arg[i])); } return Promise.all(all); } - let args = [table].slice.call(arguments); - let row = newRow.apply(null, args); + let row = newRow.apply(null, [...arguments]); let hasPrimary = getHasPrimary(table, row); if (hasPrimary) { - row = table._cache.tryAdd(row); + row = table._cache.tryAdd(context, row); } expand(table, row); Object.defineProperty(row, 'then', { @@ -24,8 +21,8 @@ function insert({ table, options }, arg) { enumerable: false, configurable: true }); - const context = getSessionContext(); - const insertP = (context.insert || insertDefault)(table, row, options).then(onResult); + const rdb = getSessionContext(context); + const insertP = rdb.insert(context, table, row, options).then(onResult); // } @@ -51,10 +48,10 @@ function insert({ table, options }, arg) { return row; function onResult([result]) { - row.hydrate(result); - if (!hasPrimary) - row = table._cache.tryAdd(row); - table._cache.tryAdd(row); + row.hydrate(context, result); + // if (!hasPrimary) + // row = table._cache.tryAdd(context, row); + row = table._cache.tryAdd(context, row); return row; } } diff --git a/src/table/joinRelation/getRelatives.js b/src/table/joinRelation/getRelatives.js index c7c67070..54ea2aff 100644 --- a/src/table/joinRelation/getRelatives.js +++ b/src/table/joinRelation/getRelatives.js @@ -2,7 +2,7 @@ var newPrimaryKeyFilter = require('../newPrimaryKeyFilter'); var emptyFilter = require('../../emptyFilter'); var negotiateExpandInverse = require('../negotiateExpandInverse'); -function getRelatives(parent, relation) { +function getRelatives(context, parent, relation) { var queryContext = parent.queryContext; let strategy = queryContext && queryContext.strategy[relation.leftAlias]; var filter = emptyFilter; @@ -24,15 +24,15 @@ function getRelatives(parent, relation) { } if (ids.length > 0) - filter = relation.childTable._primaryColumns[0].in(ids); + filter = relation.childTable._primaryColumns[0].in(context, ids); } function createCompositeFilter() { var keyFilter; for (var i = 0; i < queryContext.rows.length; i++) { - keyFilter = rowToPrimaryKeyFilter(queryContext.rows[i], relation); + keyFilter = rowToPrimaryKeyFilter(context, queryContext.rows[i], relation); if (keyFilter) - filter = filter.or(keyFilter); + filter = filter.or(context, keyFilter); } } @@ -46,14 +46,14 @@ function getRelatives(parent, relation) { } -function rowToPrimaryKeyFilter(row, relation) { +function rowToPrimaryKeyFilter(context, row, relation) { var key = relation.columns.map( function(column) { return row[column.alias]; }); if (key.some(isNullOrUndefined)) { return; } - var args = [relation.childTable].concat(key); + var args = [context, relation.childTable].concat(key); return newPrimaryKeyFilter.apply(null, args); } diff --git a/src/table/newCascadeDeleteStrategy.js b/src/table/newCascadeDeleteStrategy.js index d444c986..2e16eec9 100644 --- a/src/table/newCascadeDeleteStrategy.js +++ b/src/table/newCascadeDeleteStrategy.js @@ -1,4 +1,3 @@ -var addSubStrategies = _addSubStrategies; var newObject = require('../newObject'); function newCascadeDeleteStrategy(strategy, table) { @@ -10,7 +9,7 @@ function newCascadeDeleteStrategy(strategy, table) { c.visitOne = function(relation) { var subStrategy = newObject(); strategy[relationName] = subStrategy; - addSubStrategies(subStrategy, relation.childTable); + newCascadeDeleteStrategy(subStrategy, relation.childTable); }; c.visitMany = c.visitOne; @@ -22,9 +21,4 @@ function newCascadeDeleteStrategy(strategy, table) { return strategy; } -function _addSubStrategies(strategy, table) { - addSubStrategies = require('./newCascadeDeleteStrategy'); - addSubStrategies(strategy, table); -} - module.exports = newCascadeDeleteStrategy; \ No newline at end of file diff --git a/src/table/newGetRelated.js b/src/table/newGetRelated.js index 1768a19e..99ec8f24 100644 --- a/src/table/newGetRelated.js +++ b/src/table/newGetRelated.js @@ -1,10 +1,10 @@ -function newGetRelated(parent, relation) { +function newGetRelated(context, parent, relation) { function getRelated() { if (getRelated.expanded) return relation.getFromCache(parent); if (parent.queryContext) - return relation.getRelatives(parent).then(onRelatives); - return relation.getFromDb(parent).then(onFromDb); + return relation.getRelatives(context, parent).then(onRelatives); + return relation.getFromDb(context, parent).then(onFromDb); function onFromDb(rows) { getRelated.expanded = true; diff --git a/src/table/newManyRelation.js b/src/table/newManyRelation.js index 0bbb1f40..c7298044 100644 --- a/src/table/newManyRelation.js +++ b/src/table/newManyRelation.js @@ -23,17 +23,17 @@ function newManyRelation(joinRelation) { return fuzzyPromise(result); }; - c.getFromDb = function(parent) { - var filter = newForeignKeyFilter(joinRelation, parent); - return c.childTable.getMany(filter, null); + c.getFromDb = function(context, parent) { + var filter = newForeignKeyFilter(context, joinRelation, parent); + return c.childTable.getMany(context, filter, null); }; - c.getRelatives = function(parent) { - return getRelatives(parent, c); + c.getRelatives = function(context, parent) { + return getRelatives(context, parent, c); }; - c.toGetRelated = function(parent) { - return newGetRelated(parent, c); + c.toGetRelated = function(context, parent) { + return newGetRelated(context, parent, c); }; c.expand = function(parent) { @@ -51,8 +51,8 @@ function newManyRelation(joinRelation) { return newLeg(c); }; - c.getInnerCache = function() { - return manyCache.getInnerCache(); + c.getInnerCache = function(context) { + return manyCache.getInnerCache(context); }; return c; diff --git a/src/table/newOneRelation.js b/src/table/newOneRelation.js index c98733f6..2b2cc3a6 100644 --- a/src/table/newOneRelation.js +++ b/src/table/newOneRelation.js @@ -23,17 +23,17 @@ function newOneRelation(joinRelation) { return fuzzyPromise(row); }; - c.getFromDb = function(parent) { - var filter = newForeignKeyFilter(joinRelation, parent); - return c.childTable.tryGetFirst(filter, null); + c.getFromDb = function(context, parent) { + var filter = newForeignKeyFilter(context, joinRelation, parent); + return c.childTable.tryGetFirst(context, filter, null); }; - c.getRelatives = function(parent) { - return getRelatives(parent, c); + c.getRelatives = function(context, parent) { + return getRelatives(context, parent, c); }; - c.toGetRelated = function(parent) { - return newGetRelated(parent, c); + c.toGetRelated = function(context, parent) { + return newGetRelated(context, parent, c); }; c.expand = function(parent) { @@ -51,8 +51,8 @@ function newOneRelation(joinRelation) { return newLeg(c); }; - c.getInnerCache = function() { - return oneCache.getInnerCache(); + c.getInnerCache = function(context) { + return oneCache.getInnerCache(context); }; return c; diff --git a/src/table/newPrimaryKeyFilter.js b/src/table/newPrimaryKeyFilter.js index e179bddd..85637ed3 100644 --- a/src/table/newPrimaryKeyFilter.js +++ b/src/table/newPrimaryKeyFilter.js @@ -1,11 +1,11 @@ -function primaryKeyFilter(table) { +function primaryKeyFilter(context, table) { var primaryColumns = table._primaryColumns; - var key = arguments[1]; - var filter = primaryColumns[0].equal(key); - for (var i = 1; i < primaryColumns.length; i++) { + var key = arguments[2]; + var filter = primaryColumns[0].equal(context, key); + for (var i = 2; i < primaryColumns.length; i++) { key = arguments[i+1]; - var colFilter = primaryColumns[i].equal(key); - filter = filter.and(colFilter); + var colFilter = primaryColumns[i].equal(context, key); + filter = filter.and(context, colFilter); } return filter; } diff --git a/src/table/newQuery.js b/src/table/newQuery.js index b060d548..81b2f0d1 100644 --- a/src/table/newQuery.js +++ b/src/table/newQuery.js @@ -4,12 +4,12 @@ var extractOrderBy = require('./query/extractOrderBy'); var extractLimit = require('./query/extractLimit'); var extractOffset = require('./query/extractOffset'); -function newQuery(queries,table,filter,span,alias,innerJoin,orderBy,exclusive) { +function newQuery(context, queries,table,filter,span,alias,innerJoin,orderBy,exclusive) { filter = extractFilter(filter); - orderBy = extractOrderBy(table,alias,span.orderBy,orderBy); - var limit = extractLimit(span); - var offset = extractOffset(span); - var singleQuery = newSingleQuery(table,filter,span,alias,innerJoin,orderBy,limit,offset,exclusive); + orderBy = extractOrderBy(context, table,alias,span.orderBy,orderBy); + var limit = extractLimit(context, span); + var offset = extractOffset(context, span); + var singleQuery = newSingleQuery(context, table,filter,span,alias,innerJoin,orderBy,limit,offset,exclusive); queries.push(singleQuery); return queries; diff --git a/src/table/newRelatedTable.js b/src/table/newRelatedTable.js index 982b4bbb..7251a3f9 100644 --- a/src/table/newRelatedTable.js +++ b/src/table/newRelatedTable.js @@ -1,5 +1,4 @@ var newRelatedColumn = require('./relatedTable/relatedColumn'); -var nextRelatedTable = _nextRelatedTable; var subFilter = require('./relatedTable/subFilter'); var any = require('./relatedTable/any'); var all = require('./relatedTable/all'); @@ -15,14 +14,14 @@ function newRelatedTable(relations, isShallow, depth = 0) { // if (isShallow) // c = any(relations.slice(-1), depth); // else - c = any(relations, depth); + c = any(newRelatedTable, relations, depth); // @ts-ignore - c.all = all(relations, depth); + c.all = all(newRelatedTable, relations, depth); // @ts-ignore c.any = c; // @ts-ignore - c.none = none(relations, depth); + c.none = none(newRelatedTable, relations, depth); // @ts-ignore c.where = where(relations, depth); @@ -58,17 +57,17 @@ function newRelatedTable(relations, isShallow, depth = 0) { Object.defineProperty(c, alias, { get: function() { - return nextRelatedTable(children, false, depth); + return newRelatedTable(children, false, depth); } }); } // @ts-ignore - c.exists = function() { + c.exists = function(context) { if (isShallow) return ''; - return subFilter(relations, false, depth); + return subFilter(context, relations, false, depth); }; let cProxy = new Proxy(c, { @@ -91,9 +90,4 @@ function newRelatedTable(relations, isShallow, depth = 0) { return cProxy; } -function _nextRelatedTable(relations, isShallow, depth) { - nextRelatedTable = require('./newRelatedTable'); - return nextRelatedTable(relations, isShallow, depth); -} - module.exports = newRelatedTable; \ No newline at end of file diff --git a/src/table/newRowCache.js b/src/table/newRowCache.js index 3775c9b5..1861097e 100644 --- a/src/table/newRowCache.js +++ b/src/table/newRowCache.js @@ -6,43 +6,43 @@ function newRowCache(table) { let id = Symbol(); let c = {}; - c.tryGet = function(row) { - return getCache(table, id).tryGet(row); + c.tryGet = function(context, row) { + return getCache(context, table, id).tryGet(row); }; - c.tryAdd = function(row) { - return getCache(table, id).tryAdd(row); + c.tryAdd = function(context, row) { + return getCache(context, table, id).tryAdd(row); }; - c.tryRemove = function(row) { - return getCache(table, id).tryRemove(row); + c.tryRemove = function(context, row) { + return getCache(context, table, id).tryRemove(row); }; - c.subscribeAdded = function() { - return getCache(table, id).subscribeAdded.apply(null, arguments); + c.subscribeAdded = function(context, ...rest) { + return getCache(context, table, id).subscribeAdded.apply(null, rest); }; - c.subscribeRemoved = function() { - return getCache(table, id).subscribeRemoved.apply(null, arguments); + c.subscribeRemoved = function(context, ...rest) { + return getCache(context, table, id).subscribeRemoved.apply(null, rest); }; - c.getAll = function() { - return getCache(table, id).getAll.apply(null, arguments); + c.getAll = function(context) { + return getCache(context, table, id).getAll.apply(null, arguments); }; - c.getInnerCache = function() { - return getCache(table, id); + c.getInnerCache = function(context) { + return getCache(context, table, id); }; return c; } -function getCache(table, id) { - let cache = getSessionSingleton(id); +function getCache(context, table, id) { + let cache = getSessionSingleton(context, id); if (cache) return cache; cache = _newRowCache(table); - setSessionSingleton(id, cache); + setSessionSingleton(context, id, cache); return cache; } diff --git a/src/table/newThrow.js b/src/table/newThrow.js index 4634088c..7655d295 100644 --- a/src/table/newThrow.js +++ b/src/table/newThrow.js @@ -1,9 +1,9 @@ var tryReleaseDbClient = require('./tryReleaseDbClient'); -function newThrow(e, previousPromise) { +function newThrow(context, e, previousPromise) { return previousPromise.then(throwError, throwError); function throwError() { - tryReleaseDbClient(); + tryReleaseDbClient(context); throw e; } } diff --git a/src/table/oneRelation/getRelatives.js b/src/table/oneRelation/getRelatives.js index f4186a42..8edd96a1 100644 --- a/src/table/oneRelation/getRelatives.js +++ b/src/table/oneRelation/getRelatives.js @@ -2,7 +2,7 @@ let emptyFilter = require('../../emptyFilter'); let newForeignKeyFilter = require('../relation/newForeignKeyFilter'); let negotiateExpandInverse = require('../negotiateExpandInverse'); -function getRelatives(parent, relation) { +function getRelatives(context, parent, relation) { let queryContext = parent.queryContext; let strategy = queryContext && queryContext.strategy[relation.joinRelation.rightAlias]; @@ -22,17 +22,17 @@ function getRelatives(parent, relation) { return row[parentAlias]; }); let column = relation.joinRelation.columns[0]; - return column.in(ids); + return column.in(context, ids); } function createCompositeFilter() { let filters = queryContext.rows.map(function(row) { - return newForeignKeyFilter(relation.joinRelation, row); + return newForeignKeyFilter(context, relation.joinRelation, row); }); - return emptyFilter.or.apply(emptyFilter, filters); + return emptyFilter.or.apply(emptyFilter, [context, ...filters]); } - return relation.childTable.getMany(filter, strategy).then(onRows); + return relation.childTable.getMany(context, filter, strategy).then(onRows); function onRows(rows) { queryContext.expand(relation); diff --git a/src/table/popChanges.js b/src/table/popChanges.js index 23eb13d0..3471b27f 100644 --- a/src/table/popChanges.js +++ b/src/table/popChanges.js @@ -1,14 +1,14 @@ var getChangeSet = require('./commands/getChangeSet'); var compressChanges = require('./commands/compressChanges'); -function popChanges() { - var changeSet = getChangeSet(); +function popChanges(context) { + var changeSet = getChangeSet(context); var length = changeSet.length; if (length > 0) { var lastCmd = changeSet[length-1]; if (lastCmd.endEdit) lastCmd.endEdit(); - var compressed = compressChanges(changeSet); + var compressed = compressChanges(context, changeSet); changeSet.length = 0; return compressed; } diff --git a/src/table/promise.js b/src/table/promise.js index bc42d96d..c42deb78 100644 --- a/src/table/promise.js +++ b/src/table/promise.js @@ -1,14 +1,8 @@ -var promise = require('promise/domains'); -var deferred = require('deferred'); -let promisify = require('util').promisify; - - function newPromise(func) { if (!func) - return deferred.resolve.apply(deferred, arguments); - return new promise(func); + return Promise.resolve.apply(Promise, arguments); + return new Promise(func); } newPromise.all = Promise.all; -newPromise.denodeify = promisify || promise.denodeify; module.exports = newPromise; \ No newline at end of file diff --git a/src/table/query/extractLimit.js b/src/table/query/extractLimit.js index 9f3993dd..5d8144ee 100644 --- a/src/table/query/extractLimit.js +++ b/src/table/query/extractLimit.js @@ -1,7 +1,7 @@ var getSessionContext = require('../getSessionContext'); -function extractLimit(span) { - let limit = getSessionContext().limit; +function extractLimit(context, span) { + let limit = getSessionContext(context).limit; if (limit) return limit(span); else diff --git a/src/table/query/extractOffset.js b/src/table/query/extractOffset.js index 9912b8a5..672c139c 100644 --- a/src/table/query/extractOffset.js +++ b/src/table/query/extractOffset.js @@ -1,7 +1,7 @@ var getSessionContext = require('../getSessionContext'); -function extractOffset(span) { - let {limitAndOffset} = getSessionContext(); +function extractOffset(context, span) { + let {limitAndOffset} = getSessionContext(context); if (limitAndOffset) return limitAndOffset(span); else diff --git a/src/table/query/extractOrderBy.js b/src/table/query/extractOrderBy.js index 156fa651..9187d2c7 100644 --- a/src/table/query/extractOrderBy.js +++ b/src/table/query/extractOrderBy.js @@ -1,7 +1,7 @@ const getSessionSingleton = require('../getSessionSingleton'); -function extractOrderBy(table, alias, orderBy, originalOrderBy) { - const quote = getSessionSingleton('quote'); +function extractOrderBy(context, table, alias, orderBy, originalOrderBy) { + const quote = getSessionSingleton(context, 'quote'); alias = quote(alias); var dbNames = []; var i; diff --git a/src/table/query/newParameterized.js b/src/table/query/newParameterized.js index 4c09a4d0..55871f8a 100644 --- a/src/table/query/newParameterized.js +++ b/src/table/query/newParameterized.js @@ -1,11 +1,6 @@ var extractSql = require('./extractSql'); var extractParameters = require('./parameterized/extractParameters'); -var nextParameterized = function(text, params) { - nextParameterized = require('../query/newParameterized'); - return nextParameterized(text, params); -}; - function Parameterized(text, parameters) { this._text = text; this.parameters = parameters; @@ -18,21 +13,23 @@ Parameterized.prototype.sql = function() { Parameterized.prototype.prepend = function(other) { if (other.sql) { var params = other.parameters.concat(this.parameters); - return nextParameterized(other.sql() + this._text, params); + return newParameterized(other.sql() + this._text, params); } else - return nextParameterized(other + this._text, this.parameters); + return newParameterized(other + this._text, this.parameters); }; Parameterized.prototype.append = function(other) { if (other.sql) { var params = this.parameters.concat(other.parameters); - return nextParameterized(this._text + other.sql(), params); + return newParameterized(this._text + other.sql(), params); } else - return nextParameterized(this._text + other, this.parameters); + return newParameterized(this._text + other, this.parameters); }; -module.exports = function(text, parameters) { +function newParameterized(text, parameters) { text = extractSql(text); parameters = extractParameters(parameters); return new Parameterized(text, parameters); -}; +} + +module.exports = newParameterized; diff --git a/src/table/query/newSingleQuery.js b/src/table/query/newSingleQuery.js index 17bc656a..6698eb57 100644 --- a/src/table/query/newSingleQuery.js +++ b/src/table/query/newSingleQuery.js @@ -6,15 +6,15 @@ var negotiateExclusive = require('./singleQuery/negotiateExclusive'); var newParameterized = require('../../table/query/newParameterized'); var quote = require('../quote'); -function _new(table,filter,span,alias,innerJoin,orderBy,limit,offset,exclusive) { +function _new(context, table, filter, span, alias, innerJoin, orderBy, limit, offset, exclusive) { - var name = quote(table._dbName); - var columnSql = newColumnSql(table,span,alias); - var joinSql = newJoinSql(span,alias); - var whereSql = newWhereSql(table,filter,alias); + var name = quote(context, table._dbName); + var columnSql = newColumnSql(context, table, span, alias); + var joinSql = newJoinSql(context, span, alias); + var whereSql = newWhereSql(context, table, filter, alias); var safeLimit = negotiateLimit(limit); - var exclusiveClause = negotiateExclusive(table,alias,exclusive); - return newParameterized('select' + safeLimit + ' ' + columnSql + ' from ' + name + ' ' + quote(alias)) + var exclusiveClause = negotiateExclusive(table, alias, exclusive); + return newParameterized('select' + safeLimit + ' ' + columnSql + ' from ' + name + ' ' + quote(context, alias)) .append(innerJoin) .append(joinSql) .append(whereSql) diff --git a/src/table/query/singleQuery/columnSql/joinLegToColumnSql.js b/src/table/query/singleQuery/columnSql/joinLegToColumnSql.js index ca13b663..0039df3b 100644 --- a/src/table/query/singleQuery/columnSql/joinLegToColumnSql.js +++ b/src/table/query/singleQuery/columnSql/joinLegToColumnSql.js @@ -1,16 +1,3 @@ -var newShallowColumnSql = require('./newShallowColumnSql'); -var newJoinedColumnSql = _initJoinedColumnSql; +const { joinLegToColumnSql} = require('./sharedJoinUtils'); -function sql(leg,alias,ignoreNull) { - var span = leg.span; - var shallowColumnSql = newShallowColumnSql(span.table,alias, span, ignoreNull); - var joinedColumnSql = newJoinedColumnSql(span,alias,ignoreNull); - return ',' + shallowColumnSql + joinedColumnSql; -} - -function _initJoinedColumnSql(span,alias,ignoreNull) { - newJoinedColumnSql = require('./newJoinedColumnSql'); - return newJoinedColumnSql(span,alias,ignoreNull); -} - -module.exports = sql; \ No newline at end of file +module.exports = joinLegToColumnSql; \ No newline at end of file diff --git a/src/table/query/singleQuery/columnSql/newJoinedColumnSql.js b/src/table/query/singleQuery/columnSql/newJoinedColumnSql.js index 481ffaed..e5b9be1d 100644 --- a/src/table/query/singleQuery/columnSql/newJoinedColumnSql.js +++ b/src/table/query/singleQuery/columnSql/newJoinedColumnSql.js @@ -1,27 +1,4 @@ -var joinLegToColumnSql = require('./joinLegToColumnSql'); +const { newJoinedColumnSql } = require('./sharedJoinUtils'); -module.exports = function(span, alias, ignoreNull) { - var c = {}; - var sql = ''; - c.visitJoin = function(leg) { - var joinSql = joinLegToColumnSql(leg, alias + leg.name, ignoreNull); - sql = sql + joinSql; - }; - - c.visitOne = function(leg) { - c.visitJoin(leg); - }; - - c.visitMany = function() { - }; - - - span.legs.forEach(onEach); - - function onEach(leg) { - leg.accept(c); - } - - return sql; -}; \ No newline at end of file +module.exports = newJoinedColumnSql; \ No newline at end of file diff --git a/src/table/query/singleQuery/columnSql/newShallowColumnSql.js b/src/table/query/singleQuery/columnSql/newShallowColumnSql.js index 2dec79b3..6c8fba62 100644 --- a/src/table/query/singleQuery/columnSql/newShallowColumnSql.js +++ b/src/table/query/singleQuery/columnSql/newShallowColumnSql.js @@ -1,7 +1,7 @@ const getSessionSingleton = require('../../../getSessionSingleton'); -function _new(table, alias, span, ignoreNulls) { - const quote = getSessionSingleton('quote'); +function _new(context, table, alias, span, ignoreNulls) { + const quote = getSessionSingleton(context, 'quote'); const quotedAlias = quote(alias); let columnsMap = span.columns; var columns = table._columns; @@ -28,11 +28,11 @@ function _new(table, alias, span, ignoreNulls) { return sql; function formatColumn(column) { - const formatted = column.formatOut ? column.formatOut(quotedAlias) : quotedAlias + '.' + quote(column._dbName); + const formatted = column.formatOut ? column.formatOut(context, quotedAlias) : quotedAlias + '.' + quote(column._dbName); if (column.dbNull === null) return formatted; else { - const encoded = column.encode.unsafe(column.dbNull); + const encoded = column.encode.unsafe(context, column.dbNull); return `CASE WHEN ${formatted}=${encoded} THEN null ELSE ${formatted} END`; } } diff --git a/src/table/query/singleQuery/columnSql/sharedJoinUtils.js b/src/table/query/singleQuery/columnSql/sharedJoinUtils.js new file mode 100644 index 00000000..d6aa0e03 --- /dev/null +++ b/src/table/query/singleQuery/columnSql/sharedJoinUtils.js @@ -0,0 +1,37 @@ +var newShallowColumnSql = require('./newShallowColumnSql'); + +function joinLegToColumnSql(context, leg, alias, ignoreNull) { + var span = leg.span; + var shallowColumnSql = newShallowColumnSql(context, span.table, alias, span, ignoreNull); + var joinedColumnSql = newJoinedColumnSql(context, span, alias, ignoreNull); + return ',' + shallowColumnSql + joinedColumnSql; +} + +function newJoinedColumnSql(context, span, alias, ignoreNull) { + var c = {}; + var sql = ''; + + c.visitJoin = function(leg) { + var joinSql = joinLegToColumnSql(context, leg, alias + leg.name, ignoreNull); + sql = sql + joinSql; + }; + + c.visitOne = function(leg) { + c.visitJoin(leg); + }; + + c.visitMany = function() { + }; + + + span.legs.forEach(onEach); + + function onEach(leg) { + leg.accept(c); + } + + return sql; +} + + +module.exports = { joinLegToColumnSql, newJoinedColumnSql }; \ No newline at end of file diff --git a/src/table/query/singleQuery/joinSql/joinLegToJoinSql.js b/src/table/query/singleQuery/joinSql/joinLegToJoinSql.js index 0dcf4c80..5812d4e7 100644 --- a/src/table/query/singleQuery/joinSql/joinLegToJoinSql.js +++ b/src/table/query/singleQuery/joinSql/joinLegToJoinSql.js @@ -1,13 +1,8 @@ var joinLegToShallowJoinSql = require('./joinLegToShallowJoinSql'); -var newJoinSql = _newJoinSql; -function toJoinSql(leg,alias,childAlias) { - return joinLegToShallowJoinSql(leg,alias,childAlias).append(newJoinSql(leg.span,childAlias)); +function toJoinSql(newJoinSql, context,leg,alias,childAlias) { + return joinLegToShallowJoinSql(context,leg,alias,childAlias).append(newJoinSql(context,leg.span,childAlias)); } -function _newJoinSql() { - newJoinSql = require('../newJoinSql'); - return newJoinSql.apply(null,arguments); -} module.exports = toJoinSql; \ No newline at end of file diff --git a/src/table/query/singleQuery/joinSql/joinLegToShallowJoinSql.js b/src/table/query/singleQuery/joinSql/joinLegToShallowJoinSql.js index 6066e029..ae03ebdf 100644 --- a/src/table/query/singleQuery/joinSql/joinLegToShallowJoinSql.js +++ b/src/table/query/singleQuery/joinSql/joinLegToShallowJoinSql.js @@ -1,9 +1,9 @@ var newShallowJoinSql = require('./newShallowJoinSql'); -function toJoinSql(leg,alias,childAlias) { +function toJoinSql(context,leg,alias,childAlias) { var columns = leg.columns; var childTable = leg.span.table; - return newShallowJoinSql(childTable,columns,childTable._primaryColumns,alias,childAlias,leg.span.where).prepend(' LEFT'); + return newShallowJoinSql(context,childTable,columns,childTable._primaryColumns,alias,childAlias,leg.span.where).prepend(' LEFT'); } module.exports = toJoinSql; \ No newline at end of file diff --git a/src/table/query/singleQuery/joinSql/newDiscriminatorSql.js b/src/table/query/singleQuery/joinSql/newDiscriminatorSql.js index d14cfdfd..b680725d 100644 --- a/src/table/query/singleQuery/joinSql/newDiscriminatorSql.js +++ b/src/table/query/singleQuery/joinSql/newDiscriminatorSql.js @@ -1,7 +1,7 @@ var newDiscriminatorSqlCore = require('../newDiscriminatorSql'); -function newDiscriminatorSql(table, alias) { - var result = newDiscriminatorSqlCore(table,alias); +function newDiscriminatorSql(context, table, alias) { + var result = newDiscriminatorSqlCore(context,table,alias); if (result) return ' AND' + result; return result; diff --git a/src/table/query/singleQuery/joinSql/newShallowJoinSql.js b/src/table/query/singleQuery/joinSql/newShallowJoinSql.js index 2175ac9d..0e9679dd 100644 --- a/src/table/query/singleQuery/joinSql/newShallowJoinSql.js +++ b/src/table/query/singleQuery/joinSql/newShallowJoinSql.js @@ -1,10 +1,10 @@ -var newJoinCore = require('./newShallowJoinSqlCore'); +const newJoinCore = require('./newShallowJoinSqlCore'); const getSessionSingleton = require('../../../getSessionSingleton'); -function _new(rightTable,leftColumns,rightColumns,leftAlias,rightAlias, filter) { - const quote = getSessionSingleton('quote'); - var sql = ' JOIN ' + quote(rightTable._dbName) + ' ' + quote(rightAlias) + ' ON ('; - var joinCore = newJoinCore(rightTable,leftColumns,rightColumns,leftAlias,rightAlias,filter); +function _new(context, rightTable, leftColumns, rightColumns, leftAlias, rightAlias, filter) { + const quote = getSessionSingleton(context, 'quote'); + const sql = ' JOIN ' + quote(rightTable._dbName) + ' ' + quote(rightAlias) + ' ON ('; + const joinCore = newJoinCore(context, rightTable, leftColumns, rightColumns, leftAlias, rightAlias, filter); return joinCore.prepend(sql).append(')'); } diff --git a/src/table/query/singleQuery/joinSql/newShallowJoinSqlCore.js b/src/table/query/singleQuery/joinSql/newShallowJoinSqlCore.js index 52b71ff6..b174c7e7 100644 --- a/src/table/query/singleQuery/joinSql/newShallowJoinSqlCore.js +++ b/src/table/query/singleQuery/joinSql/newShallowJoinSqlCore.js @@ -1,8 +1,9 @@ -var newDiscriminatorSql = require('./newDiscriminatorSql'); -var newParameterized = require('../../newParameterized'); -var quote = require('../../../quote'); +const newDiscriminatorSql = require('./newDiscriminatorSql'); +const newParameterized = require('../../newParameterized'); +const getSessionSingleton = require('../../../getSessionSingleton'); -function _new(rightTable,leftColumns,rightColumns,leftAlias,rightAlias,filter) { +function _new(context, rightTable, leftColumns, rightColumns, leftAlias, rightAlias, filter) { + const quote = getSessionSingleton(context, 'quote'); leftAlias = quote(leftAlias); rightAlias = quote(rightAlias); var sql = ''; @@ -18,7 +19,7 @@ function _new(rightTable,leftColumns,rightColumns,leftAlias,rightAlias,filter) { sql += delimiter + leftAlias + '.' + quote(leftColumn._dbName) + '=' + rightAlias + '.' + quote(rightColumn._dbName); } - sql += newDiscriminatorSql(rightTable,rightAlias); + sql += newDiscriminatorSql(context, rightTable, rightAlias); var result = newParameterized(sql); if (filter) result = result.append(delimiter).append(filter); diff --git a/src/table/query/singleQuery/joinSql/oneLegToJoinSql.js b/src/table/query/singleQuery/joinSql/oneLegToJoinSql.js index 0f62624c..fd843cc2 100644 --- a/src/table/query/singleQuery/joinSql/oneLegToJoinSql.js +++ b/src/table/query/singleQuery/joinSql/oneLegToJoinSql.js @@ -1,13 +1,7 @@ var oneLegToShallowJoinSql = require('./oneLegToShallowJoinSql'); -var newJoinSql = _newJoinSql; -function toJoinSql(leg,alias,childAlias) { - return oneLegToShallowJoinSql(leg,alias,childAlias).append(newJoinSql(leg.span,childAlias)); -} - -function _newJoinSql() { - newJoinSql = require('../newJoinSql'); - return newJoinSql.apply(null,arguments); +function toJoinSql(newJoinSql, context,leg,alias,childAlias) { + return oneLegToShallowJoinSql(context,leg,alias,childAlias).append(newJoinSql(context,leg.span,childAlias)); } module.exports = toJoinSql; \ No newline at end of file diff --git a/src/table/query/singleQuery/joinSql/oneLegToShallowJoinSql.js b/src/table/query/singleQuery/joinSql/oneLegToShallowJoinSql.js index 14c112c3..aa516968 100644 --- a/src/table/query/singleQuery/joinSql/oneLegToShallowJoinSql.js +++ b/src/table/query/singleQuery/joinSql/oneLegToShallowJoinSql.js @@ -1,10 +1,10 @@ var newShallowJoinSql = require('./newShallowJoinSql'); -function toJoinSql(leg,alias,childAlias) { +function toJoinSql(context,leg,alias,childAlias) { var parentTable = leg.table; var columns = leg.columns; var childTable = leg.span.table; - return newShallowJoinSql(childTable,parentTable._primaryColumns,columns,alias,childAlias, leg.span.where).prepend(' LEFT'); + return newShallowJoinSql(context,childTable,parentTable._primaryColumns,columns,alias,childAlias, leg.span.where).prepend(' LEFT'); } module.exports = toJoinSql; \ No newline at end of file diff --git a/src/table/query/singleQuery/negotiateExclusive.js b/src/table/query/singleQuery/negotiateExclusive.js index a4b68907..71626196 100644 --- a/src/table/query/singleQuery/negotiateExclusive.js +++ b/src/table/query/singleQuery/negotiateExclusive.js @@ -1,8 +1,8 @@ var getSessionSingleton = require('../../getSessionSingleton'); -function negotiateExclusive(table, alias, _exclusive) { +function negotiateExclusive(context, table, alias, _exclusive) { if (table._exclusive || _exclusive) { - var encode = getSessionSingleton('selectForUpdateSql'); + var encode = getSessionSingleton(context, 'selectForUpdateSql'); return encode(alias); } return ''; diff --git a/src/table/query/singleQuery/newColumnSql.js b/src/table/query/singleQuery/newColumnSql.js index 8400a40c..6661b051 100644 --- a/src/table/query/singleQuery/newColumnSql.js +++ b/src/table/query/singleQuery/newColumnSql.js @@ -1,8 +1,8 @@ var newShallowColumnSql = require('./columnSql/newShallowColumnSql'); var newJoinedColumnSql = require('./columnSql/newJoinedColumnSql'); -module.exports = function(table,span,alias,ignoreNull) { - var shallowColumnSql = newShallowColumnSql(table,alias, span, ignoreNull); - var joinedColumnSql = newJoinedColumnSql(span,alias, ignoreNull); +module.exports = function(context,table,span,alias,ignoreNull) { + var shallowColumnSql = newShallowColumnSql(context,table,alias, span, ignoreNull); + var joinedColumnSql = newJoinedColumnSql(context, span,alias, ignoreNull); return shallowColumnSql + joinedColumnSql; }; \ No newline at end of file diff --git a/src/table/query/singleQuery/newDiscriminatorSql.js b/src/table/query/singleQuery/newDiscriminatorSql.js index e686ce86..f043e16c 100644 --- a/src/table/query/singleQuery/newDiscriminatorSql.js +++ b/src/table/query/singleQuery/newDiscriminatorSql.js @@ -1,7 +1,7 @@ const getSessionSingleton = require('../../getSessionSingleton'); -function newDiscriminatorSql(table, alias) { - const quote = getSessionSingleton('quote'); +function newDiscriminatorSql(context, table, alias) { + const quote = getSessionSingleton(context, 'quote'); alias = quote(alias); var result = ''; var formulaDiscriminators = table._formulaDiscriminators; diff --git a/src/table/query/singleQuery/newJoinSql.js b/src/table/query/singleQuery/newJoinSql.js index 43d77942..82044fb5 100644 --- a/src/table/query/singleQuery/newJoinSql.js +++ b/src/table/query/singleQuery/newJoinSql.js @@ -1,18 +1,18 @@ -var joinLegToJoinSql = require('./joinSql/joinLegToJoinSql'); -var oneLegToJoinSql = require('./joinSql/oneLegToJoinSql'); -var newParameterized = require('../newParameterized'); +const joinLegToJoinSql = require('./joinSql/joinLegToJoinSql'); +const oneLegToJoinSql = require('./joinSql/oneLegToJoinSql'); +const newParameterized = require('../newParameterized'); -function _new(span,alias = '') { +function newJoinSql(context,span,alias = '') { var sql = newParameterized(''); var childAlias; var c = {}; c.visitJoin = function(leg) { - sql = joinLegToJoinSql(leg,alias,childAlias).prepend(sql); + sql = joinLegToJoinSql(newJoinSql, context,leg,alias,childAlias).prepend(sql); }; c.visitOne = function(leg) { - sql = oneLegToJoinSql(leg,alias,childAlias).prepend(sql); + sql = oneLegToJoinSql(newJoinSql, context,leg,alias,childAlias).prepend(sql); }; c.visitMany = function() {}; @@ -38,4 +38,4 @@ function _new(span,alias = '') { return sql; } -module.exports = _new; \ No newline at end of file +module.exports = newJoinSql; \ No newline at end of file diff --git a/src/table/query/singleQuery/newWhereSql.js b/src/table/query/singleQuery/newWhereSql.js index 4223d0f1..98ce2368 100644 --- a/src/table/query/singleQuery/newWhereSql.js +++ b/src/table/query/singleQuery/newWhereSql.js @@ -1,16 +1,16 @@ var newDiscriminatorSql = require('./newDiscriminatorSql'); var newParameterized = require('../../../table/query/newParameterized'); -function newWhereSql(table,filter,alias) { +function newWhereSql(context, table, filter, alias) { var separator = ' where'; var result = newParameterized(''); var sql = filter.sql(); - var discriminator = newDiscriminatorSql(table, alias); + var discriminator = newDiscriminatorSql(context, table, alias); if (sql) { result = filter.prepend(separator + ' '); separator = ' AND'; } - if(discriminator) + if (discriminator) result = result.append(separator + discriminator); return result; diff --git a/src/table/quote.js b/src/table/quote.js index c6e01337..ef0101de 100644 --- a/src/table/quote.js +++ b/src/table/quote.js @@ -1,10 +1,10 @@ let tryGetSessionContext = require('./tryGetSessionContext'); -function quote(name) { - let context = tryGetSessionContext(); - if (!context) +function quote(context, name) { + let rdb = tryGetSessionContext(context); + if (!rdb) throw new Error('Rdb transaction is no longer available. Is promise chain broken ?'); - let fn = context.quote || (() => `"${name}"`); + let fn = rdb.quote || (() => `"${name}"`); return fn(name); } diff --git a/src/table/readStream/extractLimit.js b/src/table/readStream/extractLimit.js deleted file mode 100644 index 599f01a5..00000000 --- a/src/table/readStream/extractLimit.js +++ /dev/null @@ -1,7 +0,0 @@ -function extractLimit(span) { - if (span.limit) - return ' limit ' + span.limit; - return ''; -} - -module.exports = extractLimit; \ No newline at end of file diff --git a/src/table/readStream/extractOrderBy.js b/src/table/readStream/extractOrderBy.js deleted file mode 100644 index 7b3a7686..00000000 --- a/src/table/readStream/extractOrderBy.js +++ /dev/null @@ -1,59 +0,0 @@ -const getSessionSingleton = require('../getSessionSingleton'); - -function extractOrderBy(alias, span) { - const quote = getSessionSingleton('quote'); - alias = quote(alias); - var table = span.table; - var dbNames = []; - var orderBy = span.orderBy; - var i; - if (span.orderBy) { - if (typeof orderBy === 'string') - orderBy = [orderBy]; - for (i = 0; i < orderBy.length; i++) { - var nameAndDirection = extractNameAndDirection(orderBy[i]); - pushColumn(nameAndDirection.name, nameAndDirection.direction); - } - } else - for (i = 0; i < table._primaryColumns.length; i++) { - pushColumn(table._primaryColumns[i].alias); - } - - function extractNameAndDirection(orderBy) { - var elements = orderBy.split(' '); - var direction = ''; - if (elements.length > 1) { - direction = ' ' + elements[1]; - } - return { - name: elements[0], - direction: direction - }; - } - - function pushColumn(property, direction) { - direction = direction || ''; - var column = getTableColumn(property); - var jsonQuery = getJsonQuery(property, column.alias); - - dbNames.push(alias + '.' + quote(column._dbName) + jsonQuery + direction); - } - function getTableColumn(property) { - var column = table[property] || table[property.split(/(-|#)>+/g)[0]]; - if(!column){ - throw new Error(`Unable to get column on orderBy '${property}'. If jsonb query, only #>, #>>, -> and ->> allowed. Only use ' ' to seperate between query and direction. Does currently not support casting.`); - } - return column; - } - function getJsonQuery(property, column) { - let containsJson = (/(-|#)>+/g).test(property); - if(!containsJson){ - return ''; - } - return property.replace(column, ''); - } - - return ' order by ' + dbNames.join(','); -} - -module.exports = extractOrderBy; diff --git a/src/table/readStream/mySql/newQuery.js b/src/table/readStream/mySql/newQuery.js deleted file mode 100644 index 45c0ae24..00000000 --- a/src/table/readStream/mySql/newQuery.js +++ /dev/null @@ -1,16 +0,0 @@ -var newSingleQuery = require('./query/newSingleQuery'); -var newSubQueries = require('./query/newSubQueries'); -var extractFilter = require('../../query/extractFilter'); -var extractOrderBy = require('../extractOrderBy'); -var extractLimit = require('../extractLimit'); - -function newQuery(table,filter,span,alias) { - filter = extractFilter(filter); - var orderBy = extractOrderBy(alias,span); - var limit = extractLimit(span); - - var subQueries = newSubQueries(table,span,alias); - return newSingleQuery(table,filter,alias,subQueries,orderBy,limit); -} - -module.exports = newQuery; \ No newline at end of file diff --git a/src/table/readStream/mySql/query/newSingleQuery.js b/src/table/readStream/mySql/query/newSingleQuery.js deleted file mode 100644 index aea94481..00000000 --- a/src/table/readStream/mySql/query/newSingleQuery.js +++ /dev/null @@ -1,21 +0,0 @@ -var newColumnSql = require('./singleQuery/newShallowColumnSql'); -var newWhereSql = require('../../../query/singleQuery/newWhereSql'); -var template = 'select json_object(%s%s) as result from %s %s%s%s%s'; -var util = require('util'); - -function _new(table,filter,alias,subQueries,orderBy,limit) { - var c = {}; - - c.sql = function() { - var name = table._dbName; - var columnSql = newColumnSql(table,alias); - var whereSql = newWhereSql(table,filter,alias); - return util.format(template, columnSql, subQueries, name, alias, whereSql, orderBy, limit); - }; - - c.parameters = filter.parameters; - - return c; -} - -module.exports = _new; \ No newline at end of file diff --git a/src/table/readStream/mySql/query/newSubQueries.js b/src/table/readStream/mySql/query/newSubQueries.js deleted file mode 100644 index 39b45591..00000000 --- a/src/table/readStream/mySql/query/newSubQueries.js +++ /dev/null @@ -1,47 +0,0 @@ -var joinLegToQuery = _joinLegToQuery; -var oneLegToQuery = _oneLegToQuery; -var manyLegToQuery = _manyLegToQuery; - -function newSubQueries(table,span,alias) { - var result = []; - var c = {}; - var _legNo; - - c.visitJoin = function(leg) { - result.push(joinLegToQuery( alias,leg,_legNo)); - }; - c.visitOne = function(leg) { - result.push(oneLegToQuery( alias,leg,_legNo)); - }; - c.visitMany = function(leg) { - result.push(manyLegToQuery( alias,leg,_legNo)); - }; - - span.legs.forEach(onEachLeg); - - function onEachLeg(leg,legNo) { - _legNo = legNo; - leg.accept(c); - } - - return result.join(''); -} - -function _joinLegToQuery() { - joinLegToQuery = require('./newSubQueries/joinLegToQuery'); - return joinLegToQuery.apply(null,arguments); -} - -function _oneLegToQuery() { - oneLegToQuery = require('./newSubQueries/oneLegToQuery'); - return oneLegToQuery.apply(null,arguments); -} - -function _manyLegToQuery() { - manyLegToQuery = require('./newSubQueries/manyLegToQuery'); - return manyLegToQuery.apply(null,arguments); -} - - - -module.exports = newSubQueries; \ No newline at end of file diff --git a/src/table/readStream/mySql/query/newSubQueries/joinLegToQuery.js b/src/table/readStream/mySql/query/newSubQueries/joinLegToQuery.js deleted file mode 100644 index 86976e9c..00000000 --- a/src/table/readStream/mySql/query/newSubQueries/joinLegToQuery.js +++ /dev/null @@ -1,20 +0,0 @@ -var newShallowJoinSql = require('../../../../query/singleQuery/joinSql/newShallowJoinSqlCore'); -const quote = require('../../../../quote'); -var newQuery = require('./newQueryCore'); -var util = require('util'); - -function joinLegToQuery(parentAlias,leg,legNo) { - var childAlias = parentAlias + 'x' + legNo; - var span = leg.span; - var childTable = span.table; - var parentTable = leg.table; - var childColumns = span.table._primaryColumns; - var parentColumns = leg.columns; - - var shallowJoin = newShallowJoinSql(parentTable,childColumns,parentColumns,childAlias,parentAlias); - var query = newQuery(childTable,span,childAlias); - - return util.format(',\'%s\',(select %s from %s %s where %s)', leg.name, query.sql(), quote(childTable._dbName), quote(childAlias), shallowJoin); -} - -module.exports = joinLegToQuery; \ No newline at end of file diff --git a/src/table/readStream/mySql/query/newSubQueries/manyLegToQuery.js b/src/table/readStream/mySql/query/newSubQueries/manyLegToQuery.js deleted file mode 100644 index a988b2f9..00000000 --- a/src/table/readStream/mySql/query/newSubQueries/manyLegToQuery.js +++ /dev/null @@ -1,22 +0,0 @@ -var newShallowJoinSql = require('../../../../query/singleQuery/joinSql/newShallowJoinSqlCore'); -var extractOrderBy = require('../../../extractOrderBy'); -var newQuery = require('./newQueryCore'); -var util = require('util'); - -function manyLegToQuery(rightAlias,leg,legNo) { - var leftAlias = rightAlias + 'x' + legNo; - var span = leg.span; - var rightTable = leg.table; - var rightColumns = rightTable._primaryColumns; - var leftColumns = leg.columns; - var orderBy = extractOrderBy(leftAlias, span); - - var shallowJoin = newShallowJoinSql(rightTable,leftColumns,rightColumns,leftAlias,rightAlias); - var query = newQuery(span.table,span,leftAlias); - - - return util.format(',\'%s\',(select cast(concat(\'[\',ifnull(group_concat(%s%s),\'\'),\']\') as json) from %s %s where %s)', - leg.name, query.sql(), orderBy, span.table._dbName, leftAlias, shallowJoin); -} - -module.exports = manyLegToQuery; diff --git a/src/table/readStream/mySql/query/newSubQueries/newQueryCore.js b/src/table/readStream/mySql/query/newSubQueries/newQueryCore.js deleted file mode 100644 index 3c910374..00000000 --- a/src/table/readStream/mySql/query/newSubQueries/newQueryCore.js +++ /dev/null @@ -1,9 +0,0 @@ -var newSingleQuery = require('./newSingleQueryCore'); -var newSubQueries = require('../newSubQueries'); - -function newQueryCore(table,span,alias) { - var subQueries = newSubQueries(table,span,alias); - return newSingleQuery(table,alias,subQueries); -} - -module.exports = newQueryCore; \ No newline at end of file diff --git a/src/table/readStream/mySql/query/newSubQueries/newSingleQueryCore.js b/src/table/readStream/mySql/query/newSubQueries/newSingleQueryCore.js deleted file mode 100644 index b12886ab..00000000 --- a/src/table/readStream/mySql/query/newSubQueries/newSingleQueryCore.js +++ /dev/null @@ -1,18 +0,0 @@ -var newColumnSql = require('../singleQuery/newShallowColumnSql'); -var template = 'json_object(%s%s)'; -var util = require('util'); - -function _new(table,alias,subQueries) { - var c = {}; - - c.sql = function() { - var columnSql = newColumnSql(table,alias); - return util.format(template, columnSql, subQueries); - }; - - c.parameters = []; - - return c; -} - -module.exports = _new; \ No newline at end of file diff --git a/src/table/readStream/mySql/query/newSubQueries/oneLegToQuery.js b/src/table/readStream/mySql/query/newSubQueries/oneLegToQuery.js deleted file mode 100644 index 5b8a0a82..00000000 --- a/src/table/readStream/mySql/query/newSubQueries/oneLegToQuery.js +++ /dev/null @@ -1,22 +0,0 @@ -var newShallowJoinSql = require('../../../../query/singleQuery/joinSql/newShallowJoinSqlCore'); -var newQuery = require('./newQueryCore'); -var extractOrderBy = require('../../../../query/extractOrderBy'); -var util = require('util'); - -function manyLegToQuery(rightAlias,leg,legNo) { - var leftAlias = rightAlias + 'x' + legNo; - var span = leg.span; - var rightTable = leg.table; - var rightColumns = rightTable._primaryColumns; - var leftColumns = leg.columns; - var orderBy = extractOrderBy(rightTable,rightAlias); - - var shallowJoin = newShallowJoinSql(rightTable,leftColumns,rightColumns,leftAlias,rightAlias); - var query = newQuery(span.table,span,leftAlias); - - - return util.format(',\'%s\',(select %s from %s %s where %s%s LIMIT 1)', - leg.name, query.sql(), span.table._dbName, leftAlias, shallowJoin, orderBy); -} - -module.exports = manyLegToQuery; diff --git a/src/table/readStream/mySql/query/singleQuery/newShallowColumnSql.js b/src/table/readStream/mySql/query/singleQuery/newShallowColumnSql.js deleted file mode 100644 index 9773b548..00000000 --- a/src/table/readStream/mySql/query/singleQuery/newShallowColumnSql.js +++ /dev/null @@ -1,18 +0,0 @@ -var util = require('util'); -const quote = require('../../../../quote'); - -function _new(table,alias) { - var columnFormat = '\'%s\',%s.%s'; - var columns = table._columns; - var sql = ''; - var separator = ''; - for (var i = 0; i < columns.length; i++) { - var column = columns[i]; - if (!('serializable' in column && !column.serializable)) - sql = sql + separator + util.format(columnFormat, quote(column.alias), alias, quote(column._dbName)); - separator = ','; - } - return sql; -} - -module.exports = _new; \ No newline at end of file diff --git a/src/table/readStream/newQuery.js b/src/table/readStream/newQuery.js deleted file mode 100644 index d3524024..00000000 --- a/src/table/readStream/newQuery.js +++ /dev/null @@ -1,32 +0,0 @@ -var newMySqlQuery = require('./mySql/newQuery'); -var newPgQuery = require('./pg/newQuery'); - -function newQuery(db) { - var c = {}; - var _newQuery; - - c.visitPg = function() { - _newQuery = newPgQuery; - }; - c.visitMySql = function() { - _newQuery = newMySqlQuery; - }; - - c.visitSqlite = function() { - throw new Error('Sqlite not supported'); - }; - - c.visitSap = function() { - throw new Error('Sap not supported'); - }; - - db.accept(c); - - var args = []; - for (var i = 1; i < arguments.length; i++) { - args.push(arguments[i]); - } - return _newQuery.apply(null, args); -} - -module.exports = newQuery; \ No newline at end of file diff --git a/src/table/readStream/newQueryStream.js b/src/table/readStream/newQueryStream.js deleted file mode 100644 index 826d4e9e..00000000 --- a/src/table/readStream/newQueryStream.js +++ /dev/null @@ -1,8 +0,0 @@ -var getSessionSingleton = require('../getSessionSingleton'); - -function newQueryStream(query, options) { - var dbClient = getSessionSingleton('dbClient'); - return dbClient.streamQuery(query, options); -} - -module.exports = newQueryStream; \ No newline at end of file diff --git a/src/table/readStream/pg/newQuery.js b/src/table/readStream/pg/newQuery.js deleted file mode 100644 index b7b044ce..00000000 --- a/src/table/readStream/pg/newQuery.js +++ /dev/null @@ -1,8 +0,0 @@ -var newQueryCore = require('./newQueryCore'); - -function newQuery() { - var query = newQueryCore.apply(null, arguments); - return query.prepend('select row_to_json(r)::text as result from (').append(') r'); -} - -module.exports = newQuery; \ No newline at end of file diff --git a/src/table/readStream/pg/newQueryCore.js b/src/table/readStream/pg/newQueryCore.js deleted file mode 100644 index 29088eca..00000000 --- a/src/table/readStream/pg/newQueryCore.js +++ /dev/null @@ -1,17 +0,0 @@ -var newSingleQuery = require('./query/newSingleQuery'); -var newSubQueries = require('./query/newSubQueries'); -var extractFilter = require('../../query/extractFilter'); -var extractOrderBy = require('../extractOrderBy'); -var extractLimit = require('../extractLimit'); -var newParameterized = require('../../query/newParameterized'); - -function newQuery(table,filter,span,alias) { - filter = extractFilter(filter); - var orderBy = extractOrderBy(alias,span); - var limit = extractLimit(span); - var subQueries = newSubQueries(table,span,alias); - var query = newSingleQuery(table,filter,span,alias,subQueries,orderBy,limit); - return newParameterized(query.sql(), query.parameters); -} - -module.exports = newQuery; \ No newline at end of file diff --git a/src/table/readStream/pg/query/newSingleQuery.js b/src/table/readStream/pg/query/newSingleQuery.js deleted file mode 100644 index 039a6d6f..00000000 --- a/src/table/readStream/pg/query/newSingleQuery.js +++ /dev/null @@ -1,19 +0,0 @@ -var newColumnSql = require('./singleQuery/newShallowColumnSql'); -var newWhereSql = require('../../../query/singleQuery/newWhereSql'); - -function _new(table,filter,span, alias,subQueries,orderBy,limit) { - var c = {}; - - c.sql = function() { - var name = table._dbName; - var columnSql = newColumnSql(table,alias,span); - var whereSql = newWhereSql(table,filter,alias); - return 'select ' + columnSql + subQueries + ' from ' + name + ' ' + alias + whereSql + orderBy + limit; - }; - - c.parameters = filter.parameters; - - return c; -} - -module.exports = _new; \ No newline at end of file diff --git a/src/table/readStream/pg/query/newSubQueries.js b/src/table/readStream/pg/query/newSubQueries.js deleted file mode 100644 index 39b45591..00000000 --- a/src/table/readStream/pg/query/newSubQueries.js +++ /dev/null @@ -1,47 +0,0 @@ -var joinLegToQuery = _joinLegToQuery; -var oneLegToQuery = _oneLegToQuery; -var manyLegToQuery = _manyLegToQuery; - -function newSubQueries(table,span,alias) { - var result = []; - var c = {}; - var _legNo; - - c.visitJoin = function(leg) { - result.push(joinLegToQuery( alias,leg,_legNo)); - }; - c.visitOne = function(leg) { - result.push(oneLegToQuery( alias,leg,_legNo)); - }; - c.visitMany = function(leg) { - result.push(manyLegToQuery( alias,leg,_legNo)); - }; - - span.legs.forEach(onEachLeg); - - function onEachLeg(leg,legNo) { - _legNo = legNo; - leg.accept(c); - } - - return result.join(''); -} - -function _joinLegToQuery() { - joinLegToQuery = require('./newSubQueries/joinLegToQuery'); - return joinLegToQuery.apply(null,arguments); -} - -function _oneLegToQuery() { - oneLegToQuery = require('./newSubQueries/oneLegToQuery'); - return oneLegToQuery.apply(null,arguments); -} - -function _manyLegToQuery() { - manyLegToQuery = require('./newSubQueries/manyLegToQuery'); - return manyLegToQuery.apply(null,arguments); -} - - - -module.exports = newSubQueries; \ No newline at end of file diff --git a/src/table/readStream/pg/query/newSubQueries/joinLegToQuery.js b/src/table/readStream/pg/query/newSubQueries/joinLegToQuery.js deleted file mode 100644 index 25d7564c..00000000 --- a/src/table/readStream/pg/query/newSubQueries/joinLegToQuery.js +++ /dev/null @@ -1,19 +0,0 @@ -var newShallowJoinSql = require('../../../../query/singleQuery/joinSql/newShallowJoinSqlCore'); -var newQuery = require('../../newQueryCore'); -var newParameterized = require('../../../../query/newParameterized'); -var util = require('util'); - -function joinLegToQuery(parentAlias,leg,legNo) { - var childAlias = parentAlias + 'x' + legNo; - var span = leg.span; - var parentTable = leg.table; - var childColumns = span.table._primaryColumns; - var parentColumns = leg.columns; - - var shallowJoin = newShallowJoinSql(parentTable,childColumns,parentColumns,childAlias,parentAlias); - var filter = newParameterized(shallowJoin); - var query = newQuery(span.table,filter,span,childAlias); - return util.format(',(select row_to_json(r) from (%s limit 1) r) "%s"', query.sql(), leg.name ); -} - -module.exports = joinLegToQuery; \ No newline at end of file diff --git a/src/table/readStream/pg/query/newSubQueries/manyLegToQuery.js b/src/table/readStream/pg/query/newSubQueries/manyLegToQuery.js deleted file mode 100644 index 126b7d11..00000000 --- a/src/table/readStream/pg/query/newSubQueries/manyLegToQuery.js +++ /dev/null @@ -1,22 +0,0 @@ -var newShallowJoinSql = require('../../../../query/singleQuery/joinSql/newShallowJoinSqlCore'); -var newQuery = require('../../newQueryCore'); -var newParameterized = require('../../../../query/newParameterized'); -var extractOrderBy = require('../../../../query/extractOrderBy'); -var util = require('util'); - -function manyLegToQuery(rightAlias, leg, legNo) { - var leftAlias = rightAlias + 'x' + legNo; - var span = leg.span; - var rightTable = leg.table; - var rightColumns = rightTable._primaryColumns; - var leftColumns = leg.columns; - var orderBy = extractOrderBy(rightTable, rightAlias); - - var shallowJoin = newShallowJoinSql(rightTable, leftColumns, rightColumns, leftAlias, rightAlias); - var filter = newParameterized(shallowJoin); - var query = newQuery(span.table, filter, span, leftAlias, orderBy); - return util.format(',(select coalesce(json_agg(row_to_json(r)),\'[]\') from (%s) r ) "%s"', query.sql(), leg.name); - -} - -module.exports = manyLegToQuery; \ No newline at end of file diff --git a/src/table/readStream/pg/query/newSubQueries/oneLegToQuery.js b/src/table/readStream/pg/query/newSubQueries/oneLegToQuery.js deleted file mode 100644 index 842275b1..00000000 --- a/src/table/readStream/pg/query/newSubQueries/oneLegToQuery.js +++ /dev/null @@ -1,19 +0,0 @@ -var newShallowJoinSql = require('../../../../query/singleQuery/joinSql/newShallowJoinSqlCore'); -var newQuery = require('../../newQueryCore'); -var newParameterized = require('../../../../query/newParameterized'); -var util = require('util'); - -function oneLegToQuery(rightAlias,leg,legNo) { - var leftAlias = rightAlias + 'x' + legNo; - var span = leg.span; - var rightTable = leg.table; - var rightColumns = rightTable._primaryColumns; - var leftColumns = leg.columns; - - var shallowJoin = newShallowJoinSql(rightTable,leftColumns,rightColumns,leftAlias,rightAlias); - var filter = newParameterized(shallowJoin); - var query = newQuery(span.table,filter,span,leftAlias); - return util.format(',(select row_to_json(r) from (%s limit 1) r) "%s"', query.sql(), leg.name ); -} - -module.exports = oneLegToQuery; \ No newline at end of file diff --git a/src/table/readStream/pg/query/singleQuery/newShallowColumnSql.js b/src/table/readStream/pg/query/singleQuery/newShallowColumnSql.js deleted file mode 100644 index 11d5a608..00000000 --- a/src/table/readStream/pg/query/singleQuery/newShallowColumnSql.js +++ /dev/null @@ -1,20 +0,0 @@ -var util = require('util'); -const quote = require('../../../../quote'); - -function _new(table,alias,span) { - let columnsMap = span.columns; - var columnFormat = '%s as "%s"'; - var columns = table._columns; - var sql = ''; - var separator = alias + '.'; - for (var i = 0; i < columns.length; i++) { - var column = columns[i]; - if (!('serializable' in column && !column.serializable) && (!columnsMap || (columnsMap.get(column)))) { - sql = sql + separator + util.format(columnFormat, quote(column._dbName), quote(column.alias)); - separator = ',' + alias + '.'; - } - } - return sql; -} - -module.exports = _new; \ No newline at end of file diff --git a/src/table/readStreamDefault/createBatchFilter.js b/src/table/readStreamDefault/createBatchFilter.js deleted file mode 100644 index f29563b2..00000000 --- a/src/table/readStreamDefault/createBatchFilter.js +++ /dev/null @@ -1,39 +0,0 @@ -var emptyFilter = require('../../emptyFilter'); - -function createBatchFilter(table, filter, strategy, lastDto) { - if (!lastDto) { - return filter; - } - - var orderBy = strategy.orderBy; - - for (var i = 0; i < strategy.orderBy.length; i++) { - var subFilter = createSubFilter(i); - filter = filter.or(subFilter); - } - - function createSubFilter(index) { - var subFilter = emptyFilter; - for (var i = 0; i < index + 1; i++) { - var order = orderBy[i]; - var elements = order.split(' '); - var name = elements[0]; - var direction = elements[1] || 'asc'; - var value = lastDto[name]; - if (index === i) { - if (direction === 'asc') - subFilter = subFilter.and(table[name].greaterThan(value)); - else - subFilter = subFilter.and(table[name].lessThan(value)); - } else - subFilter = subFilter.and(table[name].eq(value)); - } - return subFilter; - } - - return filter; -} - - - -module.exports = createBatchFilter; diff --git a/src/table/relatedTable/aggregate.js b/src/table/relatedTable/aggregate.js index b8ff1582..13b83fe0 100644 --- a/src/table/relatedTable/aggregate.js +++ b/src/table/relatedTable/aggregate.js @@ -1,10 +1,9 @@ -let newRelatedTable = _newRelatedTable; let tryGetSessionContext = require('../tryGetSessionContext'); function newAggregate(_relations) { - function aggregate(fn) { - const includeMany = tryGetSessionContext()?.engine === 'mssql'; + function aggregate(context, fn) { + const includeMany = tryGetSessionContext(context)?.engine === 'mssql'; let { relations, alias } = extract(includeMany, _relations); const table = relations[relations.length - 1].childTable; if (!relations[0].isMany || includeMany) @@ -40,9 +39,4 @@ function newAggregate(_relations) { } -function _newRelatedTable() { - newRelatedTable = require('../newRelatedTable'); - return newRelatedTable.apply(null, arguments); -} - module.exports = newAggregate; \ No newline at end of file diff --git a/src/table/relatedTable/all.js b/src/table/relatedTable/all.js index b4ebb3bd..82aa8e86 100644 --- a/src/table/relatedTable/all.js +++ b/src/table/relatedTable/all.js @@ -1,24 +1,18 @@ -let newRelatedTable = _newRelatedTable; const negotiateRawSqlFilter = require('../column/negotiateRawSqlFilter'); let subFilter = require('./subFilter'); let isShallow = true; -function newAll(relations, depth) { +function newAll(newRelatedTable, relations, depth) { - function all(fn) { + function all(context, fn) { let relatedTable = newRelatedTable(relations, isShallow, depth + 1); let arg = typeof fn === 'function' ? fn(relatedTable) : fn; - let anyFilter = negotiateRawSqlFilter(arg); - let anySubFilter = subFilter(relations, anyFilter, depth); - let notFilter = subFilter(relations, anyFilter.not(), depth).not(); - return anySubFilter.and(notFilter); + let anyFilter = negotiateRawSqlFilter(context, arg); + let anySubFilter = subFilter(context, relations, anyFilter, depth); + let notFilter = subFilter(context, relations, anyFilter.not(), depth).not(); + return anySubFilter.and(context, notFilter); } return all; } -function _newRelatedTable() { - newRelatedTable = require('../newRelatedTable'); - return newRelatedTable.apply(null, arguments); -} - module.exports = newAll; \ No newline at end of file diff --git a/src/table/relatedTable/any.js b/src/table/relatedTable/any.js index b9cc0147..737a700b 100644 --- a/src/table/relatedTable/any.js +++ b/src/table/relatedTable/any.js @@ -1,26 +1,19 @@ -let newRelatedTable = _newRelatedTable; const negotiateRawSqlFilter = require('../column/negotiateRawSqlFilter'); -// let subFilter = require('./subFilterAny'); let subFilter = require('./subFilter'); let isShallow = true; -function newAny(relations, depth) { +function newAny(newRelatedTable, relations, depth) { - function any(fn) { + function any(context, fn) { let relatedTable = newRelatedTable(relations, isShallow, depth + 1); let arg = typeof fn === 'function' ? fn(relatedTable) : fn; - let filter = negotiateRawSqlFilter(arg); - let sub = subFilter(relations, filter, depth); + let filter = negotiateRawSqlFilter(context, arg); + let sub = subFilter(context, relations, filter, depth); return sub; } return any; } -function _newRelatedTable() { - newRelatedTable = require('../newRelatedTable'); - return newRelatedTable.apply(null, arguments); -} - module.exports = newAny; // diff --git a/src/table/relatedTable/childColumn.js b/src/table/relatedTable/childColumn.js index 3f025dcd..ee3b0fce 100644 --- a/src/table/relatedTable/childColumn.js +++ b/src/table/relatedTable/childColumn.js @@ -5,16 +5,16 @@ const getSessionSingleton = require('../getSessionSingleton'); const _quote = require('../quote'); -function childColumn(column, relations) { - const quote = getSessionSingleton('quote'); - const context = getSessionContext(); - const outerAlias = 'y' + context.aggregateCount++; +function childColumn(context, column, relations) { + const quote = getSessionSingleton(context, 'quote'); + const rdb = getSessionContext(context); + const outerAlias = 'y' + rdb.aggregateCount++; const outerAliasQuoted = quote(outerAlias); const alias = 'x' + relations.length; - const foreignKeys = getForeignKeys(relations[0]); + const foreignKeys = getForeignKeys(context, relations[0]); const select = ` LEFT JOIN (SELECT ${foreignKeys},${alias}.${quote(column._dbName)} as prop`; - const innerJoin = relations.length > 1 ? newJoin(relations).sql() : ''; - const onClause = createOnClause(relations[0], outerAlias); + const innerJoin = relations.length > 1 ? newJoin(context, relations).sql() : ''; + const onClause = createOnClause(context, relations[0], outerAlias); const from = ` FROM ${quote(relations.at(-1).childTable._dbName)} ${alias} ${innerJoin}) ${outerAliasQuoted} ON (${onClause})`; const join = select + from ; @@ -26,13 +26,13 @@ function childColumn(column, relations) { }; } -function createOnClause(relation, rightAlias) { +function createOnClause(context, relation, rightAlias) { var c = {}; var sql = ''; let leftAlias = relation.parentTable._rootAlias || relation.parentTable._dbName; c.visitJoin = function(relation) { - sql = newJoinCore(relation.childTable,relation.columns,relation.childTable._primaryColumns,leftAlias,rightAlias).sql(); + sql = newJoinCore(context, relation.childTable,relation.columns,relation.childTable._primaryColumns,leftAlias,rightAlias).sql(); }; c.visitOne = function(relation) { @@ -47,20 +47,20 @@ function createOnClause(relation, rightAlias) { var parentTable = relation.parentTable; var columns = joinRelation.columns; - sql = newJoinCore(childTable,parentTable._primaryColumns,columns,leftAlias, rightAlias).sql(); + sql = newJoinCore(context, childTable,parentTable._primaryColumns,columns,leftAlias, rightAlias).sql(); } relation.accept(c); return sql; } -function getForeignKeys(relation) { +function getForeignKeys(context, relation) { let columns; let alias = 'x1'; if (relation.joinRelation) columns = relation.joinRelation.columns; else columns = relation.childTable._primaryColumns; - return columns.map(x => `${alias}.${_quote(x._dbName)}`).join(','); + return columns.map(x => `${alias}.${_quote(context, x._dbName)}`).join(','); } module.exports = childColumn; \ No newline at end of file diff --git a/src/table/relatedTable/columnAggregate.js b/src/table/relatedTable/columnAggregate.js index 60b16bb2..1c532c3b 100644 --- a/src/table/relatedTable/columnAggregate.js +++ b/src/table/relatedTable/columnAggregate.js @@ -1,8 +1,8 @@ const getSessionSingleton = require('../getSessionSingleton'); var newJoinArray = require('./joinSqlArray'); -function columnAggregate(operator, column, relations, coalesce = true) { - const quote = getSessionSingleton('quote'); +function columnAggregate(context, operator, column, relations, coalesce = true) { + const quote = getSessionSingleton(context, 'quote'); let tableAlias = relations.reduce((prev,relation) => { return prev + relation.toLeg().name; @@ -13,7 +13,7 @@ function columnAggregate(operator, column, relations, coalesce = true) { return { expression: (alias) => coalesce ? `COALESCE(${operator}(${tableAlias}.${columnName}), 0) as ${quote(alias)}` : `${operator}(${tableAlias}.${columnName}) as ${alias}`, - joins: newJoinArray(relations) + joins: newJoinArray(context, relations) }; } diff --git a/src/table/relatedTable/columnAggregateGroup.js b/src/table/relatedTable/columnAggregateGroup.js index 6431cf94..80662e6f 100644 --- a/src/table/relatedTable/columnAggregateGroup.js +++ b/src/table/relatedTable/columnAggregateGroup.js @@ -3,21 +3,21 @@ var getSessionContext = require('../getSessionContext'); var newJoinCore = require('../query/singleQuery/joinSql/newShallowJoinSqlCore'); const getSessionSingleton = require('../getSessionSingleton'); -function columnAggregate(operator, column, relations, coalesce = true) { - const quote = getSessionSingleton('quote'); - const context = getSessionContext(); - const outerAlias = 'y' + context.aggregateCount++; +function columnAggregate(context, operator, column, relations, coalesce = true) { + const quote = getSessionSingleton(context, 'quote'); + const rdb = getSessionContext(context); + const outerAlias = 'y' + rdb.aggregateCount++; const outerAliasQuoted = quote(outerAlias); const alias = quote('x' + relations.length); const foreignKeys = getForeignKeys(relations[0]); const select = ` LEFT JOIN (SELECT ${foreignKeys},${operator}(${alias}.${quote(column._dbName)}) as amount`; - const innerJoin = relations.length > 1 ? newJoin(relations).sql() : ''; - const onClause = createOnClause(relations[0], outerAlias); + const innerJoin = relations.length > 1 ? newJoin(context, relations).sql() : ''; + const onClause = createOnClause(context, relations[0], outerAlias); const from = ` FROM ${quote(relations.at(-1).childTable._dbName)} ${alias} ${innerJoin} GROUP BY ${foreignKeys}) ${outerAliasQuoted} ON (${onClause})`; - const join = select + from ; + const join = select + from; return { - expression: (alias) => coalesce? `COALESCE(${outerAliasQuoted}.amount, 0) as ${quote(alias)}` : `${outerAliasQuoted}.amount as ${alias}`, + expression: (alias) => coalesce ? `COALESCE(${outerAliasQuoted}.amount, 0) as ${quote(alias)}` : `${outerAliasQuoted}.amount as ${alias}`, joins: [join] }; @@ -32,13 +32,13 @@ function columnAggregate(operator, column, relations, coalesce = true) { } } -function createOnClause(relation, rightAlias) { +function createOnClause(context, relation, rightAlias) { var c = {}; var sql = ''; let leftAlias = relation.parentTable._rootAlias || relation.parentTable._dbName; c.visitJoin = function(relation) { - sql = newJoinCore(relation.childTable,relation.columns,relation.childTable._primaryColumns,leftAlias,rightAlias).sql(); + sql = newJoinCore(context, relation.childTable, relation.columns, relation.childTable._primaryColumns, leftAlias, rightAlias).sql(); }; c.visitOne = function(relation) { @@ -53,7 +53,7 @@ function createOnClause(relation, rightAlias) { var parentTable = relation.parentTable; var columns = joinRelation.columns; - sql = newJoinCore(childTable,parentTable._primaryColumns,columns,leftAlias, rightAlias).sql(); + sql = newJoinCore(context, childTable, parentTable._primaryColumns, columns, leftAlias, rightAlias).sql(); } relation.accept(c); diff --git a/src/table/relatedTable/joinSql.js b/src/table/relatedTable/joinSql.js index f311389a..9f525739 100644 --- a/src/table/relatedTable/joinSql.js +++ b/src/table/relatedTable/joinSql.js @@ -1,7 +1,7 @@ var newShallowJoinSql = require('../query/singleQuery/joinSql/newShallowJoinSql'); var newParameterized = require('../query/newParameterized'); -function newJoinSql(relations, depth = 0) { +function newJoinSql(context, relations, depth = 0) { var leftAlias, rightAlias; var relation; @@ -10,7 +10,7 @@ function newJoinSql(relations, depth = 0) { c.visitJoin = function(relation) { //todo fix discriminators on childTable - sql = newShallowJoinSql(relation.parentTable,relation.childTable._primaryColumns,relation.columns,leftAlias,rightAlias).prepend(' INNER').prepend(sql); + sql = newShallowJoinSql(context, relation.parentTable, relation.childTable._primaryColumns, relation.columns, leftAlias, rightAlias).prepend(' INNER').prepend(sql); }; c.visitOne = function(relation) { @@ -25,11 +25,11 @@ function newJoinSql(relations, depth = 0) { var rightColumns = table._primaryColumns; var leftColumns = joinRelation.columns; - sql = newShallowJoinSql(table,leftColumns,rightColumns,leftAlias,rightAlias).prepend(' INNER').prepend(sql); + sql = newShallowJoinSql(context, table, leftColumns, rightColumns, leftAlias, rightAlias).prepend(' INNER').prepend(sql); } - for (let i = relations.length-1; i > depth; i--) { - leftAlias = 'x' + (i+1); + for (let i = relations.length - 1; i > depth; i--) { + leftAlias = 'x' + (i + 1); rightAlias = 'x' + i; relation = relations[i]; relation.accept(c); diff --git a/src/table/relatedTable/joinSqlArray.js b/src/table/relatedTable/joinSqlArray.js index 5f6448be..624c3c0b 100644 --- a/src/table/relatedTable/joinSqlArray.js +++ b/src/table/relatedTable/joinSqlArray.js @@ -1,6 +1,6 @@ const newShallowJoinSql = require('../query/singleQuery/joinSql/newShallowJoinSql'); -function _new(relations) { +function _new(context, relations) { let result = []; let leftAlias = relations[0].parentTable._dbName; @@ -10,11 +10,11 @@ function _new(relations) { let c = {}; c.visitJoin = function(relation) { - sql = newShallowJoinSql(relation.childTable,relation.columns,relation.childTable._primaryColumns,leftAlias,rightAlias).prepend(' LEFT').sql(); + sql = newShallowJoinSql(context, relation.childTable,relation.columns,relation.childTable._primaryColumns,leftAlias,rightAlias).prepend(' LEFT').sql(); }; c.visitOne = function(relation) { - sql = newShallowJoinSql(relation.childTable,relation.parentTable._primaryColumns,relation.joinRelation.columns,leftAlias,rightAlias).prepend(' LEFT').sql(); + sql = newShallowJoinSql(context, relation.childTable,relation.parentTable._primaryColumns,relation.joinRelation.columns,leftAlias,rightAlias).prepend(' LEFT').sql(); }; c.visitMany = c.visitOne; diff --git a/src/table/relatedTable/none.js b/src/table/relatedTable/none.js index 297dc5e3..4449d905 100644 --- a/src/table/relatedTable/none.js +++ b/src/table/relatedTable/none.js @@ -1,22 +1,16 @@ -let newRelatedTable = _newRelatedTable; const negotiateRawSqlFilter = require('../column/negotiateRawSqlFilter'); let subFilter = require('./subFilter'); let isShallow = true; -function newNone(relations, depth) { +function newNone(newRelatedTable, relations, depth) { - function none(fn) { + function none(context, fn) { let relatedTable = newRelatedTable(relations, isShallow, depth + 1); let arg = typeof fn === 'function' ? fn(relatedTable) : fn; - let filter = negotiateRawSqlFilter(arg); - return subFilter(relations, filter, depth).not(); + let filter = negotiateRawSqlFilter(context, arg); + return subFilter(context, relations, filter, depth).not(); } return none; } -function _newRelatedTable() { - newRelatedTable = require('../newRelatedTable'); - return newRelatedTable.apply(null, arguments); -} - module.exports = newNone; \ No newline at end of file diff --git a/src/table/relatedTable/relatedColumn.js b/src/table/relatedTable/relatedColumn.js index 33a8a84e..f641c5a9 100644 --- a/src/table/relatedTable/relatedColumn.js +++ b/src/table/relatedTable/relatedColumn.js @@ -14,24 +14,24 @@ function newRelatedColumn(column, relations, isShallow, depth) { c[propName] = wrapFilter(prop); } - c.groupSum = aggregateGroup.bind(null, 'sum', column, relations); - c.groupAvg = aggregateGroup.bind(null, 'avg', column, relations); - c.groupMin = aggregateGroup.bind(null, 'min', column, relations); - c.groupMax = aggregateGroup.bind(null, 'max', column, relations); - c.groupCount = aggregateGroup.bind(null, 'count', column, relations, false); - c.sum = aggregate.bind(null, 'sum', column, relations); - c.avg = aggregate.bind(null, 'avg', column, relations); - c.min = aggregate.bind(null, 'min', column, relations); - c.max = aggregate.bind(null, 'max', column, relations); - c.count = aggregate.bind(null, 'count', column, relations, false); - c.self = childColumn.bind(null, column, relations); + c.groupSum = (context, ...rest) => aggregateGroup.apply(null, [context, 'sum', column, relations, ...rest]); + c.groupAvg = (context, ...rest) => aggregateGroup.apply(null, [context, 'avg', column, relations, ...rest]); + c.groupMin = (context, ...rest) => aggregateGroup.apply(null, [context, 'min', column, relations, ...rest]); + c.groupMax = (context, ...rest) => aggregateGroup.apply(null, [context, 'max', column, relations, ...rest]); + c.groupCount = (context, ...rest) => aggregateGroup.apply(null, [context, 'count', column, relations, false, ...rest]); + c.sum = (context, ...rest) => aggregate.apply(null, [context, 'sum', column, relations, ...rest]); + c.avg = (context, ...rest) => aggregate.apply(null, [context, 'avg', column, relations, ...rest]); + c.min = (context, ...rest) => aggregate.apply(null, [context, 'min', column, relations, ...rest]); + c.max = (context, ...rest) => aggregate.apply(null, [context, 'max', column, relations, ...rest]); + c.count = (context, ...rest) => aggregate.apply(null, [context, 'count', column, relations, false, ...rest]); + c.self = (context, ...rest) => childColumn.apply(null, [context, column, relations, ...rest]); return c; function wrapFilter(filter) { return runFilter; - function runFilter() { + function runFilter(context) { var args = []; for (var i = 0; i < arguments.length; i++) { args.push(arguments[i]); @@ -40,7 +40,7 @@ function newRelatedColumn(column, relations, isShallow, depth) { var shallowFilter = filter.apply(null, args); if (isShallow) return shallowFilter; - return newSubFilter(relations, shallowFilter, depth); + return newSubFilter(context, relations, shallowFilter, depth); } } diff --git a/src/table/relatedTable/selectSql.js b/src/table/relatedTable/selectSql.js index f593297c..fdd1f9d2 100644 --- a/src/table/relatedTable/selectSql.js +++ b/src/table/relatedTable/selectSql.js @@ -2,8 +2,8 @@ var newParameterized = require('../query/newParameterized'); var newBoolean = require('../column/newBoolean'); const getSessionSingleton = require('../getSessionSingleton'); -function newSelectSql(table, alias) { - const quote = getSessionSingleton('quote'); +function newSelectSql(context, table, alias) { + const quote = getSessionSingleton(context, 'quote'); const quotedAlias = quote(alias); const colName = quote(table._primaryColumns[0]._dbName); const sql = 'SELECT ' + quotedAlias + '.' + colName + ' FROM ' + quote(table._dbName) + ' ' + quotedAlias; diff --git a/src/table/relatedTable/subFilter.js b/src/table/relatedTable/subFilter.js index 2eb3cfb6..8b759de1 100644 --- a/src/table/relatedTable/subFilter.js +++ b/src/table/relatedTable/subFilter.js @@ -2,13 +2,13 @@ var newSelect = require('./selectSql'); var newJoin = require('./joinSql'); var newWhere = require('./whereSql'); -function newSubFilter(relations, shallowFilter, depth) { +function newSubFilter(context, relations, shallowFilter, depth) { var relationCount = relations.length; var alias = 'x' + relationCount; var table = relations[relationCount-1].childTable; - var exists = newSelect(table,alias).prepend('EXISTS ('); - var join = newJoin(relations, depth); - var where = newWhere(relations,shallowFilter, depth); + var exists = newSelect(context, table,alias).prepend('EXISTS ('); + var join = newJoin(context, relations, depth); + var where = newWhere(context, relations,shallowFilter, depth); return exists.append(join).append(where).append(')'); } diff --git a/src/table/relatedTable/where.js b/src/table/relatedTable/where.js index 61a9f6ff..f1a7ac5d 100644 --- a/src/table/relatedTable/where.js +++ b/src/table/relatedTable/where.js @@ -1,11 +1,10 @@ -let newRelatedTable = _newRelatedTable; const negotiateRawSqlFilter = require('../column/negotiateRawSqlFilter'); let tryGetSessionContext = require('../tryGetSessionContext'); function newWhere(_relations, _depth) { - function where(fn) { - const includeMany = tryGetSessionContext()?.engine === 'mssql'; + function where(context, fn) { + const includeMany = tryGetSessionContext(context)?.engine === 'mssql'; let { relations, alias } = extract(includeMany, _relations); const table = relations[relations.length - 1].childTable; if (!relations[0].isMany || includeMany) @@ -13,7 +12,7 @@ function newWhere(_relations, _depth) { try { let arg = typeof fn === 'function' ? fn(table) : fn; - let anyFilter = negotiateRawSqlFilter(arg); + let anyFilter = negotiateRawSqlFilter(context, arg); delete table._rootAlias; return anyFilter; } @@ -42,9 +41,4 @@ function newWhere(_relations, _depth) { } -function _newRelatedTable() { - newRelatedTable = require('../newRelatedTable'); - return newRelatedTable.apply(null, arguments); -} - module.exports = newWhere; \ No newline at end of file diff --git a/src/table/relatedTable/whereSql.js b/src/table/relatedTable/whereSql.js index 0de2b772..93bd961f 100644 --- a/src/table/relatedTable/whereSql.js +++ b/src/table/relatedTable/whereSql.js @@ -1,6 +1,6 @@ var newShallowJoinSql = require('../query/singleQuery/joinSql/newShallowJoinSqlCore'); -function newWhereSql(relations, shallowFilter, depth = 0) { +function newWhereSql(context, relations, shallowFilter, depth = 0) { let relation = relations[depth]; var c = {}; var sql; @@ -29,7 +29,7 @@ function newWhereSql(relations, shallowFilter, depth = 0) { function where(alias, leftColumns, rightColumns) { var table = relation.childTable; - var joinCore = newShallowJoinSql(table, leftColumns, rightColumns, alias, 'x' + (depth + 1)); + var joinCore = newShallowJoinSql(context, table, leftColumns, rightColumns, alias, 'x' + (depth + 1)); if (shallowFilter && shallowFilter.sql()) { sql = joinCore.prepend(' WHERE ').append(' AND ').append(shallowFilter); } diff --git a/src/table/relation/manyCache/synchronizeAdded.js b/src/table/relation/manyCache/synchronizeAdded.js index b6abb82c..da6a41cf 100644 --- a/src/table/relation/manyCache/synchronizeAdded.js +++ b/src/table/relation/manyCache/synchronizeAdded.js @@ -1,8 +1,8 @@ var extractParentKey = require('./extractParentKey'); -function synchronizeAdded(action, joinRelation) { +function synchronizeAdded(context, action, joinRelation) { var cache = joinRelation.parentTable._cache; - cache.subscribeAdded(onAdded); + cache.subscribeAdded(context, onAdded); function onAdded(child) { var parent = extractParentKey(joinRelation, child); diff --git a/src/table/relation/manyCache/synchronizeChanged.js b/src/table/relation/manyCache/synchronizeChanged.js index d22fb277..caac7c1f 100644 --- a/src/table/relation/manyCache/synchronizeChanged.js +++ b/src/table/relation/manyCache/synchronizeChanged.js @@ -1,6 +1,6 @@ var extractParentKey = require('./extractParentKey'); -function synchronizeChanged(manyCache, joinRelation, parent, child) { +function synchronizeChanged(context, manyCache, joinRelation, parent, child) { var columns = joinRelation.columns; columns.forEach(subscribeColumn); child = null; @@ -19,9 +19,9 @@ function synchronizeChanged(manyCache, joinRelation, parent, child) { function onChanged(child) { unsubscribe(child); - manyCache.tryRemove(parent, child); + manyCache.tryRemove(context, parent, child); var newParent = extractParentKey(joinRelation, child); - manyCache.tryAdd(newParent, child); + manyCache.tryAdd(context, newParent, child); } diff --git a/src/table/relation/manyCache/synchronizeRemoved.js b/src/table/relation/manyCache/synchronizeRemoved.js index 1265774b..d8adefaf 100644 --- a/src/table/relation/manyCache/synchronizeRemoved.js +++ b/src/table/relation/manyCache/synchronizeRemoved.js @@ -1,8 +1,8 @@ var extractParentKey = require('./extractParentKey'); -function synchronizeRemoved(action, joinRelation) { +function synchronizeRemoved(context, action, joinRelation) { var cache = joinRelation.parentTable._cache; - cache.subscribeRemoved(onRemoved); + cache.subscribeRemoved(context, onRemoved); function onRemoved(child) { var parent = extractParentKey(joinRelation, child); diff --git a/src/table/relation/newForeignKeyFilter.js b/src/table/relation/newForeignKeyFilter.js index f5d4f164..d629de3f 100644 --- a/src/table/relation/newForeignKeyFilter.js +++ b/src/table/relation/newForeignKeyFilter.js @@ -1,4 +1,4 @@ -function newForeignKeyFilter(joinRelation, parentRow) { +function newForeignKeyFilter(context, joinRelation, parentRow) { var columns = joinRelation.columns; var rightTable = joinRelation.childTable; @@ -12,7 +12,7 @@ function newForeignKeyFilter(joinRelation, parentRow) { function getNextFilterPart(index) { var column = columns[index]; var pk = rightTable._primaryColumns[index]; - return column.eq(parentRow[pk.alias]); + return column.eq(context, parentRow[pk.alias]); } return filter; } diff --git a/src/table/relation/newManyCache.js b/src/table/relation/newManyCache.js index 9690991b..2c446405 100644 --- a/src/table/relation/newManyCache.js +++ b/src/table/relation/newManyCache.js @@ -9,46 +9,54 @@ var setSessionSingleton = require('../setSessionSingleton'); function newManyCache(joinRelation) { var c = {}; - var key = newId(); + var key; - c.tryAdd = function(parent, child) { - c.getInnerCache().tryAdd(parent, child); - synchronizeChanged(c, joinRelation, parent, child); + c.tryAdd = function(context, parent, child) { + c.getInnerCache(context).tryAdd(parent, child); + synchronizeChanged(context, c, joinRelation, parent, child); }; - c.tryRemove = function(parent, child) { - c.getInnerCache().tryRemove(parent, child); + c.tryRemove = function(context, parent, child) { + c.getInnerCache(context).tryRemove(parent, child); }; - c.tryGet = function(parentRow) { - return c.getInnerCache().tryGet(parentRow); + c.tryGet = function(context, parentRow) { + return c.getInnerCache(context).tryGet(parentRow); }; - c.getInnerCache = function() { - var cache = getSessionSingleton(key); + c.getInnerCache = function(context) { + const theKey = negotiateKey(); + var cache = getSessionSingleton(context, theKey); if (!cache) { cache = newCacheCore(joinRelation); - setSessionSingleton(key, cache); - fillCache(); - synchronizeAdded(c.tryAdd, joinRelation); - synchronizeRemoved(c.tryRemove, joinRelation); + setSessionSingleton(context, theKey, cache); + fillCache(context); + synchronizeAdded(context, c.tryAdd.bind(null, context), joinRelation); + synchronizeRemoved(context, c.tryRemove.bind(null, context), joinRelation); } return cache; }; - function fillCache() { + function fillCache(context) { var childTable = joinRelation.parentTable; var childCache = childTable._cache; - var children = childCache.getAll(); + var children = childCache.getAll(context); children.forEach(addToCache); function addToCache(child) { var parent = extractParentKey(joinRelation, child); - c.tryAdd(parent, child); + c.tryAdd(context, parent, child); } } + function negotiateKey() { + if (key) + return key; + key = newId(); + return key; + + } return c; diff --git a/src/table/relation/newOneCache.js b/src/table/relation/newOneCache.js index c9f428ff..a6866eb9 100644 --- a/src/table/relation/newOneCache.js +++ b/src/table/relation/newOneCache.js @@ -4,18 +4,18 @@ function newOneCache(joinRelation) { let c = {}; let cache = newManyCache(joinRelation); - c.tryGet = function(parent) { - let res = cache.tryGet(parent); + c.tryGet = function(context, parent) { + let res = cache.tryGet(context, parent); if (res.length === 0) return null; return res[0]; }; - c.getInnerCache = function() { - let _cache = cache.getInnerCache(); + c.getInnerCache = function(context) { + let _cache = cache.getInnerCache(context); let _c = {}; - _c.tryGet = function(parent) { - let res = _cache.tryGet(parent); + _c.tryGet = function(context, parent) { + let res = _cache.tryGet(context, parent); if (res.length === 0) return null; return res[0]; diff --git a/src/table/releaseDbClient.js b/src/table/releaseDbClient.js index 2005ca59..a93d958c 100644 --- a/src/table/releaseDbClient.js +++ b/src/table/releaseDbClient.js @@ -1,10 +1,10 @@ var getSessionSingleton = require('./getSessionSingleton'); var deleteSessionContext = require('./deleteSessionContext'); -function release() { - var done = getSessionSingleton('dbClientDone'); - var pool = getSessionSingleton('pool'); - deleteSessionContext(); +function release(context) { + var done = getSessionSingleton(context, 'dbClientDone'); + var pool = getSessionSingleton(context, 'pool'); + deleteSessionContext(context); if (done) done(); if (pool) diff --git a/src/table/resultToPromise.js b/src/table/resultToPromise.js index 9221b72c..7c6a2edc 100644 --- a/src/table/resultToPromise.js +++ b/src/table/resultToPromise.js @@ -1,8 +1,6 @@ -var deferred = require('deferred'); - function resultToPromise(result) { - return deferred.resolve(result); + return Promise.resolve(result); } module.exports = resultToPromise; \ No newline at end of file diff --git a/src/table/resultToRows.js b/src/table/resultToRows.js index 97644155..a271f10c 100644 --- a/src/table/resultToRows.js +++ b/src/table/resultToRows.js @@ -1,12 +1,12 @@ var dbRowsToRows = require('./resultToRows/dbRowsToRows'); -async function resultToRows(span,result) { +async function resultToRows(context, span, result) { let rows = await result[0].then(onResult); await expand(spanToStrategy(span), rows); return rows; function onResult(result) { - return dbRowsToRows(span,result); + return dbRowsToRows(context, span, result); } } @@ -15,7 +15,7 @@ async function expand(strategy, rows) { return; if (!Array.isArray(rows)) rows = [rows]; - for(let p in strategy) { + for (let p in strategy) { if (!(strategy[p] === null || strategy[p])) continue; for (let i = 0; i < rows.length; i++) { diff --git a/src/table/resultToRows/dbRowToRow.js b/src/table/resultToRows/dbRowToRow.js index 9a0f0866..b07b9fd2 100644 --- a/src/table/resultToRows/dbRowToRow.js +++ b/src/table/resultToRows/dbRowToRow.js @@ -1,13 +1,11 @@ var negotiateQueryContext = require('./negotiateQueryContext'); var decodeDbRow = require('./decodeDbRow'); -var nextDbRowToRow = _nextDbRowToRow; - -function dbRowToRow(span, dbRow) { +function dbRowToRow(context, span, dbRow) { var table = span.table; - var row = decodeDbRow(span, table, dbRow); + var row = decodeDbRow(context, span, table, dbRow); var cache = table._cache; - if (!cache.tryGet(row)) { + if (!cache.tryGet(context, row)) { var queryContext = span.queryContext; negotiateQueryContext(queryContext, row); Object.defineProperty(row, 'queryContext', { @@ -17,17 +15,17 @@ function dbRowToRow(span, dbRow) { }); row.queryContext = queryContext; } - row = cache.tryAdd(row); + row = cache.tryAdd(context, row); var c = {}; c.visitOne = function(leg) { - nextDbRowToRow(leg.span, dbRow); + dbRowToRow(context, leg.span, dbRow); leg.expand(row); }; c.visitJoin = function(leg) { - nextDbRowToRow(leg.span, dbRow); + dbRowToRow(context, leg.span, dbRow); leg.expand(row); }; @@ -43,9 +41,4 @@ function dbRowToRow(span, dbRow) { return row; } -function _nextDbRowToRow(span, dbRow) { - nextDbRowToRow = require('./dbRowToRow'); - nextDbRowToRow(span, dbRow); -} - module.exports = dbRowToRow; \ No newline at end of file diff --git a/src/table/resultToRows/dbRowsToRows.js b/src/table/resultToRows/dbRowsToRows.js index 63f2ea1c..82819882 100644 --- a/src/table/resultToRows/dbRowsToRows.js +++ b/src/table/resultToRows/dbRowsToRows.js @@ -1,10 +1,10 @@ var dbRowToRow = require('./dbRowToRow'); var newRowArray = require('../rowArray'); -function dbRowsToRows(span, dbRows) { +function dbRowsToRows(context, span, dbRows) { var rows = newRowArray(); for (var i = 0; i < dbRows.length; i++) { - var row = dbRowToRow(span, dbRows[i]); + var row = dbRowToRow(context, span, dbRows[i]); rows.push(row); } return rows; diff --git a/src/table/resultToRows/decodeDbRow.js b/src/table/resultToRows/decodeDbRow.js index 1257465d..9ff98e84 100644 --- a/src/table/resultToRows/decodeDbRow.js +++ b/src/table/resultToRows/decodeDbRow.js @@ -1,6 +1,6 @@ var newDecodeDbRow = require('./newDecodeDbRow'); -function decodeDbRow(span, table, dbRow, shouldValidate, isInsert) { +function decodeDbRow(context, span, table, dbRow, shouldValidate, isInsert) { var decode = span._decodeDbRow; if (!decode) { let aliases = new Set(); @@ -19,7 +19,7 @@ function decodeDbRow(span, table, dbRow, shouldValidate, isInsert) { }, }); } - return decode(dbRow); + return decode(context, dbRow); } module.exports = decodeDbRow; diff --git a/src/table/resultToRows/delete.js b/src/table/resultToRows/delete.js index 61e88995..f3478b7a 100644 --- a/src/table/resultToRows/delete.js +++ b/src/table/resultToRows/delete.js @@ -5,25 +5,25 @@ var newPrimaryKeyFilter = require('../newPrimaryKeyFilter'); var createPatch = require('../../client/createPatch'); var createDto = require('./toDto/createDto'); -function _delete(row, strategy, table) { +function _delete(context, row, strategy, table) { var relations = []; - removeFromCache(row, strategy, table); + removeFromCache(context, row, strategy, table); - var args = [table]; + var args = [context, table]; table._primaryColumns.forEach(function(primary) { args.push(row[primary.alias]); }); var filter = newPrimaryKeyFilter.apply(null, args); - var cmds = newDeleteCommand([], table, filter, strategy, relations); + var cmds = newDeleteCommand(context, [], table, filter, strategy, relations); cmds.forEach(function(cmd) { - pushCommand(cmd); + pushCommand(context, cmd); }); var cmd = cmds[0]; if (table._emitChanged.callbacks.length > 0) { cmd.disallowCompress = true; var dto = createDto(table, row); let patch = createPatch([dto],[]); - cmd.emitChanged = table._emitChanged.bind(null, {row: row, patch: patch}); + cmd.emitChanged = table._emitChanged.bind(null, {row: row, patch: patch}); //todo remove ? } } diff --git a/src/table/resultToRows/delete/removeFromCache.js b/src/table/resultToRows/delete/removeFromCache.js index bba7db58..ab744388 100644 --- a/src/table/resultToRows/delete/removeFromCache.js +++ b/src/table/resultToRows/delete/removeFromCache.js @@ -1,6 +1,4 @@ -var nextRemoveFromCache = _nextRemoveFromCache; - -function removeFromCache(row, strategy, table) { +function removeFromCache(context, row, strategy, table) { if (Array.isArray(row)) { removeManyRows(); return; @@ -10,7 +8,7 @@ function removeFromCache(row, strategy, table) { function removeManyRows() { row.forEach( function(rowToRemove) { - nextRemoveFromCache(rowToRemove, strategy, table); + removeFromCache(context, rowToRemove, strategy, table); }); } @@ -19,15 +17,10 @@ function removeFromCache(row, strategy, table) { for (var relationName in strategy) { var relation = relations[relationName]; var rows = relation.getRowsSync(row); - nextRemoveFromCache(rows, strategy[relationName], relation.childTable); + removeFromCache(context, rows, strategy[relationName], relation.childTable); } - table._cache.tryRemove(row); + table._cache.tryRemove(context, row); } } -function _nextRemoveFromCache(row, strategy, table) { - nextRemoveFromCache = require('./removeFromCache'); - nextRemoveFromCache(row, strategy, table); -} - module.exports = removeFromCache; \ No newline at end of file diff --git a/src/table/resultToRows/newDecodeDbRow.js b/src/table/resultToRows/newDecodeDbRow.js index 1809f06e..a6c0dc73 100644 --- a/src/table/resultToRows/newDecodeDbRow.js +++ b/src/table/resultToRows/newDecodeDbRow.js @@ -1,4 +1,3 @@ -let util = require('util'); let updateField = require('../updateField'); let newEmitEvent = require('../../emitEvent'); let extractStrategy = require('./toDto/extractStrategy'); @@ -51,7 +50,7 @@ function newDecodeDbRow(table, dbRow, filteredAliases, shouldValidate, isInsert) this._dbRow[key] = value; if (column.validate) column.validate(value, this._dbRow); - updateField(table, column, this); + updateField(this._context, table, column, this); let emit = this._emitColumnChanged[name]; if (emit) emit(this, column, value, oldValue); @@ -114,8 +113,8 @@ function newDecodeDbRow(table, dbRow, filteredAliases, shouldValidate, isInsert) let get = row._related[alias]; if (!get) { let relation = table._relations[alias]; - get = relation.toGetRelated(row); - row._relationCacheMap.set(relation, relation.getInnerCache()); + get = relation.toGetRelated(row._context, row); + row._relationCacheMap.set(relation, relation.getInnerCache(row._context)); row._related[alias] = get; } return get; @@ -144,8 +143,8 @@ function newDecodeDbRow(table, dbRow, filteredAliases, shouldValidate, isInsert) }; - Row.prototype.hydrate = function(dbRow) { - const engine = tryGetSessionContext()?.engine; + Row.prototype.hydrate = function(context, dbRow) { + const engine = tryGetSessionContext(context)?.engine; let i = offset; if (engine === 'sqlite') { const errorSeparator = '12345678-1234-1234-1234-123456789012'; @@ -153,14 +152,14 @@ function newDecodeDbRow(table, dbRow, filteredAliases, shouldValidate, isInsert) if (typeof dbRow[p] === 'string' && dbRow[p].indexOf(errorSeparator) === 0) throw new Error(dbRow[p].split(errorSeparator)[1]); let key = keys[i]; - this._dbRow[key] = columns[i].decode(dbRow[p]); + this._dbRow[key] = columns[i].decode(context, dbRow[p]); i++; } } else { for (let p in dbRow) { let key = keys[i]; - this._dbRow[key] = columns[i].decode(dbRow[p]); + this._dbRow[key] = columns[i].decode(context, dbRow[p]); i++; } } @@ -171,10 +170,10 @@ function newDecodeDbRow(table, dbRow, filteredAliases, shouldValidate, isInsert) strategy = extractStrategy(table); } strategy = purifyStrategy(table, strategy); - if (!tryGetSessionContext()) { - return toDto(strategy, table, this, new Set()); + if (!tryGetSessionContext(this._context)) { + return toDto(this._context, strategy, table, this, new Set()); } - let p = toDto(strategy, table, this); + let p = toDto(this._context, strategy, table, this); return Promise.resolve().then(() => p); }; @@ -189,37 +188,31 @@ function newDecodeDbRow(table, dbRow, filteredAliases, shouldValidate, isInsert) Row.prototype.delete = function(strategy) { strategy = extractDeleteStrategy(strategy); - _delete(this, strategy, table); + _delete(this._context, this, strategy, table); }; Row.prototype.cascadeDelete = function() { let strategy = newCascadeDeleteStrategy(newObject(), table); - _delete(this, strategy, table); + _delete(this._context, this, strategy, table); }; Row.prototype.deleteCascade = Row.prototype.cascadeDelete; Row.prototype.patch = async function(patches, options) { - await patchRow(table, this, patches, options); + await patchRow(this._context, table, this, patches, options); return this; }; - - Row.prototype[util.inspect.custom] = function() { - let dtos = toDto(undefined, table, this, new Set()); - return util.inspect(dtos, { compact: false, colors: true }); - }; - - function decodeDbRow(row) { + function decodeDbRow(context, row) { for (let i = 0; i < numberOfColumns; i++) { let index = offset + i; let key = keys[index]; if (row[key] !== undefined) - row[key] = columns[i].decode(row[key]); + row[key] = columns[i].decode(context, row[key]); if (shouldValidate && columns[i].validate) columns[i].validate(row[key], row, isInsert); } - let target = new Row(row); + let target = new Row(context, row); const p = new Proxy(target, { ownKeys: function() { return Array.from(aliases).concat(Object.keys(target._related).filter(alias => { @@ -245,9 +238,10 @@ function newDecodeDbRow(table, dbRow, filteredAliases, shouldValidate, isInsert) return value; } - function Row(dbRow) { + function Row(context, dbRow) { + this._context = context; this._relationCacheMap = new Map(); - this._cache = table._cache.getInnerCache(); + this._cache = table._cache.getInnerCache(context); this._dbRow = dbRow; this._related = {}; this._emitColumnChanged = {}; diff --git a/src/table/resultToRows/toDto.js b/src/table/resultToRows/toDto.js index eba6980a..d505fc14 100644 --- a/src/table/resultToRows/toDto.js +++ b/src/table/resultToRows/toDto.js @@ -1,11 +1,11 @@ let flags = require('../../flags'); let tryGetSessionContext = require('../tryGetSessionContext'); -function toDto(strategy, table, row, joinRelationSet) { +function toDto(context, strategy, table, row, joinRelationSet) { let result; flags.useProxy = false; - let context = tryGetSessionContext(); - let ignoreSerializable = context && context.ignoreSerializable; + let rdb = tryGetSessionContext(context); + let ignoreSerializable = rdb && rdb.ignoreSerializable; if (joinRelationSet) { result = toDtoSync(table, row, joinRelationSet, strategy, ignoreSerializable); } diff --git a/src/table/resultToRows/toDto/extractStrategy.js b/src/table/resultToRows/toDto/extractStrategy.js index 94c13615..2ae97b2d 100644 --- a/src/table/resultToRows/toDto/extractStrategy.js +++ b/src/table/resultToRows/toDto/extractStrategy.js @@ -1,5 +1,3 @@ -let extractSubStrategy = _extractSubStrategy; - //either.. //strategy, table //or.. @@ -21,7 +19,7 @@ function extractStrategy(_strategyOrTable, _optinonalTable) { visitor.visitJoin = function() { }; visitor.visitMany = function(relation) { - strategy[relationName] = extractSubStrategy(relation.childTable); + strategy[relationName] = extractStrategy(relation.childTable); }; visitor.visitOne = visitor.visitMany; @@ -33,9 +31,5 @@ function extractStrategy(_strategyOrTable, _optinonalTable) { return strategy; } -function _extractSubStrategy(table) { - extractSubStrategy = require('./extractStrategy'); - return extractSubStrategy(table); -} module.exports = extractStrategy; \ No newline at end of file diff --git a/src/table/rollback.js b/src/table/rollback.js index 8f26dc91..6c9e0fa4 100644 --- a/src/table/rollback.js +++ b/src/table/rollback.js @@ -5,27 +5,37 @@ const popChanges = require('./popChanges'); const newThrow = require('./newThrow'); const resultToPromise = require('./resultToPromise'); const conflictId = '12345678-1234-1234-1234-123456789012'; +const getSessionSingleton = require('./getSessionSingleton'); -function rollback(e) { - var executeRollback = executeQuery.bind(null, rollbackCommand); +function _rollback(context, e) { var chain = resultToPromise() - .then(popChanges) + .then(() => popChanges(context)) .then(executeRollback) - .then(releaseDbClient); + .then(() => releaseDbClient(context)); + + + function executeRollback() { + const transactionLess = getSessionSingleton(context, 'transactionLess'); + if (transactionLess) + return Promise.resolve(); + return executeQuery(context, rollbackCommand); + } if (e) { - if (e.message.indexOf('ORA-01476: divisor is equal to zero') > -1) - return newThrow(new Error('Conflict when updating a column'), chain); + if (e.message?.indexOf('ORA-01476: divisor is equal to zero') > -1) + return newThrow(context, new Error('Conflict when updating a column'), chain); let errors = e.message && e.message.split(conflictId) || []; if (errors.length > 1) { - return newThrow(new Error(errors[1]), chain); + return newThrow(context, new Error(errors[1]), chain); } else - return newThrow(e, chain); + return newThrow(context, e, chain); } return chain; } -module.exports = function(e) { - return Promise.resolve().then(() => rollback(e)); -}; \ No newline at end of file +function rollback(context, e) { + return Promise.resolve().then(() => _rollback(context, e)); +} + +module.exports = rollback; \ No newline at end of file diff --git a/src/table/rowArray/negotiateNextTick.js b/src/table/rowArray/negotiateNextTick.js index cfade6b6..c0d199a6 100644 --- a/src/table/rowArray/negotiateNextTick.js +++ b/src/table/rowArray/negotiateNextTick.js @@ -1,10 +1,9 @@ -var promise = require('promise/domains'); function negotiateNextTick(i) { if (i === 0) return; if (i % 1000 === 0) - return promise.resolve(); + return Promise.resolve(); return; } diff --git a/src/table/setSessionSingleton.js b/src/table/setSessionSingleton.js index efa29341..9979f8ce 100644 --- a/src/table/setSessionSingleton.js +++ b/src/table/setSessionSingleton.js @@ -1,5 +1,8 @@ var getSessionContext = require('./getSessionContext'); -module.exports = function(name, value) { - getSessionContext()[name] = value; -}; \ No newline at end of file +function setSessionSingleton(context, name, value) { + const rdb = getSessionContext(context); + rdb[name] = value; +} + +module.exports = setSessionSingleton; \ No newline at end of file diff --git a/src/table/tryGetFirstFromDb.js b/src/table/tryGetFirstFromDb.js index f5fbb75c..1a85d9bd 100644 --- a/src/table/tryGetFirstFromDb.js +++ b/src/table/tryGetFirstFromDb.js @@ -1,8 +1,8 @@ var getMany = require('./getMany'); -function tryGet(table, filter, strategy) { +function tryGet(context, table, filter, strategy) { strategy = setLimit(strategy); - return getMany(table, filter, strategy).then(filterRows); + return getMany(context, table, filter, strategy).then(filterRows); } function filterRows(rows) { @@ -11,9 +11,9 @@ function filterRows(rows) { return null; } -tryGet.exclusive = function(table, filter, strategy) { +tryGet.exclusive = function(context, table, filter, strategy) { strategy = setLimit(strategy); - return getMany.exclusive(table, filter, strategy).then(filterRows); + return getMany.exclusive(context, table, filter, strategy).then(filterRows); }; function setLimit(strategy) { diff --git a/src/table/tryGetFromCacheById.js b/src/table/tryGetFromCacheById.js index 9d6012c1..3db33cf9 100644 --- a/src/table/tryGetFromCacheById.js +++ b/src/table/tryGetFromCacheById.js @@ -1,12 +1,12 @@ -function tryGet(table) { +function tryGet(context, table) { var fakeRow = {}; var args = arguments; table._primaryColumns.forEach(addPkValue); function addPkValue(pkColumn, index){ - fakeRow[pkColumn.alias] = args[index + 1]; + fakeRow[pkColumn.alias] = args[index + 2]; } - return table._cache.tryGet(fakeRow); + return table._cache.tryGet(context, fakeRow); } module.exports = tryGet; \ No newline at end of file diff --git a/src/table/tryGetFromDbById.js b/src/table/tryGetFromDbById.js index 4f4d3c47..69c05b3c 100644 --- a/src/table/tryGetFromDbById.js +++ b/src/table/tryGetFromDbById.js @@ -2,18 +2,20 @@ var newPrimaryKeyFilter = require('./newPrimaryKeyFilter'); var tryGetFirstFromDb = require('./tryGetFirstFromDb'); var extractStrategy = require('./tryGetFromDbById/extractStrategy'); -function tryGet() { +function tryGet(context) { var filter = newPrimaryKeyFilter.apply(null, arguments); - var table = arguments[0]; + var table = arguments[1]; var strategy = extractStrategy.apply(null, arguments); - return tryGetFirstFromDb(table, filter, strategy); + return tryGetFirstFromDb(context, table, filter, strategy); } -tryGet.exclusive = function tryGet() { +tryGet.exclusive = function tryGet(context) { var filter = newPrimaryKeyFilter.apply(null, arguments); - var table = arguments[0]; + var table = arguments[1]; var strategy = extractStrategy.apply(null, arguments); - return tryGetFirstFromDb.exclusive(table, filter, strategy); + return tryGetFirstFromDb.exclusive(context, table, filter, strategy); + + }; module.exports = tryGet; diff --git a/src/table/tryGetFromDbById/extractStrategy.js b/src/table/tryGetFromDbById/extractStrategy.js index 560714de..c0635a42 100644 --- a/src/table/tryGetFromDbById/extractStrategy.js +++ b/src/table/tryGetFromDbById/extractStrategy.js @@ -1,6 +1,6 @@ -function extract(table) { - var lengthWithStrategy = table._primaryColumns.length + 2; +function extract(_context, table) { + var lengthWithStrategy = table._primaryColumns.length + 3; if (arguments.length === lengthWithStrategy) return arguments[lengthWithStrategy-1]; return; diff --git a/src/table/tryGetSessionContext.js b/src/table/tryGetSessionContext.js index 95ec5165..2fcbc59c 100644 --- a/src/table/tryGetSessionContext.js +++ b/src/table/tryGetSessionContext.js @@ -1,16 +1,6 @@ -let useHook = require('../useHook'); -let cls; - - -function tryGetSessionContext() { - if (useHook()) { - if (!cls) - cls = require('node-cls'); - let context = cls.getContext('rdb'); - return context && context.rdb; - } - else - return process.domain && process.domain.rdb; +function tryGetSessionContext(context) { + if (context) + return context.rdb; } module.exports = tryGetSessionContext; \ No newline at end of file diff --git a/src/table/tryReleaseDbClient.js b/src/table/tryReleaseDbClient.js index 0794d67b..35dca907 100644 --- a/src/table/tryReleaseDbClient.js +++ b/src/table/tryReleaseDbClient.js @@ -1,8 +1,8 @@ var release = require('./releaseDbClient'); -function tryReleaseDbClient() { +function tryReleaseDbClient(context) { try { - release(); + release(context); } // eslint-disable-next-line no-empty catch (e) { diff --git a/src/table/updateField.js b/src/table/updateField.js index a214a531..09ea3e6b 100644 --- a/src/table/updateField.js +++ b/src/table/updateField.js @@ -2,11 +2,11 @@ var newUpdateCommand = require('./commands/newUpdateCommand'); var pushCommand = require('./commands/pushCommand'); var lastCommandMatches = require('./commands/lastCommandMatches'); -function updateField(table, column, row, oldValue) { - if (lastCommandMatches(row)) +function updateField(context, table, column, row) { + if (lastCommandMatches(context, row)) return; - var command = newUpdateCommand(table, column, row, oldValue); - pushCommand(command); + var command = newUpdateCommand(context, table, column, row); + pushCommand(context, command); } module.exports = updateField; \ No newline at end of file diff --git a/src/table/where.js b/src/table/where.js index 1aea2878..190de921 100644 --- a/src/table/where.js +++ b/src/table/where.js @@ -2,9 +2,9 @@ const negotiateRawSqlFilter = require('./column/negotiateRawSqlFilter'); function newWhere(table) { - function where(fn) { + function where(context, fn) { let arg = typeof fn === 'function' ? fn(table) : fn; - return negotiateRawSqlFilter(arg); + return negotiateRawSqlFilter(context, arg); } return where; } diff --git a/src/tedious/deleteFromSql.js b/src/tedious/deleteFromSql.js index ed87d37e..e78dbfec 100644 --- a/src/tedious/deleteFromSql.js +++ b/src/tedious/deleteFromSql.js @@ -1,10 +1,10 @@ -var format = 'delete %s from %s as %s%s'; -var util = require('util'); -const quote = require('../table/quote'); +const format = 'delete %s from %s as %s%s'; +const formatString = require('../format'); +const quote = require('./quote'); function deleteFromSql(table, alias, whereSql) { - var name = quote(table._dbName); + const name = quote(table._dbName); alias = quote(alias); - return util.format(format, alias, name, alias, whereSql); + return formatString(format, alias, name, alias, whereSql); } module.exports = deleteFromSql; diff --git a/src/tedious/formatDateOut.js b/src/tedious/formatDateOut.js index 59457280..d54a0994 100644 --- a/src/tedious/formatDateOut.js +++ b/src/tedious/formatDateOut.js @@ -1,4 +1,4 @@ -const quote = require('../table/quote'); +const quote = require('./quote'); function formatDateOut(column, alias) { return `CONVERT(VARCHAR, ${alias}.${quote(column._dbName)}, 121)`; diff --git a/src/tedious/getManyDto.js b/src/tedious/getManyDto.js index d4cbbf81..78dce3b7 100644 --- a/src/tedious/getManyDto.js +++ b/src/tedious/getManyDto.js @@ -3,17 +3,17 @@ const negotiateRawSqlFilter = require('../table/column/negotiateRawSqlFilter'); const strategyToSpan = require('../table/strategyToSpan'); const executeQueries = require('../table/executeQueries'); -async function getManyDto(table, filter, strategy) { - filter = negotiateRawSqlFilter(filter, table); +async function getManyDto(context, table, filter, strategy) { + filter = negotiateRawSqlFilter(context, filter, table); if (strategy && strategy.where) { let arg = typeof strategy.where === 'function' ? strategy.where(table) : strategy.where; - filter = filter.and(arg); + filter = filter.and(context, arg); } - let span = strategyToSpan(table,strategy); + let span = strategyToSpan(table, strategy); let alias = table._dbName; - const query = newQuery(table, filter, span, alias); - const res = await executeQueries([query]); + const query = newQuery(context, table, filter, span, alias); + const res = await executeQueries(context, [query]); const rows = await res[0]; if (rows.length === 0) return []; diff --git a/src/tedious/getManyDto/newQueryCore.js b/src/tedious/getManyDto/newQueryCore.js index 28fb548b..b1ab9040 100644 --- a/src/tedious/getManyDto/newQueryCore.js +++ b/src/tedious/getManyDto/newQueryCore.js @@ -5,14 +5,14 @@ var extractOrderBy = require('../../table/query/extractOrderBy'); var extractLimit = require('../../table/query/extractLimit'); var limitAndOffset = require('../limitAndOffset'); -function newQuery(table,filter,span,alias) { +function newQuery(context, table, filter, span, alias) { filter = extractFilter(filter); - var orderBy = extractOrderBy(table,alias,span.orderBy); - var limit = extractLimit(span); + var orderBy = extractOrderBy(context, table, alias, span.orderBy); + var limit = extractLimit(context, span); var offset = limitAndOffset(span); - var subQueries = newSubQueries(table,span,alias); - return newSingleQuery(table,filter,span,alias,subQueries,orderBy,limit,offset); + var subQueries = newSubQueries(newQuery, context, table, span, alias); + return newSingleQuery(context, table, filter, span, alias, subQueries, orderBy, limit, offset); } module.exports = newQuery; \ No newline at end of file diff --git a/src/tedious/getManyDto/query/newSingleQuery.js b/src/tedious/getManyDto/query/newSingleQuery.js index e37c6e9c..947e360d 100644 --- a/src/tedious/getManyDto/query/newSingleQuery.js +++ b/src/tedious/getManyDto/query/newSingleQuery.js @@ -2,17 +2,17 @@ var newColumnSql = require('./singleQuery/newShallowColumnSql'); var newWhereSql = require('../../../table/query/singleQuery/newWhereSql'); var newParameterized = require('../../../table/query/newParameterized'); -function _new(table, filter, span, alias, subQueries, orderBy, limit, offset) { - var columnSql = newColumnSql(table, alias, span); - var whereSql = newWhereSql(table, filter, alias); +function _new(context, table, filter, span, alias, subQueries, orderBy, limit, offset) { + var columnSql = newColumnSql(context, table, alias, span); + var whereSql = newWhereSql(context, table, filter, alias); if (limit) limit = limit + ' '; let join = ''; const set = new Set(); - for(let key in span.aggregates) { + for (let key in span.aggregates) { const agg = span.aggregates[key]; - for(let sql of agg.joins) { + for (let sql of agg.joins) { if (!set.has(sql)) { join = join + sql; set.add(sql); diff --git a/src/tedious/getManyDto/query/newSubQueries.js b/src/tedious/getManyDto/query/newSubQueries.js index 9160144d..9c22ce35 100644 --- a/src/tedious/getManyDto/query/newSubQueries.js +++ b/src/tedious/getManyDto/query/newSubQueries.js @@ -1,26 +1,26 @@ -var joinLegToQuery = _joinLegToQuery; -var oneLegToQuery = _oneLegToQuery; -var manyLegToQuery = _manyLegToQuery; -var newParameterized = require('../../../table/query/newParameterized'); +const newParameterized = require('../../../table/query/newParameterized'); +const joinLegToQuery = require('./newSubQueries/joinLegToQuery'); +const oneLegToQuery = require('./newSubQueries/oneLegToQuery'); +const manyLegToQuery = require('./newSubQueries/manyLegToQuery'); -function newSubQueries(_table,span,alias) { +function newSubQueries(newQuery, context, _table, span, alias) { var result = newParameterized('', []); var c = {}; var _legNo; c.visitJoin = function(leg) { - result = result.append(',').append(joinLegToQuery( alias,leg,_legNo)); + result = result.append(',').append(joinLegToQuery(newQuery, context, alias, leg, _legNo)); }; c.visitOne = function(leg) { - result = result.append(',').append(oneLegToQuery( alias,leg,_legNo)); + result = result.append(',').append(oneLegToQuery(newQuery, context, alias, leg, _legNo)); }; c.visitMany = function(leg) { - result = result.append(',').append(manyLegToQuery( alias,leg,_legNo)); + result = result.append(',').append(manyLegToQuery(newQuery, context, alias, leg, _legNo)); }; span.legs.forEach(onEachLeg); - function onEachLeg(leg,legNo) { + function onEachLeg(leg, legNo) { _legNo = legNo; leg.accept(c); } @@ -28,21 +28,4 @@ function newSubQueries(_table,span,alias) { return result; } -function _joinLegToQuery() { - joinLegToQuery = require('./newSubQueries/joinLegToQuery'); - return joinLegToQuery.apply(null,arguments); -} - -function _oneLegToQuery() { - oneLegToQuery = require('./newSubQueries/oneLegToQuery'); - return oneLegToQuery.apply(null,arguments); -} - -function _manyLegToQuery() { - manyLegToQuery = require('./newSubQueries/manyLegToQuery'); - return manyLegToQuery.apply(null,arguments); -} - - - module.exports = newSubQueries; \ No newline at end of file diff --git a/src/tedious/getManyDto/query/newSubQueries/joinLegToQuery.js b/src/tedious/getManyDto/query/newSubQueries/joinLegToQuery.js index 9bed75a2..3c873fa4 100644 --- a/src/tedious/getManyDto/query/newSubQueries/joinLegToQuery.js +++ b/src/tedious/getManyDto/query/newSubQueries/joinLegToQuery.js @@ -1,15 +1,14 @@ -var newShallowJoinSql = require('../../../../table/query/singleQuery/joinSql/newShallowJoinSqlCore'); -var newQuery = require('../../newQueryCore'); +const newShallowJoinSql = require('../../../../table/query/singleQuery/joinSql/newShallowJoinSqlCore'); -function joinLegToQuery(parentAlias,leg,_legNo) { +function joinLegToQuery(newQuery, context, parentAlias, leg, _legNo) { var childAlias = parentAlias + leg.name; var span = leg.span; var parentTable = leg.table; var childColumns = span.table._primaryColumns; var parentColumns = leg.columns; - var filter = newShallowJoinSql(parentTable,childColumns,parentColumns,childAlias,parentAlias,leg.span.where); - var query = newQuery(span.table,filter,span,childAlias); + var filter = newShallowJoinSql(context, parentTable, childColumns, parentColumns, childAlias, parentAlias, leg.span.where); + var query = newQuery(context, span.table, filter, span, childAlias); return query.prepend('JSON_QUERY((').append(` FOR JSON PATH, INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER)) "${leg.name}"`); } diff --git a/src/tedious/getManyDto/query/newSubQueries/manyLegToQuery.js b/src/tedious/getManyDto/query/newSubQueries/manyLegToQuery.js index 20244a72..f9ba6cb8 100644 --- a/src/tedious/getManyDto/query/newSubQueries/manyLegToQuery.js +++ b/src/tedious/getManyDto/query/newSubQueries/manyLegToQuery.js @@ -1,15 +1,14 @@ -var newShallowJoinSql = require('../../../../table/query/singleQuery/joinSql/newShallowJoinSqlCore'); -var newQuery = require('../../newQueryCore'); +const newShallowJoinSql = require('../../../../table/query/singleQuery/joinSql/newShallowJoinSqlCore'); -function manyLegToQuery(rightAlias, leg, _legNo) { +function manyLegToQuery(newQuery, context, rightAlias, leg, _legNo) { var leftAlias = rightAlias + leg.name; var span = leg.span; var rightTable = leg.table; var rightColumns = rightTable._primaryColumns; var leftColumns = leg.columns; - var filter = newShallowJoinSql(rightTable, leftColumns, rightColumns, leftAlias, rightAlias, leg.span.where); - var query = newQuery(span.table, filter, span, leftAlias); + var filter = newShallowJoinSql(context, rightTable, leftColumns, rightColumns, leftAlias, rightAlias, leg.span.where); + var query = newQuery(context, span.table, filter, span, leftAlias); return query.prepend('JSON_QUERY( coalesce((').append(` FOR JSON PATH, INCLUDE_NULL_VALUES),'[]')) "${leg.name}"`); } diff --git a/src/tedious/getManyDto/query/newSubQueries/oneLegToQuery.js b/src/tedious/getManyDto/query/newSubQueries/oneLegToQuery.js index 764e1bfd..8884d805 100644 --- a/src/tedious/getManyDto/query/newSubQueries/oneLegToQuery.js +++ b/src/tedious/getManyDto/query/newSubQueries/oneLegToQuery.js @@ -1,19 +1,18 @@ -var newShallowJoinSql = require('../../../../table/query/singleQuery/joinSql/newShallowJoinSqlCore'); -var newQuery = require('../../newQueryCore'); -var newParameterized = require('../../../../table/query/newParameterized'); -var util = require('util'); +const newShallowJoinSql = require('../../../../table/query/singleQuery/joinSql/newShallowJoinSqlCore'); +const newParameterized = require('../../../../table/query/newParameterized'); +const formatString = require('../../../../format'); -function oneLegToQuery(rightAlias,leg,_legNo) { - var leftAlias = rightAlias + leg.name; - var span = leg.span; - var rightTable = leg.table; - var rightColumns = rightTable._primaryColumns; - var leftColumns = leg.columns; +function oneLegToQuery(newQuery, context, rightAlias, leg, _legNo) { + let leftAlias = rightAlias + leg.name; + let span = leg.span; + let rightTable = leg.table; + let rightColumns = rightTable._primaryColumns; + let leftColumns = leg.columns; - var filter = newShallowJoinSql(rightTable,leftColumns,rightColumns,leftAlias,rightAlias,leg.span.where); - var query = newQuery(span.table,filter,span,leftAlias); - var sql = 'SELECT TOP 1' + query.sql().substring(6); - return newParameterized(util.format('JSON_QUERY((%s FOR JSON PATH, INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER)) "%s"',sql, leg.name ), query.parameters); + let filter = newShallowJoinSql(context, rightTable, leftColumns, rightColumns, leftAlias, rightAlias, leg.span.where); + let query = newQuery(context, span.table, filter, span, leftAlias); + let sql = 'SELECT TOP 1' + query.sql().substring(6); + return newParameterized(formatString('JSON_QUERY((%s FOR JSON PATH, INCLUDE_NULL_VALUES, WITHOUT_ARRAY_WRAPPER)) "%s"', sql, leg.name), query.parameters); } module.exports = oneLegToQuery; \ No newline at end of file diff --git a/src/tedious/getManyDto/query/singleQuery/newShallowColumnSql.js b/src/tedious/getManyDto/query/singleQuery/newShallowColumnSql.js index 3bfbb3e9..6bd2de29 100644 --- a/src/tedious/getManyDto/query/singleQuery/newShallowColumnSql.js +++ b/src/tedious/getManyDto/query/singleQuery/newShallowColumnSql.js @@ -1,7 +1,6 @@ -const getSessionSingleton = require('../../../../table/getSessionSingleton'); +const quote = require('../../../quote'); -function _new(table,alias, span) { - const quote = getSessionSingleton('quote'); +function _new(context, table, alias, span) { alias = quote(alias); let columnsMap = span.columns; var columns = table._columns; @@ -11,7 +10,7 @@ function _new(table,alias, span) { for (var i = 0; i < columns.length; i++) { var column = columns[i]; if (!columnsMap || (columnsMap.get(column))) { - sql = sql + separator + formatColumn(column) + ' as ' + quote(column.alias); + sql = sql + separator + formatColumn(column) + ' as ' + quote(column.alias); separator = ','; } } @@ -24,11 +23,11 @@ function _new(table,alias, span) { function formatColumn(column) { - const formatted = column.formatOut && column.tsType !== 'DateColumn' ? column.formatOut(alias) : alias + '.' + quote(column._dbName); + const formatted = column.formatOut && column.tsType !== 'DateColumn' ? column.formatOut(context, alias) : alias + '.' + quote(column._dbName); if (column.dbNull === null) return formatted; else { - const encoded = column.encode.unsafe(column.dbNull); + const encoded = column.encode.unsafe(context, column.dbNull); return `CASE WHEN ${formatted}=${encoded} THEN null ELSE ${formatted} END`; } diff --git a/src/tedious/insert.js b/src/tedious/insert.js index ba00b5d1..f3ccb22c 100644 --- a/src/tedious/insert.js +++ b/src/tedious/insert.js @@ -2,11 +2,11 @@ let newInsertCommand = require('../table/commands/newInsertCommand'); let newInsertCommandCore = require('../table/commands/newInsertCommandCore'); let executeQueries = require('../table/executeQueries'); -async function insertDefault(table, row, options) { - let insertCmd = newInsertCommand(newInsertCommandCore, table, row, options); +async function insertDefault(context, table, row, options) { + let insertCmd = newInsertCommand(newInsertCommandCore.bind(null, context), table, row, options); insertCmd.disallowCompress = true; - return executeQueries([insertCmd]).then((result) => result[result.length - 1]); + return executeQueries(context, [insertCmd]).then((result) => result[result.length - 1]); } diff --git a/src/tedious/insertSql.js b/src/tedious/insertSql.js index eebe08e7..cd2e80fb 100644 --- a/src/tedious/insertSql.js +++ b/src/tedious/insertSql.js @@ -1,11 +1,11 @@ let outputInsertedSql = require('./outputInsertedSql'); let mergeSql = require('./mergeSql'); -function getSqlTemplate(_table, _row, options) { +function getSqlTemplate(_context, _table, _row, options) { if (hasConcurrency(_table, options) && hasColumns()) - return mergeSql.apply(null, arguments); + return mergeSql.apply(null, [...arguments].slice(1)); else - return insertSql.apply(null, arguments); + return insertSql.apply(null, [...arguments].slice(1)); function hasColumns() { for(let p in _row) { diff --git a/src/tedious/newDatabase.js b/src/tedious/newDatabase.js index cdfd9d18..954982b0 100644 --- a/src/tedious/newDatabase.js +++ b/src/tedious/newDatabase.js @@ -4,10 +4,6 @@ let _begin = require('../table/begin'); let commit = require('../table/commit'); let rollback = require('../table/rollback'); let newPool = require('./newPool'); -let useHook = require('../useHook'); -let promise = require('promise/domains'); -let versionArray = process.version.replace('v', '').split('.'); -let major = parseInt(versionArray[0]); let express = require('../hostExpress'); let hostLocal = require('../hostLocal'); let doQuery = require('../query'); @@ -34,15 +30,11 @@ function newDatabase(connectionString, poolOptions) { if (fn) return domain.run(runInTransaction); - else if ((major >= 12) && useHook()) { - domain.exitContext = true; - return domain.start().then(run); - } else return domain.run(run); function begin() { - return _begin(options?.readonly); + return _begin(domain, options); } async function runInTransaction() { @@ -50,10 +42,10 @@ function newDatabase(connectionString, poolOptions) { let transaction = newTransaction(domain, pool, options); await new Promise(transaction) .then(begin) - .then(fn) + .then(() => fn(domain)) .then((res) => result = res) - .then(c.commit) - .then(null, c.rollback); + .then(() => c.commit(domain)) + .then(null, (e) => c.rollback(domain,e)); return result; } @@ -61,53 +53,48 @@ function newDatabase(connectionString, poolOptions) { function run() { let p; let transaction = newTransaction(domain, pool, options); - if (useHook()) - p = new Promise(transaction); - else - p = new promise(transaction); + p = new Promise(transaction); return p.then(begin); } }; - c.createTransaction = function() { + c.createTransaction = function(options) { let domain = createDomain(); let transaction = newTransaction(domain, pool); - let p = domain.run(() => new Promise(transaction).then(_begin)); + let p = domain.run(() => new Promise(transaction).then(begin)); function run(fn) { return p.then(domain.run.bind(domain, fn)); } + + run.rollback = rollback.bind(null, domain); + run.commit = commit.bind(null, domain); return run; - }; - c.bindTransaction = function() { - // @ts-ignore - var domain = process.domain; - let p = domain.run(() => true); - function run(fn) { - return p.then(domain.run.bind(domain, fn)); + function begin() { + return _begin(domain, options); } - return run; + }; c.query = function(query) { let domain = createDomain(); let transaction = newTransaction(domain, pool); let p = domain.run(() => new Promise(transaction) - .then(() => setSessionSingleton('changes', [])) - .then(() => doQuery(query).then(onResult, onError))); + .then(() => setSessionSingleton(domain, 'changes', [])) + .then(() => doQuery(domain, query).then(onResult, onError))); return p; function onResult(result) { - releaseDbClient(); + releaseDbClient(domain); return result; } function onError(e) { - releaseDbClient(); + releaseDbClient(domain); throw e; } }; diff --git a/src/tedious/newPool.js b/src/tedious/newPool.js index 8ea1295a..3d9a8d8c 100644 --- a/src/tedious/newPool.js +++ b/src/tedious/newPool.js @@ -1,17 +1,17 @@ -var pools = require('../pools'); -var promise = require('../table/promise'); -var end = require('./pool/end'); -var newGenericPool = require('./pool/newGenericPool'); -var newId = require('../newId'); +const promisify = require('../promisify'); +const pools = require('../pools'); +const end = require('./pool/end'); +const newGenericPool = require('./pool/newGenericPool'); +const newId = require('../newId'); function newPool(connectionString, poolOptions) { - var pool = newGenericPool(connectionString, poolOptions); - var id = newId(); - var boundEnd = end.bind(null, pool, id); - var c = {}; + let pool = newGenericPool(connectionString, poolOptions); + let id = newId(); + let boundEnd = end.bind(null, pool, id); + let c = {}; c.connect = pool.connect; - c.end = promise.denodeify(boundEnd); + c.end = promisify(boundEnd); pools[id] = c; return c; } diff --git a/src/tedious/newTransaction.js b/src/tedious/newTransaction.js index fa3eb0b9..2916ddae 100644 --- a/src/tedious/newTransaction.js +++ b/src/tedious/newTransaction.js @@ -2,15 +2,15 @@ var wrapQuery = require('./wrapQuery'); var encodeBoolean = require('./encodeBoolean'); var deleteFromSql = require('./deleteFromSql'); var selectForUpdateSql = require('./selectForUpdateSql'); -var outputInsertedSql = require('./outputInsertedSql'); const limitAndOffset = require('./limitAndOffset'); +const insertSql = require('./insertSql'); const getManyDto = require('./getManyDto'); const formatDateOut = require('./formatDateOut'); const formatJSONOut = require('./formatJSONOut'); -const insertSql = require('./insertSql'); const insert = require('./insert'); +const quote = require('./quote'); -function newResolveTransaction(domain, pool, { readonly } = {}) { +function newResolveTransaction(domain, pool, { readonly = false } = {}) { var rdb = {poolFactory: pool}; if (!pool.connect) { pool = pool(); @@ -23,7 +23,6 @@ function newResolveTransaction(domain, pool, { readonly } = {}) { rdb.encodeJSON = JSON.stringify; rdb.deleteFromSql = deleteFromSql; rdb.selectForUpdateSql = selectForUpdateSql; - rdb.outputInsertedSql = outputInsertedSql; rdb.lastInsertedIsSeparate = false; rdb.insertSql = insertSql; rdb.insert = insert; @@ -44,7 +43,7 @@ function newResolveTransaction(domain, pool, { readonly } = {}) { caller.visitSqlite(); }; rdb.aggregateCount = 0; - rdb.quote = (name) => `[${name}]`; + rdb.quote = quote; if (readonly) { rdb.dbClient = { diff --git a/src/tedious/pool/defaults.js b/src/tedious/pool/defaults.js deleted file mode 100644 index f21f834a..00000000 --- a/src/tedious/pool/defaults.js +++ /dev/null @@ -1,45 +0,0 @@ -module.exports = { - // database host defaults to localhost - host: 'localhost', - - //database user's name - user: process.platform === 'win32' ? process.env.USERNAME : process.env.USER, - - //name of database to connect - database: process.platform === 'win32' ? process.env.USERNAME : process.env.USER, - - //database user's password - password: null, - - //database port - port: 5432, - - //number of rows to return at a time from a prepared statement's - //portal. 0 will return all rows at once - rows: 0, - - // binary result mode - binary: false, - - //Connection pool options - see https://github.com/coopernurse/node-pool - //number of connections to use in connection pool - //0 will disable connection pooling - poolSize: 0, - - //max milliseconds a client can go unused before it is removed - //from the pool and destroyed - poolIdleTimeout: 30000, - - //frequeny to check for idle clients within the client pool - reapIntervalMillis: 1000, - - //pool log function / boolean - poolLog: false, - - client_encoding: '', - - ssl: false, - - application_name : undefined, - fallback_application_name: undefined -}; \ No newline at end of file diff --git a/src/tedious/pool/newGenericPool.js b/src/tedious/pool/newGenericPool.js index 8f465d03..26dc0f87 100644 --- a/src/tedious/pool/newGenericPool.js +++ b/src/tedious/pool/newGenericPool.js @@ -1,8 +1,7 @@ // @ts-nocheck /* eslint-disable no-prototype-builtins */ -var EventEmitter = require('events').EventEmitter; -var defaults = require('./defaults'); +var defaults = require('../../poolDefaults'); var genericPool = require('../../generic-pool'); var tedious = require('tedious'); var parseConnectionString = require('./parseConnectionString'); @@ -40,20 +39,9 @@ function newGenericPool(connectionString, poolOptions) { client.close(); } }); - //mixin EventEmitter to pool - EventEmitter.call(pool); - for (var key in EventEmitter.prototype) { - if (EventEmitter.prototype.hasOwnProperty(key)) { - pool[key] = EventEmitter.prototype[key]; - } - } //monkey-patch with connect method pool.connect = function(cb) { - var domain = process.domain; pool.acquire(function(err, client) { - if (domain) { - cb = domain.bind(cb); - } if (err) return cb(err, null, function() {/*NOOP*/ }); client.poolCount++; cb(null, client, function(err) { diff --git a/src/tedious/quote.js b/src/tedious/quote.js new file mode 100644 index 00000000..6e67a495 --- /dev/null +++ b/src/tedious/quote.js @@ -0,0 +1 @@ +module.exports = (name) => `[${name}]`; \ No newline at end of file diff --git a/src/useHook.js b/src/useHook.js deleted file mode 100644 index c9ee4624..00000000 --- a/src/useHook.js +++ /dev/null @@ -1,9 +0,0 @@ -let flags = require('./flags'); -let versionArray = process.version.replace('v', '').split('.'); -let major = parseInt(versionArray[0]); - -function useHook() { - return flags.useHook && major > 7; -} - -module.exports = useHook; \ No newline at end of file diff --git a/src/validateDeleteConflict.js b/src/validateDeleteConflict.js index 02c02799..4c2c4140 100644 --- a/src/validateDeleteConflict.js +++ b/src/validateDeleteConflict.js @@ -1,7 +1,5 @@ // @ts-nocheck /* eslint-disable */ -let { inspect } = require('util'); -let assert = require('assert'); const toCompareObject = require('./toCompareObject'); async function validateDeleteConflict({ row, oldValue, options, table }) { @@ -16,10 +14,10 @@ async function validateDeleteConflict({ row, oldValue, options, table }) { assertDatesEqual(oldValue[p], toCompareObject(row[p])); } else - assert.deepEqual(oldValue[p], toCompareObject(row[p])); + assertDeepEqual(oldValue[p], toCompareObject(row[p])); } catch (e) { - throw new Error(`The field ${p} was changed by another user. Expected ${inspect(oldValue[p], false, 10)}, but was ${inspect(row[p], false, 10)}.`); + throw new Error(`The field ${p} was changed by another user. Expected ${inspect(oldValue[p])}, but was ${inspect(row[p])}.`); } } } @@ -85,8 +83,16 @@ function assertDatesEqual(date1, date2) { date1 = `${parts1[0]}T${time1parts[0]}`; date2 = `${parts2[0]}T${time2parts[0]}`; } - assert.deepEqual(date1, date2); + assertDeepEqual(date1, date2); } +function assertDeepEqual(a, b) { + if (JSON.stringify(a) !== JSON.stringify(b)) + throw new Error('A, b are not equal'); +} + +function inspect(obj) { + return JSON.stringify(obj, null, 2); +} module.exports = validateDeleteConflict; \ No newline at end of file diff --git a/tests/aggregate.test.js b/tests/aggregate.test.js index 0711183e..1563f2da 100644 --- a/tests/aggregate.test.js +++ b/tests/aggregate.test.js @@ -1,5 +1,6 @@ import { describe, test, beforeAll, afterAll, expect } from 'vitest'; import { fileURLToPath } from 'url'; +import setupD1 from './setupD1'; const express = require('express'); import { json } from 'body-parser'; import cors from 'cors'; @@ -13,10 +14,12 @@ const initSap = require('./initSap'); const versionArray = process.version.replace('v', '').split('.'); const major = parseInt(versionArray[0]); const port = 3010; - let server; +let d1; +let miniflare; afterAll(async () => { + await miniflare.dispose(); return new Promise((res) => { if (server) server.close(res); @@ -26,6 +29,7 @@ afterAll(async () => { }); beforeAll(async () => { + ({ d1, miniflare } = await setupD1(fileURLToPath(import.meta.url))); await createMs('mssql'); await insertData('pg'); await insertData('oracle'); @@ -34,6 +38,7 @@ beforeAll(async () => { await insertData('mssqlNative'); await insertData('mysql'); await insertData('sqlite'); + await insertData('d1'); await insertData('sqlite2'); await insertData('sap'); hostExpress(); @@ -132,6 +137,7 @@ describe('count', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -151,6 +157,7 @@ describe('count filter', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -203,6 +210,10 @@ const connections = { db: map({ db: (con) => con.sqlite(sqliteName, { size: 1 }) }), init: initSqlite }, + d1: { + db: map({ db: (con) => con.d1(d1, { size: 1 }) }), + init: initSqlite + }, sqlite2: { db: map({ db: (con) => con.sqlite(sqliteName2, { size: 1 }) }), init: initSqlite @@ -219,7 +230,7 @@ const connections = { password: 'P@assword123', connectString: 'oracle/XE', privilege: 2 - }, {size: 1} + }, { size: 1 } ) }), @@ -244,6 +255,8 @@ function getDb(name) { return connections.pg; else if (name === 'sqlite') return connections.sqlite; + else if (name === 'd1') + return connections.d1; else if (name === 'sqlite2') return connections.sqlite2; else if (name === 'sap') diff --git a/tests/classic.filters.test.js b/tests/classic.filters.test.js deleted file mode 100644 index 2b868adf..00000000 --- a/tests/classic.filters.test.js +++ /dev/null @@ -1,528 +0,0 @@ -import { fileURLToPath } from 'url'; -import { describe, test, beforeAll, expect } from 'vitest'; -import rdb from '../src/index'; -const db = require('./db'); -const initPg = require('./initPg'); -const initOracle = require('./initOracle'); -const initMs = require('./initMs'); -const initMysql = require('./initMysql'); -const initSqlite = require('./initSqlite'); -const initSap = require('./initSap'); -const dateToISOString = require('../src/dateToISOString'); -const versionArray = process.version.replace('v', '').split('.'); -const major = parseInt(versionArray[0]); - -const Order = rdb.table('order'); -Order.column('id').numeric().primary().notNullExceptInsert(), -Order.column('orderDate').date().notNull(); - -const Lines = rdb.table('orderLine'); -Lines.column('id').numeric().primary().notNullExceptInsert(); -Lines.column('orderId').numeric(); -Lines.column('product').string(); - -const Packages = rdb.table('package'); -Packages.column('packageId').numeric().primary().notNullExceptInsert().as('id'); -Packages.column('lineId').numeric(); -Packages.column('sscc').string(); - - -const lineJoin = Lines.join(Order).by('orderId').as('order'); -const packageJoin = Packages.join(Lines).by('lineId').as('line'); - -Order.hasMany(lineJoin).as('lines'); -Lines.hasMany(packageJoin).as('packages'); - - -beforeAll(async () => { - await createMs('mssql'); - await insertData('mssql'); - await insertData('pg'); - await insertData('oracle'); - if (major === 18) - await insertData('mssqlNative'); - await insertData('mysql'); - await insertData('sqlite'); - await insertData('sap'); - - async function insertData(dbName) { - const { db, init } = getDb(dbName); - await init(db); - - const george = await db.customer.insert({ - name: 'George', - balance: 177, - isActive: true - }); - - const john = await db.customer.insert({ - name: 'Harry', - balance: 200, - isActive: true - }); - const date1 = new Date(2022, 0, 11, 9, 24, 47); - const date2 = new Date(2021, 0, 11, 12, 22, 45); - - await db.order.insert([ - { - orderDate: date1, - customer: george, - deliveryAddress: { - name: 'George', - street: 'Node street 1', - postalCode: '7059', - postalPlace: 'Jakobsli', - countryCode: 'NO' - }, - lines: [ - { - product: 'Bicycle', - packages: [ - { sscc: 'aaaa' } - ] - }, - { - product: 'Small guitar', - packages: [ - { sscc: 'bbbb' } - ] - } - ] - }, - { - customer: john, - orderDate: date2, - deliveryAddress: { - name: 'Harry Potter', - street: '4 Privet Drive, Little Whinging', - postalCode: 'GU4', - postalPlace: 'Surrey', - countryCode: 'UK' - }, - lines: [ - { - product: 'Magic wand', - packages: [ - { sscc: '1234' } - ] - } - ] - } - ]); - } - - async function createMs(dbName) { - const { db } = getDb(dbName); - const sql = `IF NOT EXISTS(SELECT * FROM sys.databases WHERE name = 'demo') - BEGIN - CREATE DATABASE demo - END - `; - await db.query(sql); - } -}); - - -describe('basic filter', async () => { - - test('pg', async () => await verify('pg')); - test('oracle', async () => await verify('oracle')); - test('mssql', async () => await verify('mssql')); - if (major === 18) - test('mssqlNative', async () => await verify('mssqlNative')); - test('mysql', async () => await verify('mysql')); - test('sqlite', async () => await verify('sqlite')); - test('sap', async () => await verify('sap')); - - async function verify(dbName) { - const db = getClassicDb(dbName); - await db.transaction(async () => { - - const filter = Order.id.eq(1); - - let rows = await Order.getMany(filter); - let dtos = await rows.toDto({}); - - const date1 = new Date(2022, 0, 11, 9, 24, 47); - const expected = [ - { - id: 1, - orderDate: dateToISOString(date1), - } - ]; - - for (let i = 0; i < dtos.length; i++) { - dtos[i].orderDate = dateToISOString(new Date(rows[i].orderDate)); - } - - expect(dtos).toEqual(expected); - }); - } -}); - -describe('basic nested filter', async () => { - - test('pg', async () => await verify('pg')); - test('oracle', async () => await verify('oracle')); - test('mssql', async () => await verify('mssql')); - if (major === 18) - test('mssqlNative', async () => await verify('mssqlNative')); - test('mysql', async () => await verify('mysql')); - test('sqlite', async () => await verify('sqlite')); - test('sap', async () => await verify('sap')); - - async function verify(dbName) { - const db = getClassicDb(dbName); - - await db.transaction(async () => { - const filter = Order.lines.packages.sscc.startsWith('aaa'); - let rows = await Order.getMany(filter); - let dtos = await rows.toDto({}); - - const date1 = new Date(2022, 0, 11, 9, 24, 47); - const expected = [ - { - id: 1, - orderDate: dateToISOString(date1), - } - ]; - - for (let i = 0; i < dtos.length; i++) { - dtos[i].orderDate = dateToISOString(new Date(rows[i].orderDate)); - } - - expect(dtos).toEqual(expected); - }); - } -}); - -describe('any filter', async () => { - - test('pg', async () => await verify('pg')); - test('oracle', async () => await verify('oracle')); - test('mssql', async () => await verify('mssql')); - if (major === 18) - test('mssqlNative', async () => await verify('mssqlNative')); - test('mysql', async () => await verify('mysql')); - test('sqlite', async () => await verify('sqlite')); - test('sap', async () => await verify('sap')); - - async function verify(dbName) { - const db = getClassicDb(dbName); - await db.transaction(async () => { - - const filter = Order.lines(x => x.product.startsWith('Bic')); - - let rows = await Order.getMany(filter); - let dtos = await rows.toDto({}); - - const date1 = new Date(2022, 0, 11, 9, 24, 47); - const expected = [ - { - id: 1, - orderDate: dateToISOString(date1), - } - ]; - - for (let i = 0; i < dtos.length; i++) { - dtos[i].orderDate = dateToISOString(new Date(rows[i].orderDate)); - } - - expect(dtos).toEqual(expected); - }); - } -}); - -describe('all filter', async () => { - - test('pg', async () => await verify('pg')); - test('oracle', async () => await verify('oracle')); - test('mssql', async () => await verify('mssql')); - if (major === 18) - test('mssqlNative', async () => await verify('mssqlNative')); - test('mysql', async () => await verify('mysql')); - test('sqlite', async () => await verify('sqlite')); - test('sap', async () => await verify('sap')); - - async function verify(dbName) { - const db = getClassicDb(dbName); - await db.transaction(async () => { - - const filter = Order.lines.all(x => x.product.contains('Bic').or(x.packages(x => x.sscc.eq('bbbb')))); - - let rows = await Order.getMany(filter); - let dtos = await rows.toDto({}); - - const date1 = new Date(2022, 0, 11, 9, 24, 47); - const expected = [ - { - id: 1, - orderDate: dateToISOString(date1), - } - ]; - - for (let i = 0; i < dtos.length; i++) { - dtos[i].orderDate = dateToISOString(new Date(rows[i].orderDate)); - } - - expect(dtos).toEqual(expected); - }); - } -}); - -describe('none filter', async () => { - - test('pg', async () => await verify('pg')); - test('oracle', async () => await verify('oracle')); - test('mssql', async () => await verify('mssql')); - if (major === 18) - test('mssqlNative', async () => await verify('mssqlNative')); - test('mysql', async () => await verify('mysql')); - test('sqlite', async () => await verify('sqlite')); - test('sap', async () => await verify('sap')); - - async function verify(dbName) { - const db = getClassicDb(dbName); - await db.transaction(async () => { - - const filter = Order.lines.none(x => x.product.contains('l')); - - let rows = await Order.getMany(filter); - let dtos = await rows.toDto({}); - - const date2 = new Date(2021, 0, 11, 12, 22, 45); - const expected = [ - { - id: 2, - orderDate: dateToISOString(date2), - } - ]; - - for (let i = 0; i < dtos.length; i++) { - dtos[i].orderDate = dateToISOString(new Date(rows[i].orderDate)); - } - - expect(dtos).toEqual(expected); - }); - } -}); - -describe('any-subFilter filter', async () => { - - test('pg', async () => await verify('pg')); - test('oracle', async () => await verify('oracle')); - test('mssql', async () => await verify('mssql')); - if (major === 18) - test('mssqlNative', async () => await verify('mssqlNative')); - test('mysql', async () => await verify('mysql')); - test('sqlite', async () => await verify('sqlite')); - test('sap', async () => await verify('sap')); - - async function verify(dbName) { - const db = getClassicDb(dbName); - await db.transaction(async () => { - - const filter = Order.lines(x => x.packages.sscc.startsWith('aaa')); - - let rows = await Order.getMany(filter); - let dtos = await rows.toDto({}); - - const date1 = new Date(2022, 0, 11, 9, 24, 47); - const expected = [ - { - id: 1, - orderDate: dateToISOString(date1), - } - ]; - - for (let i = 0; i < dtos.length; i++) { - dtos[i].orderDate = dateToISOString(new Date(rows[i].orderDate)); - } - - expect(dtos).toEqual(expected); - }); - } -}); - -describe('any-subFilter filter nested', async () => { - - test('pg', async () => await verify('pg')); - test('oracle', async () => await verify('oracle')); - test('mssql', async () => await verify('mssql')); - if (major === 18) - test('mssqlNative', async () => await verify('mssqlNative')); - test('mysql', async () => await verify('mysql')); - test('sqlite', async () => await verify('sqlite')); - test('sap', async () => await verify('sap')); - - async function verify(dbName) { - const db = getClassicDb(dbName); - await db.transaction(async () => { - - const filter = Order.lines(x => x.packages(x => x.sscc.startsWith('aaa'))); - - let rows = await Order.getMany(filter); - let dtos = await rows.toDto({}); - - const date1 = new Date(2022, 0, 11, 9, 24, 47); - const expected = [ - { - id: 1, - orderDate: dateToISOString(date1), - } - ]; - - for (let i = 0; i < dtos.length; i++) { - dtos[i].orderDate = dateToISOString(new Date(rows[i].orderDate)); - } - - expect(dtos).toEqual(expected); - }); - } -}); - -describe('any-subFilter filter nested chained', async () => { - - test('pg', async () => await verify('pg')); - test('oracle', async () => await verify('oracle')); - test('mssql', async () => await verify('mssql')); - if (major === 18) - test('mssqlNative', async () => await verify('mssqlNative')); - test('mysql', async () => await verify('mysql')); - test('sqlite', async () => await verify('sqlite')); - test('sap', async () => await verify('sap')); - - async function verify(dbName) { - const db = getClassicDb(dbName); - await db.transaction(async () => { - - const filter = Order.lines(x => x.packages(x => x.line.order.id.eq(1))); - - let rows = await Order.getMany(filter); - let dtos = await rows.toDto({}); - - const date1 = new Date(2022, 0, 11, 9, 24, 47); - const expected = [ - { - id: 1, - orderDate: dateToISOString(date1), - } - ]; - - for (let i = 0; i < dtos.length; i++) { - dtos[i].orderDate = dateToISOString(new Date(rows[i].orderDate)); - } - - expect(dtos).toEqual(expected); - }); - } -}); - - -function getDb(name) { - if (name === 'mssql') - return { - db: - db.mssql({ - server: 'mssql', - options: { - encrypt: false, - database: 'master' - }, - authentication: { - type: 'default', - options: { - userName: 'sa', - password: 'P@assword123', - } - } - }), - init: initMs - - }; - else if (name === 'mssqlNative') - return { - db: db.mssqlNative('server=mssql;Database=demo;Trusted_Connection=No;Uid=sa;pwd=P@assword123;Driver={ODBC Driver 18 for SQL Server};TrustServerCertificate=yes'), - init: initMs - }; - else if (name === 'pg') - return { - db: db.postgres('postgres://postgres:postgres@postgres/postgres'), - init: initPg - }; - else if (name === 'oracle') - return { - db: db.oracle( - { - user: 'sys', - password: 'P@assword123', - connectString: 'oracle/XE', - privilege: 2 - }, { size: 1 } - - ), - init: initOracle - }; - else if (name === 'sqlite') - return { - db: db.sqlite(sqliteName), - init: initSqlite - }; - else if (name === 'sap') - return { - db: db.sap(`Driver=${__dirname}/libsybdrvodb.so;SERVER=sapase;Port=5000;UID=sa;PWD=sybase;DATABASE=master`), - init: initSap - }; - else if (name === 'mysql') - return { - db: db.mysql('mysql://test:test@mysql/test'), - init: initMysql - }; - - throw new Error('unknown db'); -} - - -const pathSegments = fileURLToPath(import.meta.url).split('/'); -const lastSegment = pathSegments[pathSegments.length - 1]; -const fileNameWithoutExtension = lastSegment.split('.')[0]; -const sqliteName = `demo.${fileNameWithoutExtension}.db`; - -function getClassicDb(name) { - if (name === 'mssql') - return rdb.mssql({ - server: 'mssql', - options: { - encrypt: false, - database: 'master' - }, - authentication: { - type: 'default', - options: { - userName: 'sa', - password: 'P@assword123', - } - } - }); - else if (name === 'mssqlNative') - return rdb.mssqlNative('server=mssql;Database=demo;Trusted_Connection=No;Uid=sa;pwd=P@assword123;Driver={ODBC Driver 18 for SQL Server};TrustServerCertificate=yes'); - else if (name === 'pg') - return rdb.postgres('postgres://postgres:postgres@postgres/postgres'); - else if (name === 'sqlite') - return rdb.sqlite(sqliteName); - else if (name === 'sap') - return rdb.sap(`Driver=${__dirname}/libsybdrvodb.so;SERVER=sapase;Port=5000;UID=sa;PWD=sybase;DATABASE=master`); - else if (name === 'oracle') - return rdb.oracle({ - user: 'sys', - password: 'P@assword123', - connectString: 'oracle/XE', - privilege: 2 - }); - else if (name === 'mysql') - return rdb.mysql('mysql://test:test@mysql/test'); - else - throw new Error('unknown db'); -} - - diff --git a/tests/conflicts.test.js b/tests/conflicts.test.js index 44c0c283..c472f201 100644 --- a/tests/conflicts.test.js +++ b/tests/conflicts.test.js @@ -1,6 +1,7 @@ import { fileURLToPath } from 'url'; const map = require('./db'); import { describe, test, beforeAll, afterAll, expect } from 'vitest'; +import setupD1 from './setupD1'; const express = require('express'); import { json } from 'body-parser'; import cors from 'cors'; @@ -14,8 +15,11 @@ const versionArray = process.version.replace('v', '').split('.'); const major = parseInt(versionArray[0]); const port = 3007; let server; +let d1; +let miniflare; beforeAll(async () => { + ({ d1, miniflare } = await setupD1(fileURLToPath(import.meta.url))); await createMs('mssql'); hostExpress(); @@ -40,6 +44,7 @@ beforeAll(async () => { }, 20000); afterAll(async () => { + await miniflare.dispose(); return new Promise((res) => { if (server) server.close(res); @@ -56,6 +61,7 @@ describe('optimistic fail', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -101,6 +107,7 @@ describe('insert skipOnConflict with overwrite column', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -156,6 +163,7 @@ describe('savechanges overload overwrite', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -212,6 +220,7 @@ describe('savechanges overload optimistic', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -251,7 +260,7 @@ describe('savechanges overload optimistic', () => { catch (e) { error = e; } - expect(error.message).toEqual('The field name was changed by another user. Expected \'John\', but was \'John 1\'.'); + expect(error.message).toEqual('The field name was changed by another user. Expected "John", but was "John 1".'); } }); @@ -263,6 +272,7 @@ describe('insert empty skipOnConflict', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -302,6 +312,7 @@ describe('columnDiscriminator insert skipOnConflict with overwrite column', () = test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -365,6 +376,7 @@ describe('insert overwrite with skipOnConflict column', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -420,6 +432,7 @@ describe('insert overwrite with optimistic column changed', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -475,6 +488,7 @@ describe('insert overwrite with optimistic column unchanged', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -562,6 +576,10 @@ const connections = { db: map({ db: (con) => con.sqlite(sqliteName, { size: 1 }) }), init: initSqlite }, + d1: { + db: map({ db: (con) => con.d1(d1, { size: 1 }) }), + init: initSqlite + }, sqlite2: { db: map({ db: (con) => con.sqlite(sqliteName2, { size: 1 }) }), init: initSqlite @@ -578,7 +596,7 @@ const connections = { password: 'P@assword123', connectString: 'oracle/XE', privilege: 2 - }, {size: 1} + }, { size: 1 } ) }), @@ -603,6 +621,8 @@ function getDb(name) { return connections.pg; else if (name === 'sqlite') return connections.sqlite; + else if (name === 'd1') + return connections.d1; else if (name === 'sqlite2') return connections.sqlite2; else if (name === 'sap') diff --git a/tests/d1.test.js b/tests/d1.test.js new file mode 100644 index 00000000..a819b15b --- /dev/null +++ b/tests/d1.test.js @@ -0,0 +1,65 @@ +import { describe, beforeAll, afterAll, test, expect } from 'vitest'; +import { Miniflare } from 'miniflare'; +import { fileURLToPath } from 'url'; +import path from 'path'; + +// Determine the SQLite filename dynamically +const pathSegments = fileURLToPath(import.meta.url).split('/'); +const lastSegment = pathSegments[pathSegments.length - 1]; +const fileNameWithoutExtension = lastSegment.split('.')[0]; + +let miniflare; +let d1; + +async function setupD1() { + const sqliteName = path.join(__dirname, `demo.d1.${fileNameWithoutExtension}.db`); + miniflare = new Miniflare({ + modules: true, // Enable module mode explicitly for ES module support + script: 'export default { fetch() {} };', // Minimal worker script as a module + d1Databases: { + DB: sqliteName, // D1 binding + }, + envPath: true, // Load environment variables from .env if needed + }); + + await miniflare.getBindings(); + d1 = await miniflare.getD1Database('DB'); +} + +describe('Cloudflare D1 Database Tests', () => { + + beforeAll(async () => { + await setupD1(); + // Create the table if it doesn’t exist + await d1.prepare( + `CREATE TABLE IF NOT EXISTS my_table ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT, + value INTEGER + );` + ).run(); + }); + + afterAll(async () => { + await miniflare.dispose(); + }); + + test('query database without worker', async () => { + const result = await d1.prepare('SELECT * FROM my_table').all(); + expect(result).toBeDefined(); + expect(result.results.length).toBe(0); + }); + + test('insert and retrieve data', async () => { + await d1.prepare('INSERT INTO my_table (name, value) VALUES (?, ?)') + .bind('test', 123) + .run(); + + const result = await d1.prepare('SELECT * FROM my_table WHERE name = ?') + .bind('test') + .all(); + + expect(result.results[0].name).toBe('test'); + expect(result.results[0].value).toBe(123); + }); +}); diff --git a/tests/dataTypes.test.js b/tests/dataTypes.test.js index 03c1558b..95076d0e 100644 --- a/tests/dataTypes.test.js +++ b/tests/dataTypes.test.js @@ -1,5 +1,6 @@ import { describe, test, beforeAll, afterAll, expect } from 'vitest'; import { fileURLToPath } from 'url'; +import setupD1 from './setupD1'; const express = require('express'); const map = require('./db'); import { json } from 'body-parser'; @@ -15,8 +16,11 @@ const versionArray = process.version.replace('v', '').split('.'); const major = parseInt(versionArray[0]); const port = 3005; let server; +let d1; +let miniflare; afterAll(async () => { + await miniflare.dispose(); return new Promise((res) => { if (server) server.close(res); @@ -26,7 +30,7 @@ afterAll(async () => { }); beforeAll(async () => { - + ({ d1, miniflare } = await setupD1(fileURLToPath(import.meta.url))); await createMs('mssql'); await insertData('pg'); await insertData('oracle'); @@ -35,6 +39,7 @@ beforeAll(async () => { await insertData('mssqlNative'); await insertData('mysql'); await insertData('sqlite'); + await insertData('d1'); await insertData('sqlite2'); await insertData('sap'); hostExpress(); @@ -142,6 +147,10 @@ const connections = { db: map({ db: (con) => con.sqlite(sqliteName, { size: 1 }) }), init: initSqlite }, + d1: { + db: map({ db: (con) => con.d1(d1, { size: 1 }) }), + init: initSqlite + }, sqlite2: { db: map({ db: (con) => con.sqlite(sqliteName2, { size: 1 }) }), init: initSqlite @@ -158,7 +167,7 @@ const connections = { password: 'P@assword123', connectString: 'oracle/XE', privilege: 2 - }, {size: 1} + }, { size: 1 } ) }), @@ -183,6 +192,8 @@ function getDb(name) { return connections.pg; else if (name === 'sqlite') return connections.sqlite; + else if (name === 'd1') + return connections.d1; else if (name === 'sqlite2') return connections.sqlite2; else if (name === 'sap') diff --git a/tests/dateformat.test.js b/tests/dateformat.test.js index bd840e5a..844ab55f 100644 --- a/tests/dateformat.test.js +++ b/tests/dateformat.test.js @@ -1,7 +1,7 @@ -import { describe, test, beforeAll, expect } from 'vitest'; +import { describe, test, beforeAll, expect, afterAll } from 'vitest'; import { fileURLToPath } from 'url'; +import setupD1 from './setupD1'; const map = require('./db'); - const initPg = require('./initPg'); const initOracle = require('./initOracle'); const initMs = require('./initMs'); @@ -10,15 +10,18 @@ const initSqlite = require('./initSqlite'); const initSap = require('./initSap'); const port = 3002; +let d1; +let miniflare; beforeAll(async () => { - + ({ d1, miniflare } = await setupD1(fileURLToPath(import.meta.url))); await insertData('pg'); await insertData('oracle'); await insertData('mssql'); await insertData('mysql'); await insertData('sap'); await insertData('sqlite'); + await insertData('d1'); async function insertData(dbName) { const { db, init } = getDb(dbName); @@ -72,6 +75,11 @@ beforeAll(async () => { } }); +afterAll(async () => { + await miniflare.dispose(); +}); + + // describe('dateformat raw', () => { // test('pg', async () => { @@ -186,6 +194,18 @@ describe('dateformat get', () => { expect(result).toEqual({ id: 1, date: '2023-08-05T12:00:00', datetime: '2023-08-05T12:00:00', datetime_tz: '2023-08-05T12:00:00-03:00' }); }); + test('d1', async () => { + const { db } = getDb('d1'); + const result = await db.datetestWithTz.getOne(); + expect(result).toEqual({ id: 1, date: '2023-07-14T12:00:00', datetime: '2023-07-14T12:00:00', datetime_tz: '2023-07-14T12:00:00-08:00' }); + result.date = newValue; + result.datetime = newValue; + result.datetime_tz = newValue; + await result.saveChanges(); + await result.refresh(); + expect(result).toEqual({ id: 1, date: '2023-08-05T12:00:00', datetime: '2023-08-05T12:00:00', datetime_tz: '2023-08-05T12:00:00-03:00' }); + }); + }); @@ -195,7 +215,6 @@ const fileNameWithoutExtension = lastSegment.split('.')[0]; const sqliteName = `demo.${fileNameWithoutExtension}.db`; const sqliteName2 = `demo.${fileNameWithoutExtension}2.db`; - const connections = { mssql: { db: @@ -230,6 +249,10 @@ const connections = { db: map({ db: (con) => con.sqlite(sqliteName, { size: 1 }) }), init: initSqlite }, + d1: { + db: map({ db: (con) => con.d1(d1, { size: 1 }) }), + init: initSqlite + }, sqlite2: { db: map({ db: (con) => con.sqlite(sqliteName2, { size: 1 }) }), init: initSqlite @@ -246,7 +269,7 @@ const connections = { password: 'P@assword123', connectString: 'oracle/XE', privilege: 2 - }, {size: 1} + }, { size: 1 } ) }), @@ -271,6 +294,8 @@ function getDb(name) { return connections.pg; else if (name === 'sqlite') return connections.sqlite; + else if (name === 'd1') + return connections.d1; else if (name === 'sqlite2') return connections.sqlite2; else if (name === 'sap') diff --git a/tests/delete.test.js b/tests/delete.test.js index 20a12725..ee53a0ca 100644 --- a/tests/delete.test.js +++ b/tests/delete.test.js @@ -1,5 +1,6 @@ import { describe, test, beforeAll, afterAll, expect } from 'vitest'; import { fileURLToPath } from 'url'; +import setupD1 from './setupD1'; const map = require('./db'); import express from 'express'; import cors from 'cors'; @@ -18,8 +19,11 @@ const date1 = new Date(2022, 0, 11, 9, 24, 47); const date2 = new Date(2021, 0, 11, 12, 22, 45); let server = null; const port = 3002; +let d1; +let miniflare; afterAll(async () => { + await miniflare.dispose(); return new Promise((res) => { if (server) server.close(res); @@ -28,8 +32,8 @@ afterAll(async () => { }); }); - beforeAll(async () => { + ({ d1, miniflare } = await setupD1(fileURLToPath(import.meta.url))); await insertData('pg'); await insertData('oracle'); await insertData('mssql'); @@ -38,6 +42,7 @@ beforeAll(async () => { await insertData('mysql'); await insertData('sap'); await insertData('sqlite'); + await insertData('d1'); await insertData('sqlite2'); hostExpress(); @@ -111,6 +116,7 @@ describe('deleteCascade', () => { test('mysql', async () => await verify('mysql')); test('sap', async () => await verify('sap')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); async function verify(dbName) { @@ -144,8 +150,6 @@ describe('deleteCascade http', () => { } }); - - const pathSegments = fileURLToPath(import.meta.url).split('/'); const lastSegment = pathSegments[pathSegments.length - 1]; const fileNameWithoutExtension = lastSegment.split('.')[0]; @@ -186,6 +190,10 @@ const connections = { db: map({ db: (con) => con.sqlite(sqliteName, { size: 1 }) }), init: initSqlite }, + d1: { + db: map({ db: (con) => con.d1(d1, { size: 1 }) }), + init: initSqlite + }, sqlite2: { db: map({ db: (con) => con.sqlite(sqliteName2, { size: 1 }) }), init: initSqlite @@ -202,7 +210,7 @@ const connections = { password: 'P@assword123', connectString: 'oracle/XE', privilege: 2 - }, {size: 1} + }, { size: 1 } ) }), @@ -227,6 +235,8 @@ function getDb(name) { return connections.pg; else if (name === 'sqlite') return connections.sqlite; + else if (name === 'd1') + return connections.d1; else if (name === 'sqlite2') return connections.sqlite2; else if (name === 'sap') diff --git a/tests/getMany.test.js b/tests/getMany.test.js index 0ad4ed90..b18dd002 100644 --- a/tests/getMany.test.js +++ b/tests/getMany.test.js @@ -1,5 +1,6 @@ import { describe, test, beforeAll, afterAll, expect } from 'vitest'; import { fileURLToPath } from 'url'; +import setupD1 from './setupD1'; const express = require('express'); import { json } from 'body-parser'; import cors from 'cors'; @@ -15,8 +16,11 @@ const versionArray = process.version.replace('v', '').split('.'); const major = parseInt(versionArray[0]); const port = 3000; let server; +let d1; +let miniflare; afterAll(async () => { + await miniflare.dispose(); return new Promise((res) => { if (server) server.close(res); @@ -27,6 +31,7 @@ afterAll(async () => { beforeAll(async () => { + ({ d1, miniflare } = await setupD1(fileURLToPath(import.meta.url))); await createMs('mssql'); await insertData('pg'); await insertData('mssql'); @@ -34,6 +39,7 @@ beforeAll(async () => { await insertData('mssqlNative'); await insertData('mysql'); await insertData('sqlite'); + await insertData('d1'); await insertData('sqlite2'); await insertData('sap'); await insertData('oracle'); @@ -136,6 +142,7 @@ describe('offset', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -169,6 +176,7 @@ describe('boolean filter', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -191,6 +199,7 @@ describe('empty array-filter', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -212,6 +221,7 @@ describe('AND empty-array', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -231,6 +241,7 @@ describe('AND one in array', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -250,6 +261,7 @@ describe('boolean true filter', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -271,6 +283,7 @@ describe('any-subFilter filter nested', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -306,6 +319,7 @@ describe('any-subFilter filter nested where', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -342,6 +356,7 @@ describe('getMany hasOne sub filter', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -379,6 +394,7 @@ describe('getMany none sub filter', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -414,6 +430,7 @@ describe('getMany', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -447,6 +464,7 @@ describe('getAll orderBy array', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -481,6 +499,7 @@ describe('getMany with column strategy', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -510,6 +529,7 @@ describe('aggregate', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -555,6 +575,7 @@ describe('aggregate each row', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -653,6 +674,7 @@ describe('getMany with relations', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -730,6 +752,7 @@ describe('getMany with filtered relations', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -804,6 +827,7 @@ describe('getMany composite', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); async function verify(dbName) { @@ -853,6 +877,7 @@ describe('getMany raw filter', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); async function verify(dbName) { @@ -887,6 +912,7 @@ describe('getMany raw filter where', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); async function verify(dbName) { @@ -1050,6 +1076,10 @@ const connections = { db: map({ db: (con) => con.sqlite(sqliteName, { size: 1 }) }), init: initSqlite }, + d1: { + db: map({ db: (con) => con.d1(d1, { size: 1 }) }), + init: initSqlite + }, sqlite2: { db: map({ db: (con) => con.sqlite(sqliteName2, { size: 1 }) }), init: initSqlite @@ -1091,6 +1121,8 @@ function getDb(name) { return connections.pg; else if (name === 'sqlite') return connections.sqlite; + else if (name === 'd1') + return connections.d1; else if (name === 'sqlite2') return connections.sqlite2; else if (name === 'sap') diff --git a/tests/initOracle.js b/tests/initOracle.js index c491a6cd..a412efaa 100644 --- a/tests/initOracle.js +++ b/tests/initOracle.js @@ -135,7 +135,7 @@ BEGIN `INSERT INTO "datetest"("date", "tdatetime", "tdatetime_tz") VALUES(TO_TIMESTAMP('2023-07-14T12:00:00.000', 'YYYY-MM-DD"T"HH24:MI:SS.FF6'), TO_TIMESTAMP('2023-07-14T12:00:00.000', 'YYYY-MM-DD"T"HH24:MI:SS.FF6'), TO_TIMESTAMP('2023-07-14T12:00:00.000', 'YYYY-MM-DD"T"HH24:MI:SS.FF6') ) - `, 'COMMIT']; + `]; module.exports = async function(db) { await db.transaction(async (db) => { @@ -143,4 +143,9 @@ module.exports = async function(db) { await db.query(statements[i]); } }); + // await db.transaction(async (db) => { + // for (let i = 0; i < statements.length; i++) { + // await db.query(statements[i]); + // } + // }); }; \ No newline at end of file diff --git a/tests/insert.test.js b/tests/insert.test.js index 1b14ff0d..2c5a2954 100644 --- a/tests/insert.test.js +++ b/tests/insert.test.js @@ -1,5 +1,6 @@ import { describe, test, beforeAll, expect, afterAll } from 'vitest'; import { fileURLToPath } from 'url'; +import setupD1 from './setupD1'; const express = require('express'); import { json } from 'body-parser'; import cors from 'cors'; @@ -15,9 +16,11 @@ const versionArray = process.version.replace('v', '').split('.'); const major = parseInt(versionArray[0]); const port = 3010; let server; +let d1; +let miniflare; beforeAll(async () => { - + ({ d1, miniflare } = await setupD1(fileURLToPath(import.meta.url))); await createMs('mssql'); hostExpress(); @@ -42,6 +45,7 @@ beforeAll(async () => { }); afterAll(async () => { + await miniflare.dispose(); return new Promise((res) => { if (server) server.close(res); @@ -93,6 +97,7 @@ describe('validate', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -132,6 +137,7 @@ describe('validate chained', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -168,6 +174,7 @@ describe('validate JSONSchema', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -205,6 +212,7 @@ describe('validate notNull', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -238,6 +246,7 @@ describe('validate notNullExceptInsert', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -281,6 +290,7 @@ describe('insert autoincremental', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -321,6 +331,7 @@ describe('insert default', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -358,6 +369,7 @@ describe('insert default override', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -394,6 +406,7 @@ describe('insert dbNull', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -445,6 +458,7 @@ describe('insert autoincremental with relations', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -596,6 +610,7 @@ describe('insert autoincremental with relations and strategy', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -758,6 +773,10 @@ const connections = { db: map({ db: (con) => con.sqlite(sqliteName, { size: 1 }) }), init: initSqlite }, + d1: { + db: map({ db: (con) => con.d1(d1, { size: 1 }) }), + init: initSqlite + }, sqlite2: { db: map({ db: (con) => con.sqlite(sqliteName2, { size: 1 }) }), init: initSqlite @@ -774,7 +793,7 @@ const connections = { password: 'P@assword123', connectString: 'oracle/XE', privilege: 2 - }, {size: 1} + }, { size: 1 } ) }), @@ -799,6 +818,8 @@ function getDb(name) { return connections.pg; else if (name === 'sqlite') return connections.sqlite; + else if (name === 'd1') + return connections.d1; else if (name === 'sqlite2') return connections.sqlite2; else if (name === 'sap') diff --git a/tests/insertAndForget.test.js b/tests/insertAndForget.test.js index cef351d2..f4232305 100644 --- a/tests/insertAndForget.test.js +++ b/tests/insertAndForget.test.js @@ -1,5 +1,6 @@ import { describe, test, beforeAll, expect, afterAll } from 'vitest'; import { fileURLToPath } from 'url'; +import setupD1 from './setupD1'; const express = require('express'); import { json } from 'body-parser'; import cors from 'cors'; @@ -15,9 +16,11 @@ const versionArray = process.version.replace('v', '').split('.'); const major = parseInt(versionArray[0]); const port = 3011; let server; +let d1; +let miniflare; beforeAll(async () => { - + ({ d1, miniflare } = await setupD1(fileURLToPath(import.meta.url))); await createMs('mssql'); hostExpress(); @@ -42,6 +45,7 @@ beforeAll(async () => { }); afterAll(async () => { + await miniflare.dispose(); return new Promise((res) => { if (server) server.close(res); @@ -60,6 +64,7 @@ describe('insertAndForget autoincremental with relations', () => { test('mssqlNative', async () => await verify('mssqlNative')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); @@ -219,6 +224,10 @@ const connections = { db: map({ db: (con) => con.sqlite(sqliteName, { size: 1 }) }), init: initSqlite }, + d1: { + db: map({ db: (con) => con.d1(d1, { size: 1 }) }), + init: initSqlite + }, sqlite2: { db: map({ db: (con) => con.sqlite(sqliteName2, { size: 1 }) }), init: initSqlite @@ -235,7 +244,7 @@ const connections = { password: 'P@assword123', connectString: 'oracle/XE', privilege: 2 - }, {size: 1} + }, { size: 1 } ) }), @@ -260,6 +269,8 @@ function getDb(name) { return connections.pg; else if (name === 'sqlite') return connections.sqlite; + else if (name === 'd1') + return connections.d1; else if (name === 'sqlite2') return connections.sqlite2; else if (name === 'sap') diff --git a/tests/readonly.test.js b/tests/readonly.test.js index 8c306f90..90c9f961 100644 --- a/tests/readonly.test.js +++ b/tests/readonly.test.js @@ -1,5 +1,6 @@ import { describe, test, beforeAll, afterAll, expect } from 'vitest'; import { fileURLToPath } from 'url'; +import setupD1 from './setupD1'; const map = require('./db2'); import express from 'express'; import cors from 'cors'; @@ -12,14 +13,18 @@ const initSqlite = require('./initSqlite'); const initSap = require('./initSap'); const port = 3009; let server; +let d1; +let miniflare; beforeAll(async () => { + ({ d1, miniflare } = await setupD1(fileURLToPath(import.meta.url))); await insertData('pg'); await insertData('oracle'); await insertData('mssql'); await insertData('mysql'); await insertData('sap'); await insertData('sqlite'); + await insertData('d1'); await insertData('sqlite2'); async function insertData(dbName) { @@ -74,6 +79,11 @@ beforeAll(async () => { } }); +afterAll(async () => { + await miniflare.dispose(); +}); + + describe('readonly everything', () => { const options = { readonly: true }; @@ -90,6 +100,7 @@ describe('readonly everything', () => { test('mssql', async () => await verify('mssql')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -221,6 +232,7 @@ describe('readonly table', () => { test('mssql', async () => await verify('mssql')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -274,6 +286,7 @@ describe('readonly column', () => { test('mssql', async () => await verify('mssql')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -329,6 +342,7 @@ describe('readonly table delete', () => { test('mssql', async () => await verify('mssql')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -367,6 +381,7 @@ describe('readonly nested table delete', () => { test('mssql', async () => await verify('mssql')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -404,6 +419,7 @@ describe('readonly on grandChildren table delete', () => { test('mssql', async () => await verify('mssql')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -442,6 +458,7 @@ describe('readonly nested table delete override', () => { test('mssql', async () => await verify('mssql')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -475,6 +492,7 @@ describe('readonly column no change', () => { test('mssql', async () => await verify('mssql')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -521,6 +539,7 @@ describe('readonly nested column', () => { test('mssql', async () => await verify('mssql')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -564,6 +583,7 @@ describe('readonly nested table', () => { test('mssql', async () => await verify('mssql')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -602,6 +622,7 @@ describe('readonly table with column override', () => { test('mssql', async () => await verify('mssql')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -649,6 +670,7 @@ describe('readonly column delete', () => { test('mssql', async () => await verify('mssql')); test('mysql', async () => await verify('mysql')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('sap', async () => await verify('sap')); test('http', async () => await verify('http')); @@ -714,6 +736,10 @@ const connections = { db: map({ db: (con) => con.sqlite(sqliteName, { size: 1 }) }), init: initSqlite }, + d1: { + db: map({ db: (con) => con.d1(d1, { size: 1 }) }), + init: initSqlite + }, sqlite2: { db: map({ db: (con) => con.sqlite(sqliteName2, { size: 1 }) }), init: initSqlite @@ -730,7 +756,7 @@ const connections = { password: 'P@assword123', connectString: 'oracle/XE', privilege: 2 - }, {size: 1} + }, { size: 1 } ) }), @@ -755,6 +781,8 @@ function getDb(name) { return connections.pg; else if (name === 'sqlite') return connections.sqlite; + else if (name === 'd1') + return connections.d1; else if (name === 'sqlite2') return connections.sqlite2; else if (name === 'sap') diff --git a/tests/setupD1.js b/tests/setupD1.js new file mode 100644 index 00000000..f555bc23 --- /dev/null +++ b/tests/setupD1.js @@ -0,0 +1,25 @@ +import { Miniflare } from 'miniflare'; + +export default async function setupD1(path) { + const pathSegments = path.split('/'); + const lastSegment = pathSegments[pathSegments.length - 1]; + const fileNameWithoutExtension = lastSegment.split('.')[0]; + let miniflare; + let d1; + const sqliteName = `demo.d1.${fileNameWithoutExtension}.db`; + + miniflare = new Miniflare({ + modules: true, // Enable module mode explicitly for ES module support + script: 'export default { fetch() {} };', // Minimal worker script as a module + d1Databases: { + DB: sqliteName, // D1 binding + }, + envPath: true, // Load environment variables from .env if needed + }); + + await miniflare.getBindings(); + d1 = await miniflare.getD1Database('DB'); + return { miniflare, d1 }; +} + + diff --git a/tests/update.test.js b/tests/update.test.js index 0f7093aa..805c561c 100644 --- a/tests/update.test.js +++ b/tests/update.test.js @@ -1,5 +1,6 @@ import { describe, test, beforeAll, afterAll, expect } from 'vitest'; import { fileURLToPath } from 'url'; +import setupD1 from './setupD1'; const map = require('./db'); import express from 'express'; import cors from 'cors'; @@ -19,8 +20,11 @@ const date1 = new Date(2022, 0, 11, 9, 24, 47); const date2 = new Date(2021, 0, 11, 12, 22, 45); let server = null; const port = 3002; +let d1; +let miniflare; afterAll(async () => { + await miniflare.dispose(); return new Promise((res) => { if (server) server.close(res); @@ -31,6 +35,7 @@ afterAll(async () => { beforeAll(async () => { + ({ d1, miniflare } = await setupD1(fileURLToPath(import.meta.url))); await insertData('pg'); await insertData('oracle'); await insertData('mssql'); @@ -39,6 +44,7 @@ beforeAll(async () => { await insertData('mysql'); await insertData('sap'); await insertData('sqlite'); + await insertData('d1'); await insertData('sqlite2'); hostExpress(); @@ -113,6 +119,7 @@ describe('update date in array', () => { test('mysql', async () => await verify('mysql')); test('sap', async () => await verify('sap')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('http', async () => await verify('http')); async function verify(dbName) { @@ -137,6 +144,7 @@ describe('update multiple in array', () => { test('mysql', async () => await verify('mysql')); test('sap', async () => await verify('sap')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('http', async () => await verify('http')); async function verify(dbName) { @@ -218,6 +226,7 @@ describe('delete row', () => { test('mysql', async () => await verify('mysql')); test('sap', async () => await verify('sap')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('http', async () => await verify('http')); async function verify(dbName) { @@ -241,6 +250,7 @@ describe('update boolean', () => { test('mysql', async () => await verify('mysql')); test('sap', async () => await verify('sap')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('http', async () => await verify('http')); async function verify(dbName) { @@ -263,6 +273,7 @@ describe('update date', () => { test('mysql', async () => await verify('mysql')); test('sap', async () => await verify('sap')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('http', async () => await verify('http')); async function verify(dbName) { @@ -287,6 +298,7 @@ describe('add hasOne', () => { test('mysql', async () => await verify('mysql')); test('sap', async () => await verify('sap')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('http', async () => await verify('http')); async function verify(dbName) { @@ -365,6 +377,10 @@ const connections = { db: map({ db: (con) => con.sqlite(sqliteName, { size: 1 }) }), init: initSqlite }, + d1: { + db: map({ db: (con) => con.d1(d1, { size: 1 }) }), + init: initSqlite + }, sqlite2: { db: map({ db: (con) => con.sqlite(sqliteName2, { size: 1 }) }), init: initSqlite @@ -381,7 +397,7 @@ const connections = { password: 'P@assword123', connectString: 'oracle/XE', privilege: 2 - }, {size: 1} + }, { size: 1 } ) }), @@ -406,6 +422,8 @@ function getDb(name) { return connections.pg; else if (name === 'sqlite') return connections.sqlite; + else if (name === 'd1') + return connections.d1; else if (name === 'sqlite2') return connections.sqlite2; else if (name === 'sap') diff --git a/tests/updateJSON.test.js b/tests/updateJSON.test.js index 7d0752c2..324ec3d0 100644 --- a/tests/updateJSON.test.js +++ b/tests/updateJSON.test.js @@ -1,5 +1,6 @@ import { describe, test, beforeAll, afterAll, expect } from 'vitest'; import { fileURLToPath } from 'url'; +import setupD1 from './setupD1'; const map = require('./db'); import express from 'express'; import cors from 'cors'; @@ -18,8 +19,11 @@ const date1 = new Date(2022, 0, 11, 9, 24, 47); const date2 = new Date(2021, 0, 11, 12, 22, 45); let server = null; const port = 3002; +let d1; +let miniflare; async function globalSetup() { + ({ d1, miniflare } = await setupD1(fileURLToPath(import.meta.url))); await insertData('pg'); await insertData('oracle'); await insertData('mssql'); @@ -28,6 +32,7 @@ async function globalSetup() { await insertData('mysql'); await insertData('sap'); await insertData('sqlite'); + await insertData('d1'); await insertData('sqlite2'); hostExpress(); } @@ -90,7 +95,8 @@ function hostExpress() { server = app.listen(port, () => console.log(`Example app listening on port ${port}!`)); } -function globalTeardown() { +async function globalTeardown() { + await miniflare.dispose(); return new Promise((res) => { if (server) server.close(res); @@ -116,6 +122,7 @@ describe('updateChanges', () => { test('mysql', async () => await verify('mysql')); test('sap', async () => await verify('sap')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('http', async () => await verify('http')); async function verify(dbName) { @@ -176,6 +183,7 @@ describe('replace then return rows', () => { test('mysql', async () => await verify('mysql')); test('sap', async () => await verify('sap')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('http', async () => await verify('http')); async function verify(dbName) { @@ -246,6 +254,7 @@ describe('replace', () => { test('mysql', async () => await verify('mysql')); test('sap', async () => await verify('sap')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('http', async () => await verify('http')); async function verify(dbName) { @@ -319,6 +328,7 @@ describe('update with JSON', () => { test('mysql', async () => await verify('mysql')); test('sap', async () => await verify('sap')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('http', async () => await verify('http')); async function verify(dbName) { @@ -392,6 +402,7 @@ describe('update with JSON then return rows', () => { test('mysql', async () => await verify('mysql')); test('sap', async () => await verify('sap')); test('sqlite', async () => await verify('sqlite')); + test('d1', async () => await verify('d1')); test('http', async () => await verify('http')); async function verify(dbName) { @@ -484,6 +495,10 @@ const connections = { db: map({ db: (con) => con.sqlite(sqliteName, { size: 1 }) }), init: initSqlite }, + d1: { + db: map({ db: (con) => con.d1(d1, { size: 1 }) }), + init: initSqlite + }, sqlite2: { db: map({ db: (con) => con.sqlite(sqliteName2, { size: 1 }) }), init: initSqlite @@ -525,6 +540,8 @@ function getDb(name) { return connections.pg; else if (name === 'sqlite') return connections.sqlite; + else if (name === 'd1') + return connections.d1; else if (name === 'sqlite2') return connections.sqlite2; else if (name === 'sap')