Skip to content

Commit b1a0006

Browse files
committed
Initial commit
1 parent 5403ced commit b1a0006

7 files changed

+8033
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/.idea/
2+
/node_modules/

package-lock.json

+7,892
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"name": "hmmjs",
3+
"version": "1.0.0",
4+
"description": "client side mongoose like database query interface",
5+
"main": "index.js",
6+
"scripts": {
7+
"test": "echo \"Error: no test specified\" && exit 1"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/ThinhVu/hmmjs.git"
12+
},
13+
"keywords": [],
14+
"author": "",
15+
"license": "ISC",
16+
"bugs": {
17+
"url": "https://github.com/ThinhVu/hmmjs/issues"
18+
},
19+
"homepage": "https://github.com/ThinhVu/hmmjs#readme",
20+
"dependencies": {
21+
"jest": "^29.3.1",
22+
"mongodb": "^4.11.0",
23+
"mongoose": "^6.7.2"
24+
}
25+
}

src/builder.js

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
const chain = hmm => new Proxy({}, {
2+
get(target, p) {
3+
switch (p) {
4+
case '$':
5+
return hmm.send(hmm.payload);
6+
case 'toString':
7+
return () => JSON.stringify(hmm.payload)
8+
default:
9+
return function (...args) {
10+
hmm.payload.fns.push({n: p, args})
11+
return chain(hmm)
12+
}
13+
}
14+
}
15+
})
16+
17+
module.exports = send => new Proxy({}, {
18+
get(target, p) {
19+
return chain({send, payload: {model: p, fns: []}})
20+
}
21+
})

src/builder.test.js

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const hmmFactory = require('./builder')
2+
3+
describe('hmm-builder', function () {
4+
it('should build correct post payload', () => {
5+
const hmm = hmmFactory(() => {})
6+
const hmm2Str = hmm.user.find({_id: 1}, {username: 1, password: 1}).sort({createdDate: -1}).limit(10).toString()
7+
const output = {
8+
model: 'user',
9+
fns: [
10+
{ n: 'find', args: [{_id: 1}, {username: 1, password: 1}]},
11+
{ n: 'sort', args: [{createdDate: -1}]},
12+
{ n: 'limit', args: [10] }
13+
]
14+
}
15+
expect(hmm2Str).toEqual(JSON.stringify(output))
16+
})
17+
18+
it('should post a payload', async () => {
19+
const post = payload => fetch({ method: 'POST', url: 'http://localhost:3000/api/', body: payload })
20+
const mockPost = jest.fn(payload => "RESPONSE:" + JSON.stringify(payload))
21+
const hmm = hmmFactory(mockPost)
22+
const qry = hmm.user.find({_id: 1}, { username: 1, password: 1 }).sort({createdDate: -1}).limit(10)
23+
const hmm2Str = qry.toString()
24+
const rs = await qry.$
25+
expect(mockPost.mock.calls.length).toBe(1)
26+
expect(JSON.stringify(mockPost.mock.calls[0][0])).toBe(hmm2Str)
27+
expect(rs).toEqual("RESPONSE:" + hmm2Str)
28+
})
29+
})

src/executor.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
module.exports = (dbi, convertArgs) => {
2+
return async payload => {
3+
const {model, fns} = payload
4+
let imme = dbi[model]
5+
for (const fn of fns)
6+
imme = imme[fn.n](...(convertArgs ? convertArgs(fn.args): fn.args))
7+
return imme
8+
}
9+
}

src/executor.test.js

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
const executorFac = require('./executor')
2+
const {ObjectID} = require('mongodb')
3+
const {default: db, model, Schema} = require('mongoose')
4+
const UserModel = model('User', new Schema({u: String, p: String, age: Number}))
5+
6+
let hmmExec;
7+
8+
describe('executor', () => {
9+
beforeAll(async () => {
10+
await db.connect('mongodb://localhost:27017/hmm')
11+
const dbi = { user: UserModel }
12+
const convertArgs = args => args.map(arg => typeof (arg) !== 'object'
13+
? arg
14+
: Object.keys(arg).reduce((prev, k) => {
15+
prev[k] = k === '_id'
16+
? new ObjectID(arg[k])
17+
: arg[k];
18+
return prev
19+
}, {}))
20+
hmmExec = executorFac(dbi, convertArgs)
21+
// init user
22+
await UserModel.deleteMany()
23+
for (let i = 0; i < 100; ++i)
24+
await UserModel.create({ u: `u${i}`, p: `p${i}`, age: i })
25+
})
26+
27+
it('should execute 1', async () => {
28+
const payload = {
29+
model: 'user',
30+
fns: [
31+
{ n: 'find', args: [{u: 'u10'}, {u: 1, p: 1}]},
32+
{ n: 'limit', args: [1] }
33+
]
34+
}
35+
const rs = await hmmExec(payload)
36+
expect(rs.length).toEqual(1)
37+
expect(rs[0].p).toEqual('p10')
38+
expect(rs[0].age).toEqual(undefined)
39+
})
40+
41+
it('should execute 2', async () => {
42+
const payload = {
43+
model: 'user',
44+
fns: [
45+
{ n: 'find', args: [{age: {$gt: 10}}, {u: 1, p: 1}]},
46+
{ n: 'sort', args: [{age: 1}] },
47+
{ n: 'limit', args: [10] }
48+
]
49+
}
50+
const rs = await hmmExec(payload)
51+
expect(rs.length).toEqual(10)
52+
expect(rs[0].p).toEqual('p11')
53+
expect(rs[rs.length - 1].p).toEqual('p20')
54+
})
55+
})

0 commit comments

Comments
 (0)