forked from dominictarr/crdt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
set.js
158 lines (130 loc) · 3.45 KB
/
set.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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
'use strict';
var inherits = require('util').inherits
var EventEmitter = require('events').EventEmitter
var Row = require('./row')
var between = require('between')
inherits(Set, EventEmitter)
module.exports = Set
//set
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/*
a set is just a query.
could expand this to enable replicating a subset of a document.
that could enable massive documents that are too large to fit in memory.
as long as they could be partitioned.
heh, join queries? or rather, recursive queries,
for when rows have sets.
that is my vibe. don't make a database you have to
_map_ to your application. pre-map the database.
could also specify sets like
//set of all things
{type: 'thing'}
//set of things with thier parts
{ type: 'thing',
parts: {
parent_id: function (val) {return val == this.id}
}
}
or use map-reduces. remember, if the the reduce is
monotonic you don't have to remember each input.
*/
function Set(doc, key, value) {
var array = this._array = []
var rows = this.rows = {}
var set = this
var filter
if ('function' === typeof key) {
filter = this.filter = key
key = null
} else {
//DO NOT CHANGE once you have created the set.
if(key === '__proto__') throw new Error('__proto__ is illegal key')
this.key = key
this.value = value
}
function add(row) {
if (rows[row.id]) {
return
}
array.push(row)
rows[row.id] = row
set.emit('add', row)
function remove (_, changed) {
if ((key && row.state[key] === value) ||
(filter && filter(row.state))
) {
set.emit('changes', row, changed)
return
}
delete rows[row.id]
var i = array.indexOf(row)
if(~i) array.splice(i, 1)
set.emit('changes', row, changed)
set.emit('remove', row)
row.removeListener('changes', remove)
}
row.on('changes', remove)
}
if (!filter) {
doc.sets.on(key, function (row, changed) {
if(changed[key] !== value) return
add(row)
})
} else {
doc.on('create', function (row) {
if (filter(row.state)) {
add(row)
}
})
}
this.rm = this.remove = function (row) {
row = this.get(row)
if(!row) return
if (key) {
return row.set(key, null)
} else {
throw new Error("Set cannot remove rows with arbitary filters")
}
}
for(var id in doc.rows) {
var row = doc.get(id)
if (key && row.get(key) === value) {
add(row)
} else if (filter && filter(row.state)) {
add(row)
}
}
this.setMaxListeners(Infinity)
}
Set.prototype.onEach = function (callback) {
this.forEach(callback)
this.on("add", callback)
}
Set.prototype.asArray = function () {
return this._array
}
Set.prototype.toJSON = function () {
return this._array.map(function (e) {
return e.state
}).sort(function (a, b) {
return between.strord(a._sort || a.id, b._sort || b.id)
})
}
Set.prototype.each =
Set.prototype.forEach = function (iter) {
return this._array.forEach(iter)
}
Set.prototype.get = function (id) {
if(!arguments.length)
return this.array
if(id === '__proto__') throw new Error('__proto__ is invalid id')
return (
'string' === typeof id ? this.rows[id]
: 'number' === typeof id ? this.rows[id]
: id && id.id ? this.rows[id.id]
: null
)
}
Set.prototype.has = function (row) {
return this.get(row)
}