diff --git a/lib/statement/select.js b/lib/statement/select.js index 142c3f5..17afecd 100644 --- a/lib/statement/select.js +++ b/lib/statement/select.js @@ -47,20 +47,36 @@ const Select = function (source, criteria = {}, options = {}) { this.fields = []; } - _.castArray(options.fields || []).forEach((f) => { + // add user-defined fields + this.fields = _.castArray(options.fields || []).reduce((all, field) => { if (options.document) { - this.fields.push(parseKey(`body.${f}`).field); + // document fields need to be aliased + all.push({ + value: parseKey(`body.${field}`).field, + alias: field + }); + } else { + all.push(parseKey(field).field); } - this.fields.push(parseKey(f).field); - }); + return all; + }, this.fields); + // interpolate unsafe user-defined expressions _.forEach(options.exprs, (expr, name) => { - this.fields.push(`${expr} AS ${name}`); + this.fields.push({ + value: expr, + alias: name + }); }); if (this.fields.length === 0) { + // if the user didn't specify anything this.fields = ['*']; + } else if (options.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 + this.fields.push('id'); } if (Object.prototype.hasOwnProperty.call(criteria, 'conditions') && Object.prototype.hasOwnProperty.call(criteria, 'params')) { @@ -89,7 +105,16 @@ const Select = function (source, criteria = {}, options = {}) { * @return {String} A SQL SELECT statement. */ Select.prototype.format = function () { - let sql = `SELECT ${this.fields.join(',')} FROM `; + const selectList = this.fields.map(f => { + if (_.isPlainObject(f)) { + // aliased definitions for document fields + return `${f.value} AS "${f.alias}"`; + } + + return f; + }); + + let sql = `SELECT ${selectList.join(',')} FROM `; if (this.only) { sql += 'ONLY '; } diff --git a/lib/util/docify.js b/lib/util/docify.js index 58de66e..da84b91 100644 --- a/lib/util/docify.js +++ b/lib/util/docify.js @@ -23,11 +23,15 @@ exports = module.exports = function (result) { return null; } - const returnDoc = _.cloneDeep(row.body); + if (row.body) { + const returnDoc = _.cloneDeep(row.body); - returnDoc.id = row.id; + returnDoc.id = row.id; - return returnDoc; + return returnDoc; + } + + return row; } if (_.isArray(result)) { diff --git a/test/queryable/findDoc.js b/test/queryable/findDoc.js index 54dc590..a3a2f1c 100644 --- a/test/queryable/findDoc.js +++ b/test/queryable/findDoc.js @@ -173,6 +173,15 @@ describe('findDoc', function () { }); }); + it('restricts fields', function () { + return db.docs.findDoc({title: 'Document 1'}, {fields: ['title']}).then(docs => { + assert.lengthOf(docs, 1); + assert.equal(docs[0].id, 1); + assert.equal(docs[0].title, 'Document 1'); + assert.isUndefined(docs[0].description); + }); + }); + it('passing object without hasOwnProperty method', function () { const criteria = Object.create(null); criteria.title = 'Document 1'; diff --git a/test/statement/select.js b/test/statement/select.js index eee7c37..9c5d053 100644 --- a/test/statement/select.js +++ b/test/statement/select.js @@ -67,6 +67,15 @@ describe('Select', function () { assert.equal(result.format(), `SELECT "field"->>'element',"field"#>>'{array,0}',"field"#>>'{array,1,nested,2,element}' FROM testsource WHERE TRUE ORDER BY 1`); }); + it('should alias fields in document mode', function () { + const result = new Select(source, {}, { + fields: ['one', 'two'], + document: true + }); + + assert.equal(result.format(), `SELECT "body"->>'one' AS "one","body"->>'two' AS "two",id FROM testsource WHERE TRUE ORDER BY 1`); + }); + it('should add expressions', function () { const result = new Select(source, {}, { exprs: { @@ -75,7 +84,7 @@ describe('Select', function () { } }); - assert.equal(result.format(), 'SELECT col1 + col2 AS colsum,col1 - col2 AS coldiff FROM testsource WHERE TRUE ORDER BY 1'); + assert.equal(result.format(), 'SELECT col1 + col2 AS "colsum",col1 - col2 AS "coldiff" FROM testsource WHERE TRUE ORDER BY 1'); }); it('should add fields and expressions', function () { @@ -87,7 +96,7 @@ describe('Select', function () { } }); - assert.equal(result.format(), 'SELECT "col1","col2",col1 + col2 AS colsum,col1 - col2 AS coldiff FROM testsource WHERE TRUE ORDER BY 1'); + assert.equal(result.format(), 'SELECT "col1","col2",col1 + col2 AS "colsum",col1 - col2 AS "coldiff" FROM testsource WHERE TRUE ORDER BY 1'); }); it('should add an offset', function () { diff --git a/test/util/docify.js b/test/util/docify.js index cfd3ff2..60c90da 100644 --- a/test/util/docify.js +++ b/test/util/docify.js @@ -16,6 +16,10 @@ describe('docify', function () { assert.deepEqual(docs, [{id: 1, val: 'val1'}, {id: 2, val: 'val2'}]); }); + it('docifies a row without a body', function () { + assert.deepEqual(docify({id: 1, field: 'value'}), {id: 1, field: 'value'}); + }); + it('returns null if there is no row', function () { assert.equal(docify(), null); });