memory-orm
Version:
client side ORM + map reduce
270 lines (269 loc) • 7.37 kB
JavaScript
Object.defineProperty(exports, '__esModule', { value: true })
exports.Finder = void 0
const tslib_1 = require('tslib')
const cloneDeep_1 = tslib_1.__importDefault(require('lodash/cloneDeep'))
const merge_1 = tslib_1.__importDefault(require('lodash/merge'))
const union_1 = tslib_1.__importDefault(require('lodash/union'))
const uniq_1 = tslib_1.__importDefault(require('lodash/uniq'))
const get_1 = tslib_1.__importDefault(require('lodash/get'))
const set_1 = tslib_1.__importDefault(require('lodash/set'))
const mem_1 = require('./mem')
const datum_1 = require('./datum')
function each_by_id({ from }, process) {
if (from instanceof Array) {
for (const item of from) {
process(item.id || item)
}
}
}
function each({ from }, process) {
if (from instanceof Array) {
for (const item of from) {
process(item)
}
} else if (from instanceof Object) {
for (const id in from) {
const item = from[id]
item._id = id
process(item)
}
}
}
function validate(item, meta, chklist) {
if (!item || !chklist) {
return false
}
for (let chk of chklist) {
if (!chk(item, meta)) {
return false
}
}
return true
}
class Finder {
constructor() {}
join({ $name, model, all, map, list }) {
this.$name = $name
this.all = all
this.map = map
this.list = list
this.model = model
mem_1.State.notify(this.$name.list)
}
calculate(query, memory) {
if (query._step >= mem_1.State.step[this.$name.list]) {
return
}
const base = mem_1.State.base(this.$name.list)
delete query._reduce
query._step = mem_1.step()
const ctx = {
map: this.map,
query,
memory,
cache: cloneDeep_1.default(base.$format),
paths: {
_reduce: {
list: [],
hash: {},
},
},
}
if (query._all_ids) {
let ids = query._all_ids
if (query._is_uniq) {
ids = uniq_1.default(ids)
}
this.reduce(ctx, ids)
} else if (query === query.all) {
this.reduce(ctx, Object.keys(memory))
} else if (query._is_uniq) {
let ids = []
for (const partition of query.$partition) {
const tgt = get_1.default(query.all, `reduce.${partition}`)
ids = union_1.default(ids, tgt)
}
this.reduce(ctx, ids)
} else {
for (const partition of query.$partition) {
const tgt = get_1.default(query.all, `reduce.${partition}`)
this.reduce(ctx, tgt)
}
}
this.finish(ctx)
}
reduce({ map, cache, paths, query, memory }, ids) {
if (!ids) {
return
}
for (let id of ids) {
const o = memory[id]
if (o) {
const { meta, item, $group } = o
if (!validate(item, meta, query._filters)) {
continue
}
for (let [path, a] of $group) {
const o = (paths[path] = cache[path])
map.reduce(query, path, item, o, a)
}
}
}
}
finish({ map, paths, query }) {
for (const path in paths) {
const o = paths[path]
map.finish(query, path, o, this.list)
set_1.default(query, path, o)
}
for (const path in query.$sort) {
const cmd = query.$sort[path]
const from = get_1.default(query, path)
if (from) {
const sorted = map.order(query, path, from, from, cmd, this.list)
const dashed = map.dash(query, path, sorted, from, cmd, this.list)
const result = map.post_proc(query, path, dashed, from, cmd, this.list)
this.list.bless(result, query)
result.from = from
set_1.default(query, path, result)
}
}
}
data_set(type, from, parent) {
const meta = mem_1.State.meta()
const base = mem_1.State.base(this.$name.list)
const journal = mem_1.State.journal(this.$name.list)
const { deploys } = this.$name
return this[type]({
base,
journal,
meta,
model: this.model,
all: this.all,
deploys,
from,
parent,
})
}
data_emitter({ base, journal }, { item, $group }) {
if (!base.$format) {
throw new Error('bad context.')
}
const order = (keys, cmd) => {
if ('string' === typeof keys) {
keys = [keys]
}
const path = [`_reduce`, ...keys].join('.')
base.$sort[path] = cmd
journal.$sort[path] = cmd
}
const reduce = (keys, cmd) => {
if ('string' === typeof keys) {
keys = [keys]
}
const path = [`_reduce`, ...keys].join('.')
cmd = reduce.default(keys, cmd)
$group.push([path, cmd])
const map = base.$format[path] || (base.$format[path] = {})
const map_j = journal.$format[path] || (journal.$format[path] = {})
this.map.init(map, cmd)
this.map.init(map_j, cmd)
}
reduce.default = reduce.default_origin = function (keys, cmd) {
if (keys.length) {
return cmd
}
reduce.default = (_keys, cmd) => cmd
const bare = {
set: item.id,
list: true,
}
return Object.assign(bare, cmd)
}
return { reduce, order }
}
data_init({ model, parent, deploys }, { item }, { reduce, order }) {
model.bless(item)
parent && merge_1.default(item, parent)
model.deploy.call(item, model)
for (const deploy of deploys) {
deploy.call(item, { o: item, model, reduce, order })
}
}
data_entry({ model }, { item }, { reduce, order }) {
model.map_partition(item, reduce)
model.map_reduce(item, reduce)
if (reduce.default === reduce.default_origin) {
reduce([], {})
}
model.order(item, order)
}
reset(ctx) {
ctx.journal.$memory = mem_1.PureObject()
const news = (ctx.base.$memory = ctx.all.$memory = mem_1.PureObject())
this.merge(ctx)
for (let key in ctx.base.$memory) {
const old = ctx.base.$memory[key]
const item = news[key]
if (item == null) {
ctx.model.delete(old)
}
}
return true
}
merge(ctx) {
let is_hit = false
each(ctx, (item) => {
const o = new datum_1.Datum(ctx.meta, item)
const emit = this.data_emitter(ctx, o)
this.data_init(ctx, o, emit)
this.data_entry(ctx, o, emit)
const id = item.id
if (!id) {
throw new Error(`detect bad data: ${JSON.stringify(item)}`)
}
ctx.journal.$memory[id] = o
ctx.base.$memory[id] = o
const old = ctx.base.$memory[item.id]
if (old != null) {
ctx.model.update(item, old.item)
} else {
ctx.model.create(item)
}
return (is_hit = true)
})
return is_hit
}
remove(ctx) {
let is_hit = false
each_by_id(ctx, (id) => {
const old = ctx.base.$memory[id]
if (old != null) {
ctx.model.delete(old.item)
delete ctx.journal.$memory[id]
delete ctx.base.$memory[id]
is_hit = true
}
})
return is_hit
}
update(ctx, parent) {
let is_hit = false
each_by_id(ctx, (id) => {
const old = ctx.base.$memory[id]
if (!old) {
return
}
merge_1.default(old.item, parent)
old.$group = []
const emit = this.data_emitter(ctx, old)
this.data_entry(ctx, old, emit)
ctx.model.update(old.item, old.item)
is_hit = true
})
return is_hit
}
}
exports.Finder = Finder
//# sourceMappingURL=finder.js.map