diff --git a/.eslintrc.json b/.eslintrc.json index d1a9a5c6c..c64a114ea 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -28,7 +28,7 @@ "no-else-return": "off", "no-multiple-empty-lines": "off", "no-nested-ternary": "off", - "no-only-tests/no-only-tests": "error", + "no-only-tests/no-only-tests": [ "error", { "block": [ "describe", "it", "describeMigration" ] } ], "no-restricted-syntax": "off", "no-underscore-dangle": "off", "nonblock-statement-body-position": "off", diff --git a/lib/model/migrations/.eslintrc.json b/lib/model/migrations/.eslintrc.json new file mode 100644 index 000000000..93a99d9dd --- /dev/null +++ b/lib/model/migrations/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "extends": "../../../.eslintrc.json", + "rules": { + "no-restricted-modules": [ "error", { "patterns": [ "../*" ] } ] + } +} diff --git a/lib/model/migrations/20180727-02-add-md5-to-blobs.js b/lib/model/migrations/20180727-02-add-md5-to-blobs.js index de05f99a4..c66eb52bb 100644 --- a/lib/model/migrations/20180727-02-add-md5-to-blobs.js +++ b/lib/model/migrations/20180727-02-add-md5-to-blobs.js @@ -8,7 +8,7 @@ // except according to the terms contained in the LICENSE file. // -const { md5sum } = require('../../util/crypto'); +const { md5sum } = require('../../util/crypto'); // eslint-disable-line no-restricted-modules const up = (knex) => knex.schema.table('blobs', (blobs) => { blobs.string('md5', 32); }) diff --git a/lib/model/migrations/20180727-03-add-form-attachments-table.js b/lib/model/migrations/20180727-03-add-form-attachments-table.js index 80aea61ab..33ebf322d 100644 --- a/lib/model/migrations/20180727-03-add-form-attachments-table.js +++ b/lib/model/migrations/20180727-03-add-form-attachments-table.js @@ -23,7 +23,7 @@ const up = (knex) => fa.index([ 'formId' ]); }).then(() => { - const { expectedFormAttachments } = require('../../data/schema'); + const { expectedFormAttachments } = require('../../data/schema'); // eslint-disable-line no-restricted-modules const { uniq, pluck } = require('ramda'); // now add all expected attachments on extant forms. diff --git a/lib/model/migrations/20190520-01-add-form-versioning.js b/lib/model/migrations/20190520-01-add-form-versioning.js index 2d11c8ce3..9148d1ac6 100644 --- a/lib/model/migrations/20190520-01-add-form-versioning.js +++ b/lib/model/migrations/20190520-01-add-form-versioning.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { shasum, sha256sum } = require('../../util/crypto'); +const { shasum, sha256sum } = require('../../util/crypto'); // eslint-disable-line no-restricted-modules const assert = require('assert').strict; const check = (message, query) => diff --git a/lib/model/migrations/20191007-01-backfill-client-audits.js b/lib/model/migrations/20191007-01-backfill-client-audits.js index c6551c255..bb3c8ceef 100644 --- a/lib/model/migrations/20191007-01-backfill-client-audits.js +++ b/lib/model/migrations/20191007-01-backfill-client-audits.js @@ -7,9 +7,9 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { parseClientAudits } = require('../../data/client-audits'); -const { getFormFields } = require('../../data/schema'); -const { traverseXml, findOne, root, node, text } = require('../../util/xml'); +const { parseClientAudits } = require('../../data/client-audits'); // eslint-disable-line no-restricted-modules +const { getFormFields } = require('../../data/schema'); // eslint-disable-line no-restricted-modules +const { traverseXml, findOne, root, node, text } = require('../../util/xml'); // eslint-disable-line no-restricted-modules const up = (db) => new Promise((resolve, reject) => { const work = []; diff --git a/lib/model/migrations/20191231-02-add-schema-storage.js b/lib/model/migrations/20191231-02-add-schema-storage.js index d71604530..791d1caa6 100644 --- a/lib/model/migrations/20191231-02-add-schema-storage.js +++ b/lib/model/migrations/20191231-02-add-schema-storage.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { getFormFields } = require('../../data/schema'); +const { getFormFields } = require('../../data/schema'); // eslint-disable-line no-restricted-modules const up = async (db) => { await db.schema.createTable('form_fields', (fields) => { @@ -51,7 +51,7 @@ const up = async (db) => { // this config hardcoding would be dangerous with tests except that // tests will never invoke this path. const config = require('config').get('default.database'); - const db2 = require('../migrate').knexConnect(config); + const db2 = require('../migrate').knexConnect(config); // eslint-disable-line no-restricted-modules return db2.select('projectId', 'xmlFormId').from('forms').where({ currentDefId: formDefId }) .then(([{ projectId, xmlFormId }]) => { process.stderr.write(`\n!!!!\nThe database upgrade to v0.8 has failed because the Form '${xmlFormId}' in Project ${projectId} has an invalid schema. It tries to bind multiple instance nodes at the path ${path}.\n!!!!\n\n`); diff --git a/lib/model/migrations/20200220-01-repair-submission-parsing.js b/lib/model/migrations/20200220-01-repair-submission-parsing.js index d1bd9e0ee..279977ce3 100644 --- a/lib/model/migrations/20200220-01-repair-submission-parsing.js +++ b/lib/model/migrations/20200220-01-repair-submission-parsing.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { Submission } = require('../frames'); +const { Submission } = require('../frames'); // eslint-disable-line no-restricted-modules const up = async (db) => { const work = []; diff --git a/lib/model/migrations/20210120-01-instance-names.js b/lib/model/migrations/20210120-01-instance-names.js index 832407dfc..a16d515b4 100644 --- a/lib/model/migrations/20210120-01-instance-names.js +++ b/lib/model/migrations/20210120-01-instance-names.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { Submission } = require('../frames'); +const { Submission } = require('../frames'); // eslint-disable-line no-restricted-modules const up = async (db) => { await db.schema.table('submission_defs', (sds) => { diff --git a/lib/model/migrations/20211008-01-track-select-many-options.js b/lib/model/migrations/20211008-01-track-select-many-options.js index 413e0f1aa..62397fc8f 100644 --- a/lib/model/migrations/20211008-01-track-select-many-options.js +++ b/lib/model/migrations/20211008-01-track-select-many-options.js @@ -8,10 +8,10 @@ // except according to the terms contained in the LICENSE file. const { map } = require('ramda'); -const { getFormFields } = require('../../data/schema'); -const { getSelectMultipleResponses } = require('../../data/submission'); -const { Form } = require('../frames'); -const { construct } = require('../../util/util'); +const { getFormFields } = require('../../data/schema'); // eslint-disable-line no-restricted-modules +const { getSelectMultipleResponses } = require('../../data/submission'); // eslint-disable-line no-restricted-modules +const { Form } = require('../frames'); // eslint-disable-line no-restricted-modules +const { construct } = require('../../util/util'); // eslint-disable-line no-restricted-modules const up = async (db) => { // add select many flag, options field to fields diff --git a/lib/model/migrations/20230109-01-add-form-schema.js b/lib/model/migrations/20230109-01-add-form-schema.js index 3f591473e..8b0446e2e 100644 --- a/lib/model/migrations/20230109-01-add-form-schema.js +++ b/lib/model/migrations/20230109-01-add-form-schema.js @@ -7,7 +7,7 @@ // including this file, may be copied, modified, propagated, or distributed // except according to the terms contained in the LICENSE file. -const { getFormFields, compare } = require('../../data/schema'); +const { getFormFields, compare } = require('../../data/schema'); // eslint-disable-line no-restricted-modules /* Steps of this migration 1. remove check field collision trigger diff --git a/lib/model/query/forms.js b/lib/model/query/forms.js index 97f04f8e3..508cc37e3 100644 --- a/lib/model/query/forms.js +++ b/lib/model/query/forms.js @@ -242,14 +242,16 @@ const createVersion = (partial, form, publish, duplicating = false) => async ({ // skip checking for structural change if duplicating because user has already // been warning at the time of form definition upload if (!duplicating) { - await Forms.checkStructuralChange(prevFields, fields) - .then(Forms.rejectIfWarnings); + await Forms.checkStructuralChange(prevFields, fields); } // If we haven't been rejected or warned yet, make a new schema id schemaId = await Forms._newSchema(); } } + // Let's check for warnings before pushing to Enketo or to DB + await Forms.rejectIfWarnings(); + // If not publishing, check whether there is an existing draft that we have access to. // If not, generate a draft token and enketoId. let { draftToken, enketoId } = form.def; diff --git a/lib/util/db.js b/lib/util/db.js index e6afa12ad..dc85da51f 100644 --- a/lib/util/db.js +++ b/lib/util/db.js @@ -117,7 +117,7 @@ const unjoiner = (...frames) => { return new frames[0](primary, bag); }; - unjoin.fields = sql`${sql.join(fields, sql`,`)}`; // FIXME remove wrapping sql`` + unjoin.fields = sql.join(fields, sql`,`); return unjoin; }; diff --git a/package-lock.json b/package-lock.json index aa0282bc1..bd02f8ac8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,7 +26,7 @@ "htmlparser2": "~3.9", "knex": "~0.21", "luxon": "~0.3", - "minio": "^7.1.3", + "minio": "^8.0.3", "morgan": "~1.9", "multer": "^1.4.5-lts.1", "mustache": "~2.3", @@ -6291,11 +6291,6 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "node_modules/json-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-stream/-/json-stream-1.0.0.tgz", - "integrity": "sha512-H/ZGY0nIAg3QcOwE1QN/rK/Fa7gJn7Ii5obwp6zyPO4xiPNwpIMjqy2gwjBEGqzkF/vSWEIBQCBuN19hYiL6Qg==" - }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -6905,29 +6900,45 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "node_modules/minio": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minio/-/minio-7.1.3.tgz", - "integrity": "sha512-xPrLjWkTT5E7H7VnzOjF//xBp9I40jYB4aWhb2xTFopXXfw+Wo82DDWngdUju7Doy3Wk7R8C4LAgwhLHHnf0wA==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/minio/-/minio-8.0.3.tgz", + "integrity": "sha512-+FIYQ+HZ5GrBjEmIYienRgEikqaTWAflXIV5lJOtUzfYxn3NvjQx7BsJSORXExlqgzWxKTWsqkyk2wiyFjs9/w==", + "license": "Apache-2.0", "dependencies": { "async": "^3.2.4", "block-stream2": "^2.1.0", "browser-or-node": "^2.1.1", - "buffer-crc32": "^0.2.13", - "fast-xml-parser": "^4.2.2", + "buffer-crc32": "^1.0.0", + "eventemitter3": "^5.0.1", + "fast-xml-parser": "^4.4.1", "ipaddr.js": "^2.0.1", - "json-stream": "^1.0.0", "lodash": "^4.17.21", "mime-types": "^2.1.35", "query-string": "^7.1.3", + "stream-json": "^1.8.0", "through2": "^4.0.2", "web-encoding": "^1.1.5", - "xml": "^1.0.1", - "xml2js": "^0.5.0" + "xml2js": "^0.5.0 || ^0.6.2" }, "engines": { "node": "^16 || ^18 || >=20" } }, + "node_modules/minio/node_modules/buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/minio/node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "license": "MIT" + }, "node_modules/minio/node_modules/ipaddr.js": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", @@ -10411,6 +10422,21 @@ "node": ">= 0.8" } }, + "node_modules/stream-chain": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", + "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==", + "license": "BSD-3-Clause" + }, + "node_modules/stream-json": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.9.1.tgz", + "integrity": "sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==", + "license": "BSD-3-Clause", + "dependencies": { + "stream-chain": "^2.2.5" + } + }, "node_modules/streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -11459,7 +11485,8 @@ "node_modules/xml": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", - "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==" + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", + "dev": true }, "node_modules/xml2js": { "version": "0.5.0", @@ -16267,11 +16294,6 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, - "json-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-stream/-/json-stream-1.0.0.tgz", - "integrity": "sha512-H/ZGY0nIAg3QcOwE1QN/rK/Fa7gJn7Ii5obwp6zyPO4xiPNwpIMjqy2gwjBEGqzkF/vSWEIBQCBuN19hYiL6Qg==" - }, "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", @@ -16726,26 +16748,36 @@ "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "minio": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minio/-/minio-7.1.3.tgz", - "integrity": "sha512-xPrLjWkTT5E7H7VnzOjF//xBp9I40jYB4aWhb2xTFopXXfw+Wo82DDWngdUju7Doy3Wk7R8C4LAgwhLHHnf0wA==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/minio/-/minio-8.0.3.tgz", + "integrity": "sha512-+FIYQ+HZ5GrBjEmIYienRgEikqaTWAflXIV5lJOtUzfYxn3NvjQx7BsJSORXExlqgzWxKTWsqkyk2wiyFjs9/w==", "requires": { "async": "^3.2.4", "block-stream2": "^2.1.0", "browser-or-node": "^2.1.1", - "buffer-crc32": "^0.2.13", - "fast-xml-parser": "^4.2.2", + "buffer-crc32": "^1.0.0", + "eventemitter3": "^5.0.1", + "fast-xml-parser": "^4.4.1", "ipaddr.js": "^2.0.1", - "json-stream": "^1.0.0", "lodash": "^4.17.21", "mime-types": "^2.1.35", "query-string": "^7.1.3", + "stream-json": "^1.8.0", "through2": "^4.0.2", "web-encoding": "^1.1.5", - "xml": "^1.0.1", - "xml2js": "^0.5.0" + "xml2js": "^0.5.0 || ^0.6.2" }, "dependencies": { + "buffer-crc32": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-1.0.0.tgz", + "integrity": "sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w==" + }, + "eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==" + }, "ipaddr.js": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.2.0.tgz", @@ -19364,6 +19396,19 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" }, + "stream-chain": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", + "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==" + }, + "stream-json": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.9.1.tgz", + "integrity": "sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==", + "requires": { + "stream-chain": "^2.2.5" + } + }, "streamsearch": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", @@ -20157,7 +20202,8 @@ "xml": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", - "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==" + "integrity": "sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw==", + "dev": true }, "xml2js": { "version": "0.5.0", diff --git a/package.json b/package.json index 5e07c76dc..5bb0feb5e 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "htmlparser2": "~3.9", "knex": "~0.21", "luxon": "~0.3", - "minio": "^7.1.3", + "minio": "^8.0.3", "morgan": "~1.9", "multer": "^1.4.5-lts.1", "mustache": "~2.3", diff --git a/test/db-migrations/utils.js b/test/db-migrations/utils.js index 5a1610bb7..b102e8bcd 100644 --- a/test/db-migrations/utils.js +++ b/test/db-migrations/utils.js @@ -77,22 +77,22 @@ function assertRowsMatch(actualRows, expectedRows) { const remainingRows = [...actualRows]; for (let i=0; i _.pick(r, Object.keys(x))); + const filteredRemainingRows = remainingRows.map(r => _.pick(r, Object.keys(expectedRow))); assert.fail( `Expected row ${i} not found:\njson=` + - JSON.stringify({ remainingRows, filteredRemainingRows, expectedRow: x }), + JSON.stringify({ remainingRows, filteredRemainingRows, expectedRow }), ); } } diff --git a/test/integration/api/forms/forms.js b/test/integration/api/forms/forms.js index 635eb3e76..c649fd5f0 100644 --- a/test/integration/api/forms/forms.js +++ b/test/integration/api/forms/forms.js @@ -158,6 +158,25 @@ describe('api: /projects/:id/forms (create, read, update)', () => { })); })); + it('should fail on warnings even for valid xlsx files', testService(async (service) => { + await service.login('alice', (asAlice) => + asAlice.post('/v1/projects/1/forms') + .send(readFileSync(appRoot + '/test/data/simple.xlsx')) + .set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') + .expect(200)); + + global.xlsformTest = 'warning'; // set up the mock service to warn. + return service.login('alice', (asAlice) => + asAlice.post('/v1/projects/1/forms/simple2/draft') + .send(readFileSync(appRoot + '/test/data/simple.xlsx')) + .set('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') + .expect(400) + .then(({ body }) => { + body.code.should.equal(400.16); + body.details.warnings.xlsFormWarnings.should.eql([ 'warning 1', 'warning 2' ]); + })); + })); + it('should create the form for xlsx files with warnings given ignoreWarnings', testService((service) => { global.xlsformTest = 'warning'; // set up the mock service to warn. return service.login('alice', (asAlice) => diff --git a/test/unit/util/db.js b/test/unit/util/db.js index 21742afb6..b9e7930ce 100644 --- a/test/unit/util/db.js +++ b/test/unit/util/db.js @@ -205,8 +205,7 @@ describe('util/db', () => { const T = Frame.define(table('frames'), 'x', 'y'); const U = Frame.define(into('extra'), 'z'); it('should generate fields', () => { - unjoiner(T, U) - .fields.should.eql(sql`"frames"."x" as "frames!x","frames"."y" as "frames!y","z" as "z"`); + sql`${unjoiner(T, U).fields}`.should.eql(sql`"frames"."x" as "frames!x","frames"."y" as "frames!y","z" as "z"`); }); it('should unjoin data', () => { @@ -219,7 +218,7 @@ describe('util/db', () => { it('should optionally unjoin optional data', () => { const unjoin = unjoiner(T, Option.of(U)); - unjoin.fields.should.eql(sql`"frames"."x" as "frames!x","frames"."y" as "frames!y","z" as "z"`); + sql`${unjoin.fields}`.should.eql(sql`"frames"."x" as "frames!x","frames"."y" as "frames!y","z" as "z"`); unjoin({ 'frames!x': 3, 'frames!y': 4, z: 5 }) .should.eql(new T({ x: 3, y: 4 }, { extra: Option.of(new U({ z: 5 })) })); unjoin({ 'frames!x': 3, 'frames!y': 4 }) @@ -239,7 +238,7 @@ describe('util/db', () => { it('should provide the appropriate arguments when not extended', () => { let run = false; extender(T)(U)((fields, extend, options, x, y, z) => { - fields.should.eql(sql`"frames"."x" as "frames!x","frames"."y" as "frames!y"`); + sql`${fields}`.should.eql(sql`"frames"."x" as "frames!x","frames"."y" as "frames!y"`); (sql`${extend|| true}`).should.eql(sql``); x.should.equal(2); y.should.equal(3); @@ -252,7 +251,7 @@ describe('util/db', () => { it('should provide the appropriate arguments when extended', () => { let run = false; extender(T)(U)((fields, extend, options, x, y, z) => { - fields.should.eql(sql`"frames"."x" as "frames!x","frames"."y" as "frames!y","a" as "a","b" as "b"`); + sql`${fields}`.should.eql(sql`"frames"."x" as "frames!x","frames"."y" as "frames!y","a" as "a","b" as "b"`); (sql`${extend|| true}`).should.eql(sql`${true}`); x.should.equal(2); y.should.equal(3);