Skip to content

Commit 81106a4

Browse files
committed
support zango db
1 parent 657fea8 commit 81106a4

10 files changed

Lines changed: 431 additions & 10 deletions

File tree

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"src/*"
4343
],
4444
"scripts": {
45-
"test": "npx lab",
45+
"test": "npx lab test/zango-party-test.js",
4646
"build": "parcel build --no-scope-hoist",
4747
"prepare": "npm run build",
4848
"watch": "parcel watch",
@@ -95,14 +95,16 @@
9595
"uuid": "^3.2.1",
9696
"uuidv4": "^6.2.12",
9797
"vm2": "^3.9.2",
98-
"websocket": "github:sevenbitbyte/WebSocket-Node#parcel-build"
98+
"websocket": "github:sevenbitbyte/WebSocket-Node#parcel-build",
99+
"zangodb": "github:sevenbitbyte/zangodb#hash-patch"
99100
},
100101
"devDependencies": {
101102
"@dataparty/bouncer-model": "1.4.3",
102103
"@hapi/code": "^9.0.1",
103104
"@hapi/lab": "^25.0.1",
104105
"better-docs": "^1.1.6",
105106
"docdash": "^1.1.1",
107+
"fake-indexeddb": "^4.0.0",
106108
"jsdoc": "^3.6.2",
107109
"minami": "^1.2.3",
108110
"mongodb-client-encryption": "^2.2.1",

src/bouncer/crufler-admin.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ module.exports = class AdminCrufler extends ICrufler {
9595

9696
let resultSet = await this.db.find(crufl.type, mongoQuery)
9797

98-
debug('set',resultSet)
98+
debug('resultSet',resultSet)
9999

100100
let msgs = []
101101

@@ -118,7 +118,7 @@ module.exports = class AdminCrufler extends ICrufler {
118118
}
119119
}
120120

121-
debug(msgs)
121+
debug('applyFind found msgs', msgs)
122122
return msgs
123123
}
124124

src/bouncer/db/loki-db.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const ObjectId = require('bson-objectid')
99

1010
const MongoQuery = require('../mongo-query')
1111
const { promisfy } = require('promisfy')
12-
const debug = require('debug')('dataparty.local.loki-db')
12+
const debug = require('debug')('bouncer.db.loki-db')
1313

1414

1515
module.exports = class LokiDb extends IDb {

src/bouncer/db/zango-db.js

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
'use strict'
2+
3+
const IDb = require('../idb')
4+
const Hoek = require('@hapi/hoek')
5+
const zango = require('zangodb')
6+
const reach = require('../../utils/reach')
7+
const ObjectId = require('bson-objectid')
8+
9+
const MongoQuery = require('../mongo-query')
10+
const { promisfy } = require('promisfy')
11+
const debug = require('debug')('bouncer.db.zango-db')
12+
13+
14+
/*
15+
if (!process.browser) {
16+
global.indexedDB = require('fake-indexeddb');
17+
global.IDBKeyRange = require('fake-indexeddb/lib/FDBKeyRange');
18+
}
19+
*/
20+
21+
module.exports = class ZangoDb extends IDb {
22+
23+
constructor ({dbname, factory}) {
24+
super(factory)
25+
debug('constructor')
26+
this.zango = null
27+
this.dbname = dbname
28+
this.error = null
29+
}
30+
31+
32+
async start(){
33+
34+
debug('starting')
35+
36+
37+
let collectionSettings = {}
38+
39+
for(const name of this.factory.getValidators()){
40+
debug('creating collection', name)
41+
42+
const indexSettings = reach(this.factory, 'model.IndexSettings.'+name)
43+
44+
const indices = ['$meta.id'].concat(indexSettings.unique).concat(indexSettings.indices)
45+
46+
collectionSettings[this.prefix+name] = indices.length > 0 ? indices : true
47+
}
48+
49+
debug('dbname',this.dbname, collectionSettings)
50+
51+
this.zango = new zango.Db(this.dbname, collectionSettings)
52+
53+
}
54+
55+
async getCollectionNames(){
56+
57+
const names = this.factory.getValidators()
58+
59+
return names.map(name=>{return name.replace(this.prefix,'')})
60+
}
61+
62+
63+
async getCollection(name){
64+
let collection = this.zango.collection(this.prefix+name)
65+
66+
return collection
67+
}
68+
69+
/** convert db documnet to plain object with $meta field */
70+
documentToObject(doc){
71+
let obj = Object.assign({},doc)
72+
obj.$meta = {
73+
id: Hoek.reach(obj,'meta.id', {default: obj._id}),
74+
type: Hoek.reach(doc,'meta.type'),
75+
created: Hoek.reach(obj,'meta.created', {default: (new Date()).toISOString()}),
76+
revision: Hoek.reach(obj,'meta.revision', {default: 1}),
77+
removed: Hoek.reach(obj,'meta.removed')
78+
}
79+
80+
delete obj.meta
81+
delete obj._id
82+
83+
return obj
84+
}
85+
86+
87+
/** convert object with $meta field to db representation*/
88+
documentFromObject(obj){
89+
let doc = Object.assign({},obj)
90+
doc._id = Hoek.reach(obj,'$meta.id', {default: obj._id}),
91+
doc.meta = {
92+
id: Hoek.reach(obj,'$meta.id', {default: obj._id}),
93+
type: Hoek.reach(obj,'$meta.type'),
94+
created: Hoek.reach(obj,'$meta.created', {default: (new Date()).toISOString()}),
95+
revision: Hoek.reach(obj,'$meta.revision', {default: 1}),
96+
removed: Hoek.reach(obj,'$meta.removed')
97+
}
98+
99+
100+
delete doc.$meta
101+
102+
return doc
103+
}
104+
105+
ensureId(obj){
106+
let temp = {...obj}
107+
if(!reach(temp,'$meta.id')){
108+
temp.$meta.id = (new ObjectId()).toHexString()
109+
}
110+
111+
let dbDoc = this.documentFromObject(temp)
112+
113+
return dbDoc
114+
}
115+
116+
async find(collectionName, mongoQuery){
117+
118+
let query = mongoQuery.getQueryDoc()
119+
120+
debug('find collection=', collectionName, ' query=', JSON.stringify(query,null,2))
121+
let collection = await this.getCollection(collectionName)
122+
let resultSet = collection.find(query)
123+
124+
125+
if(mongoQuery.hasLimit()){
126+
resultSet = resultSet.limit(mongoQuery.getLimit())
127+
}
128+
129+
if(mongoQuery.hasSort()){
130+
resultSet = resultSet.sort( mongoQuery.getSort() )
131+
}
132+
133+
return (await resultSet.toArray()).map(this.documentToObject) || []
134+
}
135+
136+
async insertMany(collectionName, docs){
137+
debug('insert collection=', collectionName, ' docs=', JSON.stringify(docs,null,2))
138+
let collection = await this.getCollection(collectionName)
139+
140+
let resultSet = []
141+
142+
for(let obj of docs){
143+
let temp = {...obj}
144+
if(temp._id===undefined){ temp._id = (new ObjectId()).toString(); temp.$meta.id=temp._id; }
145+
146+
let dbDoc = this.documentFromObject(temp)
147+
148+
const stripped = this.stripMeta(temp)
149+
150+
debug('validating', stripped,'from', temp)
151+
152+
await this.factory.validate(collectionName, stripped)
153+
154+
debug('its good, inserting', dbDoc)
155+
156+
await collection.insert( dbDoc )
157+
158+
debug('inserted', dbDoc)
159+
160+
const finalObj = this.documentToObject(dbDoc)
161+
162+
debug('returning', finalObj)
163+
164+
this.emitChange(finalObj, 'create')
165+
166+
resultSet.push(finalObj)
167+
}
168+
169+
170+
return resultSet
171+
172+
}
173+
174+
async update(collectionName, docs){
175+
debug('update collection', collectionName, ' docs', docs)
176+
177+
let collection = await this.getCollection(collectionName)
178+
179+
let objs = []
180+
181+
for(let obj of docs){
182+
let dbDoc = this.documentFromObject(obj)
183+
184+
debug('updating',obj, 'to', dbDoc)
185+
186+
const stripped = this.stripMeta(dbDoc)
187+
const meta = this.onlyMeta(obj)
188+
189+
debug('validating', stripped,'from', dbDoc)
190+
191+
await this.factory.validate(collectionName, stripped)
192+
193+
debug('its good, updating', dbDoc)
194+
195+
let old = await collection.findOne( {'_id': dbDoc._id})
196+
197+
debug('found old', old)
198+
dbDoc.meta.revision = old.meta.revision++
199+
200+
201+
let mergedDoc = {...old, ...dbDoc}
202+
203+
await collection.update({'_id': dbDoc._id}, mergedDoc)
204+
205+
const finalObj = this.documentToObject(mergedDoc)
206+
207+
this.emitChange(finalObj, 'update')
208+
209+
objs.push( finalObj )
210+
211+
}
212+
213+
return objs
214+
}
215+
216+
async findAndRemove(collectionName, obj){
217+
debug('findAndRemove collection', collectionName, ' obj', obj)
218+
219+
let collection = await this.getCollection(collectionName)
220+
221+
const dbDoc = await collection.findOne( {'_id': obj.$meta.id})
222+
223+
debug('found old doc', dbDoc)
224+
225+
await collection.remove( { '_id': obj.$meta.id } )
226+
227+
debug('dbDoc', dbDoc)
228+
229+
let finalObj = this.documentToObject(dbDoc)
230+
231+
finalObj.$meta.removed = true
232+
233+
this.emitChange(finalObj, 'remove')
234+
235+
debug('obj', finalObj)
236+
237+
return finalObj
238+
}
239+
}

src/bouncer/idb.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ module.exports = class IDb extends EventEmitter {
4646
ensureId(obj){ throw new Error('not implemented') }
4747

4848
stripMeta(doc){
49-
const {meta, $meta, ...rawMsg} = doc
49+
const {_id, meta, $meta, ...rawMsg} = doc
5050
return rawMsg
5151
}
5252

src/bouncer/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ module.exports = {
66
MongoQuery: require('./mongo-query'),
77

88
LokiDb: require('./db/loki-db'),
9-
TingoDb: require('./db/tingo-db')
9+
TingoDb: require('./db/tingo-db'),
10+
ZangoDb: require('./db/zango-db')
1011
}

src/party/index-browser.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const IParty = require('./iparty')
22
const PeerParty = require('./peer/peer-party')
33
const CloudParty = require('./cloud/cloud-party')
44
const LokiParty = require('./local/loki-party')
5+
const ZangoParty = require('./local/zango-party')
56

67
const IDocument = require('./idocument')
78
const DocumentFactory = require('./document-factory')
@@ -12,6 +13,6 @@ const LokiDb = require('../bouncer/db/loki-db')
1213
module.exports = {
1314
IDocument, IParty, DocumentFactory,
1415
CloudDocument,
15-
CloudParty, LokiParty, PeerParty,
16+
CloudParty, LokiParty, ZangoParty, PeerParty,
1617
LokiDb
17-
}
18+
}

src/party/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ const PeerParty = require('./peer/peer-party')
33
const CloudParty = require('./cloud/cloud-party')
44
const LokiParty = require('./local/loki-party')
55
const TingoParty = require('./local/tingo-party')
6+
const ZangoParty = require('./local/zango-party')
67
const MongoParty = require('./mongo/mongo-party')
78

9+
810
const IDocument = require('./idocument')
911
const DocumentFactory = require('./document-factory')
1012
const CloudDocument = require('./cloud/cloud-document')
@@ -13,5 +15,5 @@ module.exports = {
1315
IDocument, IParty, DocumentFactory,
1416
CloudDocument,
1517
CloudParty, LokiParty, PeerParty, MongoParty,
16-
TingoParty
18+
TingoParty, ZangoParty
1719
}

src/party/local/zango-party.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
2+
'use strict'
3+
4+
const debug = require('debug')('dataparty.zango-party')
5+
6+
const IParty = require('../iparty')
7+
const ZangoDb = require('../../bouncer/db/zango-db')
8+
const AdminCrufler = require('../../bouncer/crufler-admin')
9+
10+
const Qb = require('../qb')
11+
12+
13+
/**
14+
* @class
15+
* @alias module:dataparty.ZangoParty
16+
* @interface
17+
*/
18+
class ZangoParty extends IParty {
19+
20+
constructor ({dbname, qbOptions, ...options}) {
21+
super(options)
22+
23+
this.db = new ZangoDb({
24+
dbname, factory: this.factory,
25+
})
26+
27+
this.crufler = new AdminCrufler({
28+
db: this.db
29+
})
30+
31+
32+
this.qb = new Qb({
33+
call: this.handleCall.bind(this),
34+
cache: this.cache,
35+
...qbOptions
36+
})
37+
}
38+
39+
async start(){
40+
await super.start()
41+
await this.db.start()
42+
}
43+
44+
45+
async handleCall(ask){
46+
return await this.crufler.handleCall(ask)
47+
}
48+
}
49+
50+
module.exports = ZangoParty

0 commit comments

Comments
 (0)