@sqb/connect
Version:
Multi-dialect database connection framework written with TypeScript
62 lines (61 loc) • 1.94 kB
JavaScript
import { splitString } from 'fast-tokenizer';
const FIELD_PATTERN = /^([+-])?([a-z_$]\w*)$/i;
const NO_DOT_BRACKET_PATTERN = /[^.]\(/g;
export class FieldsProjection {
}
(function (FieldsProjection) {
class Item {
}
FieldsProjection.Item = Item;
})(FieldsProjection || (FieldsProjection = {}));
export function parseFieldsProjection(projection, keepCase) {
const arr = Array.isArray(projection) ? projection : [projection];
if (!(arr && arr.length))
return;
const out = new FieldsProjection();
for (let s of arr) {
if (!keepCase)
s = s.toLowerCase();
parse(s, out);
}
return out;
}
function parse(input, target) {
/** Add dot before brackets which is required to split fields */
input = input.replace(NO_DOT_BRACKET_PATTERN, s => s.charAt(0) + '.' + s.substring(1));
const fields = splitString(input, {
delimiters: '.',
brackets: true,
keepBrackets: false,
});
for (let i = 0; i < fields.length; i++) {
const f = fields[i];
if (f.includes(',')) {
const subFields = splitString(f, {
delimiters: ',',
brackets: true,
keepBrackets: true,
});
for (const n of subFields) {
parse(n, target);
}
continue;
}
const m = FIELD_PATTERN.exec(f);
/* istanbul ignore next */
if (!m)
throw new TypeError(`Invalid field path (${input})`);
const fieldName = m[2];
const treeItem = (target[fieldName] =
target[fieldName] || new FieldsProjection.Item());
if (m[1])
treeItem.sign = m[1];
if (i === fields.length - 1) {
delete treeItem.projection;
}
else {
target = treeItem.projection =
treeItem.projection || new FieldsProjection();
}
}
}