Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

uniqorm

Package Overview
Dependencies
Maintainers
1
Versions
123
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

uniqorm - npm Package Compare versions

Comparing version 2.6.1 to 2.7.0

lib/helpers.js

29

lib/AssociatedField.js

@@ -14,3 +14,3 @@ /* UNIQORM

const Field = require('./Field');
const {ArgumentError} = require('errorex');
const {normalizeAttributes} = require('./helpers');

@@ -44,3 +44,3 @@ /**

this._foreignKey = def.foreignKey;
this._attributes = adjustAttributes(def.attributes);
this._attributes = normalizeAttributes(def.attributes);
if (def.filter)

@@ -144,9 +144,2 @@ def.filter = Array.isArray(def.filter) ? def.filter : [def.filter];

returnsAttribute(attribute) {
return (this.attributes && this.attributes.hasOwnProperty(attribute)) ||
(this.towards &&
/* istanbul ignore next */
this.towards.returnsAttribute(attribute));
}
/**

@@ -165,3 +158,4 @@ *

if (!this._def.fieldName && !this._def.attributes && !this.towards)
this._attributes = adjustAttributes(this.foreignModel.getDataFields());
this._attributes =
normalizeAttributes(Object.keys(this.foreignModel.fields));

@@ -210,17 +204,2 @@ if (this._attributes)

function adjustAttributes(attributes) {
if (!attributes)
return null;
if (Array.isArray(attributes)) {
const result = {};
for (const f of attributes)
result[f] = null;
return result;
}
/* istanbul ignore next */
if (typeof attributes !== 'object')
throw new ArgumentError('You must provide an object value');
return attributes;
}
/**

@@ -227,0 +206,0 @@ * Expose `AssociatedField`.

@@ -106,2 +106,3 @@ /* UNIQORM

/* istanbul ignore next */
// noinspection JSMethodCanBeStatic

@@ -108,0 +109,0 @@ /**

@@ -15,2 +15,4 @@ /* UNIQORM

const {ArgumentError} = require('errorex');
const {normalizeAttributes} = require('./helpers');
const DataField = require('./DataField');
const Op = sqb.Op;

@@ -22,3 +24,3 @@

*/
const COLUMN_PATTERN = /^([a-zA-Z][\w$]*)(?:\.?([\w$]+))?$/;
const COLUMN_PATTERN = /^([_a-zA-Z][\w$]*)(?:\.?([\w$]+))?$/;
const SORT_ORDER_PATTERN = /^([-+])?([a-zA-Z][\w$]*)(?:\.?([\w$]+))?$/i;

@@ -28,2 +30,3 @@

*
* @class
*/

@@ -59,9 +62,13 @@ class FindContext {

this._resultRows = null;
this._build = {
values: {},
attributes: {},
columns: new Map(),
joins: null,
children: null
};
this._attrNode = {};
this._columns = new Map();
this._joins = null;
this._query = null;
this._values = {};
this._children = null;
this._masterColumn = null;
this._masterAttr = null;
this._detailField = null;
this._detailColumn = null;
this._resultRows = null;
}

@@ -75,6 +82,8 @@

return Promise.resolve().then(() => {
this._build();
const query = this._query;
// Execute
const isChild = !!this._masterColumn;
const query = this._buildQuery();
return query.execute({
values: this._build.values,
values: this._values,
autoCommit: this.autoCommit,

@@ -87,3 +96,3 @@ objectRows: true,

if (scope) {
scope.attributes = this._build.attributes;
scope.attributes = this.attributes;
scope.query = resp.query;

@@ -93,9 +102,9 @@ }

if (!(resp && resp.rows))
return;
return [];
/* Create key value array for children */
if (this._build.children) {
for (const child of this._build.children) {
if (this._children) {
for (const child of this._children) {
const prm = '__' + child._detailField;
const arr = child._build.values[prm] =
child._build.values[prm] || [];
const arr = child._values[prm] =
child._values[prm] || [];
for (const row of resp.rows) {

@@ -112,5 +121,5 @@ const keyValue = row[child._masterColumn];

for (const row of resp.rows) {
const obj = this._wrapRec(row, {}, this._build.attributes);
if (this._build.children) {
for (const child of this._build.children) {
const obj = this._wrapRec(row, {}, this._attrNode);
if (this._children) {
for (const child of this._children) {
const masterKey = row[child._masterColumn];

@@ -121,3 +130,4 @@ /* istanbul ignore else */

obj[child._masterAttr] =
(child._resultRows && child._resultRows[masterKey]) || null;
(child._resultRows && child._resultRows[masterKey]) ||
null;
}

@@ -154,45 +164,13 @@ }

/**
* @return {Query}
*/
_buildQuery() {
/* istanbul ignore else */
if (this.attributes)
this._addAttributes({
model: this.model,
tableAlias: 't',
attributes: this.attributes,
targetNode: this._build.attributes
});
_build() {
if (!this._masterColumn) // If not child context
this._processAttributes();
/* 1. Prepare order columns */
const orderColumns = this._prepareOrderColumns();
const selectColumns = [];
const joins = [];
const orderColumns = [];
/* 1. Prepare order columns */
if (this.sort) {
for (const col of this.sort) {
if (typeof col !== 'string')
throw new ArgumentError('Invalid element in "sort" property');
const m = col.match(SORT_ORDER_PATTERN);
if (!m)
throw new ArgumentError('"%s" is not a valid order expression', col);
let fieldName = m[2];
let field = this.model.getField(fieldName);
if (field.foreignModel) {
let tableAlias = 't';
while (field) {
const join = this._addJoin(field, tableAlias);
tableAlias = join.joinAlias;
/* istanbul ignore else */
if (field.fieldName)
fieldName = tableAlias + '.' + field.fieldName;
field = field.towards;
}
} else {
fieldName = 't.' + (field.fieldName);
}
orderColumns.push((m[1] || '') + fieldName);
}
}
/* 2. Phase: Add joins needed for filter clause and prepare an override map for expressions */

@@ -230,8 +208,8 @@ const operatorOverrides = {};

/* 3. Phase: Prepare select columns */
for (const [key, col] of this._build.columns.entries())
for (const [key, col] of this._columns.entries())
selectColumns.push(key + ' ' + col.colName);
/* 4. Phase: Prepare joins */
if (this._build.joins) {
for (const join of this._build.joins.values()) {
if (this._joins) {
for (const join of this._joins.values()) {

@@ -252,3 +230,3 @@ joins.push(

/* 5. Phase: Create Query */
return this.connection
this._query = this.connection
.select(...selectColumns)

@@ -271,10 +249,16 @@ .from(this.model.tableNameFull + ' t')

_addAttributes(options) {
const silent = this.silent;
const model = options.model;
/**
* @private
*/
_processAttributes() {
const {silent} = this;
const getAttrOptions = (attrKey, v) => {
const processField = (context, model, attrKey, v, tableAlias, targetNode) => {
v = v || attrKey;
/* Convert string item to object representation */
if (typeof v === 'string') {
const m = v.match(COLUMN_PATTERN);
if (!m)
throw new ArgumentError('Invalid column definition "%s"', v);
v = {fieldName: m[1]};

@@ -284,168 +268,158 @@ if (m[2])

}
let result;
v.fieldName = v.fieldName || attrKey;
const field = model.getField(v.fieldName, silent);
if (!field) return;
/* If is an associated field */
if (field.foreignModel) {
result = {
ascField: field
/* If field is a data field */
if (field instanceof DataField) {
targetNode[attrKey] = {
column: context._addColumn(tableAlias, field.fieldName)
};
/* If requested a sub field */
if (v.subField) {
if (field.hasMany) {
/* istanbul ignore next */
if (silent) return;
throw new ArgumentError('`%s` is an One2Many associated field and sub values can not be used to return as single value', v.fieldName);
}
if (field.returnsSingleValue) {
/* istanbul ignore next */
if (silent) return;
throw new ArgumentError('`%s` is an single value associated field and has no sub value `%s`', v.fieldName, v.attribute);
}
if (!field.returnsAttribute(v.subField))
throw new ArgumentError('`%s` has no attribute named `%s`', v.fieldName, v.subField);
result.attribute = v.subField;
} else {
if (v.attributes) {
for (const n of Object.getOwnPropertyNames(v.attributes)) {
if (!field.returnsAttribute(v.attributes[n] ||
/* istanbul ignore next */n)) {
/* istanbul ignore next */
if (silent) continue;
throw new ArgumentError('`%s` has no attribute named `%s`', v.fieldName, n);
}
result.attributes = result.attributes || {};
result.attributes[n] = v.attributes[n];
}
/* istanbul ignore next */
if (!result.attributes) return;
}
}
} else {
result = {
attribute: field.fieldName
};
return;
}
return result;
};
Object.getOwnPropertyNames(options.attributes).forEach(attrKey => {
const request = getAttrOptions(attrKey,
const attrInfo = typeof v === 'object' ? v : {};
let ctx = context;
/* If field is a One2Many associated field */
if (field.hasMany) {
if (v.subField) {
/* istanbul ignore next */
options.attributes[attrKey] || attrKey);
if (!request) return;
request.targetAttr = request.targetAttr || attrKey;
if (!request.ascField) {
options.targetNode[request.targetAttr] = {
column: this._addColumn(options.tableAlias, request.attribute)
};
return;
}
const ascField = request.ascField;
let tableAlias = options.tableAlias;
let ctx = this;
let targetNode;
/* If has many rows */
if (ascField.hasMany) {
options.targetNode[request.targetAttr] = {};
const masterCol = this._addColumn(options.tableAlias, ascField.key);
if (silent) return;
throw new ArgumentError('`%s` is an One2Many associated field and sub values can not be used to return as single value', v.fieldName);
}
if (v.returnsSingleValue) {
/* istanbul ignore next */
if (silent) return;
throw new ArgumentError('`%s` is an single value associated field and has no sub value `%s`', v.fieldName, v.subField);
}
// Add key field to master query. We will use key value to match with detail records
const masterCol = context._addColumn(tableAlias, field.key);
// Create a new FindContext for nested query
ctx = new FindContext({
model: ascField.foreignModel,
// attributes: inf.attributes,
connection: this.connection,
autoCommit: this.autoCommit,
silent: this.silent,
filter: [Op.in(ascField.foreignKey,
new RegExp('__' + ascField.foreignKey)),
...(ascField.filter || /* istanbul ignore next */[])],
sort: request.sort,
limit: request.limit,
offset: request.offset
model: field.foreignModel,
//attributes: attrInfo.attributes,
connection: context.connection,
autoCommit: context.autoCommit,
silent,
filter: [Op.in(field.foreignKey,
new RegExp('__' + field.foreignKey)),
...(field.filter || /* istanbul ignore next */[])],
sort: attrInfo.sort,
limit: attrInfo.limit,
offset: attrInfo.offset
});
const detailCol = ctx._addColumn('t', ascField.foreignField.fieldName);
// Add detail key field to nested query. We will use key value to match with master record
ctx._masterColumn = masterCol.colName;
ctx._masterAttr = request.targetAttr;
ctx._detailColumn = detailCol.colName;
ctx._detailField = ascField.foreignKey;
this._build.children = this._build.children || [];
this._build.children.push(ctx);
targetNode = ctx._build.attributes;
ctx._masterAttr = attrKey;
ctx._detailColumn =
ctx._addColumn('t', field.foreignField.fieldName).colName;
ctx._detailField = field.foreignKey;
context._children = context._children || [];
context._children.push(ctx);
targetNode = ctx._attrNode;
} else {
const j = this._addJoin(ascField, tableAlias);
/* If field is a One2One associated field */
tableAlias = ctx._addJoin(field, tableAlias).joinAlias;
targetNode = targetNode[attrKey] || (targetNode[attrKey] = {});
}
let fld = field;
while (fld.towards) {
fld = fld.towards;
model = fld.model;
const j = ctx._addJoin(fld, tableAlias);
tableAlias = j.joinAlias;
targetNode = options.targetNode[request.targetAttr] ||
(options.targetNode[request.targetAttr] = {});
}
let fld = ascField;
while (fld) {
const node = targetNode;
/* If field returns single value */
if (fld.returnsSingleValue) {
/* istanbul ignore else */
if (!field.hasMany) {
/* If requested single attribute of multi attribute field */
if (v.subField) {
if (fld.fieldName) {
node.column = ctx._addColumn(tableAlias, fld.fieldName);
if (silent) return;
throw new ArgumentError('`%s` is an single value associated field and has no sub value `%s`', v.fieldName, v.subField);
}
} else
/* If requested single attribute of multi attribute field */
if (request.attribute) {
/* istanbul ignore else */
if (fld.attributes.hasOwnProperty(request.attribute)) {
const f = ctx.model.getField(request.attribute);
node.column = ctx._addColumn(tableAlias, f.fieldName);
}
} else
/* If requested some attributes of multi attribute field */
if (request.attributes) {
/* istanbul ignore else */
if (!ascField.hasMany)
node.columns = node.columns || {};
for (const n of Object.getOwnPropertyNames(request.attributes)) {
const t = request.attributes[n] || n;
/* istanbul ignore else */
if (fld.attributes.hasOwnProperty(t)) {
const f = fld.foreignModel.getField(t);
(ascField.hasMany ?
/*istanbul ignore next */node : node.columns)[n] = {
column: ctx._addColumn(tableAlias, f.fieldName)
};
}
}
} else
/* */
if (fld.attributes) {
if (!ascField.hasMany)
node.columns = node.columns || {};
for (const n of Object.getOwnPropertyNames(fld.attributes)) {
const f = fld.foreignModel.getField(fld.attributes[n] || n);
(ascField.hasMany ? node : node.columns)[n] = {
column: ctx._addColumn(tableAlias, f.fieldName)
};
}
const f = field.foreignModel.getField(v.subField);
targetNode.column = ctx._addColumn(tableAlias, f.fieldName);
return;
}
fld = fld && fld.towards;
if (fld) {
const j = ctx._addJoin(fld, tableAlias);
tableAlias = j.joinAlias;
/* If field is an associated field and returns single value */
if (fld.fieldName) {
targetNode.column = ctx._addColumn(tableAlias, fld.fieldName);
return;
}
}
});
attrInfo.attributes = attrInfo.attributes ||
normalizeAttributes(fld.foreignModel.getDataFields());
/* If requested some attributes of multi attribute field */
targetNode = field.hasMany ? targetNode :
(targetNode.columns = targetNode.columns || {});
for (const n of Object.keys(attrInfo.attributes)) {
const v = attrInfo.attributes[n];
const fname = typeof v === 'string' ? v :
(v ? v.fieldName : n);
const f = fld.foreignModel.getField(fname);
if (f instanceof DataField) {
targetNode[n] = {
column: ctx._addColumn(tableAlias, f.fieldName)
};
} else {
processField(ctx, fld.foreignModel,
fname, v, tableAlias, targetNode);
}
}
};
const srcAttributes = this.attributes ||
normalizeAttributes(this.model.getDataFields());
for (const attrKey of Object.keys(srcAttributes)) {
processField(this, this.model, attrKey,
srcAttributes[attrKey], 't', this._attrNode);
}
//console.log(this._attrNode);
}
_prepareOrderColumns() {
if (!this.sort)
return [];
const orderColumns = [];
for (const col of this.sort) {
if (typeof col !== 'string')
throw new ArgumentError('Invalid element in "sort" property');
const m = col.match(SORT_ORDER_PATTERN);
if (!m)
throw new ArgumentError('"%s" is not a valid order expression', col);
let fieldName = m[2];
let field = this.model.getField(fieldName);
if (field.foreignModel) {
let tableAlias = 't';
while (field) {
const join = this._addJoin(field, tableAlias);
tableAlias = join.joinAlias;
/* istanbul ignore else */
if (field.fieldName)
fieldName = tableAlias + '.' + field.fieldName;
field = field.towards;
}
} else {
fieldName = 't.' + (field.fieldName);
}
orderColumns.push((m[1] || '') + fieldName);
}
return orderColumns;
}
_addColumn(tableAlias, fieldName) {
const s = (tableAlias + '.' + fieldName);
let o = this._build.columns.get(s);
let o = this._columns.get(s);
if (o)
return o;
o = {
colName: 'col' + (this._build.columns.size + 1),
colName: 'col' + (this._columns.size + 1),
source: s
};
this._build.columns.set(s, o);
this._columns.set(s, o);
return o;

@@ -455,3 +429,3 @@ }

_addJoin(ascField, parentAlias) {
this._build.joins = this._build.joins || new Map();
this._joins = this._joins || new Map();
let s = ascField.key + '>' + ascField.foreignModel.name + '.' +

@@ -462,10 +436,10 @@ ascField.foreignKey;

let join = this._build.joins.get(s);
let join = this._joins.get(s);
if (!join) {
join = {
ascField,
joinAlias: 'j' + (this._build.joins.size + 1),
joinAlias: 'j' + (this._joins.size + 1),
targetAlias: parentAlias
};
this._build.joins.set(s, join);
this._joins.set(s, join);
}

@@ -495,7 +469,7 @@ return join;

/**/
if (this._build.children) {
if (this._children) {
if (scope)
scope.children = scope.children || {};
const promises = [];
for (const childContext of this._build.children) {
for (const childContext of this._children) {
const scp = scope ?

@@ -502,0 +476,0 @@ scope.children[childContext._masterAttr] = {} : null;

@@ -23,2 +23,7 @@ /* UNIQORM

const FindContext = require('./FindContext');
const {
normalizeFindOptions,
normalizeUpdateValues,
prepareKeyValues
} = require('./helpers');

@@ -222,3 +227,3 @@ /**

if (typeof values !== 'object')
values = this._prepareKeyValues(values);
values = prepareKeyValues(this, values);
options = options || {};

@@ -238,4 +243,4 @@

*
* @param {Object} options
* @param {Object|Array} options.attributes
* @param {Object} [options]
* @param {Object|Array} [options.attributes]
* @param {Boolean} [options.autoCommit]

@@ -262,3 +267,3 @@ * @param {Object} [options.connection]

options.silent : this.orm.options.silent;
const opts = this._prepareFindOptions(options, silent);
const opts = normalizeFindOptions(options, silent);
opts.model = this;

@@ -296,3 +301,3 @@ opts.connection = options.connection || this.orm.pool;

options.silent : this.orm.options.silent;
values = this._prepareUpdateValues(values, silent);
values = normalizeUpdateValues(this, values, silent);
const returning = options.returning &&

@@ -350,3 +355,3 @@ this._prepareReturning(options.returning, silent);

options.silent : this.orm.options.silent;
values = this._prepareUpdateValues(values, silent);
values = normalizeUpdateValues(this, values, silent);
const returning = options.returning &&

@@ -412,3 +417,3 @@ this._prepareReturning(options.returning, silent);

if (typeof values !== 'object')
values = this._prepareKeyValues(values);
values = prepareKeyValues(this, values);

@@ -472,80 +477,2 @@ const dbobj = (options.connection || this.orm.pool);

_prepareFindOptions(options, silent) {
let i = 0;
const addAttribute = (target, key, value) => {
if (typeof value === 'string' || value == null)
target[key] = value && value !== key ? value : null;
else if (Array.isArray(value))
value = {attributes: value};
/* istanbul ignore else */
if (isPlainObject(value)) {
value.fieldName = value.fieldName || key;
target[key] = this._prepareFindOptions(value, silent);
}
i++;
};
const parseAttributes = (target, value) => {
if (Array.isArray(value)) {
const COLUMN_PATTERN = /^([a-zA-Z][\w$]*)(?:\.?([\w$]+))? *([\w$]+)?$/;
for (const v of value) {
if (typeof v === 'string') {
const m = v.match(COLUMN_PATTERN);
if (!m) {
if (silent) continue;
throw new ArgumentError('"%s" is not a valid column name', v);
}
addAttribute(target, (m[3] || m[2] || m[1]),
m[1] + (m[2] ? '.' + m[2] : ''));
continue;
}
if (isPlainObject(v)) {
parseAttributes(target, v);
continue;
}
/* istanbul ignore next */
if (!silent)
throw new ArgumentError('"%s" is not a valid column name', v);
}
} else {
/* istanbul ignore else */
if (isPlainObject(value)) {
for (const v of Object.getOwnPropertyNames(value))
addAttribute(target, v, value[v]);
}
}
return i && target || /* istanbul ignore next */null;
};
const result = merge.deep.clone(options);
result.attributes = parseAttributes({}, options.attributes);
result.filter = !options.filter || Array.isArray(options.filter) ?
options.filter : [options.filter];
result.sort = !options.sort || Array.isArray(options.sort) ?
options.sort : [options.sort];
return result;
}
/**
*
* @param {Object} attributes
* @param {Boolean} silent
* @param {Boolean} [removePrimaryKey]
* @return {Object}
* @private
*/
_prepareUpdateValues(attributes, silent, removePrimaryKey) {
const values = {};
Object.getOwnPropertyNames(attributes).forEach((name) => {
const field = this.getField(name, silent);
/* istanbul ignore else */
if (field && field.dataType && (!(field.primaryKey && removePrimaryKey)))
values[field.fieldName] = field.parseValue(attributes[name]);
});
return values;
}
_prepareReturning(value, silent) {

@@ -555,3 +482,3 @@ let attributes;

(typeof value === 'object' ? value : [value]);
attributes = this._prepareFindOptions({attributes}, silent).attributes;
attributes = normalizeFindOptions({attributes}, silent).attributes;
/* Be sure key fields exists in attributes */

@@ -589,20 +516,2 @@ /* istanbul ignore else */

_prepareKeyValues(keyValues) {
/* istanbul ignore next */
if (!(this.keyFields && this.keyFields.length))
return null;
if (typeof keyValues !== 'object')
return {
[this.keyFields[0]]: keyValues == null ?
/* istanbul ignore next */null : keyValues
};
else {
const result = {};
for (const n of this.keyFields)
result[n] = keyValues[n] == null ?
/* istanbul ignore next */null : keyValues[n];
return result;
}
}
_responseReturning(dbobj, resp, options) {

@@ -609,0 +518,0 @@

{
"name": "uniqorm",
"description": "Multi dialect and multi schema ORM framework for enterprise level NodeJS applications",
"version": "2.6.1",
"version": "2.7.0",
"author": "Panates Ltd.",

@@ -26,3 +26,3 @@ "contributors": [

"putil-isplainobject": "^1.0.1",
"putil-merge": "^2.0.2",
"putil-merge": "^2.1.0",
"putil-waterfall": "^2.1.1"

@@ -36,4 +36,5 @@ },

"nyc": "^13.1.0",
"sqb": "^3.5.5",
"sqb-connect-pg": "^3.0.16"
"sqb": "^3.5.6",
"sqb-connect-pg": "^3.0.16",
"rejected-or-not": "^1.0.1"
},

@@ -40,0 +41,0 @@ "peerDependencies": {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc