diff --git a/server/api/domain/domainControllerHelper.js b/server/api/domain/domainControllerHelper.js index 901634c..e033a39 100644 --- a/server/api/domain/domainControllerHelper.js +++ b/server/api/domain/domainControllerHelper.js @@ -25,7 +25,7 @@ function statusByErr(err) { if (err.code === '-70001') { return 404; } else if (err.code === '-70002') { - return 403; + return 410; } return 500; diff --git a/server/components/orm/insertQuery.js b/server/components/orm/insertQuery.js index 5dda9d2..70888d6 100644 --- a/server/components/orm/insertQuery.js +++ b/server/components/orm/insertQuery.js @@ -98,7 +98,7 @@ export default function (config, body, predicates, poolConfig, joins) { WHEN NOT MATCHED ${refAliasesString && `AND ${refAliasesString} IS NOT NULL`} THEN INSERT ${refAliasesString && `WHEN NOT MATCHED THEN RAISERROR 70001`} ${tPredicates && `WHEN MATCHED AND NOT (${tPredicates}) THEN RAISERROR 70002`} - WHEN MATCHED ${refAliasesString && `AND ${refAliasesString} IS NOT NULL`} THEN UPDATE SET + WHEN MATCHED ${refAliasesString && `AND ${refAliasesString} IS NOT NULL`} THEN UPDATE SET ${updateMatched.join(', ')} ${refAliasesString && `WHEN MATCHED THEN RAISERROR 70001`} `; diff --git a/server/components/orm/selectQuery.js b/server/components/orm/selectQuery.js index 4ebfdd0..f802afa 100644 --- a/server/components/orm/selectQuery.js +++ b/server/components/orm/selectQuery.js @@ -16,9 +16,12 @@ export default function (parameters) { let joins = _.cloneDeep(parameters.joins) || config.joins; let req = params.req; let orderBy; + let whereOptional = []; let groupBy = params['groupBy:']; + return makeQuery(config); + function parseOrderByParams(params) { let arr = params.split(','); @@ -37,7 +40,7 @@ export default function (parameters) { if (colPrefixMatch) { colPrefix = colPrefixMatch[1]; - let refField = _.find(config.fields, {alias: colPrefix}); + let refField = _.find(config.fields, { alias: colPrefix }); if (refField && !refField.fields) { colPrefix = `[${colPrefix}].`; colName = colPrefixMatch[2]; @@ -224,8 +227,7 @@ export default function (parameters) { if (params[param]) { result.params.push(params[param]); return `[${param}] = ?`; - } - else if (p.match(/\?}$/)) { + } else if (p.match(/\?}$/)) { return ''; } else { throw new Error(`Required parameter missing: "${param}"`); @@ -240,27 +242,39 @@ export default function (parameters) { if (refTableNames.size > 0) { //debug('refTableNames', [...refTableNames]); for (let ref of refTableNames) { + + const parentIdRef = `[${ref[1].alias}].id`; + if (ref[1].optional) { result.query += ' LEFT'; } + let localField = alias + '.[' + ref[1].field + ']'; if (ref[1].expr) { localField = ref[1].expr; } - result.query += ` JOIN ${ref[1].tableName} as [${ref[1].alias}] on [${ref[1].alias}].id = ${localField} `; + result.query += ` JOIN ${ref[1].tableName} as [${ref[1].alias}] on ${parentIdRef} = ${localField} `; + + if (ref[1].optional === 'not null') { + whereOptional.push(`${parentIdRef} is not null or ${localField} is null`); + } + //debug('predicatesForJoin', 'predicates:', predicates); let predicatesForJoin = _.filter(predicates, (p) => { return p.collection === ref[1].alias; }); + _.each(predicatesForJoin, (p) => { - result.query += `AND (${p.field ? `${ref[1].alias}.${p.field} ` : ''}${p.sql}) `; + result.query += `AND (${p.field ? `${ref[1].alias}.${escaped(p.field)} ` : ''}${p.sql}) `; if (_.isArray(p.params)) { Array.prototype.push.apply(result.params, p.params); } }); + //debug('predicatesForJoin', predicatesForJoin); + } } @@ -318,7 +332,7 @@ export default function (parameters) { if (field) { field = field.refConfig.fields[match[2]]; - } + } debug('makePredicate dot ref field', field); @@ -402,7 +416,7 @@ export default function (parameters) { let predField = fields[pred.field]; // TODO support pred.dbField let predAlias = (predField && predField.field === pred.field && !groupBy) ? '' : (alias + '.'); - predicateStr += `(${predAlias}${pred.field} ${pred.sql}) AND `; + predicateStr += `(${predAlias}${escaped(pred.field)} ${pred.sql}) AND `; } else if (!pred.field && pred.collection === alias) { // or maybe better check for field in modelPredicates @@ -423,7 +437,7 @@ export default function (parameters) { try { - let {searchFields, searchFor} = params['q:']; + let { searchFields, searchFor } = params['q:']; if (_.isString(searchFields)) { withPredicate = true; @@ -437,6 +451,11 @@ export default function (parameters) { } + if (whereOptional.length) { + withPredicate = true; + predicateStr += `${whereOptional.map(p => `(${p})`).join(' AND ')} AND `; + } + if (offset && offset !== '*') { try { let offsetId = parseInt(offset.match(/[\d]+$/)[0]); @@ -502,5 +521,11 @@ export default function (parameters) { return result; } - return makeQuery(config); }; + +function escaped(field) { + if (/\[.+]/.test(field)) { + return field; + } + return `[${field}]`; +}