hide-a-bed 1.2.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +145 -50
- package/build/build.mjs +16 -0
- package/build/build.rewrite-imports.mjs +14 -0
- package/cjs/impl/bulk.cjs +77 -0
- package/cjs/impl/crud.cjs +64 -0
- package/cjs/impl/patch.cjs +52 -0
- package/cjs/impl/query.cjs +72 -0
- package/cjs/impl/stream.cjs +49 -0
- package/cjs/index.cjs +54 -0
- package/cjs/schema/bulk.cjs +50 -0
- package/cjs/schema/config.cjs +27 -0
- package/cjs/schema/crud.cjs +47 -0
- package/cjs/schema/patch.cjs +38 -0
- package/cjs/schema/query.cjs +51 -0
- package/impl/bulk.mjs +19 -10
- package/impl/crud.mjs +2 -4
- package/impl/patch.mjs +36 -0
- package/impl/query.mjs +4 -0
- package/impl/stream.mjs +10 -1
- package/index.mjs +6 -3
- package/package.json +28 -3
- package/schema/bulk.mjs +11 -3
- package/schema/crud.mjs +2 -1
- package/schema/patch.mjs +18 -0
- package/schema/query.mjs +0 -1
- package/tsconfig.json +13 -0
package/README.md
CHANGED
|
@@ -1,73 +1,168 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
A simple way to abstract couchdb, and make your interface to the database testable.
|
|
1
|
+
API
|
|
2
|
+
-------------
|
|
5
3
|
|
|
6
|
-
|
|
7
|
-
-----
|
|
4
|
+
### Document Operations
|
|
8
5
|
|
|
9
|
-
|
|
6
|
+
#### get(config, id)
|
|
7
|
+
Get a single document by ID.
|
|
8
|
+
- `config`: Object with `couch` URL string
|
|
9
|
+
- `id`: Document ID string
|
|
10
|
+
- Returns: Promise resolving to document object or null if not found
|
|
10
11
|
|
|
12
|
+
```javascript
|
|
13
|
+
const config = { couch: 'http://localhost:5984/mydb' }
|
|
14
|
+
const doc = await get(config, 'doc-123')
|
|
15
|
+
if (doc) {
|
|
16
|
+
console.log(doc._id, doc._rev)
|
|
17
|
+
}
|
|
11
18
|
```
|
|
12
|
-
npm i hide-a-bed --save
|
|
13
|
-
npm i hide-a-bed-stub --save-dev
|
|
14
19
|
|
|
15
|
-
|
|
20
|
+
#### put(config, doc)
|
|
21
|
+
Save a document.
|
|
22
|
+
- `config`: Object with `couch` URL string
|
|
23
|
+
- `doc`: Document object with `_id` property
|
|
24
|
+
- Returns: Promise resolving to response with `ok`, `id`, `rev` properties
|
|
16
25
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
startkey: apiResult.startTime,
|
|
24
|
-
endkey: apiResult.endTime
|
|
25
|
-
}
|
|
26
|
-
const queryResults = await db.query(config, '_design/userThings/_view/byTime', query)
|
|
27
|
-
return queryResults.rows
|
|
26
|
+
```javascript
|
|
27
|
+
const config = { couch: 'http://localhost:5984/mydb' }
|
|
28
|
+
const doc = {
|
|
29
|
+
_id: 'doc-123',
|
|
30
|
+
type: 'user',
|
|
31
|
+
name: 'Alice'
|
|
28
32
|
}
|
|
29
|
-
|
|
33
|
+
const result = await put(config, doc)
|
|
34
|
+
// result: { ok: true, id: 'doc-123', rev: '1-abc123' }
|
|
30
35
|
```
|
|
31
36
|
|
|
32
|
-
|
|
37
|
+
#### patch(config, id, properties)
|
|
38
|
+
Update specific properties of a document with retry mechanism.
|
|
39
|
+
- `config`: Object with:
|
|
40
|
+
- `couch`: URL string
|
|
41
|
+
- `retries`: Optional number of retry attempts (default: 5)
|
|
42
|
+
- `delay`: Optional milliseconds between retries (default: 1000)
|
|
43
|
+
- `id`: Document ID string
|
|
44
|
+
- `properties`: Object with properties to update
|
|
45
|
+
- Returns: Promise resolving to response with `ok`, `id`, `rev` properties
|
|
46
|
+
|
|
47
|
+
```javascript
|
|
48
|
+
const config = {
|
|
49
|
+
couch: 'http://localhost:5984/mydb',
|
|
50
|
+
retries: 3,
|
|
51
|
+
delay: 500
|
|
52
|
+
}
|
|
53
|
+
const properties = {
|
|
54
|
+
name: 'Alice Smith',
|
|
55
|
+
updated: true
|
|
56
|
+
}
|
|
57
|
+
const result = await patch(config, 'doc-123', properties)
|
|
58
|
+
// result: { ok: true, id: 'doc-123', rev: '2-xyz789' }
|
|
33
59
|
```
|
|
34
|
-
import db from 'hide-a-bed'
|
|
35
|
-
import { doStuff } from './doStuff'
|
|
36
|
-
import { callSomeApi } from './api'
|
|
37
|
-
// the config object needs a couch url
|
|
38
|
-
const config = { couch: 'http://localhost:5984/mydb' }
|
|
39
|
-
// build up a service api for all your external calls that can be mocked/stubbed
|
|
40
|
-
const services = { db, callSomeApi }
|
|
41
|
-
const afterStuff = await doStuff(config, services, 'happy-doc-id')
|
|
42
60
|
|
|
43
|
-
|
|
61
|
+
#### remove(config, id)
|
|
62
|
+
Delete a document by ID.
|
|
63
|
+
- `config`: Object with `couch` URL string
|
|
64
|
+
- `id`: Document ID string to delete
|
|
65
|
+
- Returns: Promise resolving to response with `ok` and `rev` properties
|
|
44
66
|
|
|
45
|
-
|
|
67
|
+
```javascript
|
|
68
|
+
const config = { couch: 'http://localhost:5984/mydb' }
|
|
69
|
+
const result = await remove(config, 'doc-123')
|
|
70
|
+
// result: { ok: true, id: 'doc-123', rev: '2-def456' }
|
|
46
71
|
```
|
|
47
|
-
import { setup } from 'hide-a-bed-stub' // different package, since installed with --save-dev reduces space
|
|
48
|
-
import { doStuff } from './doStuff'
|
|
49
|
-
import { callSomeApiMock } from './test/mock/api'
|
|
50
|
-
// the config object needs a couch url, prove to yourself that its mocked with a fakeurl
|
|
51
|
-
const config = { couch: 'http://fakeurl:5984/mydb' }
|
|
52
72
|
|
|
53
|
-
|
|
54
|
-
|
|
73
|
+
### Bulk Operations
|
|
74
|
+
|
|
75
|
+
#### bulkSave(config, docs)
|
|
76
|
+
Save multiple documents in one request.
|
|
77
|
+
- `config`: Object with `couch` URL string
|
|
78
|
+
- `docs`: Array of document objects, each with `_id`
|
|
79
|
+
- Returns: Promise resolving to array of results with `ok`, `id`, `rev` for each doc
|
|
55
80
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
81
|
+
```javascript
|
|
82
|
+
const config = { couch: 'http://localhost:5984/mydb' }
|
|
83
|
+
const docs = [
|
|
84
|
+
{ _id: 'doc1', type: 'user', name: 'Alice' },
|
|
85
|
+
{ _id: 'doc2', type: 'user', name: 'Bob' }
|
|
86
|
+
]
|
|
87
|
+
const results = await bulkSave(config, docs)
|
|
88
|
+
// results: [
|
|
89
|
+
// { ok: true, id: 'doc1', rev: '1-abc123' },
|
|
90
|
+
// { ok: true, id: 'doc2', rev: '1-def456' }
|
|
91
|
+
// ]
|
|
92
|
+
```
|
|
59
93
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
94
|
+
#### bulkGet(config, ids)
|
|
95
|
+
Get multiple documents by ID.
|
|
96
|
+
- `config`: Object with `couch` URL string
|
|
97
|
+
- `ids`: Array of document ID strings
|
|
98
|
+
- Returns: Promise resolving to array of documents
|
|
64
99
|
|
|
100
|
+
```javascript
|
|
101
|
+
const config = { couch: 'http://localhost:5984/mydb' }
|
|
102
|
+
const ids = ['doc1', 'doc2']
|
|
103
|
+
const docs = await bulkGet(config, ids)
|
|
104
|
+
// docs: [
|
|
105
|
+
// { _id: 'doc1', _rev: '1-abc123', type: 'user', name: 'Alice' },
|
|
106
|
+
// { _id: 'doc2', _rev: '1-def456', type: 'user', name: 'Bob' }
|
|
107
|
+
// ]
|
|
65
108
|
```
|
|
66
109
|
|
|
67
|
-
|
|
68
|
-
|
|
110
|
+
#### bulkRemove(config, ids)
|
|
111
|
+
Delete multiple documents in one request.
|
|
112
|
+
- `config`: Object with `couch` URL string
|
|
113
|
+
- `ids`: Array of document ID strings to delete
|
|
114
|
+
- Returns: Promise resolving to array of results with `ok`, `id`, `rev` for each deletion
|
|
69
115
|
|
|
70
|
-
|
|
116
|
+
```javascript
|
|
117
|
+
const config = { couch: 'http://localhost:5984/mydb' }
|
|
118
|
+
const ids = ['doc1', 'doc2']
|
|
119
|
+
const results = await bulkRemove(config, ids)
|
|
120
|
+
// results: [
|
|
121
|
+
// { ok: true, id: 'doc1', rev: '2-ghi789' },
|
|
122
|
+
// { ok: true, id: 'doc2', rev: '2-jkl012' }
|
|
123
|
+
// ]
|
|
124
|
+
```
|
|
71
125
|
|
|
126
|
+
### View Queries
|
|
127
|
+
|
|
128
|
+
#### query(config, view, options)
|
|
129
|
+
Query a view with options.
|
|
130
|
+
- `config`: Object with `couch` URL string
|
|
131
|
+
- `view`: View path string (e.g. '_design/doc/_view/name')
|
|
132
|
+
- `options`: Optional object with query parameters:
|
|
133
|
+
- `startkey`: Start key for range
|
|
134
|
+
- `endkey`: End key for range
|
|
135
|
+
- `key`: Exact key match
|
|
136
|
+
- `descending`: Boolean to reverse sort
|
|
137
|
+
- `skip`: Number of results to skip
|
|
138
|
+
- `limit`: Max number of results
|
|
139
|
+
- `include_docs`: Boolean to include full docs
|
|
140
|
+
- `reduce`: Boolean to reduce results
|
|
141
|
+
- `group`: Boolean to group results
|
|
142
|
+
- `group_level`: Number for group level
|
|
143
|
+
- Returns: Promise resolving to response with `rows` array
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
const config = { couch: 'http://localhost:5984/mydb' }
|
|
147
|
+
const view = '_design/users/_view/by_name'
|
|
148
|
+
const options = {
|
|
149
|
+
startkey: 'A',
|
|
150
|
+
endkey: 'B',
|
|
151
|
+
include_docs: true,
|
|
152
|
+
limit: 10
|
|
153
|
+
}
|
|
154
|
+
const result = await query(config, view, options)
|
|
155
|
+
// result: {
|
|
156
|
+
// rows: [
|
|
157
|
+
// {
|
|
158
|
+
// id: 'doc1',
|
|
159
|
+
// key: 'Alice',
|
|
160
|
+
// value: 1,
|
|
161
|
+
// doc: { _id: 'doc1', name: 'Alice', type: 'user' }
|
|
162
|
+
// },
|
|
163
|
+
// // ... more rows
|
|
164
|
+
// ]
|
|
165
|
+
// }
|
|
166
|
+
```
|
|
72
167
|
|
|
73
168
|
|
package/build/build.mjs
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import esbuild from 'esbuild'
|
|
2
|
+
import { globSync } from 'glob'
|
|
3
|
+
import { RewriteImportsPlugin } from './build.rewrite-imports.mjs'
|
|
4
|
+
|
|
5
|
+
esbuild
|
|
6
|
+
.build({
|
|
7
|
+
entryPoints: globSync('./**/*.mjs', {
|
|
8
|
+
ignore: ['./node_modules/**/*', './tests/**/*', './build/**/*']
|
|
9
|
+
}),
|
|
10
|
+
outdir: 'cjs',
|
|
11
|
+
format: 'cjs',
|
|
12
|
+
outExtension: { '.js': '.cjs' },
|
|
13
|
+
bundle: false,
|
|
14
|
+
plugins: [new RewriteImportsPlugin()]
|
|
15
|
+
})
|
|
16
|
+
.catch(() => process.exit(1))
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
|
|
3
|
+
export class RewriteImportsPlugin {
|
|
4
|
+
name = 'rewrite-imports'
|
|
5
|
+
|
|
6
|
+
setup (build) {
|
|
7
|
+
build.onLoad({ filter: /\.mjs$/ }, async (args) => {
|
|
8
|
+
const contents = fs
|
|
9
|
+
.readFileSync(args.path, 'utf8')
|
|
10
|
+
.replace(/(from\s+['"].*?)\.mjs(['"])/g, '$1.cjs$2')
|
|
11
|
+
return { contents, loader: 'js' }
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var bulk_exports = {};
|
|
30
|
+
__export(bulk_exports, {
|
|
31
|
+
bulkGet: () => bulkGet,
|
|
32
|
+
bulkRemove: () => bulkRemove,
|
|
33
|
+
bulkSave: () => bulkSave
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(bulk_exports);
|
|
36
|
+
var import_needle = __toESM(require("needle"), 1);
|
|
37
|
+
var import_bulk = require("../schema/bulk.cjs");
|
|
38
|
+
const opts = {
|
|
39
|
+
json: true,
|
|
40
|
+
headers: {
|
|
41
|
+
"Content-Type": "application/json"
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
const bulkSave = import_bulk.BulkSave.implement(async (config, docs) => {
|
|
45
|
+
if (!docs) return { ok: false, error: "noDocs", reason: "no docs provided" };
|
|
46
|
+
if (!docs.length) return { ok: false, error: "noDocs", reason: "no docs provided" };
|
|
47
|
+
const url = `${config.couch}/_bulk_docs`;
|
|
48
|
+
const body = { docs };
|
|
49
|
+
const resp = await (0, import_needle.default)("post", url, body, opts);
|
|
50
|
+
if (resp.statusCode !== 201) throw new Error("could not save");
|
|
51
|
+
const results = resp?.body || [];
|
|
52
|
+
return results;
|
|
53
|
+
});
|
|
54
|
+
const bulkGet = import_bulk.BulkGet.implement(async (config, ids) => {
|
|
55
|
+
const keys = ids;
|
|
56
|
+
const url = `${config.couch}/_all_docs?include_docs=true`;
|
|
57
|
+
const body = { keys };
|
|
58
|
+
const resp = await (0, import_needle.default)("post", url, body, opts);
|
|
59
|
+
if (resp.statusCode !== 200) throw new Error("could not fetch");
|
|
60
|
+
const rows = resp?.body?.rows || [];
|
|
61
|
+
const docs = [];
|
|
62
|
+
rows.forEach((r) => {
|
|
63
|
+
if (r.error) return;
|
|
64
|
+
if (!r.key) return;
|
|
65
|
+
if (!r.doc) return;
|
|
66
|
+
const doc = r.doc;
|
|
67
|
+
docs.push(doc);
|
|
68
|
+
});
|
|
69
|
+
return docs;
|
|
70
|
+
});
|
|
71
|
+
const bulkRemove = import_bulk.BulkRemove.implement(async (config, ids) => {
|
|
72
|
+
const docs = await bulkGet(config, ids);
|
|
73
|
+
docs.forEach((d) => {
|
|
74
|
+
d._deleted = true;
|
|
75
|
+
});
|
|
76
|
+
return bulkSave(config, docs);
|
|
77
|
+
});
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var crud_exports = {};
|
|
30
|
+
__export(crud_exports, {
|
|
31
|
+
get: () => get,
|
|
32
|
+
put: () => put
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(crud_exports);
|
|
35
|
+
var import_needle = __toESM(require("needle"), 1);
|
|
36
|
+
var import_crud = require("../schema/crud.cjs");
|
|
37
|
+
const opts = {
|
|
38
|
+
json: true,
|
|
39
|
+
headers: {
|
|
40
|
+
"Content-Type": "application/json"
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
const get = import_crud.CouchGet.implement(async (config, id) => {
|
|
44
|
+
const url = `${config.couch}/${id}`;
|
|
45
|
+
const resp = await (0, import_needle.default)("get", url, opts);
|
|
46
|
+
if (resp.statusCode === 404) return null;
|
|
47
|
+
const result = resp?.body || {};
|
|
48
|
+
if (resp.statusCode !== 200) {
|
|
49
|
+
throw new Error(result.reason || "failed");
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
});
|
|
53
|
+
const put = import_crud.CouchPut.implement(async (config, doc) => {
|
|
54
|
+
const url = `${config.couch}/${doc._id}`;
|
|
55
|
+
const body = doc;
|
|
56
|
+
const resp = await (0, import_needle.default)("put", url, body, opts);
|
|
57
|
+
const result = resp?.body || {};
|
|
58
|
+
result.statusCode = resp.statusCode;
|
|
59
|
+
if (resp.statusCode === 409) {
|
|
60
|
+
result.ok = false;
|
|
61
|
+
result.error = "conflict";
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var patch_exports = {};
|
|
20
|
+
__export(patch_exports, {
|
|
21
|
+
patch: () => patch
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(patch_exports);
|
|
24
|
+
var import_crud = require("./crud.cjs");
|
|
25
|
+
var import_patch = require("../schema/patch.cjs");
|
|
26
|
+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
27
|
+
const patch = import_patch.CouchPatch.implement(async (config, id, properties) => {
|
|
28
|
+
const maxRetries = config.retries || 5;
|
|
29
|
+
const delay = config.delay || 1e3;
|
|
30
|
+
let attempts = 0;
|
|
31
|
+
while (attempts <= maxRetries) {
|
|
32
|
+
try {
|
|
33
|
+
const doc = await (0, import_crud.get)(config, id);
|
|
34
|
+
const updatedDoc = { ...doc, ...properties };
|
|
35
|
+
const result = await (0, import_crud.put)(config, updatedDoc);
|
|
36
|
+
if (result.ok) {
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
attempts++;
|
|
40
|
+
if (attempts > maxRetries) {
|
|
41
|
+
throw new Error(`Failed to patch after ${maxRetries} attempts`);
|
|
42
|
+
}
|
|
43
|
+
await sleep(delay);
|
|
44
|
+
} catch (err) {
|
|
45
|
+
attempts++;
|
|
46
|
+
if (attempts > maxRetries) {
|
|
47
|
+
throw new Error(`Failed to patch after ${maxRetries} attempts: ${err.message}`);
|
|
48
|
+
}
|
|
49
|
+
await sleep(delay);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var query_exports = {};
|
|
30
|
+
__export(query_exports, {
|
|
31
|
+
query: () => query,
|
|
32
|
+
queryString: () => queryString
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(query_exports);
|
|
35
|
+
var import_zod = require("zod");
|
|
36
|
+
var import_needle = __toESM(require("needle"), 1);
|
|
37
|
+
var import_query = require("../schema/query.cjs");
|
|
38
|
+
var import_lodash = __toESM(require("lodash"), 1);
|
|
39
|
+
const { includes } = import_lodash.default;
|
|
40
|
+
const query = import_query.SimpleViewQuery.implement(async (config, view, options) => {
|
|
41
|
+
const qs = queryString(options, ["key", "startkey", "endkey", "reduce", "group", "group_level", "stale", "limit"]);
|
|
42
|
+
const opts = {
|
|
43
|
+
json: true,
|
|
44
|
+
headers: {
|
|
45
|
+
"Content-Type": "application/json"
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
const url = `${config.couch}/${view}?${qs.toString()}`;
|
|
49
|
+
const results = await (0, import_needle.default)("get", url, opts);
|
|
50
|
+
const body = results.body;
|
|
51
|
+
if (body.error) throw new Error(body.error);
|
|
52
|
+
return body;
|
|
53
|
+
});
|
|
54
|
+
function queryString(options, params) {
|
|
55
|
+
const parts = Object.keys(options).map((key) => {
|
|
56
|
+
let value = options[key];
|
|
57
|
+
if (includes(params, key)) {
|
|
58
|
+
if (typeof value === "string" && key !== "stale") value = `"${value}"`;
|
|
59
|
+
if (Array.isArray(value)) {
|
|
60
|
+
value = "[" + value.map((i) => {
|
|
61
|
+
if (i === null) return "null";
|
|
62
|
+
if (typeof i === "string") return `"${i}"`;
|
|
63
|
+
if (typeof i === "object" && Object.keys(i).length === 0) return "{}";
|
|
64
|
+
if (typeof i === "object") return JSON.stringify(i);
|
|
65
|
+
return i;
|
|
66
|
+
}).join(",") + "]";
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return `${key}=${value}`;
|
|
70
|
+
});
|
|
71
|
+
return parts.join("&");
|
|
72
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var stream_exports = {};
|
|
30
|
+
__export(stream_exports, {
|
|
31
|
+
queryStream: () => queryStream
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(stream_exports);
|
|
34
|
+
var import_needle = __toESM(require("needle"), 1);
|
|
35
|
+
var import_query = require("./query.cjs");
|
|
36
|
+
var import_JSONStream = __toESM(require("JSONStream"), 1);
|
|
37
|
+
const queryStream = (config, view, options) => new Promise((resolve, reject) => {
|
|
38
|
+
if (!options) options = {};
|
|
39
|
+
const { onRow, ...rest } = options;
|
|
40
|
+
const qs = (0, import_query.queryString)(rest, ["key", "startkey", "endkey", "reduce", "group", "group_level", "stale", "limit"]);
|
|
41
|
+
const url = `${config.couch}/${view}?${qs.toString()}`;
|
|
42
|
+
const streamer = import_JSONStream.default.parse("rows.*");
|
|
43
|
+
streamer.on("data", onRow);
|
|
44
|
+
streamer.on("end", (err) => {
|
|
45
|
+
if (err) return reject(err);
|
|
46
|
+
resolve(null);
|
|
47
|
+
});
|
|
48
|
+
import_needle.default.get(url).pipe(streamer);
|
|
49
|
+
});
|
package/cjs/index.cjs
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var index_exports = {};
|
|
20
|
+
__export(index_exports, {
|
|
21
|
+
bulkGet: () => import_bulk.bulkGet,
|
|
22
|
+
bulkRemove: () => import_bulk.bulkRemove,
|
|
23
|
+
bulkSave: () => import_bulk.bulkSave,
|
|
24
|
+
get: () => import_crud.get,
|
|
25
|
+
patch: () => import_patch.patch,
|
|
26
|
+
put: () => import_crud.put,
|
|
27
|
+
query: () => import_query.query,
|
|
28
|
+
queryStream: () => import_stream.queryStream,
|
|
29
|
+
schema: () => schema
|
|
30
|
+
});
|
|
31
|
+
module.exports = __toCommonJS(index_exports);
|
|
32
|
+
var import_bulk = require("./impl/bulk.cjs");
|
|
33
|
+
var import_crud = require("./impl/crud.cjs");
|
|
34
|
+
var import_patch = require("./impl/patch.cjs");
|
|
35
|
+
var import_query = require("./impl/query.cjs");
|
|
36
|
+
var import_stream = require("./impl/stream.cjs");
|
|
37
|
+
var import_bulk2 = require("./schema/bulk.cjs");
|
|
38
|
+
var import_config = require("./schema/config.cjs");
|
|
39
|
+
var import_query2 = require("./schema/query.cjs");
|
|
40
|
+
var import_patch2 = require("./schema/patch.cjs");
|
|
41
|
+
var import_crud2 = require("./schema/crud.cjs");
|
|
42
|
+
const schema = {
|
|
43
|
+
CouchConfig: import_config.CouchConfig,
|
|
44
|
+
SimpleViewQuery: import_query2.SimpleViewQuery,
|
|
45
|
+
SimpleViewQueryResponse: import_query2.SimpleViewQueryResponse,
|
|
46
|
+
BulkSave: import_bulk2.BulkSave,
|
|
47
|
+
BulkGet: import_bulk2.BulkGet,
|
|
48
|
+
CouchGet: import_crud2.CouchGet,
|
|
49
|
+
CouchPut: import_crud2.CouchPut,
|
|
50
|
+
CouchDoc: import_crud2.CouchDoc,
|
|
51
|
+
CouchDocResponse: import_crud2.CouchDocResponse,
|
|
52
|
+
PatchConfig: import_patch2.PatchConfig,
|
|
53
|
+
PatchDoc: import_patch2.PatchDoc
|
|
54
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var bulk_exports = {};
|
|
20
|
+
__export(bulk_exports, {
|
|
21
|
+
BulkGet: () => BulkGet,
|
|
22
|
+
BulkRemove: () => BulkRemove,
|
|
23
|
+
BulkSave: () => BulkSave,
|
|
24
|
+
BulkSaveResponseSchema: () => BulkSaveResponseSchema
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(bulk_exports);
|
|
27
|
+
var import_zod = require("zod");
|
|
28
|
+
var import_config = require("./config.cjs");
|
|
29
|
+
var import_crud = require("./crud.cjs");
|
|
30
|
+
const BulkSaveResponseSchema = import_zod.z.array(import_zod.z.object({
|
|
31
|
+
ok: import_zod.z.boolean().nullish(),
|
|
32
|
+
id: import_zod.z.string().nullish(),
|
|
33
|
+
rev: import_zod.z.string().nullish(),
|
|
34
|
+
error: import_zod.z.string().nullish().describe("if an error occured, one word reason, eg conflict"),
|
|
35
|
+
reason: import_zod.z.string().nullish().describe("a full error message")
|
|
36
|
+
}));
|
|
37
|
+
const BulkSave = import_zod.z.function().args(
|
|
38
|
+
import_config.CouchConfig,
|
|
39
|
+
import_zod.z.array(import_zod.z.object({
|
|
40
|
+
_id: import_zod.z.string()
|
|
41
|
+
}).passthrough())
|
|
42
|
+
).returns(import_zod.z.promise(BulkSaveResponseSchema));
|
|
43
|
+
const BulkGet = import_zod.z.function().args(
|
|
44
|
+
import_config.CouchConfig,
|
|
45
|
+
import_zod.z.array(import_zod.z.string().describe("the ids to get"))
|
|
46
|
+
).returns(import_zod.z.promise(import_zod.z.array(import_crud.CouchDoc)));
|
|
47
|
+
const BulkRemove = import_zod.z.function().args(
|
|
48
|
+
import_config.CouchConfig,
|
|
49
|
+
import_zod.z.array(import_zod.z.string().describe("the ids to delete"))
|
|
50
|
+
).returns(import_zod.z.promise(BulkSaveResponseSchema));
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var config_exports = {};
|
|
20
|
+
__export(config_exports, {
|
|
21
|
+
CouchConfig: () => CouchConfig
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(config_exports);
|
|
24
|
+
var import_zod = require("zod");
|
|
25
|
+
const CouchConfig = import_zod.z.object({
|
|
26
|
+
couch: import_zod.z.string().describe("the url of the couch db")
|
|
27
|
+
}).passthrough().describe("The std config object");
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var crud_exports = {};
|
|
20
|
+
__export(crud_exports, {
|
|
21
|
+
CouchDoc: () => CouchDoc,
|
|
22
|
+
CouchDocResponse: () => CouchDocResponse,
|
|
23
|
+
CouchGet: () => CouchGet,
|
|
24
|
+
CouchPut: () => CouchPut
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(crud_exports);
|
|
27
|
+
var import_zod = require("zod");
|
|
28
|
+
var import_config = require("./config.cjs");
|
|
29
|
+
const CouchDoc = import_zod.z.object({
|
|
30
|
+
_id: import_zod.z.string().describe("the couch doc id"),
|
|
31
|
+
_rev: import_zod.z.string().optional().describe("the doc revision")
|
|
32
|
+
}).passthrough();
|
|
33
|
+
const CouchDocResponse = import_zod.z.object({
|
|
34
|
+
ok: import_zod.z.boolean().optional().describe("did the request succeed"),
|
|
35
|
+
error: import_zod.z.string().optional().describe("the error message, if did not succed"),
|
|
36
|
+
statusCode: import_zod.z.number(),
|
|
37
|
+
id: import_zod.z.string().optional().describe("the couch doc id"),
|
|
38
|
+
rev: import_zod.z.string().optional().describe("the new rev of the doc")
|
|
39
|
+
});
|
|
40
|
+
const CouchPut = import_zod.z.function().args(
|
|
41
|
+
import_config.CouchConfig,
|
|
42
|
+
CouchDoc
|
|
43
|
+
).returns(import_zod.z.promise(CouchDocResponse));
|
|
44
|
+
const CouchGet = import_zod.z.function().args(
|
|
45
|
+
import_config.CouchConfig,
|
|
46
|
+
import_zod.z.string().describe("the couch doc id")
|
|
47
|
+
).returns(import_zod.z.promise(CouchDoc.nullable()));
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var patch_exports = {};
|
|
20
|
+
__export(patch_exports, {
|
|
21
|
+
CouchPatch: () => CouchPatch,
|
|
22
|
+
PatchConfig: () => PatchConfig,
|
|
23
|
+
PatchProperties: () => PatchProperties
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(patch_exports);
|
|
26
|
+
var import_zod = require("zod");
|
|
27
|
+
var import_config = require("./config.cjs");
|
|
28
|
+
var import_crud = require("./crud.cjs");
|
|
29
|
+
const PatchConfig = import_config.CouchConfig.extend({
|
|
30
|
+
retries: import_zod.z.number().min(0).max(100).optional(),
|
|
31
|
+
delay: import_zod.z.number().min(0).optional()
|
|
32
|
+
});
|
|
33
|
+
const PatchProperties = import_zod.z.record(import_zod.z.string(), import_zod.z.any());
|
|
34
|
+
const CouchPatch = import_zod.z.function().args(
|
|
35
|
+
PatchConfig,
|
|
36
|
+
import_zod.z.string().describe("the couch doc id"),
|
|
37
|
+
PatchProperties
|
|
38
|
+
).returns(import_zod.z.promise(import_crud.CouchDocResponse));
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var query_exports = {};
|
|
20
|
+
__export(query_exports, {
|
|
21
|
+
SimpleViewQuery: () => SimpleViewQuery,
|
|
22
|
+
SimpleViewQueryResponse: () => SimpleViewQueryResponse
|
|
23
|
+
});
|
|
24
|
+
module.exports = __toCommonJS(query_exports);
|
|
25
|
+
var import_zod = require("zod");
|
|
26
|
+
var import_config = require("./config.cjs");
|
|
27
|
+
const SimpleViewQueryResponse = import_zod.z.object({
|
|
28
|
+
error: import_zod.z.string().optional().describe("if something is wrong"),
|
|
29
|
+
rows: import_zod.z.array(import_zod.z.object({
|
|
30
|
+
id: import_zod.z.string().optional(),
|
|
31
|
+
key: import_zod.z.any().nullable(),
|
|
32
|
+
value: import_zod.z.any().nullable(),
|
|
33
|
+
doc: import_zod.z.object({}).passthrough().optional()
|
|
34
|
+
}))
|
|
35
|
+
}).passthrough();
|
|
36
|
+
const SimpleViewQuery = import_zod.z.function().args(
|
|
37
|
+
import_config.CouchConfig,
|
|
38
|
+
import_zod.z.string().describe("the view name"),
|
|
39
|
+
import_zod.z.object({
|
|
40
|
+
startkey: import_zod.z.any().optional(),
|
|
41
|
+
endkey: import_zod.z.any().optional(),
|
|
42
|
+
descending: import_zod.z.boolean().optional().describe("sort results descending"),
|
|
43
|
+
skip: import_zod.z.number().positive().optional().describe("skip this many rows"),
|
|
44
|
+
limit: import_zod.z.number().positive().optional().describe("limit the results to this many rows"),
|
|
45
|
+
key: import_zod.z.any().optional(),
|
|
46
|
+
include_docs: import_zod.z.boolean().optional().describe("join the id to the doc and return it"),
|
|
47
|
+
reduce: import_zod.z.boolean().optional().describe("reduce the results"),
|
|
48
|
+
group: import_zod.z.boolean().optional().describe("group the results"),
|
|
49
|
+
group_level: import_zod.z.number().positive().optional().describe("group the results at this level")
|
|
50
|
+
}).optional().describe("query options")
|
|
51
|
+
).returns(import_zod.z.promise(SimpleViewQueryResponse));
|
package/impl/bulk.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
import needle from 'needle'
|
|
3
|
+
import { BulkSave, BulkGet, BulkRemove } from '../schema/bulk.mjs'
|
|
3
4
|
|
|
4
5
|
const opts = {
|
|
5
6
|
json: true,
|
|
@@ -8,9 +9,10 @@ const opts = {
|
|
|
8
9
|
}
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
if (!docs
|
|
12
|
+
/** @type { import('../schema/bulk.mjs').BulkSaveSchema } */
|
|
13
|
+
export const bulkSave = BulkSave.implement(async (config, docs) => {
|
|
14
|
+
if (!docs) return { ok: false, error: 'noDocs', reason: 'no docs provided' }
|
|
15
|
+
if (!docs.length) return { ok: false, error: 'noDocs', reason: 'no docs provided' }
|
|
14
16
|
|
|
15
17
|
const url = `${config.couch}/_bulk_docs`
|
|
16
18
|
const body = { docs }
|
|
@@ -18,27 +20,34 @@ export async function bulkSave (config, docs) {
|
|
|
18
20
|
if (resp.statusCode !== 201) throw new Error('could not save')
|
|
19
21
|
const results = resp?.body || []
|
|
20
22
|
return results
|
|
21
|
-
}
|
|
23
|
+
})
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
/** @type { import('../schema/bulk.mjs').BulkGetSchema } */
|
|
26
|
+
export const bulkGet = BulkGet.implement(async (config, ids) => {
|
|
24
27
|
const keys = ids
|
|
25
28
|
const url = `${config.couch}/_all_docs?include_docs=true`
|
|
26
29
|
const body = { keys }
|
|
27
30
|
const resp = await needle('post', url, body, opts)
|
|
28
31
|
if (resp.statusCode !== 200) throw new Error('could not fetch')
|
|
29
32
|
const rows = resp?.body?.rows || []
|
|
33
|
+
/** @type {Array<import('../schema/crud.mjs').CouchDocSchema>} */
|
|
30
34
|
const docs = []
|
|
31
|
-
rows.forEach(
|
|
35
|
+
rows.forEach((
|
|
36
|
+
/** @type {{ error?: any, key?: string, doc?: import('../schema/crud.mjs').CouchDocSchema }} */ r
|
|
37
|
+
) => {
|
|
32
38
|
if (r.error) return
|
|
33
39
|
if (!r.key) return
|
|
34
40
|
if (!r.doc) return
|
|
35
|
-
|
|
41
|
+
/** @type { import('../schema/crud.mjs').CouchDocSchema } */
|
|
42
|
+
const doc = r.doc
|
|
43
|
+
docs.push(doc)
|
|
36
44
|
})
|
|
37
45
|
return docs
|
|
38
|
-
}
|
|
46
|
+
})
|
|
39
47
|
|
|
40
|
-
|
|
48
|
+
/** @type { import('../schema/bulk.mjs').BulkRemoveSchema } */
|
|
49
|
+
export const bulkRemove = BulkRemove.implement(async (config, ids) => {
|
|
41
50
|
const docs = await bulkGet(config, ids)
|
|
42
51
|
docs.forEach(d => { d._deleted = true })
|
|
43
52
|
return bulkSave(config, docs)
|
|
44
|
-
}
|
|
53
|
+
})
|
package/impl/crud.mjs
CHANGED
|
@@ -12,11 +12,9 @@ const opts = {
|
|
|
12
12
|
export const get = CouchGet.implement(async (config, id) => {
|
|
13
13
|
const url = `${config.couch}/${id}`
|
|
14
14
|
const resp = await needle('get', url, opts)
|
|
15
|
+
if (resp.statusCode === 404) return null
|
|
15
16
|
const result = resp?.body || {}
|
|
16
|
-
|
|
17
|
-
if (resp.statusCode !== 200) {
|
|
18
|
-
throw new Error('not found')
|
|
19
|
-
}
|
|
17
|
+
if (resp.statusCode !== 200) { throw new Error(result.reason || 'failed') }
|
|
20
18
|
return result
|
|
21
19
|
})
|
|
22
20
|
|
package/impl/patch.mjs
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { get, put } from './crud.mjs'
|
|
2
|
+
import { CouchPatch } from '../schema/patch.mjs'
|
|
3
|
+
|
|
4
|
+
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))
|
|
5
|
+
|
|
6
|
+
export const patch = CouchPatch.implement(async (config, id, properties) => {
|
|
7
|
+
const maxRetries = config.retries || 5
|
|
8
|
+
const delay = config.delay || 1000
|
|
9
|
+
let attempts = 0
|
|
10
|
+
|
|
11
|
+
while (attempts <= maxRetries) {
|
|
12
|
+
try {
|
|
13
|
+
const doc = await get(config, id)
|
|
14
|
+
const updatedDoc = { ...doc, ...properties }
|
|
15
|
+
const result = await put(config, updatedDoc)
|
|
16
|
+
|
|
17
|
+
// Check if the response indicates a conflict
|
|
18
|
+
if (result.ok) {
|
|
19
|
+
return result
|
|
20
|
+
}
|
|
21
|
+
// If not ok, treat as conflict and retry
|
|
22
|
+
attempts++
|
|
23
|
+
if (attempts > maxRetries) {
|
|
24
|
+
throw new Error(`Failed to patch after ${maxRetries} attempts`)
|
|
25
|
+
}
|
|
26
|
+
await sleep(delay)
|
|
27
|
+
} catch (err) {
|
|
28
|
+
// Handle other errors (network, etc)
|
|
29
|
+
attempts++
|
|
30
|
+
if (attempts > maxRetries) {
|
|
31
|
+
throw new Error(`Failed to patch after ${maxRetries} attempts: ${err.message}`)
|
|
32
|
+
}
|
|
33
|
+
await sleep(delay)
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
})
|
package/impl/query.mjs
CHANGED
|
@@ -27,6 +27,10 @@ export const query = SimpleViewQuery.implement(async (config, view, options) =>
|
|
|
27
27
|
return body
|
|
28
28
|
})
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* @param {{ [key: string]: any }} options - The options object containing query parameters.
|
|
32
|
+
* @param {string[]} params - The list of parameter names to include in the query string.
|
|
33
|
+
*/
|
|
30
34
|
export function queryString (options, params) {
|
|
31
35
|
const parts = Object.keys(options).map(key => {
|
|
32
36
|
let value = options[key]
|
package/impl/stream.mjs
CHANGED
|
@@ -2,8 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
import needle from 'needle'
|
|
4
4
|
import { queryString } from './query.mjs'
|
|
5
|
+
// @ts-ignore
|
|
5
6
|
import JSONStream from 'JSONStream'
|
|
6
7
|
|
|
8
|
+
/**
|
|
9
|
+
* @param {any} config
|
|
10
|
+
* @param {any} view
|
|
11
|
+
* @param {any} options
|
|
12
|
+
*/
|
|
7
13
|
export const queryStream = (config, view, options) => new Promise((resolve, reject) => {
|
|
8
14
|
if (!options) options = {}
|
|
9
15
|
|
|
@@ -12,7 +18,10 @@ export const queryStream = (config, view, options) => new Promise((resolve, reje
|
|
|
12
18
|
const url = `${config.couch}/${view}?${qs.toString()}`
|
|
13
19
|
const streamer = JSONStream.parse('rows.*')
|
|
14
20
|
streamer.on('data', onRow)
|
|
15
|
-
|
|
21
|
+
/**
|
|
22
|
+
* @param {any} err
|
|
23
|
+
*/
|
|
24
|
+
streamer.on('end', (/** @type any */err) => {
|
|
16
25
|
if (err) return reject(err)
|
|
17
26
|
resolve(null) // all work should be done in the stream
|
|
18
27
|
})
|
package/index.mjs
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { bulkGet, bulkSave, bulkRemove } from './impl/bulk.mjs'
|
|
2
2
|
import { get, put } from './impl/crud.mjs'
|
|
3
|
+
import { patch } from './impl/patch.mjs'
|
|
3
4
|
import { query } from './impl/query.mjs'
|
|
4
5
|
import { queryStream } from './impl/stream.mjs'
|
|
5
6
|
import { BulkSave, BulkGet } from './schema/bulk.mjs'
|
|
6
7
|
import { CouchConfig } from './schema/config.mjs'
|
|
7
8
|
import { SimpleViewQuery, SimpleViewQueryResponse } from './schema/query.mjs'
|
|
9
|
+
import { PatchConfig, PatchDoc } from './schema/patch.mjs'
|
|
8
10
|
import { CouchDoc, CouchDocResponse, CouchPut, CouchGet } from './schema/crud.mjs'
|
|
9
11
|
|
|
10
12
|
const schema = {
|
|
@@ -16,8 +18,9 @@ const schema = {
|
|
|
16
18
|
CouchGet,
|
|
17
19
|
CouchPut,
|
|
18
20
|
CouchDoc,
|
|
19
|
-
CouchDocResponse
|
|
21
|
+
CouchDocResponse,
|
|
22
|
+
PatchConfig,
|
|
23
|
+
PatchDoc
|
|
20
24
|
}
|
|
21
25
|
|
|
22
|
-
export { get, put, bulkGet, bulkSave, bulkRemove, query, queryStream, schema }
|
|
23
|
-
|
|
26
|
+
export { get, put, patch, bulkGet, bulkSave, bulkRemove, query, queryStream, schema }
|
package/package.json
CHANGED
|
@@ -1,10 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hide-a-bed",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "An abstraction over couchdb calls that includes easy mock/stubs with pouchdb",
|
|
5
|
-
"
|
|
5
|
+
"module": "index.mjs",
|
|
6
|
+
"main": "cjs/index.cjs",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
"import": "./index.mjs",
|
|
10
|
+
"require": "./cjs/index.cjs",
|
|
11
|
+
"default": "./cjs/index.cjs"
|
|
12
|
+
},
|
|
6
13
|
"scripts": {
|
|
7
|
-
"
|
|
14
|
+
"clean": "(find . -name \"*.mts\" -type f -delete || true) && (find . -name \"*.map\" -type f -delete || true)",
|
|
15
|
+
"build": "npm run clean && tsc && npm run build:cjs",
|
|
16
|
+
"build:cjs": "rm -rf cjs && node build/build.mjs",
|
|
17
|
+
"test": "standard && tape tests/*.mjs",
|
|
18
|
+
"lint:fix": "standard --fix",
|
|
19
|
+
"prepublish": "npm run build"
|
|
8
20
|
},
|
|
9
21
|
"repository": {
|
|
10
22
|
"type": "git",
|
|
@@ -25,5 +37,18 @@
|
|
|
25
37
|
"lodash": "^4.17.21",
|
|
26
38
|
"needle": "^3.2.0",
|
|
27
39
|
"zod": "^3.22.4"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/lodash": "^4.17.15",
|
|
43
|
+
"@types/needle": "^3.3.0",
|
|
44
|
+
"esbuild": "^0.24.2",
|
|
45
|
+
"glob": "^11.0.0",
|
|
46
|
+
"standard": "17.1.0",
|
|
47
|
+
"tape": "5.8.1",
|
|
48
|
+
"typescript": "5.6.2"
|
|
49
|
+
},
|
|
50
|
+
"volta": {
|
|
51
|
+
"node": "20.17.0",
|
|
52
|
+
"npm": "10.8.2"
|
|
28
53
|
}
|
|
29
54
|
}
|
package/schema/bulk.mjs
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { z } from 'zod'
|
|
2
2
|
import { CouchConfig } from './config.mjs'
|
|
3
|
+
import { CouchDoc } from './crud.mjs'
|
|
3
4
|
|
|
4
5
|
export const BulkSaveResponseSchema = z.array(z.object({
|
|
5
6
|
ok: z.boolean().nullish(),
|
|
6
|
-
id: z.string(),
|
|
7
|
+
id: z.string().nullish(),
|
|
7
8
|
rev: z.string().nullish(),
|
|
8
9
|
error: z.string().nullish().describe('if an error occured, one word reason, eg conflict'),
|
|
9
10
|
reason: z.string().nullish().describe('a full error message')
|
|
@@ -16,9 +17,16 @@ export const BulkSave = z.function().args(
|
|
|
16
17
|
_id: z.string()
|
|
17
18
|
}).passthrough())
|
|
18
19
|
).returns(z.promise(BulkSaveResponseSchema))
|
|
19
|
-
/** @typedef { z.infer<typeof
|
|
20
|
+
/** @typedef { z.infer<typeof BulkSave> } BulkSaveSchema */
|
|
20
21
|
|
|
21
22
|
export const BulkGet = z.function().args(
|
|
22
23
|
CouchConfig,
|
|
23
24
|
z.array(z.string().describe('the ids to get'))
|
|
24
|
-
)
|
|
25
|
+
).returns(z.promise(z.array(CouchDoc)))
|
|
26
|
+
/** @typedef { z.infer<typeof BulkGet> } BulkGetSchema */
|
|
27
|
+
|
|
28
|
+
export const BulkRemove = z.function().args(
|
|
29
|
+
CouchConfig,
|
|
30
|
+
z.array(z.string().describe('the ids to delete'))
|
|
31
|
+
).returns(z.promise(BulkSaveResponseSchema))
|
|
32
|
+
/** @typedef { z.infer<typeof BulkRemove> } BulkRemoveSchema */
|
package/schema/crud.mjs
CHANGED
|
@@ -5,6 +5,7 @@ export const CouchDoc = z.object({
|
|
|
5
5
|
_id: z.string().describe('the couch doc id'),
|
|
6
6
|
_rev: z.string().optional().describe('the doc revision')
|
|
7
7
|
}).passthrough()
|
|
8
|
+
/** @typedef { z.infer<typeof CouchDoc> } CouchDocSchema */
|
|
8
9
|
|
|
9
10
|
export const CouchDocResponse = z.object({
|
|
10
11
|
ok: z.boolean().optional().describe('did the request succeed'),
|
|
@@ -22,4 +23,4 @@ export const CouchPut = z.function().args(
|
|
|
22
23
|
export const CouchGet = z.function().args(
|
|
23
24
|
CouchConfig,
|
|
24
25
|
z.string().describe('the couch doc id')
|
|
25
|
-
).returns(z.promise(CouchDoc))
|
|
26
|
+
).returns(z.promise(CouchDoc.nullable()))
|
package/schema/patch.mjs
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from 'zod'
|
|
2
|
+
import { CouchConfig } from './config.mjs'
|
|
3
|
+
import { CouchDocResponse } from './crud.mjs'
|
|
4
|
+
|
|
5
|
+
export const PatchConfig = CouchConfig.extend({
|
|
6
|
+
retries: z.number().min(0).max(100).optional(),
|
|
7
|
+
delay: z.number().min(0).optional()
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
export const PatchProperties = z.record(z.string(), z.any())
|
|
11
|
+
|
|
12
|
+
export const CouchPatch = z.function()
|
|
13
|
+
.args(
|
|
14
|
+
PatchConfig,
|
|
15
|
+
z.string().describe('the couch doc id'),
|
|
16
|
+
PatchProperties
|
|
17
|
+
)
|
|
18
|
+
.returns(z.promise(CouchDocResponse))
|
package/schema/query.mjs
CHANGED
package/tsconfig.json
ADDED