Skip to content

Commit

Permalink
add src
Browse files Browse the repository at this point in the history
  • Loading branch information
litstat committed Mar 1, 2024
1 parent 74ff9b6 commit 644c5d4
Show file tree
Hide file tree
Showing 12 changed files with 2,127 additions and 0 deletions.
131 changes: 131 additions & 0 deletions src/cascade.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import has from 'underscore/modules/_has.js';
import isFunction from 'underscore/modules/isFunction.js';

import { array } from 'helpers/array';
import { log, warn } from 'helpers/log';

import { model } from './data';
import { single } from './model';

export async function cascade(data, fields, expeditor) {
if (data.length === 0 || fields.length === 0) {
return;
}

if (has(expeditor, 'children')) {
var previous = expeditor.children;
}

var children = expeditor.children = [];

if (previous) {
children._previous = previous;
}

collect(data, fields, expeditor);

var promises = children.map(expeditor =>
expeditor.sequent()
);

var res = await Promise.all(promises);

promises = children.map((expeditor, i) => {
if (expeditor.fields) {
return cascade(res[i], expeditor.fields, expeditor);
}
});

return Promise.all(promises);
}

function collect(data, fields, expeditor) {
var m = model(expeditor.model);

fields.forEach(field => {
var sequence = m._parse(field);
var step = sequence.find(step => step.field);
var index = sequence.indexOf(step);
var info = m._info(step.field);

var tailField = sequence
.slice(index + 1)
.map(step => step.chunk)
.join('.');

if (info.model) {
propagate(data, step, info, tailField, expeditor);
}
else if (isFunction(m[step.field])) {
var calculated =
m[step.field + 'Field'] ||
m[step.field].field;

if (calculated) {
fields = array(calculated);
fields = single(fields);
log('expand "' + step.field + '" to', { fields });
collect(data, fields, expeditor);
}
}
else if (m.fieldsMap[step.field] >= 0) {
// field belongs to model
}
else {
warn('model "' + m.aka + '"',
'has no property "' + step.field + '"',
'in field "' + field + '"');
}
});
}

function propagate(data, step, info, tailField, expeditor) {
var children = expeditor.children;

var k = [
info.model,
step.field,
step.filter && step.filter.list.map(filter => filter.expression),
];

var child = children[k];

if (!child) {
children[k] = child = spawn(data, step, info, expeditor);
children.push(child);
}

if (tailField) {
child.fields.push(tailField);
}
}

function spawn(data, step, info, expeditor) {
var fields = [];
var params = {};

params[info.index] = data.map(row => row[info.field]);

if (step.filter) {
step.filter.list.forEach(filter => {
if (filter.operator === '=' && filter.value.indexOf('..') === -1) {
params[filter.field] = filter.value.split(',');
}
else {
fields.push(filter.field);
}
});
}

return expeditor.spawn({
field: step.field,
nullable: step.nullable,

inversed: [ info.inverse || expeditor.model ].concat(expeditor.inversed), // copy
index: info.index,
model: info.model,

fields,
params,
});
}
149 changes: 149 additions & 0 deletions src/collection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import { nativeIsArray, nativeKeys } from 'underscore/modules/_setup.js';

import { applyOwnIf } from 'helpers/apply';
import { isObject } from 'helpers/is';
import { log, raise } from 'helpers/log';
import { measure } from 'helpers/measure';

import { collection, model } from './data';
import { Index } from './index';

export function register(name, records) {
if (!(c = collection(name, !!records))) {
var m = model(name);
var c = new Collection(m.aka);

collection(m.name, c);
collection(m.aka, c);
}

if (records) {
c.splice(records);
}

return c;
}

export class Collection {
constructor(name) {
this.indexes = {};
this.index('');

if (name) {
this.model = name;
}

if (this.initialize) {
this.initialize(name);
}
}

index(...keys) {
var k = keys.length < 2 ? keys[0] || '' : keys.join('-');
var i = this.indexes[k];
var m = model(this.model);

if (!i) {
keys = k.split('-');
i = this.indexes[k] = new Index(keys);

if (k) {
measure('create index in "' + this.model + '" for keys ' + keys, () => {
this.find().forEach(i.register, i);
});
}

if (m) {
var onetime = keys.some(k => {
var step = m._parse(k).find(step => step.field);
var info = m._info(step.field);

// one-to-many relation
return info.model && info.index !== 'id';
});

if (onetime) {
log(this, 'one-time', { index: i });
delete this.indexes[k];
}
}
}

return i;
}

splice() {
measure('splice "' + this.model + '"', this._splice, this, arguments);
}

_splice(records, doRemove) {
var m = model(this.model);
var i = this.index(m && m.origin || 'id');

var record = records[0];
var isTuple = nativeIsArray(record);
var isRecord = m && record instanceof m.constructor;

for (var j = 0; j < records.length; j++) {
record = records[j];

if (m) {
if (isTuple || !isRecord) {
record = records[j] = m.create(record);
}
}

var values = i.records(record);
var exist = values && values[0];

if (exist && !isTuple && !isRecord) {
applyOwnIf(record, exist);
}

if (doRemove) {
if (exist) {
records[j] = exist;
}
else {
records.splice(j--, 1);
}
}

for (var k in this.indexes) {
if (exist) {
this.indexes[k].unregister(exist);
}

if (!doRemove) {
this.indexes[k].register(record);
}
}
}
}

find(params = {}, buffer) {
if (!isObject(params)) {
params = { id: params };
}

var keys = nativeKeys(params);

return this
.index(...keys)
.select(params, buffer);
}

findOne(params) {
return this.find(params)[0];
}

findOrFail(params) {
var record = this.find(params)[0];

if (record) {
return record;
}

raise('not found', this.model, 'using', JSON.stringify(params));
}
}
91 changes: 91 additions & 0 deletions src/data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import has from 'underscore/modules/_has.js';
import { nativeCreate } from 'underscore/modules/_setup.js';
import noop from 'underscore/modules/noop.js';

import { applyOwn } from 'helpers/apply';

var collections = {};
const models = {};

export const data = {
collections,
extras: {},
indexes,
models,
similars: {},
views: {},
};

export const fetchRefId = { fetchRefId: true };

export const opt = {
akaRe: '',
classify: false,
extra: false,
keySorter: false, // (a, b) => a <=> b
request: noop,
};

export function init(config) {
return applyOwn(opt, config);
}

export function fork() {
collections = data.collections = nativeCreate(collections);
}

export function free() {
collections = data.collections = Object.getPrototypeOf(collections);
}

/**
* 'set' = true - find in fork
* 'set' = falsy - find in collections
* 'set' = smth - save in current storage
*/
export function collection(name, set) {
if (set === true) {
if (!has(collections, name)) {
return;
}
}
else if (set) {
collections[name] = set;
}

return collections[name];
}

export function model(name, set) {
if (set) {
models[name] = set;
}

return models[name];
}

export function find(name, params, buffer) {
return collection(name).find(params, buffer);
}

export function findOne(name, params) {
return collection(name).findOne(params);
}

export function findOrFail(name, params) {
return collection(name).findOrFail(params);
}

export function index(name, ...keys) {
return collection(name).index(...keys);
}

function indexes() {
var hash = {};

for (var name in collections) {
hash[name] = collections[name].indexes;
}

return hash;
}
Loading

0 comments on commit 644c5d4

Please sign in to comment.