Loading lib/readable.js +7 −3 Changes for lib/readable.js: 7 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -88,7 +88,12 @@ Readable.prototype.count = function (conditions = {}, params = []) { * @return {Promise} Number of matching documents. */ Readable.prototype.countDoc = function (criteria = {}) { const query = new Select(this, criteria, {exprs: {count: 'COUNT(1)'}, order: null, single: true, generator: 'docGenerator'}); const query = new Select(this, criteria, { exprs: {count: 'COUNT(1)'}, order: null, single: true, document: true }); return this.db.query(query).then(res => res.count); }; Loading @@ -113,7 +118,6 @@ Readable.prototype.find = function (criteria = {}, options = {}) { */ Readable.prototype.findDoc = function (criteria = {}, options = {}) { options.document = true; options.generator = 'docGenerator'; return this.find(criteria, options); }; Loading Loading @@ -254,7 +258,7 @@ Readable.prototype.searchDoc = function (plan, options = {}) { conditions: `${tsv} @@ to_tsquery($1)`, params: [plan.term], where: plan.where, nestedGenerator: options.document ? 'docGenerator' : 'tableGenerator' isDocument: options.document }; options.document = true; // ensure document result handling activates Loading lib/statement/delete.js +5 −28 Changes for lib/statement/delete.js: 5 added lines, 28 removed lines. Original line number Diff line number Diff line 'use strict'; const _ = require('lodash'); const parseKey = require('../util/parse-key'); const where = require('./where'); const Statement = require('./statement'); /** * Represents a DELETE query. Loading @@ -14,35 +13,13 @@ const where = require('./where'); * @param {Object} [options] - {@link https://massivejs.org/docs/options-objects|Delete options}. */ const Delete = function (source, criteria = {}, options = {}) { if (source.isPkSearch(criteria, options)) { options.generator = 'tableGenerator'; // pks are always table columns Statement.call(this, source, options); if (!_.isPlainObject(criteria)) { // primitive unary pk search criteria = _.fromPairs([[source.pk[0], criteria]]); options.single = source.loader !== 'join'; } } const {conditions, params} = where(source, criteria, 0, options.generator); this.source = source; // options governing query behavior this.build = options.build || false; this.decompose = options.decompose; this.document = options.document || false; this.single = options.single || false; this.stream = options.stream || false; // options governing SQL statement elements, in rough order of appearance: this.only = options.only || false; this.conditions = conditions; this.returning = options.fields ? options.fields.map(f => parseKey(f, source).lhs) : ['*']; this.params = params; this.setCriteria(criteria); }; Delete.prototype = Object.create(Statement.prototype); /** * Format this object into a SQL DELETE. * Loading lib/statement/insert.js +5 −9 Changes for lib/statement/insert.js: 5 added lines, 9 removed lines. Original line number Diff line number Diff line 'use strict'; const _ = require('lodash'); const parseKey = require('../util/parse-key'); const prepareParams = require('../util/prepare-params'); const Statement = require('./statement'); /** * Represents an INSERT query. Loading @@ -14,20 +14,15 @@ const prepareParams = require('../util/prepare-params'); * @param {Object} [options] - {@link https://massivejs.org/docs/options-objects|Insert options}. */ const Insert = function (source, record, options = {}) { this.source = source; Statement.call(this, source, options); this.records = _.castArray(record); const fields = this.compileFieldSet(this.records); // options governing query behavior this.build = options.build || false; this.decompose = options.decompose; this.document = options.document || false; this.single = !_.isArray(record); this.stream = options.stream || false; // options governing SQL statement elements, in rough order of appearance: this.only = options.only || false; this.columns = _.intersection(fields, this.source.columnNames); this.junctions = _.difference(fields, this.source.columnNames); Loading Loading @@ -55,9 +50,10 @@ const Insert = function (source, record, options = {}) { this.onConflictIgnore = options.onConflictIgnore; this.onConflictUpdate = options.onConflictUpdate; this.onConflictUpdateExclude = options.onConflictUpdateExclude; this.returning = options.fields ? options.fields.map(f => parseKey(f, source).lhs) : ['*']; }; Insert.prototype = Object.create(Statement.prototype); /** * Build the set of unique column names being targeted across all records. * Loading lib/statement/select.js +9 −28 Changes for lib/statement/select.js: 9 added lines, 28 removed lines. Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ const _ = require('lodash'); const parseKey = require('../util/parse-key'); const where = require('./where'); const Statement = require('./statement'); /** * Represents a SELECT query. Loading @@ -14,34 +14,13 @@ const where = require('./where'); * @param {Object} [options] - {@link https://massivejs.org/docs/options-objects|Select options}. */ const Select = function (source, criteria = {}, options = {}) { if (!!source.isPkSearch && source.isPkSearch(criteria)) { options.generator = 'tableGenerator'; // pks are always table columns Statement.call(this, source, options); if (!_.isPlainObject(criteria)) { // primitive unary pk search criteria = _.fromPairs([[source.pk[0], criteria]]); options.single = source.loader !== 'join'; } } const {conditions, params} = where(source, criteria, 0, options.generator); this.source = source; // options governing query behavior; some also affect statement generation, // such as options.document with buildSelectList. this.build = options.build || false; this.document = options.document || false; this.decompose = options.decompose; this.single = options.single || false; this.stream = options.stream || false; this.setCriteria(criteria); // options governing SQL statement elements, in rough order of appearance: this.distinct = options.distinct || false; this.selectList = this.buildSelectList(options.fields, options.exprs); this.only = options.only || false; this.conditions = conditions; this.order = _.reduce(options.order, (acc, val) => { const direction = val.direction && val.direction.toLowerCase() === 'desc' ? ' DESC' : ' ASC'; const nulls = val.nulls ? ` NULLS ${val.nulls === 'first' ? 'FIRST' : 'LAST'}` : ''; Loading @@ -55,7 +34,6 @@ const Select = function (source, criteria = {}, options = {}) { this.pageLength = options.pageLength; this.forUpdate = options.forUpdate || false; this.forShare = options.forShare || false; this.params = params; // with pageLength set for keyset pagination, add last values of ordering // fields to criteria Loading @@ -78,6 +56,8 @@ const Select = function (source, criteria = {}, options = {}) { } }; Select.prototype = Object.create(Statement.prototype); /** * Build a list of strings comprising fields (plus aliases, for document * tables and joined or compound Readables) and expressions to be retrieved Loading Loading @@ -118,9 +98,10 @@ Select.prototype.buildSelectList = function (fields, exprs) { // we got nothing *explicitly*, error state throw new Error('At least one of fields or exprs must be supplied and must define a field or expression to select.'); } else if (this.document) { // if the user *did* specify something, but we're querying a document table // and so require the id field in addition to whatever they're after } else if (this.document && fields) { // if we're querying fields on a document table, the id must always be // included. Expressions always need to be fully qualified, so expression- // only queries (e.g. countDoc) aren't affected here. selectList.unshift('"id"'); } Loading lib/statement/statement.js 0 → 100644 +60 −0 Changes for lib/statement/statement.js: 60 added lines, 0 removed lines. Original line number Diff line number Diff line 'use strict'; const _ = require('lodash'); const parseKey = require('../util/parse-key'); const where = require('./where'); /** * An SQL DML statement. * * @class * @param {Table} source - Database object to query. * @param {Object} [options] - {@link https://massivejs.org/docs/options-objects|Update options}. */ const Statement = function (source, options = {}) { this.source = source; // query and result processing options this.build = options.build || false; this.decompose = options.decompose; this.document = options.document || false; this.single = options.single || false; this.stream = options.stream || false; // common SQL statement modifications this.only = options.only || false; this.returning = options.fields ? options.fields.map(f => parseKey(f, source).lhs) : ['*']; return this; }; /** * Set the conditions and parameters for SELECT, UPDATE, and DELETE queries. * * @param {Object} criteria - A criteria object. * @param {Array} [initialParams] - Existing parameters which will be prepended * to parameters generated from criteria. */ Statement.prototype.setCriteria = function (criteria, initialParams = []) { this.isPkSearch = this.source.isPkSearch(criteria, this); if (this.isPkSearch && !_.isPlainObject(criteria)) { // primitive unary pk search this.criteria = _.fromPairs([[this.source.pk[0], criteria]]); this.single = this.source.loader !== 'join'; } else { this.criteria = criteria; } const {conditions, params} = where( this.source, this.criteria, initialParams.length, !this.isPkSearch && this.document ); this.conditions = conditions; this.params = initialParams.length ? initialParams.concat(params) : params; }; module.exports = Statement; Loading
lib/readable.js +7 −3 Changes for lib/readable.js: 7 added lines, 3 removed lines. Original line number Diff line number Diff line Loading @@ -88,7 +88,12 @@ Readable.prototype.count = function (conditions = {}, params = []) { * @return {Promise} Number of matching documents. */ Readable.prototype.countDoc = function (criteria = {}) { const query = new Select(this, criteria, {exprs: {count: 'COUNT(1)'}, order: null, single: true, generator: 'docGenerator'}); const query = new Select(this, criteria, { exprs: {count: 'COUNT(1)'}, order: null, single: true, document: true }); return this.db.query(query).then(res => res.count); }; Loading @@ -113,7 +118,6 @@ Readable.prototype.find = function (criteria = {}, options = {}) { */ Readable.prototype.findDoc = function (criteria = {}, options = {}) { options.document = true; options.generator = 'docGenerator'; return this.find(criteria, options); }; Loading Loading @@ -254,7 +258,7 @@ Readable.prototype.searchDoc = function (plan, options = {}) { conditions: `${tsv} @@ to_tsquery($1)`, params: [plan.term], where: plan.where, nestedGenerator: options.document ? 'docGenerator' : 'tableGenerator' isDocument: options.document }; options.document = true; // ensure document result handling activates Loading
lib/statement/delete.js +5 −28 Changes for lib/statement/delete.js: 5 added lines, 28 removed lines. Original line number Diff line number Diff line 'use strict'; const _ = require('lodash'); const parseKey = require('../util/parse-key'); const where = require('./where'); const Statement = require('./statement'); /** * Represents a DELETE query. Loading @@ -14,35 +13,13 @@ const where = require('./where'); * @param {Object} [options] - {@link https://massivejs.org/docs/options-objects|Delete options}. */ const Delete = function (source, criteria = {}, options = {}) { if (source.isPkSearch(criteria, options)) { options.generator = 'tableGenerator'; // pks are always table columns Statement.call(this, source, options); if (!_.isPlainObject(criteria)) { // primitive unary pk search criteria = _.fromPairs([[source.pk[0], criteria]]); options.single = source.loader !== 'join'; } } const {conditions, params} = where(source, criteria, 0, options.generator); this.source = source; // options governing query behavior this.build = options.build || false; this.decompose = options.decompose; this.document = options.document || false; this.single = options.single || false; this.stream = options.stream || false; // options governing SQL statement elements, in rough order of appearance: this.only = options.only || false; this.conditions = conditions; this.returning = options.fields ? options.fields.map(f => parseKey(f, source).lhs) : ['*']; this.params = params; this.setCriteria(criteria); }; Delete.prototype = Object.create(Statement.prototype); /** * Format this object into a SQL DELETE. * Loading
lib/statement/insert.js +5 −9 Changes for lib/statement/insert.js: 5 added lines, 9 removed lines. Original line number Diff line number Diff line 'use strict'; const _ = require('lodash'); const parseKey = require('../util/parse-key'); const prepareParams = require('../util/prepare-params'); const Statement = require('./statement'); /** * Represents an INSERT query. Loading @@ -14,20 +14,15 @@ const prepareParams = require('../util/prepare-params'); * @param {Object} [options] - {@link https://massivejs.org/docs/options-objects|Insert options}. */ const Insert = function (source, record, options = {}) { this.source = source; Statement.call(this, source, options); this.records = _.castArray(record); const fields = this.compileFieldSet(this.records); // options governing query behavior this.build = options.build || false; this.decompose = options.decompose; this.document = options.document || false; this.single = !_.isArray(record); this.stream = options.stream || false; // options governing SQL statement elements, in rough order of appearance: this.only = options.only || false; this.columns = _.intersection(fields, this.source.columnNames); this.junctions = _.difference(fields, this.source.columnNames); Loading Loading @@ -55,9 +50,10 @@ const Insert = function (source, record, options = {}) { this.onConflictIgnore = options.onConflictIgnore; this.onConflictUpdate = options.onConflictUpdate; this.onConflictUpdateExclude = options.onConflictUpdateExclude; this.returning = options.fields ? options.fields.map(f => parseKey(f, source).lhs) : ['*']; }; Insert.prototype = Object.create(Statement.prototype); /** * Build the set of unique column names being targeted across all records. * Loading
lib/statement/select.js +9 −28 Changes for lib/statement/select.js: 9 added lines, 28 removed lines. Original line number Diff line number Diff line Loading @@ -2,7 +2,7 @@ const _ = require('lodash'); const parseKey = require('../util/parse-key'); const where = require('./where'); const Statement = require('./statement'); /** * Represents a SELECT query. Loading @@ -14,34 +14,13 @@ const where = require('./where'); * @param {Object} [options] - {@link https://massivejs.org/docs/options-objects|Select options}. */ const Select = function (source, criteria = {}, options = {}) { if (!!source.isPkSearch && source.isPkSearch(criteria)) { options.generator = 'tableGenerator'; // pks are always table columns Statement.call(this, source, options); if (!_.isPlainObject(criteria)) { // primitive unary pk search criteria = _.fromPairs([[source.pk[0], criteria]]); options.single = source.loader !== 'join'; } } const {conditions, params} = where(source, criteria, 0, options.generator); this.source = source; // options governing query behavior; some also affect statement generation, // such as options.document with buildSelectList. this.build = options.build || false; this.document = options.document || false; this.decompose = options.decompose; this.single = options.single || false; this.stream = options.stream || false; this.setCriteria(criteria); // options governing SQL statement elements, in rough order of appearance: this.distinct = options.distinct || false; this.selectList = this.buildSelectList(options.fields, options.exprs); this.only = options.only || false; this.conditions = conditions; this.order = _.reduce(options.order, (acc, val) => { const direction = val.direction && val.direction.toLowerCase() === 'desc' ? ' DESC' : ' ASC'; const nulls = val.nulls ? ` NULLS ${val.nulls === 'first' ? 'FIRST' : 'LAST'}` : ''; Loading @@ -55,7 +34,6 @@ const Select = function (source, criteria = {}, options = {}) { this.pageLength = options.pageLength; this.forUpdate = options.forUpdate || false; this.forShare = options.forShare || false; this.params = params; // with pageLength set for keyset pagination, add last values of ordering // fields to criteria Loading @@ -78,6 +56,8 @@ const Select = function (source, criteria = {}, options = {}) { } }; Select.prototype = Object.create(Statement.prototype); /** * Build a list of strings comprising fields (plus aliases, for document * tables and joined or compound Readables) and expressions to be retrieved Loading Loading @@ -118,9 +98,10 @@ Select.prototype.buildSelectList = function (fields, exprs) { // we got nothing *explicitly*, error state throw new Error('At least one of fields or exprs must be supplied and must define a field or expression to select.'); } else if (this.document) { // if the user *did* specify something, but we're querying a document table // and so require the id field in addition to whatever they're after } else if (this.document && fields) { // if we're querying fields on a document table, the id must always be // included. Expressions always need to be fully qualified, so expression- // only queries (e.g. countDoc) aren't affected here. selectList.unshift('"id"'); } Loading
lib/statement/statement.js 0 → 100644 +60 −0 Changes for lib/statement/statement.js: 60 added lines, 0 removed lines. Original line number Diff line number Diff line 'use strict'; const _ = require('lodash'); const parseKey = require('../util/parse-key'); const where = require('./where'); /** * An SQL DML statement. * * @class * @param {Table} source - Database object to query. * @param {Object} [options] - {@link https://massivejs.org/docs/options-objects|Update options}. */ const Statement = function (source, options = {}) { this.source = source; // query and result processing options this.build = options.build || false; this.decompose = options.decompose; this.document = options.document || false; this.single = options.single || false; this.stream = options.stream || false; // common SQL statement modifications this.only = options.only || false; this.returning = options.fields ? options.fields.map(f => parseKey(f, source).lhs) : ['*']; return this; }; /** * Set the conditions and parameters for SELECT, UPDATE, and DELETE queries. * * @param {Object} criteria - A criteria object. * @param {Array} [initialParams] - Existing parameters which will be prepended * to parameters generated from criteria. */ Statement.prototype.setCriteria = function (criteria, initialParams = []) { this.isPkSearch = this.source.isPkSearch(criteria, this); if (this.isPkSearch && !_.isPlainObject(criteria)) { // primitive unary pk search this.criteria = _.fromPairs([[this.source.pk[0], criteria]]); this.single = this.source.loader !== 'join'; } else { this.criteria = criteria; } const {conditions, params} = where( this.source, this.criteria, initialParams.length, !this.isPkSearch && this.document ); this.conditions = conditions; this.params = initialParams.length ? initialParams.concat(params) : params; }; module.exports = Statement;