@deep-foundation/deeplinks
Version:
[](https://www.npmjs.com/package/@deep-foundation/deeplinks) [](https://gitpod.io/#https://github.com/deep-fo
818 lines • 37.8 kB
JavaScript
import _remove from 'lodash/remove.js';
import _isEqual from 'lodash/isEqual.js';
import _mean from 'lodash/mean.js';
import _sum from 'lodash/sum.js';
import _min from 'lodash/min.js';
import _max from 'lodash/max.js';
import EventEmitter from 'events';
import React, { createContext, useContext, useEffect, useMemo, useRef, useState } from 'react';
import Debug from 'debug';
import { minilinksQuery, minilinksQueryIs } from './minilinks-query.js';
import { useDebounceCallback } from '@react-hook/debounce';
import { Observable } from '@apollo/client/index.js';
import get from 'get-value';
import { _ids, random, useDebouncedInput } from './client.js';
import { Traveler } from './traveler.js';
const debug = Debug('deeplinks:minilinks');
const log = debug.extend('log');
const error = debug.extend('error');
;
const nativeLinkKeys = ['id', 'type_id', 'from_id', 'to_id', 'value', 'type', 'typed', 'from', 'out', 'outByType', 'to', 'in', 'inByType', '_applies', '_namespaces', 'ml'];
export function toPlain(link) {
return {
id: link._id || link.id,
type_id: link._type_id || link.type_id,
from_id: link._from_id || link.from_id,
to_id: link._to_id || link.to_id,
value: link.value || undefined,
};
}
export class MinilinksLink {
get type_id() {
var _a;
return (((_a = this.ml) === null || _a === void 0 ? void 0 : _a.virtualInverted[this._type_id]) || this._type_id);
}
get from_id() {
var _a;
return (((_a = this.ml) === null || _a === void 0 ? void 0 : _a.virtualInverted[this._from_id]) || this._from_id);
}
get to_id() {
var _a;
return (((_a = this.ml) === null || _a === void 0 ? void 0 : _a.virtualInverted[this._to_id]) || this._to_id);
}
set type_id(id) {
this._type_id = id;
}
set from_id(id) {
this._from_id = id;
}
set to_id(id) {
this._to_id = id;
}
get typed() {
var _a, _b;
return this.ml._traveled(((_b = (_a = this.ml) === null || _a === void 0 ? void 0 : _a.byType) === null || _b === void 0 ? void 0 : _b[this.id]) || []);
}
get type() {
var _a, _b;
return this.ml._traveled((_b = (_a = this.ml) === null || _a === void 0 ? void 0 : _a.byId) === null || _b === void 0 ? void 0 : _b[this.type_id]);
}
get in() {
var _a, _b;
return this.ml._traveled(((_b = (_a = this.ml) === null || _a === void 0 ? void 0 : _a.byTo) === null || _b === void 0 ? void 0 : _b[this.id]) || []);
}
get inByType() {
var _a, _b, _c, _d, _e;
const hash = {};
for (let i = 0; i < (((_c = (_b = (_a = this.ml) === null || _a === void 0 ? void 0 : _a.byTo) === null || _b === void 0 ? void 0 : _b[this.id]) === null || _c === void 0 ? void 0 : _c.length) || 0); i++) {
const element = (_e = (_d = this.ml) === null || _d === void 0 ? void 0 : _d.byTo) === null || _e === void 0 ? void 0 : _e[this.id][i];
hash[element.type_id] = hash[element.type_id] || this.ml._traveled([]);
hash[element.type_id].push(element);
}
return hash;
}
get out() {
var _a, _b;
return this.ml._traveled((_b = (_a = this.ml) === null || _a === void 0 ? void 0 : _a.byFrom) === null || _b === void 0 ? void 0 : _b[this.id]);
}
get outByType() {
var _a, _b, _c, _d, _e, _f;
const hash = {};
for (let i = 0; i < (((_c = (_b = (_a = this.ml) === null || _a === void 0 ? void 0 : _a.byFrom) === null || _b === void 0 ? void 0 : _b[this.id]) === null || _c === void 0 ? void 0 : _c.length) || 0); i++) {
const element = (_f = (_e = (_d = this.ml) === null || _d === void 0 ? void 0 : _d.byFrom) === null || _e === void 0 ? void 0 : _e[this.id]) === null || _f === void 0 ? void 0 : _f[i];
hash[element.type_id] = hash[element.type_id] || this.ml._traveled([]);
hash[element.type_id].push(element);
}
return hash;
}
get from() {
var _a, _b;
return (_b = (_a = this.ml) === null || _a === void 0 ? void 0 : _a.byId) === null || _b === void 0 ? void 0 : _b[this.from_id];
}
get to() {
var _a, _b;
return (_b = (_a = this.ml) === null || _a === void 0 ? void 0 : _a.byId) === null || _b === void 0 ? void 0 : _b[this.to_id];
}
get displayId() {
return this._id || this.id;
}
get value() {
return (this === null || this === void 0 ? void 0 : this.string) || (this === null || this === void 0 ? void 0 : this.number) || (this === null || this === void 0 ? void 0 : this.object);
}
get name() {
var _a;
return (_a = this.ml) === null || _a === void 0 ? void 0 : _a.name(this.id);
}
get symbol() {
var _a;
return (_a = this.ml) === null || _a === void 0 ? void 0 : _a.symbol(this.id);
}
travel(query) {
var _a, _b;
return ((_a = this === null || this === void 0 ? void 0 : this.ml) === null || _a === void 0 ? void 0 : _a.deep) ? new Traveler((_b = this.ml) === null || _b === void 0 ? void 0 : _b.deep, [this], query ? [{ query }] : [], 'local') : undefined;
}
toString() {
return `${this.symbol} ${this.id} ${this.name}`;
}
valueOf() {
var _a;
return (_a = this === null || this === void 0 ? void 0 : this.value) === null || _a === void 0 ? void 0 : _a.value;
}
constructor(link) {
var _a, _b, _c;
this._applies = [];
this._namespaces = [];
this.ml = link.ml;
this.id = link.id;
this._id = link._id;
this._type_id = link.type_id;
this._from_id = link.from_id;
this._to_id = link.to_id;
this._applies = link._applies;
if (link.value) {
if (typeof ((_a = link === null || link === void 0 ? void 0 : link.value) === null || _a === void 0 ? void 0 : _a.value) === 'string' && !this.string)
this.string = link.value;
if (typeof ((_b = link === null || link === void 0 ? void 0 : link.value) === null || _b === void 0 ? void 0 : _b.value) === 'number' && !this.number)
this.number = link.value;
if (typeof ((_c = link === null || link === void 0 ? void 0 : link.value) === null || _c === void 0 ? void 0 : _c.value) === 'object' && !this.object)
this.object = link.value;
}
const keys = Object.keys(link);
for (const key of keys) {
if (!nativeLinkKeys.includes(key))
this[key] = link[key];
}
}
toPlain() {
return toPlain(this);
}
is(query) {
return minilinksQueryIs(query, this);
}
}
export const MinilinksGeneratorOptionsDefault = {
id: 'id',
type_id: 'type_id',
type: 'type',
typed: 'typed',
from_id: 'from_id',
from: 'from',
out: 'out',
to_id: 'to_id',
to: 'to',
in: 'in',
inByType: 'inByType',
outByType: 'outByType',
equal: (ol, nl) => {
const _ol = toPlain(ol);
const _nl = toPlain(nl);
return _ol.type_id == _nl.type_id && _ol.from_id == _nl.from_id && _ol.to_id == _nl.to_id && _isEqual(_ol.value, _nl.value);
},
Link: MinilinksLink,
};
export function Minilinks(options) {
return function minilinks(linksArray = [], memory = {}) {
const mc = new MinilinkCollection(options, memory);
mc.add(linksArray);
return mc;
};
}
export class MinilinkCollection {
query(query, options) {
this.emitter.emit('select.before', {
minilinks: this, query, options
});
const result = minilinksQuery(query, this);
if ((options === null || options === void 0 ? void 0 : options.aggregate) === 'count')
return result === null || result === void 0 ? void 0 : result.length;
if ((options === null || options === void 0 ? void 0 : options.aggregate) === 'avg')
return _mean(result === null || result === void 0 ? void 0 : result.map(l => { var _a; return (_a = l === null || l === void 0 ? void 0 : l.value) === null || _a === void 0 ? void 0 : _a.value; }));
if ((options === null || options === void 0 ? void 0 : options.aggregate) === 'sum')
return _sum(result === null || result === void 0 ? void 0 : result.map(l => { var _a; return (_a = l === null || l === void 0 ? void 0 : l.value) === null || _a === void 0 ? void 0 : _a.value; }));
if ((options === null || options === void 0 ? void 0 : options.aggregate) === 'min')
return _min(result === null || result === void 0 ? void 0 : result.map(l => { var _a; return (_a = l === null || l === void 0 ? void 0 : l.value) === null || _a === void 0 ? void 0 : _a.value; }));
if ((options === null || options === void 0 ? void 0 : options.aggregate) === 'max')
return _max(result === null || result === void 0 ? void 0 : result.map(l => { var _a; return (_a = l === null || l === void 0 ? void 0 : l.value) === null || _a === void 0 ? void 0 : _a.value; }));
this._traveled(result);
this.emitter.emit('select', {
minilinks: this, query, options, localData: result,
});
return result;
}
select(query, options) {
return this.query(query, options);
}
id(start, ...path) {
const paths = [start, ...(path[path.length - 1] === true ? path.slice(0, -1) : path)];
const [link] = this.query({
id: {
_id: paths
}
});
const result = link === null || link === void 0 ? void 0 : link.id;
if (!result && path[path.length - 1] !== true) {
const precached = get(_ids, paths.join('.'));
if (precached)
return precached;
throw new Error(`Id not found by ${JSON.stringify([start, ...path])}`);
}
else {
return result;
}
}
;
name(input) {
var _a, _b, _c, _d;
const id = typeof (input) === 'number' || typeof (input) === 'string' ? input : input === null || input === void 0 ? void 0 : input.id;
if (!id)
return null;
const it = this.byId[id];
if ((it === null || it === void 0 ? void 0 : it.type_id) === _ids['@deep-foundation/core']['Package'])
return (_a = it === null || it === void 0 ? void 0 : it.value) === null || _a === void 0 ? void 0 : _a.value;
return ((_d = (_c = (_b = it === null || it === void 0 ? void 0 : it.inByType[_ids['@deep-foundation/core']['Contain']]) === null || _b === void 0 ? void 0 : _b.find((c) => { var _a; return !!((_a = c === null || c === void 0 ? void 0 : c.value) === null || _a === void 0 ? void 0 : _a.value); })) === null || _c === void 0 ? void 0 : _c.value) === null || _d === void 0 ? void 0 : _d.value) || id;
}
symbol(input) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
const id = typeof (input) === 'number' || typeof (input) === 'string' ? input : input === null || input === void 0 ? void 0 : input.id;
if (!id)
return null;
return ((_e = (_d = (_c = (_b = (_a = this.byId[id]) === null || _a === void 0 ? void 0 : _a.inByType) === null || _b === void 0 ? void 0 : _b[_ids['@deep-foundation/core']['Symbol']]) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.value) === null || _e === void 0 ? void 0 : _e.value) || ((_l = (_k = (_j = (_h = (_g = (_f = this.byId[id]) === null || _f === void 0 ? void 0 : _f.type) === null || _g === void 0 ? void 0 : _g.inByType) === null || _h === void 0 ? void 0 : _h[_ids['@deep-foundation/core']['Symbol']]) === null || _j === void 0 ? void 0 : _j[0]) === null || _k === void 0 ? void 0 : _k.value) === null || _l === void 0 ? void 0 : _l.value) || '📍';
}
subscribe(query, options) {
const ml = this;
this.emitter.emit('subscribe.before', {
minilinks: this, query, options,
});
return new Observable((observer) => {
let prev = ml.query(query, options);
let t;
observer.next(prev);
let listener = (oldL, newL) => {
clearTimeout(t);
t = setTimeout(() => {
const data = ml.query(query, options);
if (!_isEqual(prev, data)) {
prev = data;
this.emitter.emit('subscribe', {
minilinks: this, query, options, localData: data,
});
observer.next(data);
}
}, 300);
};
ml.emitter.on('added', listener);
ml.emitter.on('updated', listener);
ml.emitter.on('removed', listener);
return () => {
ml.emitter.removeListener('added', listener);
ml.emitter.removeListener('updated', listener);
ml.emitter.removeListener('removed', listener);
};
});
}
add(linksArray, applyName = '') {
log('add', linksArray, this);
const { byId, byFrom, byTo, byType, links, options } = this;
const anomalies = [];
const errors = [];
const newLinks = this._traveled([]);
for (let l = 0; l < linksArray.length; l++) {
if (!!byId[linksArray[l][options.id]])
errors.push(new Error(`${linksArray[l][options.id]} can't add because already exists in collection`));
if (byId[linksArray[l][options.id]]) {
if (options.handler)
options.handler(byId[linksArray[l][options.id]], this);
}
else {
const isVirtual = linksArray[l].id < 0;
if (isVirtual && !this.virtual.hasOwnProperty(linksArray[l].id)) {
this.virtual[linksArray[l].id] = undefined;
}
const link = new this.options.Link(Object.assign({ ml: this, _applies: [applyName], _namespaces: [], _id: isVirtual ? undefined : linksArray[l].id }, linksArray[l]));
byId[link[options.id]] = link;
if (link[options.from_id]) {
if (byFrom[link[options.from_id]])
byFrom[link[options.from_id]].push(link);
else
byFrom[link[options.from_id]] = this._traveled([link]);
}
if (link[options.to_id]) {
if (byTo[link[options.to_id]])
byTo[link[options.to_id]].push(link);
else
byTo[link[options.to_id]] = this._traveled([link]);
}
if (link[options.type_id]) {
if (byType[link[options.type_id]])
byType[link[options.type_id]].push(link);
else
byType[link[options.type_id]] = this._traveled([link]);
}
links.push(link);
newLinks.push(link);
}
}
for (let l = 0; l < newLinks.length; l++) {
const link = newLinks[l];
const type = byId[link[options.type_id]];
const from = byId[link[options.from_id]];
const to = byId[link[options.to_id]];
if (type) {
}
else if (link[options.type_id])
anomalies.push(new Error(`${link[options.id]} link.type_id ${link[options.type_id]} not found`));
if (from) {
}
else if (link[options.from_id])
anomalies.push(new Error(`${link[options.id]} link.from_id ${link[options.from_id]} not found`));
if (to) {
}
else if (link[options.to_id])
anomalies.push(new Error(`${link[options.id]} link.to_id ${link[options.to_id]} not found`));
if (options.handler)
options.handler(link, this);
}
for (let l = 0; l < newLinks.length; l++) {
const link = newLinks[l];
if (!this._updating) {
this.emitter.emit('added', undefined, link, applyName);
this.emitter.emit(`link.${link.id}`, undefined, link, applyName);
}
}
return {
anomalies,
errors,
};
}
remove(idsArray, applyName) {
log('remove', idsArray, this);
const { byId, byFrom, byTo, byType, types, links, options } = this;
const anomalies = [];
const errors = [];
const oldLinksArray = this._traveled([]);
const oldLinksObject = {};
for (let l = 0; l < idsArray.length; l++) {
const id = idsArray[l];
const link = byId[id];
log('remove old l:', l, 'id:', id, 'link:', link);
if (link) {
oldLinksArray.push(link);
oldLinksObject[id] = link;
}
}
for (let l = 0; l < idsArray.length; l++) {
const id = idsArray[l];
const link = oldLinksArray[l];
if (!link)
errors.push(new Error(`${id} can't delete because not exists in collection`));
_remove((byFrom === null || byFrom === void 0 ? void 0 : byFrom[link === null || link === void 0 ? void 0 : link[options.from_id]]) || [], (r) => r.id === id);
_remove((byTo === null || byTo === void 0 ? void 0 : byTo[link === null || link === void 0 ? void 0 : link[options.to_id]]) || [], (r) => r.id === id);
_remove((byType === null || byType === void 0 ? void 0 : byType[link === null || link === void 0 ? void 0 : link[options.type_id]]) || [], (r) => r.id === id);
byId === null || byId === void 0 ? true : delete byId[id];
}
_remove(links, l => idsArray.includes(l[options.id]));
for (let l = 0; l < oldLinksArray.length; l++) {
const link = oldLinksArray[l];
log('emit removed link', link, '_updating', this._updating);
if (!this._updating) {
this.emitter.emit('removed', link, undefined, applyName);
this.emitter.emit(`link.${link.id}`, link, undefined, applyName);
}
}
return {
anomalies,
errors,
};
}
_toPlainLinksArray(linkOrLinks, applyOptions, plainLinksArray, returnLinksPathsById) {
var _a;
const links = Array.isArray(linkOrLinks) ? linkOrLinks : [linkOrLinks];
plainLinksArray.push(...links.filter(l => l.__typename === 'links').map(l => (Object.assign(Object.assign({}, l), { id: l.id, type_id: l.type_id, from_id: l.from_id, to_id: l.to_id, value: l.value }))));
for (let l in links) {
for (let r in ((applyOptions === null || applyOptions === void 0 ? void 0 : applyOptions.return) || {})) {
this._toPlainLinksArray(links[l][r] || [], (_a = applyOptions === null || applyOptions === void 0 ? void 0 : applyOptions.return) === null || _a === void 0 ? void 0 : _a[r], plainLinksArray, returnLinksPathsById);
}
}
}
apply(_input, applyName = '', applyOptions) {
var _a, _b, _c, _d;
const result = [];
const input = Array.isArray(_input) ? _input : Array.isArray(_input === null || _input === void 0 ? void 0 : _input.data) ? _input === null || _input === void 0 ? void 0 : _input.data : [];
const returning = (_input === null || _input === void 0 ? void 0 : _input.return) || {};
const _applyOptions = Object.assign({ return: returning }, applyOptions);
const deep = _input === null || _input === void 0 ? void 0 : _input.deep;
const namespace = deep === null || deep === void 0 ? void 0 : deep.namespace;
log('apply', input, this);
const { byId, byFrom, byTo, byType, types, links, options } = this;
const toAdd = [];
const toUpdate = [];
const beforeUpdate = {};
const toRemove = [];
const _byId = {};
const linksArray = [];
const returnLinksPathsById = {};
for (let l = 0; l < input.length; l++) {
const link = input[l];
this._toPlainLinksArray(link, _applyOptions, linksArray, returnLinksPathsById);
}
const virtualizedLinks = {};
for (let l = 0; l < linksArray.length; l++) {
let link = linksArray[l];
if (!virtualizedLinks[link.id] && !link.from_id && !link.to_id) {
const virtualId = this.virtualInverted[link.id];
const compatable = [];
if (virtualId)
compatable.push(virtualId);
if (!compatable.length && virtualizedLinks[link.type_id]) {
compatable.push((_a = this.byType[virtualizedLinks[link.type_id].id]) === null || _a === void 0 ? void 0 : _a.find(l => !l._id));
}
if (!compatable.length)
compatable.push((_b = this.byType[link.type_id]) === null || _b === void 0 ? void 0 : _b.find(l => !l._id));
if (compatable[0]) {
virtualizedLinks[link.id] = compatable[0];
}
}
}
let needRepeatIdentification = true;
while (needRepeatIdentification) {
let hasIdentifiedVirtualizedPerCycle = false;
for (let l = 0; l < linksArray.length; l++) {
let link = linksArray[l];
if (!virtualizedLinks[link.id]) {
if (link.from_id && link.to_id) {
const virtual = this.virtualInverted[link.id];
const compatable = [];
if (virtualizedLinks[link.to_id]) {
compatable.push((_c = this.byTo[virtualizedLinks[link.to_id].id]) === null || _c === void 0 ? void 0 : _c.find(l => { var _a, _b; return l.from_id === ((_a = virtualizedLinks[link.from_id]) === null || _a === void 0 ? void 0 : _a.id) || l.from_id === link.from_id && l.type_id === ((_b = virtualizedLinks[link.type_id]) === null || _b === void 0 ? void 0 : _b.id) || l.type_id === link.type_id && !l._id; }));
}
if (!compatable.length)
compatable.push((_d = this.byTo[link.to_id]) === null || _d === void 0 ? void 0 : _d.find(l => { var _a, _b; return l.from_id === ((_a = virtualizedLinks[link.from_id]) === null || _a === void 0 ? void 0 : _a.id) || l.from_id === link.from_id && l.type_id === ((_b = virtualizedLinks[link.type_id]) === null || _b === void 0 ? void 0 : _b.id) || l.type_id === link.type_id && !l._id; }));
if (compatable[0]) {
virtualizedLinks[link.id] = compatable[0];
hasIdentifiedVirtualizedPerCycle = true;
}
}
}
}
if (!hasIdentifiedVirtualizedPerCycle)
needRepeatIdentification = false;
}
for (let l = 0; l < linksArray.length; l++) {
let link = linksArray[l];
let old = byId[link.id];
const virtual = virtualizedLinks[link.id] || (this.virtualInverted[link.id] ? this.byId[this.virtualInverted[link.id]] : undefined);
if (virtual && !old) {
old = virtual;
if (!virtual._id) {
this.virtual[virtual.id] = link.id;
this.virtualInverted[link.id] = virtual.id;
virtual._id = link.id;
link = Object.assign(Object.assign({}, link), { _id: link.id, id: virtual.id });
}
}
if (!old && !virtual) {
link._applies = [applyName];
if (namespace)
link._namespaces = [namespace];
this.emitter.emit('apply', old, link, applyName);
this.emitter.emit('+apply', old, link, applyName);
toAdd.push(link);
}
else {
if (!~old._applies.indexOf(applyName)) {
link._applies = old._applies = [...old._applies, applyName];
this.emitter.emit('apply', old, link, applyName);
this.emitter.emit('+apply', old, link, applyName);
}
else {
link._applies = old._applies;
}
if (!options.equal(old, link)) {
toUpdate.push(link);
beforeUpdate[link.id] = old;
}
if (namespace) {
if (!~old._namespaces.indexOf(namespace)) {
link._namespaces = old._namespaces = [...old._namespaces, namespace];
}
else {
link._namespaces = old._namespaces;
}
}
}
_byId[link.id] = link;
}
for (let l = 0; l < links.length; l++) {
const link = links[l];
if (!_byId[link._id]) {
const index = link._applies.indexOf(applyName);
const isVirtualAndNeedToDelete = link._applies.length == 2 && link._applies.includes('');
if (!!~index) {
if (link._applies.length === 1 || isVirtualAndNeedToDelete) {
toRemove.push(link);
}
else {
link._applies.splice(index, 1);
this.emitter.emit('apply', link, link, applyName);
this.emitter.emit('-apply', link, link, applyName);
}
}
}
}
const r1 = this.remove(toRemove.map(l => l[options.id]), applyName);
const a1 = this.add(toAdd);
this._updating = true;
const r2 = this.remove(toUpdate.map(l => l[options.id]), applyName);
const a2 = this.add(toUpdate);
for (let i = 0; i < toUpdate.length; i++) {
const l = toUpdate[i];
this.emitter.emit('updated', beforeUpdate[l.id], byId[l.id], applyName);
this.emitter.emit(`link.${l.id}`, beforeUpdate[l.id], byId[l.id], applyName);
}
this._updating = false;
return {
errors: [...r1.errors, ...a1.errors, ...r2.errors, ...a2.errors],
anomalies: [...r1.anomalies, ...a1.anomalies, ...r2.anomalies, ...a2.anomalies],
data: this._traveled(input.map(i => this.byId[i === null || i === void 0 ? void 0 : i.id])),
plainLinks: linksArray,
};
}
update(linksArray, applyName) {
log('update', linksArray, this);
const { byId, byFrom, byTo, byType, types, links, options } = this;
const toUpdate = [];
const beforeUpdate = {};
const _byId = {};
for (let l = 0; l < linksArray.length; l++) {
let link = linksArray[l];
let old = byId[link.id];
const virtualIds = Object.keys(this.virtual);
let virtual;
for (let i = 0; i < virtualIds.length; i++) {
const v = this.byId[virtualIds[i]];
if ((!link.type_id || link.type_id == v._type_id) &&
(!link.from_id || link.from_id == v._from_id) &&
(!link.to_id || link.to_id == v._to_id) &&
(!link.value || _isEqual(link.value, v.value))) {
virtual = v;
break;
}
}
if (virtual) {
if (old)
throw new Error(`somehow we have oldLink.id ${old.id} and virtualLink.id ${virtual.id} virtualLink._id = ${virtual._id}`);
old = virtual;
virtual._id = link.id;
link = Object.assign(Object.assign({}, link), { _id: link.id, id: virtual.id });
}
if (old) {
if (!options.equal(old, link)) {
toUpdate.push(link);
beforeUpdate[link.id] = old;
}
}
_byId[link.id] = link;
}
this._updating = true;
const r2 = this.remove(toUpdate.map(l => l[options.id]), applyName);
const a2 = this.add(toUpdate, applyName);
for (let i = 0; i < toUpdate.length; i++) {
const l = toUpdate[i];
this.emitter.emit('updated', beforeUpdate[l.id], byId[l.id], applyName);
this.emitter.emit(`link.${l.id}`, beforeUpdate[l.id], byId[l.id], applyName);
}
this._updating = false;
return { errors: [...r2.errors, ...a2.errors], anomalies: [...r2.anomalies, ...a2.anomalies] };
}
constructor(options, memory) {
this.useMinilinksQuery = useMinilinksQuery;
this.useMinilinksFilter = useMinilinksFilter;
this.useMinilinksApply = useMinilinksApply;
this.useMinilinksSubscription = useMinilinksSubscription;
this.useMinilinksId = useMinilinksId;
this.useMinilinksHandle = useMinilinksHandle;
this.toPlain = toPlain;
this.virtual = {};
this.virtualInverted = {};
this.virtualCounter = -1;
this.types = {};
this.byId = {};
this.byFrom = {};
this.byTo = {};
this.byType = {};
this.links = this._traveled([]);
this._updating = false;
const _options = options || MinilinksGeneratorOptionsDefault;
this.types = this.byType = (memory === null || memory === void 0 ? void 0 : memory.types) || {};
this.byId = (memory === null || memory === void 0 ? void 0 : memory.byId) || {};
this.byFrom = (memory === null || memory === void 0 ? void 0 : memory.byFrom) || {};
this.byTo = (memory === null || memory === void 0 ? void 0 : memory.byTo) || {};
this.links = (memory === null || memory === void 0 ? void 0 : memory.links) || [];
this.options = _options;
this.emitter = new EventEmitter();
}
_traveled(array) {
if (!array)
return array;
array.travel = (query) => this.deep ? new Traveler(this.deep, array, query ? [{ query }] : [], 'local') : undefined;
return array;
}
}
export const minilinks = Minilinks(MinilinksGeneratorOptionsDefault);
export function useMinilinksConstruct(options) {
const mlRef = useRef(useMemo(() => {
return new MinilinkCollection(options);
}, []));
const ml = mlRef.current;
return { ml, ref: mlRef };
}
export function useMinilinksFilter(ml, filter, results, interval) {
const [state, setState] = useState();
const action = useDebounceCallback((l, ml, ol, nl) => {
setState(results(l, ml, ol, nl));
}, 500, true);
const refs = useRef({});
useEffect(() => {
if (refs.current.addedListener)
ml.emitter.removeListener('added', refs.current.addedListener);
if (refs.current.updatedListener)
ml.emitter.removeListener('updated', refs.current.updatedListener);
if (refs.current.removedListener)
ml.emitter.removeListener('removed', refs.current.removedListener);
if (refs.current.applyListener)
ml.emitter.removeListener('apply', refs.current.applyListener);
refs.current.addedListener = (ol, nl) => {
if (filter(nl, ol, nl)) {
action(nl, ml, ol, nl);
}
};
ml.emitter.on('added', refs.current.addedListener);
refs.current.updatedListener = (ol, nl) => {
if (filter(nl, ol, nl)) {
action(nl, ml, ol, nl);
}
};
ml.emitter.on('updated', refs.current.updatedListener);
refs.current.removedListener = (ol, nl) => {
if (filter(ol, ol, nl)) {
action(ol, ml, ol, nl);
}
};
ml.emitter.on('removed', refs.current.removedListener);
refs.current.applyListener = (ol, nl) => {
if (filter(nl, ol, nl)) {
action(nl, ml, ol, nl);
}
};
let timeout;
if (interval)
timeout = setTimeout(() => {
action(undefined, ml);
}, interval);
ml.emitter.on('apply', refs.current.applyListener);
return () => {
clearTimeout(timeout);
ml.emitter.removeListener('added', refs.current.addedListener);
ml.emitter.removeListener('updated', refs.current.updatedListener);
ml.emitter.removeListener('removed', refs.current.removedListener);
ml.emitter.removeListener('apply', refs.current.applyListener);
};
}, [ml]);
useEffect(() => {
setState(results(undefined, ml, undefined, undefined));
}, [ml, filter, results]);
return state;
}
;
export function useMinilinksHandle(ml, handler) {
useEffect(() => {
const addedListener = (ol, nl) => {
handler('added', ol, nl);
};
ml.emitter.on('added', addedListener);
const updatedListener = (ol, nl) => {
handler('updated', ol, nl);
};
ml.emitter.on('updated', updatedListener);
const removedListener = (ol, nl) => {
handler('removed', ol, nl);
};
ml.emitter.on('removed', removedListener);
const applyListener = (ol, nl) => {
handler('apply', ol, nl);
};
ml.emitter.on('apply', applyListener);
return () => {
ml.emitter.removeListener('added', addedListener);
ml.emitter.removeListener('updated', updatedListener);
ml.emitter.removeListener('removed', removedListener);
ml.emitter.removeListener('apply', applyListener);
};
}, []);
}
;
const defaultMinilinksApplyResult = { errors: [], anomalies: [], data: [], plainLinks: [] };
export function useMinilinksApply(ml, name, data) {
const [strictName] = useState(name);
useEffect(() => {
return () => {
if (ml)
ml.apply(Array.isArray(data) ? [] : Object.assign(Object.assign({}, data), { data: [] }), strictName);
};
}, []);
const results = useMemo(() => {
if (ml)
return ml.apply(data, strictName);
return defaultMinilinksApplyResult;
}, [data]);
return results;
}
export function useMinilinksQuery(ml, query, options) {
const miniName = useMemo(() => random(), []);
useMemo(() => {
ml.emitter.emit('useQuery.mount', { minilinks: ml, query, options });
}, []);
const { _q, _o } = useDebouncedInput(query, options, options === null || options === void 0 ? void 0 : options.debounce);
const results = useMemo(() => ml.query(_q, _o), [ml, _q]);
useMemo(() => {
ml.emitter.emit('useQuery', {
minilinks: ml, query: _q, options: _o,
localData: results,
});
return () => {
ml.emitter.emit('useQuery.unmount', {
minilinks: ml, query: _q, options: _o,
localData: results,
});
};
}, [results]);
return results;
}
;
export function useMinilinksSubscription(ml, query, options) {
const miniName = useMemo(() => random(), []);
const { _q, _o } = useDebouncedInput(query, options, options === null || options === void 0 ? void 0 : options.debounce);
useMemo(() => {
ml.emitter.emit('useSubscription.mount', { minilinks: ml, query: _q, options: _o });
}, []);
const [d, setD] = useState();
const sRef = useRef();
const qPrevRef = useRef(_q);
const q = useMemo(() => _isEqual(_q, qPrevRef.current) ? qPrevRef.current : _q, [_q]);
qPrevRef.current = q;
useEffect(() => {
setD(ml.query(q));
if (sRef.current)
sRef.current.unsubscribe();
const obs = ml.subscribe(q, _o);
const sub = sRef.current = obs.subscribe({
next: (links) => {
setD(links);
},
error: (error) => {
throw new Error(error);
},
});
return () => {
sub.unsubscribe();
};
}, [q]);
let results = d || (ml ? ml.query(q) : []);
useMemo(() => {
ml.emitter.emit('useSubscription', {
minilinks: ml, query: _q, options: _o,
localData: results,
});
return () => {
ml.emitter.emit('useSubscription.unmount', {
minilinks: ml, query: _q, options: _o,
localData: results,
});
};
}, [results]);
return results;
}
;
export function useMinilinksId(ml, start, ...path) {
var _a;
const result = useMinilinksQuery(ml, { id: { _id: [start, ...path] } });
return (_a = result === null || result === void 0 ? void 0 : result[0]) === null || _a === void 0 ? void 0 : _a.id;
}
export function useMinilinksGenerator(minilinks) {
const ref = useRef(minilinks);
ref.current = useMemo(() => {
if (ref.current)
return ref.current;
return new MinilinkCollection();
}, []);
return ref.current;
}
export const MinilinksContext = createContext(undefined);
export function MinilinksProvider({ minilinks: initialMinilinks, children, }) {
const minilinks = useMinilinksGenerator(initialMinilinks);
return (React.createElement(MinilinksContext.Provider, { value: minilinks }, children));
}
export function useMinilinks() {
return useContext(MinilinksContext);
}
//# sourceMappingURL=minilinks.js.map