1 | const { join } = require('path')
|
2 | const fs = require('graceful-fs').promises
|
3 | const nodeReq = require('node-req')
|
4 | const nodeRes = require('node-res')
|
5 |
|
6 | module.exports = ({ ws, database, dir, watch }) => async (req, res) => {
|
7 | const url = decodeURI(nodeReq.url(req))
|
8 |
|
9 |
|
10 |
|
11 | if (ws && url === '/ws') {
|
12 | return ws.serve(req, req.socket, undefined)
|
13 | }
|
14 |
|
15 | let params = {}
|
16 |
|
17 |
|
18 |
|
19 | if (['POST', 'PUT'].includes(req.method)) {
|
20 |
|
21 |
|
22 | if (req.readableEnded) {
|
23 | params = req.body
|
24 | } else {
|
25 | let body = ''
|
26 | req.on('data', function (data) {
|
27 | body += data
|
28 | })
|
29 |
|
30 | await new Promise(function (resolve, reject) {
|
31 | req.on('end', resolve)
|
32 | req.on('error', reject)
|
33 | })
|
34 |
|
35 | if (body) {
|
36 | params = JSON.parse(body)
|
37 | }
|
38 | }
|
39 | } else if (req.method === 'GET') {
|
40 | params = nodeReq.get(req)
|
41 | }
|
42 |
|
43 | if (watch) {
|
44 | const filePath = join(dir, url)
|
45 | const stats = await fs.lstat(filePath).catch(_ => null)
|
46 | if (req.method === 'PUT' && stats && stats.isFile()) {
|
47 | await fs.writeFile(filePath, params.file, 'utf-8')
|
48 |
|
49 | return nodeRes.send(req, res, {})
|
50 | }
|
51 |
|
52 | if (req.method === 'GET' && stats && stats.isFile()) {
|
53 | const file = await fs.readFile(filePath, 'utf-8')
|
54 |
|
55 | return nodeRes.send(req, res, file)
|
56 | }
|
57 | }
|
58 |
|
59 | const { sortBy, skip, limit, only, without, where, search, surround, deep, text, ...other } = params
|
60 | params.where = Object.assign({}, params.where, other)
|
61 |
|
62 |
|
63 | let query = database.query(url, { deep: params.deep, text: params.text })
|
64 | if (params.sortBy) {
|
65 | if (typeof params.sortBy === 'object') {
|
66 | if (Array.isArray(params.sortBy)) {
|
67 | for (const sort of params.sortBy) {
|
68 | if (typeof sort === 'string') {
|
69 | const [key, value] = sort.split(':')
|
70 | query = query.sortBy(key, value)
|
71 | } else {
|
72 | for (const [key, value] of Object.entries(sort)) {
|
73 | query = query.sortBy(key, value)
|
74 | }
|
75 | }
|
76 | }
|
77 | } else {
|
78 | for (const [key, value] of Object.entries(params.sortBy)) {
|
79 | query = query.sortBy(key, value)
|
80 | }
|
81 | }
|
82 | } else {
|
83 | const [key, value] = params.sortBy.split(':')
|
84 | query = query.sortBy(key, value)
|
85 | }
|
86 | }
|
87 | if (params.skip) {
|
88 | query = query.skip(params.skip)
|
89 | }
|
90 | if (params.limit) {
|
91 | query = query.limit(params.limit)
|
92 | }
|
93 | if (params.only) {
|
94 | query = query.only(params.only)
|
95 | }
|
96 | if (params.without) {
|
97 | query = query.without(params.without)
|
98 | }
|
99 | if (params.where) {
|
100 | const where = {}
|
101 |
|
102 | for (const [key, value] of Object.entries(params.where)) {
|
103 | const [field, operator] = key.split('_')
|
104 |
|
105 | if (operator) {
|
106 | where[field] = {
|
107 | [`$${operator}`]: value
|
108 | }
|
109 | } else {
|
110 | where[field] = value
|
111 | }
|
112 | }
|
113 | query = query.where(where)
|
114 | }
|
115 | if (params.search) {
|
116 | if (typeof params.search === 'object') {
|
117 | query = query.search(params.search.query, params.search.value)
|
118 | } else {
|
119 | query = query.search(params.search)
|
120 | }
|
121 | }
|
122 | if (params.surround) {
|
123 | query = query.surround(params.surround.slugOrPath, params.surround.options)
|
124 | }
|
125 |
|
126 | let result
|
127 | try {
|
128 |
|
129 | result = await query.fetch()
|
130 | nodeRes.etag(res, JSON.stringify(result))
|
131 | if (nodeReq.fresh(req, res)) {
|
132 | nodeRes.status(res, 304)
|
133 | nodeRes.end(res)
|
134 | return
|
135 | }
|
136 | } catch (e) {
|
137 | nodeRes.status(res, 404)
|
138 | result = { message: e.message }
|
139 | }
|
140 | nodeRes.send(req, res, result, false)
|
141 | }
|