New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@linked-db/linked-ql

Package Overview
Dependencies
Maintainers
0
Versions
125
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@linked-db/linked-ql - npm Package Compare versions

Comparing version 0.3.8 to 0.4.0

src/query/insert/ColumnsList.js

2

package.json

@@ -14,3 +14,3 @@ {

"icon": "https://webqit.io/icon.svg",
"version": "0.3.8",
"version": "0.4.0",
"license": "MIT",

@@ -17,0 +17,0 @@ "repository": {

@@ -257,3 +257,3 @@

version_tag: null,
savepoint_date: new String('now()'),
savepoint_date: new Date,
};

@@ -277,5 +277,5 @@ // -- Find a match first

// -- Create record
const insertResult = await this.database(OBJ_INFOSCHEMA_DB).table('database_savepoints').add(savepointJson);
return new Savepoint(this, { ...insertResult.toJson(), id_following: null });
const insertResult = await this.database(OBJ_INFOSCHEMA_DB).table('database_savepoints').insert(savepointJson);
return new Savepoint(this, { ...insertResult[0], id_following: null });
}
}
import { _isTypeObject, _isNull, _isString, _isNumeric, _isUndefined, _isObject } from '@webqit/util/js/index.js';
import { _from as _arrFrom, _intersect } from '@webqit/util/arr/index.js';
import { _wrapped } from '@webqit/util/str/index.js';
import { _isObject } from '@webqit/util/js/index.js';
import Insert from '../../query/insert/Insert.js';
import Update from '../../query/update/Update.js';
import Delete from '../../query/delete/Delete.js';
import Select from '../../query/select/Select.js';

@@ -12,18 +14,14 @@ export default class AbstractTable {

constructor(database, tblName, params = {}) {
this.$ = {
database,
name: tblName,
params
};
this.$ = { database, name: tblName, params };
}
/**
* @property String
* @property Database
*/
get name() { return this.$.name; }
get database() { return this.$.database; }
/**
* @property Database
* @property String
*/
get database() { return this.$.database; }
get name() { return this.$.name; }

@@ -35,223 +33,122 @@ /**

/**
* @property Bool
*/
get dropped() { return this.$.schema.hiddenAs === 'dropped'; }
/**
* @returns Object
*/
async schema() { return await this.database.describeTable(this.name); }
/**
* ----------
* SCHEMA UTILS
* ----------
*/
/**
* Get Primary Key columns from schema.
* Counts records.
*
* @returns Array
* @param String q
*/
async primaryKeyColumns() { return (await this.columnsForConstraint('PRIMARY_KEY'))[0]; }
async count(q = '*') {
const result = await this.select([ q => q.fn('COUNT', q).as('c') ]);
return (result.rows || result)[0].c;
}
/**
* Get columns that have given constraintType.
* Selects record(s).
*
* @param String constraintType
* @param Array fields
*
* @returns Array
* @param Number|Object|Function where
*
* @param Array fields
* @param Number|Object|Function where
*/
async columnsForConstraint(constraintType) {
const schema = await this.database.describeTable(this.name);
const inlineConstraintTypesMap = { 'PRIMARY_KEY': 'primaryKey', 'UNIQUE_KEY': 'uniqueKey', 'CHECK': 'check', 'FOREIGN_KEY': 'references' };
let columns = !(constraintType in inlineConstraintTypesMap) ? [] : schema.columns.filter(col => col[inlineConstraintTypesMap[constraintType]]).map(col => [col.name]);
if (schema.constraints.length) { columns = columns.concat(schema.constraints.filter(cnst => cnst.type === constraintType).reduce((cols, cnst) => cols.concat([cnst.columns]))); }
return columns;
async select(...args) {
const query = new Select(this.database.client);
// Where and fields
if (Array.isArray(args[0])) {
query.select(...args[0]);
await this.resolveWhere(query, args[1]);
} else await this.resolveWhere(query, args[0]);
// Handle
query.from([this.database.name, this.name]);
return await this.database.client.query(query);
}
/**
* Get columns that have given indexType.
* Inserts record(s).
*
* @param String indexType
* @param Object keyValsMap
* @param Array|String returnList
*
* @returns Array
* @param Array multilineKeyValsMap
* @param Array|String returnList
*
* @param Array columns
* @param Array multilineValues
* @param Array|String returnList
*/
async columnsForIndex(indexType) {
const schema = await this.database.describeTable(this.name);
if (schema.indexes.length) { return schema.indexes.filter(index => index.type === indexType).reduce((cols, index) => cols.concat([index.columns])); }
return [];
async insert(...args) {
const query = new Insert(this.database.client);
const [ columns = [], values = [], returnList = '*' ] = await this.resolvePayload(...args);
// Payload
if (columns.length) query.columns(...columns);
for (const row of values) query.values(...row);
// Handle
query.into([this.database.name, this.name]);
if (returnList) query.returning(returnList);
return await this.database.client.query(query);
}
/**
* ----------
* QUERY UTILS
* ----------
*/
/**
* Syncs a cursor.
* Upserts record(s); with optional custom onConflict clause.
*
* @param Cursor cursor
* @param Object keyValsMap
* @param Array|String returnList
*
* @return Number
* @param Array multilineKeyValsMap
* @param Array|String returnList
*
* @param Array columns
* @param Array multilineValues
* @param Array|String returnList
*/
async syncCursor(cursor) { return await this.putAll(cursor.cache); }
/**
* @inheritdoc
*/
async match(rowObj) {
// -----------
let primaryKey, existing;
if (this.def.schema.primaryKey
&& (primaryKey = readKeyPath(rowObj, this.def.schema.primaryKey))
&& (existing = await this.get(primaryKey))) {
return {
matchingKey: 'PRIMARY_KEY',
primaryKey,
row: existing,
};
}
// -----------
const primaryKeyColumns = await this.primaryKeyColumns();
const uniqueKeyColumns = await this.columnsForConstraint('UNIQUE_KEY');
primaryKeyColumns.concat(uniqueKeyColumns).map(columns => {
return `(${ columns.map(col => `${ this.quote(obj[col]) } IN (${ columns.join(',') })`).join(' AND ') })`;
}).join(' OR ');
var match, uniqueKeys = Object.keys(this.def.schema.indexes).filter(alias => this.def.schema.indexes[alias].type === 'unique');
if (uniqueKeys.length) {
(await this.getAll()).forEach((existingRow, i) => {
if (match) return;
uniqueKeys.forEach(constraintName => {
var keyPath = this.def.schema.indexes[constraintName].keyPath;
if (existingRow && readKeyPath(rowObj, keyPath) === readKeyPath(existingRow, keyPath)) {
match = {
matchingKey: constraintName,
primaryKey: this.def.schema.primaryKey ? readKeyPath(existingRow, this.def.schema.primaryKey) : i,
row: {...existingRow},
};
}
});
});
}
return match;
async upsert(...args) {
const query = new Insert(this.database.client);
const [ columns = [], values = [], returnList = '*' ] = await this.resolvePayload(...args);
// Payload
if (columns.length) query.columns(...columns);
for (const row of values) query.values(...row);
// On-conflict
query.onConflict({ entries: columns.map((col, i) => [col, values[i]])});
if (returnList) query.returning(returnList);
// Handle
query.into([this.database.name, this.name]);
return await this.database.client.query(query);
}
/**
* -------------------------------
* Updates record(s).
*
* @param Object|Object|Function where
* @param Object payload
* @param Array|String returnList
*/
/**
* @inheritdoc
*/
async addAll(multiValues, columns = [], duplicateKeyCallback = null, forceAutoIncrement = false) {
const inserts = [], forUpdates = [];
for (const values of multiValues) {
let rowObj = values;
if (Array.isArray(values)) {
const columnNames = columns.length ? columns : (await this.schema()).columns.map(col => col.name);
if (columnNames.length && columnNames.length !== values.length) {
throw new Error(`Column/values count mismatch at line ${ multiValues.indexOf(values) }.`);
}
rowObj = columnNames.reduce((rowObj, name, i) => ({ ...rowObj, [name]: values[i], }), {});
}
// -------------
await this.handleInput(rowObj, true);
// -------------
if (await this.shouldMatchInput(rowObj) || duplicateKeyCallback) {
const match = await this.match(rowObj);
if (match && duplicateKeyCallback) {
const duplicateRow = { ...match.row };
if (duplicateKeyCallback(duplicateRow, rowObj)) {
forUpdates.push(duplicateRow);
}
// The duplicate situation had been handled
// ...positive or negative
inserts.push('0');
continue;
}
// We're finally going to add!
// We must not do this earlier...
// as "onupdate" rows will erronously take on a new timestamp on this column
await this.beforeAdd(rowObj, match);
inserts.push(await this.add(rowObj));
continue;
}
await this.beforeAdd(rowObj);
inserts.push(await this.add(rowObj));
}
// OnDuplicateKey updates
if (forUpdates.length) { inserts.push(...(await this.putAll(forUpdates))); }
return inserts.filter((n, i) => n !== 0 && inserts.indexOf(n) === i);
async update(...args) {
if (args.length < 2) throw new Error(`A "where" match cannot be ommitted.`);
const query = new Update(this.database.client);
query.table([this.database.name, this.name]);
// Where and payload
const { where, payload, returnList = '*' } = args;
await this.resolveWhere(query, where);
for (const [key, value] of Object.entries(payload)) query.set(key, value);
if (returnList) query.returning(returnList);
// Handle
return await this.database.client.query(query);
}
/**
* @inheritdoc
*/
async beforeAdd(rowObj, match) {
const timestamp = (new Date).toISOString();
for (const column of (await this.schema()).columns) {
const columnType = _isObject(column.type) ? column.type.name : column.type;
if ((columnType === 'datetime' || columnType === 'timestamp') && column.default.expr === 'CURRENT_TIMESTAMP') {
rowObj[column.name] = timestamp;
}
}
}
/**
* @inheritdoc
* Deletes record(s).
*
* @param Number|Object|Function where
* @param Array|String returnList
*/
async putAll(multiRows) {
const updates = [];
for (const rowObj of multiRows) {
// -------------
await this.handleInput(rowObj);
// -------------
if (await this.shouldMatchInput(rowObj)) {
await this.beforePut(rowObj, await this.match(rowObj));
updates.push(await this.put(rowObj));
continue;
}
await this.beforePut(rowObj);
updates.push(await this.put(rowObj));
}
return updates;
async delete(where, returnList = '*') {
if (args.length < 1) throw new Error(`A "where" match cannot be ommitted.`);
const query = new Delete(this.database.client);
query.from([this.database.name, this.name]);
// Where
await this.resolveWhere(query, where);
if (returnList) query.returning(returnList);
// Handle
return await this.database.client.query(query);
}
/**
* @inheritdoc
*/
async beforePut(rowObj, match) {
if (match && !Object.keys(rowObj).every(key => rowObj[key] === match.row[key])) {
const timestamp = (new Date).toISOString();
for (const column of (await this.schema()).columns) {
const columnType = _isObject(column.type) ? column.type.name : column.type;
if ((columnType === 'datetime' || columnType === 'timestamp') && column.onupdate === 'CURRENT_TIMESTAMP') {
rowObj[column.name] = timestamp;
}
}
}
}
/**
* @inheritdoc
*/
async deleteAll(multiIDs) {
const deletes = [];
for (const primaryKey of multiIDs) {
deletes.push(this.delete(await this.beforeDelete(primaryKey)));
}
return deletes;
}
/**
* @inheritdoc
*/
async beforeDelete(primaryKey) {
return primaryKey;
}

@@ -263,65 +160,54 @@ /**

/**
* @inheritdoc
* Helps resolve specified where condition for the query.
*
* @param Query query
* @param Number|Bool|Object|Function where
*/
async handleInput(rowObj, applyDefaults = false) {
const rowObjColumns = Object.keys(rowObj);
const schema = await this.schema();
const schemaColumns = schema.columns.map(col => col.name);
// ------------------
const unknownFields = rowObjColumns.filter(col => schemaColumns.indexOf(col) === -1);
if (unknownFields.length) { throw new Error(`Unknown column: ${ unknownFields[0] }`); }
// ------------------
for (const columnName of schemaColumns) {
const value = rowObj[columnName];
const column = schema.columns.find(col => col.name === columnName) || {};
if (rowObjColumns.includes(columnName)) {
const columnType = _isObject(column.type) ? column.type.name : column.type;
// TODO: Validate supplied value
if (columnType === 'json') {
if (!_isTypeObject(value) && (!_isString(value) || (!_wrapped(value, '[', ']') && !_wrapped(value, '{', '}')))) {
}
} else if (['char', 'tinytext', 'smalltext', 'text', 'bigtext', 'varchar'].includes(columnType)) {
if (!_isString(value)) {
}
} else if (['bit', 'tinyint', 'smallint', 'int', 'bigint', 'decimal', 'number', 'float', 'real'].includes(columnType)) {
if (!_isNumeric(value)) {
}
} else if (['enum', 'set'].includes(columnType)) {
if (!_isNumeric(value)) {
}
} else if (['date', 'datetime', 'timestamp'].includes(columnType)) {
if (!_isString(value)) {
}
}
} else if (applyDefaults && !_intersect([columnName], await this.primaryKeyColumns()).length) {
// DONE: Apply defaults...
rowObj[columnName] = ('default' in column) && !(['date', 'datetime', 'timestamp'].includes(columnType) && column.default.expr === 'CURRENT_TIMESTAMP')
? column.default.value
: null;
}
// Non-nullable
if (column.notNull && (_isNull(rowObj[columnName]) || _isUndefined(rowObj[columnName]))) {
throw new Error(`Inserting NULL on non-nullable column: ${ columnName }.`);
}
async resolveWhere(query, where) {
if (where === true) return;
if (/^\d+$/.test(where)) {
const schema = await this.database.describeTable(this.name);
const primaryKey = schema.columns?.find(col => col.primaryKey)?.name || schema.constraints.find(cons => cons.type === 'PRIMARY_KEY')?.targetColumns[0];
if (!primaryKey) throw new Error(`Cannot resolve primary key name for implied record.`);
where = { [primaryKey]: where };
}
if (_isObject(where)) {
query.where(...Object.entries(where).map(([key, val]) => q => q.equals(key, val)));
} else if (where) query.where(where);
}
/**
* @inheritdoc
* Resolves input arguments into columns and values array.
*
* @param Object keyValsMap
* @param Array|String returnList
*
* @param Array multilineKeyValsMap
* @param Array|String returnList
*
* @param Array columns
* @param Array multilineValues
* @param Array|String returnList
*/
async shouldMatchInput(rowObj) {
return (await this.schema()).columns.some(column => {
const columnType = _isObject(column.type) ? column.type.name : column.type;
return ['datetime', 'timestamp'].includes(columnType) && (
column.default.expr === 'CURRENT_TIMESTAMP' || column.onupdate === 'CURRENT_TIMESTAMP'
);
});
async resolvePayload(...args) {
let columns = [], values = [], returnList;
if (Array.isArray(args[0]) && /*important*/args[0].every(s => typeof s === 'string') && Array.isArray(args[1])) {
if (!args[1].every(s => Array.isArray(s))) throw new TypeError(`Invalid payload format.`);
[ columns, values, returnList ] = args.splice(0, 3);
} else {
const payload = [].concat(args.shift());
if (!_isObject(payload[0])) throw new TypeError(`Invalid payload format.`);
columns = Object.keys(payload[0]);
values = payload.map(row => Object.values(row));
returnList = args.shift();
}
values = values.map(row => row.map(v => {
if ([true,false,null].includes(v)) return q => q.literal(v);
if (v instanceof Date) return q => q.value(v.toISOString().split('.')[0]);
if (Array.isArray(v)) return q => q.array(v);
if (_isObject(v)) return q => q.object(v);
return q => q.value(v);
}));
return [columns, values, returnList];
}
}
/**
* @AutoIncremen
*/
const readKeyPath = (rowObj, keyPath) => {
return _arrFrom(keyPath).map(key => rowObj[key]).filter(v => v).join('-');
};
}

@@ -58,2 +58,8 @@

if (queryInstance.expandable) await queryInstance.expand(true);
let myReturningList;
if (this.params.dialect === 'mysql' && queryInstance.RETURNING_LIST?.length) {
queryInstance = queryInstance.clone();
myReturningList = queryInstance.RETURNING_LIST.splice(0);
// TODO: myReturningList
}
const result = await this.driver.query(queryInstance.toString(), params.params || []);

@@ -60,0 +66,0 @@ return result.rows || result;

import { _isObject, _isNull, _isNumeric } from '@webqit/util/js/index.js';
import SQLInsertQueryInspector from './SQLInsertQueryInspector.js';
import SQLDeleteQueryInspector from './SQLDeleteQueryInspector.js';
import Identifier from '../../query/select/Identifier.js';
import AbstractTable from '../abstracts/AbstractTable.js';

@@ -17,187 +13,2 @@ import SQLCursor from './SQLCursor.js';

getCursor() { return new SQLCursor(this); }
/**
* @inheritdoc
*/
async getAll() {
return new Promise((resolve, reject) => {
this.database.client.driver.query(`SELECT * FROM ${ this.database.name }.${ this.name }`, (err, result) => {
if (err) return reject(err);
resolve((result.rows || result));
});
});
}
/**
* @inheritdoc
*/
async get(primaryKey) {
const primaryKeyColumns = await this.primaryKeyColumns();
if (!primaryKeyColumns.length) throw new Error(`Table has no primary key defined.`);
return new Promise((resolve, reject) => {
this.database.client.driver.query(`SELECT * FROM ${ this.database.name }.${ this.name } WHERE '${ primaryKey }' IN (${ primaryKeyColumns.join(',') })`, [], (err, result) => {
if (err) return reject(err);
resolve((result.rows || result)[0]);
});
});
}
/**
* @inheritdoc
*/
async count(query = '*') {
return new Promise((resolve, reject) => {
this.database.client.driver.query(`SELECT COUNT(${ query }) AS c FROM ${ this.database.name }.${ this.name }`, (err, result) => {
if (err) return reject(err);
resolve((result.rows || result)[0].c);
});
});
}
/**
* @inheritdoc
*/
async addAll(entries, columns = [], duplicateKeyCallback = null) {
if (!entries.length) return;
let duplicateKeyUpdateObj = {};
if (!columns.length) {
if (_isObject(entries[0])) {
columns = Object.keys(entries[0]);
} else {
const schema = await this.database.describeTable(this.name);
columns = schema.columns.map(col => col.name);
}
}
return new Promise((resolve, reject) => {
let insertSql = `INSERT INTO ${ this.database.name }.${ this.name }\n\t${ columns.length ? `(${ columns.join(',') })\n\t` : `` }`;
insertSql += `VALUES\n\t${ entries.map(row => formatAddRow(Object.values(row), this.database.client.params.dialect)).join(`,\n\t`) }`;
if (duplicateKeyCallback) {
duplicateKeyCallback(duplicateKeyUpdateObj);
insertSql += ` ${ this.database.client.params.dialect === 'mysql' ? 'ON DUPLICATE KEY UPDATE' : /*postgres*/'ON CONFLICT DO UPDATE SET' } ${ formatAssignments(duplicateKeyUpdateObj, this.database.client.params.dialect) }`;
}
this.database.client.driver.query(insertSql, (err, result) => {
if (err) return reject(err);
resolve(new SQLInsertQueryInspector(
this,
result,
columns,
entries,
duplicateKeyUpdateObj
));
});
});
}
/**
* @inheritdoc
*/
async add(rowObj) {
return new Promise((resolve, reject) => {
let insertSql = `INSERT INTO ${ this.database.name }.${ this.name }\n\t(${ Object.keys(rowObj).map(key => Identifier.fromJson(this, key)).join(', ') })\n\t`;
insertSql += `VALUES\n\t${ formatAddRow(Object.values(rowObj), this.database.client.params.dialect) }\n\t`;
insertSql += 'RETURNING *';
this.database.client.driver.query(insertSql, (err, result) => {
if (err) return reject(err);
resolve(new SQLInsertQueryInspector(
this,
result,
Object.keys(rowObj),
Object.values(rowObj),
));
});
});
}
/**
* @inheritdoc
*/
async putAll(rowObjs) {
await Promise.all(rowObjs.map(rowObj => this.put(rowObj)));
return new SQLInsertQueryInspector(
this,
{},
Object.keys(rowObjs[0]),
rowObjs,
);
}
/**
* @inheritdoc
*/
async put(rowObj) {
return new Promise((resolve, reject) => {
const putSql = `INSERT INTO ${ this.database.name }.${ this.name }\n\t${ formatPutRow(rowObj, this.database.client.params.dialect) }`;
this.database.client.driver.query(putSql, (err, result) => {
if (err) return reject(err);
resolve(new SQLInsertQueryInspector(
this,
result,
Object.keys(rowObj),
Object.values(rowObj),
));
});
});
}
/**
* @inheritdoc
*/
async deleteAll(IDs = []) {
const primaryKeyColumns = await this.primaryKeyColumns();
if (!primaryKeyColumns.length) throw new Error(`Table has no primary key defined.`);
return new Promise((resolve, reject) => {
const deleteSql = `DELETE FROM ${ this.database.name }.${ this.name }${ IDs.length ? ` WHERE ${ IDs.map(id => `'${ id }' in (${ primaryKeyColumns.join(',') })`).join(' OR ') }` : ''}`;
this.database.client.driver.query(deleteSql, [], (err, result) => {
if (err) return reject(err);
resolve(new SQLDeleteQueryInspector(
this,
result
));
});
});
}
/**
* @inheritdoc
*/
async delete(primaryKey) {
const primaryKeyColumns = await this.primaryKeyColumns();
if (!primaryKeyColumns.length) throw new Error(`Table has no primary key defined.`);
return new Promise((resolve, reject) => {
const deleteSql = `DELETE FROM ${ this.database.name }.${ this.name } WHERE ${ primaryKey } IN (${ primaryKeyColumns.join(',') })`;
this.database.client.driver.query(deleteSql, [], (err, result) => {
if (err) return reject(err);
resolve(new SQLDeleteQueryInspector(
this,
result
));
});
});
}
}
/**
* --------
* HELPERS
* --------
*/
const formatVal = (val, dialect) => {
if (val instanceof Date) {
try { return `'${ val.toISOString().split('.')[0] }'`; }
catch(e) { return 'NULL'; }
}
if (val instanceof String) return val + '';
if (_isNumeric(val)) return val;
if (_isNull(val)) return 'NULL';
if (Array.isArray(val) || _isObject(val)) (val = JSON.stringify(val));
if (typeof val === 'string') return `'${ val.replace(/'/g, `''`) }'`;
throw new Error(`Couldn't serialize payload.`);
};
const formatAddRow = (values, dialect) => '(' + values.map(val => formatVal(val, dialect)).join(',') + ')';
const formatAssignments = (rowObj, dialect) => Object.keys(rowObj).map(key => `${ Identifier.fromJson(this, key) } = ${ formatVal(rowObj[key], dialect) }`).join(',');
const formatPutRow = (rowObj, dialect) => {
const assignments = formatAssignments(rowObj, dialect);
return `SET ${ assignments } ${ dialect === 'mysql' ? 'ON DUPLICATE KEY UPDATE' : /*postgres*/'ON CONFLICT DO UPDATE SET' } ${ assignments }`;
};
}

@@ -57,14 +57,2 @@ import Lexer from '../Lexer.js';

get quoteChars() { return this.constructor.getQuoteChars(this); }
/**
* A Quote helper
*
* @param String string
*
* @returns String
*/
quote(string) {
const quoteChar = this.quoteChars[0];
return `${ quoteChar }${ string.replace(new RegExp(quoteChar, 'g'), quoteChar.repeat(2)) }${ quoteChar }`;
}

@@ -249,3 +237,3 @@ /**

const router = methodName => (...args) => {
const instance = Types.reduce((prev, Type) => prev || (Type.factoryMethods ? (methodName in Type.factoryMethods && Type.factoryMethods[methodName](this, ...args)) : (methodName in Type.prototype && new Type(this))), null);
const instance = Types.reduce((prev, Type) => prev || (Type.factoryMethods ? (typeof Type.factoryMethods[methodName] === 'function' && Type.factoryMethods[methodName](this, ...args)) : (typeof Type.prototype[methodName] === 'function' && new Type(this))), null);
if (!instance) throw new Error(`Unknow method: ${ methodName }()`);

@@ -252,0 +240,0 @@ set(instance);

@@ -8,2 +8,10 @@

/**
* @constructor
*/
constructor(context) {
super(context);
this._vars = [];
}
/**
* @returns String

@@ -16,3 +24,3 @@ */

*/
get statementNode() { return this }
get statementNode() { return this; }

@@ -22,2 +30,7 @@ /**

*/
get variables() { return this._vars; }
/**
* @inheritdoc
*/
connectedNodeCallback(node) {}

@@ -24,0 +37,0 @@

@@ -10,2 +10,3 @@

import Table from '../select/Table.js';
import Field from '../select/Field.js';

@@ -40,2 +41,3 @@ /*

LIMIT_CLAUSE = null;
RETURNING_LIST = [];

@@ -172,2 +174,7 @@ /**

}
/**
* @return Void
*/
returning(...fields) { return this.build('RETURNING_LIST', fields, Field); }

@@ -186,2 +193,3 @@ /**

limit_clause: this.LIMIT_CLAUSE,
returning_list: this.RETURNING_LIST,
flags: this.FLAGS,

@@ -204,2 +212,3 @@ };

if (json.limit_clause) instance.limit(json.limit_clause);
if (json.returning_list) instance.returning(...json.returning_list);
return instance;

@@ -221,2 +230,3 @@ }

if (this.LIMIT_CLAUSE) sql.push('LIMIT', this.LIMIT_CLAUSE);
if (this.RETURNING_LIST.length) sql.push('RETURNING', this.RETURNING_LIST.join(', '));
return sql.join(' ');

@@ -235,3 +245,3 @@ }

const $body = this.mySubstitutePlaceholders(instance, body.trim());
const clausesMap = { from: { backtest: '^(?!.*\\s+DISTINCT\\s+$)', test: 'FROM' }, using: { backtest: '^(?!.*\\s+JOIN\\s+)', test: 'USING' }, join:JoinClause, where:'WHERE', orderBy:OrderByClause, limit:'LIMIT' };
const clausesMap = { from: { backtest: '^(?!.*\\s+DISTINCT\\s+$)', test: 'FROM' }, using: { backtest: '^(?!.*\\s+JOIN\\s+)', test: 'USING' }, join:JoinClause, where:'WHERE', orderBy:OrderByClause, limit:'LIMIT', returning:'RETURNING' };
const { tokens: [ maybeTablesSpec, ...tokens ], matches: clauses } = Lexer.lex($body, Object.values(clausesMap).map(x => typeof x === 'string' || x.test ? x : x.regex), { useRegex: 'i' });

@@ -265,2 +275,6 @@ // MAYBE_TABLES_SPEC (BEFORE A FROM CLAUSE) - MYSQL

}
// RETURNING
else if (clauseKey === 'returning') {
instance.returning(...Lexer.split(tokens.shift(), [',']).map(field => parseCallback(instance, field.trim(), [Field])));
}
// JOIN|ORDER_BY

@@ -267,0 +281,0 @@ else {

import { _wrapped, _unwrap } from '@webqit/util/str/index.js';
import Lexer from '../Lexer.js';
import { _wrapped } from '@webqit/util/str/index.js';
import Node from '../abstracts/Node.js';
import Expr from '../select/abstracts/Expr.js';
import Identifier from '../select/Identifier.js';
import Node from '../abstracts/Node.js';
import Lexer from '../Lexer.js';
import ColumnsList from './ColumnsList.js';
import ValuesList from './ValuesList.js';

@@ -23,6 +25,10 @@ export default class AssignmentList extends Node {

set(target_s, value_s) {
if (Array.isArray(target_s)) target_s = target_s.map(t => t instanceof Node ? t : Identifier.fromJson(this, t));
else if (!(target_s instanceof Node)) target_s = Identifier.fromJson(this, target_s);
if (Array.isArray(value_s)) value_s = value_s.map(v => v instanceof Node ? v : Expr.cast(this, v));
else if (!(value_s instanceof Node)) value_s = Expr.cast(this, value_s);
if (Array.isArray(target_s)) {
target_s = ColumnsList.fromJson(this, target_s);
if (Array.isArray(value_s)) value_s = ValuesList.fromJson(this, value_s);
else value_s = Expr.cast(this, value_s);
} else if (!(target_s instanceof Node)) {
target_s = Identifier.fromJson(this, target_s);
value_s = Expr.cast(this, value_s);
}
this.ENTRIES.push([target_s, value_s]);

@@ -36,11 +42,3 @@ return this;

toJson() {
return {
entries: this.ENTRIES.map(([target_s, value_s]) => {
if (Array.isArray(target_s)) target_s = target_s.map(t => t.toJson());
else target_s = target_s.toJson();
if (Array.isArray(value_s)) value_s = value_s.map(v => v.toJson());
else value_s = value_s.toJson();
return [target_s, value_s];
}),
};
return { entries: this.ENTRIES.map(([target_s, value_s]) => [target_s.toJson(), value_s.toJson()]), };
}

@@ -56,3 +54,3 @@

instance.set(target_s, value_s);
};
}
return instance;

@@ -65,7 +63,3 @@ }

stringify() {
return `\n\t${ this.ENTRIES.map(([target_s, value_s]) => {
if (Array.isArray(target_s)) target_s = `(${ target_s.join(', ') })`;
if (Array.isArray(value_s)) value_s = `(${ value_s.join(', ') })`;
return `${ target_s } = ${ value_s }`;
}).join(',\n\t') }`;
return `\n\t${ this.ENTRIES.map(([target_s, value_s]) => `${ target_s } = ${ value_s }`).join(',\n\t') }`;
}

@@ -82,7 +76,7 @@

if (_wrapped(target_s, '(', ')')) {
const targets = Lexer.split(_unwrap(target_s, '(', ')'), [',']).map(expr => parseCallback(instance, expr.trim(), [Identifier]));
const targets = parseCallback(instance, value_s.trim(), [ColumnsList]);;
if (!_wrapped(value_s, '(', ')')) return; // Abort... for this isn't the kind of expression we handle here
const values = /^\((\s+)?SELECT\s+/i.test(value_s)
? parseCallback(instance, value_s)
: Lexer.split(_unwrap(value_s, '(', ')'), [',']).map(expr => parseCallback(instance, expr.trim()));
? parseCallback(instance, value_s.trim())
: parseCallback(instance, value_s.trim(), [ValuesList]);
instance.set(targets, values);

@@ -89,0 +83,0 @@ } else {

@@ -7,5 +7,7 @@

import OnConflictClause from './OnConflictClause.js';
import Identifier from '../select/Identifier.js';
import Select from '../select/Select.js';
import Table from '../select/Table.js';
import ValuesList from './ValuesList.js';
import ColumnsList from './ColumnsList.js';
import Field from '../select/Field.js';

@@ -23,2 +25,3 @@ export default class Insert extends StatementNode {

ON_CONFLICT_CLAUSE = null;
RETURNING_LIST = [];

@@ -48,3 +51,3 @@ /**

*/
columns(...columns) { return this.build('COLUMNS_LIST', columns, Identifier); }
columns(...columns) { return this.build('COLUMNS_LIST', columns, ColumnsList, 'list'); }

@@ -58,3 +61,3 @@ /**

*/
values(...values) { return this.VALUES_LIST.push(values); }
values(...values) { return this.build('VALUES_LIST', values, ValuesList, 'list'); }

@@ -96,2 +99,7 @@ /**

onConflict(...onConflictSpecs) { return this.build('ON_CONFLICT_CLAUSE', onConflictSpecs, OnConflictClause); }
/**
* @return Void
*/
returning(...fields) { return this.build('RETURNING_LIST', fields, Field); }

@@ -104,7 +112,8 @@ /**

table: this.TABLE.toJson(),
columns_list: this.COLUMNS_LIST.map(c => c.toJson()),
values_list: this.VALUES_LIST.map(v => v),
columns_list: this.COLUMNS_LIST.toJson(),
values_list: this.VALUES_LIST.toJson(),
set_clause: this.SET_CLAUSE?.toJson(),
select_clause: this.SELECT_CLAUSE?.toJson(),
on_conflict_clause: this.ON_CONFLICT_CLAUSE?.toJson(),
returning_list: this.RETURNING_LIST,
flags: this.FLAGS,

@@ -122,6 +131,7 @@ };

if (json.columns_list?.length) instance.columns(...json.columns_list);
for (const values of json.values_list || []) instance.values(...values);
if (json.values_list?.length) instance.values(...json.values_list);
if (json.set_clause) instance.set(json.set_clause);
if (json.select_clause) instance.select(json.select_clause);
if (json.on_conflict_clause) instance.onConflict(json.on_conflict_clause);
if (json.returning_list?.length) instance.returning(...json.returning_list);
return instance;

@@ -139,7 +149,8 @@ }

else {
if (this.COLUMNS_LIST.length) sql.push(`(${ this.COLUMNS_LIST.join(', ') })`);
if (this.COLUMNS_LIST) sql.push(this.COLUMNS_LIST);
if (this.SELECT_CLAUSE) sql.push(this.SELECT_CLAUSE);
else sql.push('VALUES', `\n\t(${ this.VALUES_LIST.map(row => row.join(', ')).join(`),\n\t(`) })`);
else sql.push('VALUES', this.VALUES_LIST);
}
if (this.ON_CONFLICT_CLAUSE) sql.push(this.ON_CONFLICT_CLAUSE);
if (this.RETURNING_LIST.length) sql.push('RETURNING', this.RETURNING_LIST.join(', '));
return sql.join(' ');

@@ -155,3 +166,3 @@ }

const $body = this.mySubstitutePlaceholders(context, body.trim());
const { tokens: [ tableSpec, payloadSpec, onConflictSpec ], matches: [insertType, onConflictClause] } = Lexer.lex($body, ['(VALUES|VALUE|SET|SELECT)', 'ON\\s+(DUPLICATE\\s+KEY|CONFLICT)'], { useRegex:'i' });
const { tokens: [ tableSpec, payloadSpec, onConflictSpec, returnList ], matches: [insertType, onConflictClause] } = Lexer.lex($body, ['(VALUES|VALUE|SET|SELECT)', 'ON\\s+(DUPLICATE\\s+KEY|CONFLICT)', 'RETURNING'], { useRegex:'i' });
const instance = new this(context);

@@ -168,4 +179,3 @@ if (withUac) instance.withFlag('WITH_UAC');

if (tableColumnSplit.length) {
const columns = Lexer.split(_unwrap(tableColumnSplit.shift().trim(), '(', ')'), [',']).map(c => parseCallback(instance, c.trim(), [Identifier]));
instance.columns(...columns);
instance.columns(parseCallback(instance, tableColumnSplit.shift().trim(), [ColumnsList]));
}

@@ -178,4 +188,3 @@ if (/^SELECT$/i.test(insertType)) {

for (const rowPayload of Lexer.split(payloadSpec, [','])) {
const rowPayloadArray = Lexer.split(_unwrap(rowPayload.trim(), '(', ')'), [',']).map(valueExpr => parseCallback(instance, valueExpr.trim()));
instance.values(...rowPayloadArray);
instance.values(parseCallback(instance, rowPayload.trim(), [ValuesList]));
}

@@ -185,4 +194,5 @@ }

if (onConflictClause) { instance.onConflict(parseCallback(instance, `${ onConflictClause } ${ onConflictSpec }`, [OnConflictClause])); }
if (returnList) instance.returning(...Lexer.split(returnList, [',']).map(field => parseCallback(instance, field.trim(), [Field])));
return instance;
}
}

@@ -31,8 +31,3 @@

*/
toJson() {
return {
...super.toJson(),
where_clause: this.WHERE_CLAUSE?.toJson(),
};
}
toJson() { return { ...super.toJson(), where_clause: this.WHERE_CLAUSE?.toJson(), }; }

@@ -39,0 +34,0 @@ /**

@@ -17,3 +17,3 @@

import Num from '../Num.js';
import Prim from '../Prim.js';
import Literal from '../Literal.js';
import Placeholder from '../Placeholder.js';

@@ -35,4 +35,4 @@

const router = methodName => (...args) => {
const $instance = Types.reduce((prev, Type) => prev || (Type.factoryMethods ? (methodName in Type.factoryMethods && Type.factoryMethods[methodName](context, ...args)) : (methodName in Type.prototype && new Type(context))), null);
if (!$instance) throw new Error(`Unknow method: ${ methodName }()`);
const $instance = Types.reduce((prev, Type) => prev || (Type.factoryMethods ? (typeof Type.factoryMethods[methodName] === 'function' && Type.factoryMethods[methodName](context, ...args)) : (typeof Type.prototype[methodName] === 'function' && new Type(context))), null);
if (!$instance) throw new Error(`Unknown method: ${ methodName }()`);
instance = $instance;

@@ -79,5 +79,5 @@ if ($instance[methodName]) return $instance[methodName](...args); // Foward the call

Json,
Num,
Str,
Num,
Prim,
Literal,
Placeholder,

@@ -84,0 +84,0 @@ Identifier,

@@ -18,3 +18,3 @@

*/
call(...args) { return (super.call(...args), this); }
fn(...args) { return (super.fn(...args), this); }

@@ -85,3 +85,3 @@ /**

static factoryMethods = { call: (context, name, ...args) => this.names.flat().includes(name?.toUpperCase()) && new this(context) };
static factoryMethods = { fn: (context, name, ...args) => this.names.flat().includes(name?.toUpperCase()) && new this(context) };

@@ -88,0 +88,0 @@ static names = [

@@ -28,3 +28,3 @@

*/
call(name, ...args) { return (this.build('$EXPR', [name, ...args], Aggr.names.flat().includes(name.toUpperCase()) ? Aggr : Func, 'call'), this); }
fn(name, ...args) { return (this.build('$EXPR', [name, ...args], Aggr.names.flat().includes(name.toUpperCase()) ? Aggr : Func, 'fn'), this); }

@@ -31,0 +31,0 @@ /**

@@ -17,3 +17,3 @@

*/
call(name, ...args) {
fn(name, ...args) {
this.NAME = name;

@@ -40,3 +40,3 @@ return this.build('ARGS', args, Expr.Types);

const instance = (new this(context)).withFlag(...(json.flags || []));
instance.call(json.name, ...json.args);
instance.fn(json.name, ...json.args);
return instance;

@@ -57,5 +57,5 @@ }

const instance = new this(context);
instance.call(name, ...Lexer.split(args, [',']).map(arg => parseCallback(instance, arg.trim())));
instance.fn(name, ...Lexer.split(args, [',']).map(arg => parseCallback(instance, arg.trim())));
return instance;
}
}

@@ -39,3 +39,3 @@

static fromJson(context, json) {
if (typeof json === 'string' || Array.isArray(json)) json = { name: json };
if ((typeof json === 'string') || (Array.isArray(json) && json.every(s => typeof s === 'string'))) json = { name: json };
else if (typeof json?.name !== 'string' && !Array.isArray(json?.name)) return;

@@ -42,0 +42,0 @@ const instance = (new this(context)).withFlag(...(json?.flags || []));

@@ -6,2 +6,3 @@

import { _wrapped } from '@webqit/util/str/index.js';
import { _isObject } from '@webqit/util/js/index.js';
import Lexer from '../../Lexer.js';

@@ -15,3 +16,3 @@ import Str from '../str/Str.js';

*/
TYPE = '';
TYPE;

@@ -27,19 +28,19 @@ /**

/**
* Sets the value to an object
* Sets the value to an array
*
* @param Object value
*/
object(value) {
this.VALUE = typeof value === 'object' && value ? JSON.stringify(value) : value;
this.TYPE = 'OBJECT';
array(value) {
this.VALUE = Array.isArray(value) ? JSON.stringify(value) : value;
this.TYPE = 'ARRAY';
}
/**
* Sets the value to an array
* Sets the value to an object
*
* @param Object value
*/
array(value) {
this.VALUE = Array.isArray(value) ? JSON.stringify(value) : value;
this.TYPE = 'ARRAY';
object(value) {
this.VALUE = _isObject(value) ? JSON.stringify(value) : value;
this.TYPE = 'OBJECT';
}

@@ -82,2 +83,4 @@

}
static factoryMethods = { array: (context, value) => Array.isArray(value) && new this(context), object: (context, value) => _isObject(value) && new this(context) };
}

@@ -20,2 +20,9 @@

/**
* Sets the value
*
* @param String expr
*/
value(value) { this.VALUE = value; }
/**
* @inheritdoc

@@ -46,2 +53,4 @@ */

}
static factoryMethods = { value: (context, value) => /^\d+$/.test(value) && new this(context) };
}

@@ -163,3 +163,3 @@

const joinKeyAlias = `${ joinKey }:${ ( 0 | Math.random() * 9e6 ).toString( 36 ) }`;
stmt.leftJoin( j => j.query( q => q.select( field => field.name( joinKey ).as( joinKeyAlias ) ), q => q.from([rhs.schema.basename,rhs.schema.name]) ) )
stmt.leftJoin( j => j.query( q => q.select( field => field.name( joinKey ).as( joinKeyAlias ) ), q => q.from([rhs.schema.basename,rhs.schema.name].filter(s => s)) ) )
.with({ IS_SMART_JOIN: true }).as(joinAlias)

@@ -166,0 +166,0 @@ .on( on => on.equals([joinAlias,joinKeyAlias], [baseAlias,baseKey]) );

@@ -23,2 +23,13 @@

*/
$value(offset, value = undefined) {
this.OFFSET = offset;
if (arguments.length === 2) {
this.statementNode.variables.push(value);
if (this.OFFSET === 0) this.OFFSET = this.statementNode.variables.length;
}
}
/**
* @inheritdoc
*/
toJson() { return { offset: this.OFFSET }; }

@@ -25,0 +36,0 @@

@@ -28,3 +28,3 @@

*/
literal(expr) { this.VALUE = expr; }
value(expr) { this.VALUE = expr; }

@@ -36,3 +36,3 @@ /**

const quote = this.QUOTE || this.quoteChars[0];
return `${ quote }${ this.VALUE.replace(new RegExp(quote, 'g'), quote.repeat(2)) }${ quote }`;
return `${ quote }${ (this.VALUE + '').replace(new RegExp(quote, 'g'), quote.repeat(2)) }${ quote }`;
}

@@ -39,0 +39,0 @@

@@ -10,2 +10,3 @@

import Table from '../select/Table.js';
import Field from '../select/Field.js';

@@ -23,2 +24,3 @@ export default class Update extends StatementNode {

LIMIT_CLAUSE = null;
RETURNING_LIST = [];

@@ -145,2 +147,7 @@ /**

}
/**
* @return Void
*/
returning(...fields) { return this.build('RETURNING_LIST', fields, Field); }

@@ -158,2 +165,3 @@ /**

limit_clause: this.LIMIT_CLAUSE,
returning_list: this.RETURNING_LIST,
flags: this.FLAGS,

@@ -175,2 +183,3 @@ };

if (json.limit_clause) instance.limit(json.limit_clause);
if (json.returning_list?.length) instance.returning(...json.returning_list);
return instance;

@@ -191,2 +200,3 @@ }

if (this.LIMIT_CLAUSE) sql.push('LIMIT', this.LIMIT_CLAUSE);
if (this.RETURNING_LIST.length) sql.push('RETURNING', this.RETURNING_LIST.join(', '));
return sql.join(' ');

@@ -205,3 +215,3 @@ }

const $body = this.mySubstitutePlaceholders(instance, body.trim());
const clausesMap = { join:JoinClause, set:'SET', where:'WHERE', orderBy:OrderByClause, limit:'LIMIT' };
const clausesMap = { join:JoinClause, set:'SET', where:'WHERE', orderBy:OrderByClause, limit:'LIMIT', returning:'RETURNING' };
const { tokens: [ tableSpec, ...tokens ], matches: clauses } = Lexer.lex($body, Object.values(clausesMap).map(x => typeof x === 'string' || x.test ? x : x.regex), { useRegex: 'i' });

@@ -231,2 +241,6 @@ // TABLE_LIST

}
// RETURNING
else if (clauseKey === 'returning') {
instance.returning(...Lexer.split(tokens.shift(), [',']).map(field => parseCallback(instance, field.trim(), [Field])));
}
// JOIN|ORDER_BY

@@ -233,0 +247,0 @@ else {

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

//await lqlClient.alterDatabase('private', db => db.name('public'), { noCreateSavepoint: true });
console.log('DROP 4', await lqlClient.query('SELECT 2 + 3 as summm'));

@@ -90,3 +90,3 @@ console.log('DROP 4', await lqlClient.query('DROP DATABASE if exists obj_information_schema CASCADE'));

// Should see: 1,2,3
console.log('\n\n\n\n\n\nall savepoints-----', ...(await lqlClient.database('obj_information_schema').table('database_savepoints').getAll()));
console.log('\n\n\n\n\n\nall savepoints-----', ...(await lqlClient.database('obj_information_schema').table('database_savepoints').select()));

@@ -93,0 +93,0 @@ await lqlClient.query(`INSERT INTO roles (name, created_time) VALUES ('admin', now()), ('guest', now())`);

@@ -99,5 +99,5 @@

).as('subValue', false),
field => field.call('max', q => q.cast('col2', 'text', true)).as('MX'),
field => field.fn('max', q => q.cast('col2', 'text', true)).as('MX'),
field => field.expr(
q => q.call('max', 'col2').over(),
q => q.fn('max', 'col2').over(),
).as('MX'),

@@ -104,0 +104,0 @@ //field => field.path('author1', '~>', q => q.path('parent', '~>', 'fname')).as('path'),

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

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