From b66e255b4bbaaa1ec03f619f69f5ed1ff4b5e101 Mon Sep 17 00:00:00 2001 From: Sam Jeffress Date: Fri, 23 Feb 2018 09:30:38 +1100 Subject: [PATCH] feat: option to disable deepInsert (fixes #550) * added ignoreJunction option for Insert * using 'deepInsert' option as it's more meaningful for user * docs: add deepInsert to options docs --- docs/options.md | 1 + docs/persistence.md | 2 ++ lib/statement/insert.js | 6 +++--- test/statement/insert.js | 27 +++++++++++++++++++++++++++ 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/docs/options.md b/docs/options.md index 76e72e4..709650f 100644 --- a/docs/options.md +++ b/docs/options.md @@ -39,6 +39,7 @@ Certain SQL clauses are used with different types of query. For example, a `LIMI | order | `SELECT` | An array of order objects (see below) or a literal string in the form `column1 ASC, column2 DESC`. **Avoid sending user input as a literal string. If you have to, be aware of the possibility of SQL injection.** | | orderBody | `SELECT` | If querying a document table, set to `true` to apply `options.order` to fields in the document body rather than the table. | | onConflictIgnore | `INSERT` | If the inserted data would violate a unique constraint, do nothing. | +| deepInsert | `INSERT` | Specify `false` when passing a record object which contains keys that do not represent columns or junctions to prevent Massive from trying to handle the extra data. | **nb. The `exprs`, `order`, and the deprecated `columns` options interpolate values into the emitted SQL. Take care with raw strings and ensure that user input is never directly passed in through the options, or you risk opening yourself up to SQL injection attacks.** diff --git a/docs/persistence.md b/docs/persistence.md index d69c34b..7a16f3f 100644 --- a/docs/persistence.md +++ b/docs/persistence.md @@ -88,6 +88,8 @@ db.tests.insert({ Deep insert is _only_ supported when inserting single records. Attempting to deep insert an array of records will raise an exception. +If your object is going to store a property as json in postgres, you will want to ignore deep insert functions, otherwise it will look for junction tables that match the nested object. To do this use the option ` { deepInsert: false }` with the insert. + #### Options [Query options](/options) for `INSERT` statements and results processing may be used with `insert`: diff --git a/lib/statement/insert.js b/lib/statement/insert.js index db5a342..3c275c5 100644 --- a/lib/statement/insert.js +++ b/lib/statement/insert.js @@ -21,7 +21,7 @@ const Insert = function (source, record, options = {}) { this.generator = options.generator; this.stream = options.stream; this.onConflictIgnore = options.onConflictIgnore; - + this.deepInsert = options.hasOwnProperty('deepInsert') ? options.deepInsert : true; if (_.isArray(record)) { this.records = record; } else { @@ -40,7 +40,7 @@ const Insert = function (source, record, options = {}) { const recordParams = prepareParams(this.columns, this.records); - if (this.junctions.length) { + if (this.deepInsert && this.junctions.length) { if (this.records.length > 1) { throw new Error('Deep insert is only supported for single records'); } @@ -87,7 +87,7 @@ Insert.prototype.format = function () { sql += `RETURNING *`; - if (this.junctions.length) { + if (this.deepInsert && this.junctions.length) { const sourcePkList = `"${this.source.pk.join('", "')}"`; const junctionQueries = _.reduce(this.junctions, (queries, j, idx) => { diff --git a/test/statement/insert.js b/test/statement/insert.js index 674cf76..adf3091 100644 --- a/test/statement/insert.js +++ b/test/statement/insert.js @@ -117,6 +117,33 @@ describe('Insert', function () { assert.deepEqual(result.params, ['value1', 10, 'something', 101, 'j2f1', 102, null]); }); + it('should not create junction queries when options specified', function () { + const result = new Insert( + source, + { + field1: 'value1', + junction_one: [{ + j1fk: 10, + source_id: undefined, + j1field: 'something' + }], + junction_many: [{ + source_id_another_name: undefined, + j2fk: 101, + j2field: 'j2f1' + }, { + source_id_another_name: undefined, + j2fk: 102, + j2field: null + }] + }, + {deepInsert: false} + ); + + assert.equal(result.format(), 'INSERT INTO testsource ("field1") VALUES ($1) RETURNING *'); + assert.deepEqual(result.params, ['value1']); + }); + it('should throw when trying to create junction queries for multiple records', function () { try { const x = new Insert(