-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.js
137 lines (109 loc) · 2.66 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
const { EventEmitter } = require('events')
const deepEqual = require('deep-equal')
const validateModels = require('@tradle/validate-model')
module.exports = function modelManager () {
let byId = {}
let layers = []
const emitter = new EventEmitter()
function add (models, opts = {}) {
if (typeof opts === 'boolean') {
opts = { overwrite: opts }
}
const { overwrite, validate = true } = opts
// accept array or object
models = values(models).filter(model => {
const existing = get(model.id)
if (existing) {
if (!overwrite) {
if (!deepEqual(existing, model)) {
throw new Error(`model ${model.id} already exists`)
}
return false
}
}
return true
})
const layer = {}
models.forEach(model => {
layer[model.id] = model
})
// test before we commit
if (validate) {
validateModels(Object.assign(flatten(), layer))
}
layers.push(layer)
Object.assign(byId, layer)
emitter.emit('change')
return this
}
function get (id) {
if (id) return byId[id]
return { ...byId }
}
function subClassOf (superId) {
return subset(function (model) {
return model.subClassOf === superId
})
}
function subset (filter) {
const matches = {}
for (const id in byId) {
const model = byId[id]
if (filter(model)) matches[id] = model
}
return matches
}
function update (models) {
return add(models, true)
}
function remove (ids) {
let updated
[].concat(ids).forEach(id => {
if (id in byId) {
delete byId[id]
layers.forEach(layer => {
delete layer[id]
})
updated = true
}
})
if (updated) emitter.emit('change')
return this
}
function reset () {
byId = {}
layers = []
emitter.emit('change')
return this
}
function flatten (offset = 0) {
if (offset === 0) return get()
const flat = {}
layers.slice(offset)
.forEach(layer => Object.assign(flat, layer))
return flat
}
function exportArray () {
return Object.keys(byId).map(id => byId[id])
}
return Object.assign(emitter, {
add,
remove,
get,
subClassOf,
update,
reset,
forms: () => subClassOf('tradle.Form'),
products: () => subClassOf('tradle.FinancialProduct'),
clone: () => modelManager().add(byId),
layers: () => layers.slice(),
base: () => layers[0],
rest: () => flatten(1),
array: exportArray,
flatten
})
}
function values (objOrArray) {
if (Array.isArray(objOrArray)) return objOrArray
return Object.keys(objOrArray).map(key => objOrArray[key])
}