@eldoy/webdb 0.4.1 → 0.5.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.
Files changed (3) hide show
  1. package/README.md +149 -167
  2. package/index.js +145 -221
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,279 +1,261 @@
1
1
  # WebDB
2
2
 
3
- Document database API backed by CouchDB, exposed through a Mongo-style client.
3
+ A small, fast document database API with a portable query language and native backend execution.
4
+
5
+ WebDB exposes a **single, well-defined interface** (`get` / `set`) designed to cover most web application use cases without sacrificing performance or backend features.
6
+
7
+ ---
8
+
9
+ ## Installation
4
10
 
5
- ### Installation
6
11
  ```sh
7
12
  npm i @eldoy/webdb
8
13
  ```
9
14
 
10
- ### Usage
15
+ ---
16
+
17
+ ## Usage
11
18
 
12
19
  ```js
13
20
  var webdb = require('@eldoy/webdb')
14
21
  var db = webdb('http://admin:mysecretpassword@localhost:5984')
22
+ ```
23
+
24
+ WebDB supports **named collections**:
25
+
26
+ ```js
27
+ var users = db('user')
28
+ ```
29
+
30
+ Databases are created automatically on first use.
31
+
32
+ ---
33
+
34
+ ## Insert
35
+
36
+ ### Insert one document
37
+
38
+ ```js
39
+ var doc = await users.set({ name: 'Alice' })
40
+ console.log(doc.id)
41
+ ```
42
+
43
+ The input object may be mutated to attach `id`.
44
+
45
+ ---
15
46
 
16
- // Create one
17
- var doc = await db('user').create({ name: 'Heimdal' })
47
+ ### Bulk insert
18
48
 
19
- // Bulk insert
20
- var n = await db('user').bulk([
49
+ ```js
50
+ var docs = await users.set([
21
51
  { name: 'A' },
22
52
  { name: 'B' }
23
53
  ])
54
+ ```
24
55
 
25
- // Update one or many
26
- var n = await db('user').update(
27
- { name: 'A' },
28
- { active: true }
29
- )
30
-
31
- // Set (update exactly one)
32
- var updated = await db('user').set(
33
- { name: 'A' },
34
- { name: 'B', active: true }
35
- )
56
+ Returns the inserted documents (same object references).
36
57
 
37
- // Remove (delete exactly one)
38
- var removed = await db('user').remove(
39
- { name: 'B' }
40
- )
58
+ ---
41
59
 
42
- // Put (create or update one)
43
- var doc = await db('user').put(
44
- { email: 'a@example.com' },
45
- { email: 'a@example.com', name: 'Alice' }
46
- )
60
+ ## Query (Read)
47
61
 
48
- // Get one (first match)
49
- var doc = await db('user').get({ name: 'Heimdal' })
62
+ ### Get first matching document
50
63
 
51
- // Create indexes
52
- await db('user').index([
53
- ['name'],
54
- ['name', 'email']
55
- ])
64
+ ```js
65
+ var doc = await users.get({ name: 'Alice' })
66
+ ```
56
67
 
57
- // Find
58
- var docs = await db('user').find({ name: 'Heimdal' })
68
+ Returns `null` if no match exists.
59
69
 
60
- // Find with sort
61
- var docs = await db('user').find(
62
- { name: 'Heimdal' },
63
- { sort: [{ name: 'asc' }] }
64
- )
70
+ ---
65
71
 
66
- // Find with limit
67
- var docs = await db('user').find(
68
- { name: 'Heimdal' },
69
- { limit: 1 }
70
- )
72
+ ### Count
71
73
 
72
- // Find with projection
73
- var docs = await db('user').find(
74
- { name: 'Heimdal' },
75
- { fields: ['name', 'email'] }
76
- )
74
+ ```js
75
+ var r = await users.get({ active: true }, { count: true })
76
+ console.log(r.count)
77
+ ```
77
78
 
78
- // Delete one or many
79
- var n = await db('user').delete({ active: false })
79
+ ---
80
80
 
81
- // Count
82
- var n = await db('user').count({ name: 'Heimdal' })
81
+ ### Streaming / batch reads
83
82
 
84
- // Batch processing (streamed pagination)
85
- await db('user').batch(
83
+ ```js
84
+ await users.get(
86
85
  { active: true },
87
- { size: 500, sort: [{ created: 'asc' }] },
86
+ { batch: 100, sort: { created: 1 } },
88
87
  async function (docs) {
89
- // handle a chunk
88
+ // process a batch
90
89
  }
91
90
  )
92
-
93
- // Drop a specific database
94
- await db('user').drop()
95
-
96
- // Server-level compact
97
- await db.compact('user')
98
-
99
- // Drop all databases
100
- await db.drop()
101
91
  ```
102
92
 
103
- ### Mango Query Options
93
+ Streaming controls **delivery**, not execution.
94
+ Internal buffering is allowed.
95
+
96
+ ---
104
97
 
105
- WebDB queries map directly to CouchDB Mango selectors. All Mango operators and options work as expected through `find()` and `batch()`.
98
+ ## Query Operators
106
99
 
107
- #### Comparison Operators
108
- Mango supports standard comparison operators inside selectors:
100
+ Supported predicates:
109
101
 
110
102
  ```
111
- $eq equal
112
- $ne not equal
113
- $gt greater than
114
- $gte greater than or equal
115
- $lt less than
116
- $lte less than or equal
117
- $regex regular expression matching
103
+ $eq $ne
104
+ $gt $gte
105
+ $lt $lte
106
+ $in $nin
107
+ $regex
108
+ $exists
118
109
  ```
119
110
 
120
- Example:
111
+ Examples:
121
112
 
122
113
  ```js
123
- await db('user').find({
124
- age: { $gte: 18 }
125
- })
114
+ await users.get({ age: { $gte: 18 } })
115
+ await users.get({ email: { $regex: '@example.com$' } })
126
116
  ```
127
117
 
128
- #### Logical Operators
118
+ Logical operators:
129
119
 
130
- Combine conditions using logical operators:
131
-
132
- ```
133
- $and
134
- $or
135
- $not
136
- $nor
120
+ ```js
121
+ $and $or $not
137
122
  ```
138
123
 
139
124
  Example:
140
125
 
141
126
  ```js
142
- await db('user').find({
127
+ await users.get({
143
128
  $or: [{ role: 'admin' }, { active: true }]
144
129
  })
145
130
  ```
146
131
 
147
- #### Sorting
132
+ ---
148
133
 
149
- Sorting requires an index on every field in the sort specification:
134
+ ## Sorting, Limiting, Projection
150
135
 
151
- ```js
152
- await db('user').index([['created']])
136
+ ### Sort
153
137
 
154
- await db('user').find(
138
+ ```js
139
+ await users.get(
155
140
  {},
156
- { sort: [{ created: 'asc' }] }
141
+ { sort: { created: 1 } }
157
142
  )
158
143
  ```
159
144
 
160
- #### Limiting
145
+ Sorting may require backend support or indexes.
146
+ If unsupported, the adapter may throw.
161
147
 
162
- Limit returned documents:
148
+ ---
149
+
150
+ ### Limit / skip
163
151
 
164
152
  ```js
165
- await db('user').find({}, { limit: 10 })
153
+ await users.get({}, { skip: 10, limit: 5 })
166
154
  ```
167
155
 
168
- #### Projection (fields)
156
+ ---
169
157
 
170
- Return only selected fields:
158
+ ### Projection (fields)
171
159
 
172
160
  ```js
173
- await db('user').find(
161
+ await users.get(
174
162
  {},
175
- { fields: ['name', 'email'] }
163
+ { fields: { name: true, email: true } }
176
164
  )
177
165
  ```
178
166
 
179
- #### Date Handling
167
+ Notes:
180
168
 
181
- CouchDB stores dates as strings.
182
- Using ISO-8601 timestamps (`new Date().toISOString()`) enables:
169
+ * Projection is inclusive if any field is `true`
170
+ * `id` is included by default
171
+ * Excluding `id` is **best-effort**
172
+ * Adapters may still return `id`
183
173
 
184
- * correct lexical comparison
185
- * correct sorting
186
- * correct `$gt` / `$lt` range queries
174
+ ---
187
175
 
188
- Example:
176
+ ## Update
177
+
178
+ ### Update matching documents
189
179
 
190
180
  ```js
191
- await db('log').find({
192
- created: { $gt: "2024-01-01T00:00:00.000Z" }
193
- })
181
+ var r = await users.set(
182
+ { active: false },
183
+ { active: true }
184
+ )
185
+
186
+ console.log(r.n)
194
187
  ```
195
188
 
196
- ISO strings compare and sort in true chronological order.
189
+ Rules:
197
190
 
198
- #### Batch Queries
191
+ * Shallow merge
192
+ * `undefined` removes a field
193
+ * `null` sets field to `null`
199
194
 
200
- `batch()` supports all Mango options:
195
+ ---
201
196
 
202
- * `size` (page size)
203
- * `limit`
204
- * `sort`
205
- * `fields`
206
- * standard selectors
197
+ ## Delete
207
198
 
208
- Example:
199
+ ### Delete matching documents
209
200
 
210
201
  ```js
211
- await db('user').batch(
212
- { created: { $gt: cutoff } },
213
- { size: 100, sort: [{ created: 'asc' }] },
214
- async function (docs) {
215
- // process chunk
216
- }
217
- )
202
+ var r = await users.set({ inactive: true }, null)
203
+ console.log(r.n)
218
204
  ```
219
205
 
220
- All Mango selectors and options work identically in both `find()` and `batch()`.
221
-
222
-
223
- ### Notes on Indexing, Sorting, and Mango Queries
206
+ ---
224
207
 
225
- **1. Selector fields and indexes**
226
-
227
- Mango performs best when the selector matches an existing index.
228
- Any field used in `{ selector: … }` benefits from being part of an index, but it is not required unless sorting is used.
229
-
230
- **2. Sorting requires indexing**
231
-
232
- Mango enforces that **every field in the sort must be indexed**.
233
- Example:
208
+ ### Clear collection
234
209
 
235
210
  ```js
236
- await db('user').index([['age']])
237
- await db('user').find({}, { sort: [{ age: 'asc' }] }) // valid
211
+ await users.set({}, null)
238
212
  ```
239
213
 
240
- Sorting without the correct index returns an error.
214
+ Deletes all documents in the collection.
241
215
 
242
- **3. Compound indexes**
216
+ ---
243
217
 
244
- An index like:
218
+ ## Adapter Extensions (Optional)
219
+
220
+ Adapters may expose additional APIs outside dbspec:
245
221
 
246
222
  ```js
247
- await db('user').index([['name', 'email']])
223
+ await users.drop() // drop a collection
224
+ await db.drop() // drop all collections
225
+ await db.compact('user')
226
+ await db.info()
248
227
  ```
249
228
 
250
- supports selectors and sorts that use `name`, or `name` and `email` together, in the defined order.
229
+ These are **adapter-specific** and non-portable.
251
230
 
252
- **4. Projection (`fields`)**
231
+ ---
253
232
 
254
- Projection returns only selected fields.
255
- Unindexed projection works fine; indexing does not affect `fields`.
233
+ ## Escape Hatch (`data`)
256
234
 
257
- **5. Pagination (batch)**
235
+ Native backend access is available via:
258
236
 
259
- `batch()` uses Mango bookmarks internally.
260
- It respects all options: `sort`, `limit`, `fields`, and `size`.
237
+ ```js
238
+ users.data
239
+ ```
261
240
 
262
- **6. Create-on-first-use**
241
+ This exposes the underlying client directly.
263
242
 
264
- Databases are auto-created when used. Explicit `drop()` allows clean-state tests.
243
+ Use of `data` is **explicitly non-portable** and bypasses dbspec guarantees.
265
244
 
266
- **7. Null results**
245
+ ---
267
246
 
268
- `get()` returns `null` when no match exists.
247
+ ## Design Notes
269
248
 
270
- ### ID note
249
+ * The reference implementation prioritizes **native execution**
250
+ * No client-side emulation of query semantics
251
+ * Performance scales with the backend
252
+ * Most web apps do not require the escape hatch
253
+ * When switching adapters, application query logic remains stable
271
254
 
272
- CouchDB stores documents with `_id`, but write responses return the same value as `id`.
273
- Use `doc.id` after `create()`, and `_id` for all queries and stored documents.
255
+ ---
274
256
 
275
- ### Acknowledgements
257
+ ## License
276
258
 
277
- Created by [Tekki AS](https://tekki.no)
259
+ ISC
278
260
 
279
- ISC Licensed.
261
+ Created by [Vidar Eldøy](https://eldoy.com)
package/index.js CHANGED
@@ -3,14 +3,10 @@ var nano = require('nano')
3
3
  module.exports = function (url) {
4
4
  var server = nano(url)
5
5
 
6
- var db = function (name) {
7
- return api(name, server)
6
+ function db(name) {
7
+ return collection(name, server)
8
8
  }
9
9
 
10
- //
11
- // SERVER-LEVEL OPS (drop all, compact specific)
12
- //
13
-
14
10
  db.drop = async function () {
15
11
  var list = await server.db.list()
16
12
  for (var i = 0; i < list.length; i++) {
@@ -23,269 +19,197 @@ module.exports = function (url) {
23
19
  }
24
20
 
25
21
  db.info = async function () {
26
- return await server.info()
22
+ return server.info()
27
23
  }
28
24
 
29
25
  return db
30
26
  }
31
27
 
32
- //
33
- // COLLECTION-LEVEL API (ordered to match test suite)
34
- //
28
+ function collection(name, server) {
29
+ var handle = null
30
+ var initPromise = null
35
31
 
36
- function api(name, server) {
37
- return {
38
- //
39
- // CRUD
40
- //
32
+ function init() {
33
+ if (initPromise) return initPromise
41
34
 
42
- create: async function (doc) {
43
- var db = await ensure(name, server)
44
- return db.insert(doc)
45
- },
35
+ initPromise = (async function () {
36
+ try {
37
+ await server.db.get(name)
38
+ } catch (e) {
39
+ try {
40
+ await server.db.create(name)
41
+ } catch (e2) {}
42
+ }
43
+ handle = server.db.use(name)
44
+ return handle
45
+ })()
46
46
 
47
- bulk: async function (docs) {
48
- var db = await ensure(name, server)
49
- await db.bulk({ docs: docs })
50
- return docs.length
51
- },
47
+ return initPromise
48
+ }
52
49
 
53
- put: async function (query, update) {
54
- var dbi = await ensure(name, server)
55
-
56
- // find one match
57
- var r = await dbi.find({
58
- selector: query,
59
- limit: 1
60
- })
61
-
62
- // create if not found
63
- if (!r.docs.length) {
64
- var created = await dbi.insert(update)
65
- return {
66
- _id: created.id,
67
- _rev: created.rev,
68
- ...update
50
+ var data = new Proxy(
51
+ {},
52
+ {
53
+ get: function (_, prop) {
54
+ return async function () {
55
+ var db = await init()
56
+ return db[prop].apply(db, arguments)
69
57
  }
70
58
  }
59
+ }
60
+ )
71
61
 
72
- // update existing
73
- var cur = r.docs[0]
74
- var next = {}
75
-
76
- for (var k in cur) next[k] = cur[k]
77
- for (var k in update) next[k] = update[k]
78
-
79
- var res = await dbi.insert(next)
80
-
81
- next._id = res.id
82
- next._rev = res.rev
83
- return next
84
- },
62
+ return {
63
+ data: data,
85
64
 
86
- update: async function (query, update) {
87
- var db = await ensure(name, server)
88
- var r = await db.find({ selector: query })
89
- if (!r.docs.length) return 0
65
+ get: async function (query, opts, onBatch) {
66
+ var db = await init()
67
+ opts = opts || {}
90
68
 
91
- var out = []
92
- for (var i = 0; i < r.docs.length; i++) {
93
- var cur = r.docs[i]
94
- var next = {}
95
- for (var k in cur) next[k] = cur[k]
96
- for (var k in update) next[k] = update[k]
97
- out.push(next)
69
+ if (opts.count) {
70
+ var r = await db.find({ selector: query })
71
+ return { count: r.docs.length }
98
72
  }
99
73
 
100
- await db.bulk({ docs: out })
101
- return out.length
102
- },
74
+ if (onBatch) {
75
+ var batch = opts.batch || 100
76
+ var remaining = opts.limit
77
+ var bookmark = null
103
78
 
104
- get: async function (query) {
105
- var dbi = await ensure(name, server)
106
- var r = await dbi.find({ selector: query, limit: 1 })
107
- return r.docs[0] || null
108
- },
109
-
110
- set: async function (query, update) {
111
- var dbi = await ensure(name, server)
112
-
113
- // find one
114
- var r = await dbi.find({
115
- selector: query,
116
- limit: 1
117
- })
118
-
119
- if (!r.docs.length) return null
79
+ for (;;) {
80
+ var limit = batch
81
+ if (remaining !== undefined && remaining < limit) {
82
+ limit = remaining
83
+ }
120
84
 
121
- var cur = r.docs[0]
122
- var next = {}
123
-
124
- // merge current doc + update
125
- for (var k in cur) next[k] = cur[k]
126
- for (var k in update) next[k] = update[k]
127
-
128
- // write updated doc
129
- var res = await dbi.insert(next)
130
-
131
- // return updated document shape
132
- next._id = res.id
133
- next._rev = res.rev
134
- return next
135
- },
85
+ var q = { selector: query, limit: limit }
86
+ if (opts.sort) q.sort = normalizeSort(opts.sort)
136
87
 
137
- remove: async function (query) {
138
- var dbi = await ensure(name, server)
88
+ var mf = opts.fields && normalizeFields(opts.fields)
89
+ if (mf) q.fields = mf
90
+ if (bookmark) q.bookmark = bookmark
139
91
 
140
- // find one
141
- var r = await dbi.find({
142
- selector: query,
143
- limit: 1
144
- })
92
+ var r = await db.find(q)
93
+ if (!r.docs.length) break
145
94
 
146
- if (!r.docs.length) return null
95
+ normalizeDocs(r.docs)
96
+ await onBatch(r.docs)
147
97
 
148
- var doc = r.docs[0]
98
+ if (remaining !== undefined) {
99
+ remaining -= r.docs.length
100
+ if (remaining <= 0) break
101
+ }
149
102
 
150
- // mark as deleted
151
- var res = await dbi.insert({
152
- _id: doc._id,
153
- _rev: doc._rev,
154
- _deleted: true
155
- })
156
-
157
- return {
158
- _id: res.id,
159
- _rev: res.rev
103
+ if (!r.bookmark || r.docs.length < limit) break
104
+ bookmark = r.bookmark
105
+ }
106
+ return
160
107
  }
161
- },
162
-
163
- delete: async function (query) {
164
- var dbi = await ensure(name, server)
165
108
 
166
- var r = await dbi.find({ selector: query })
167
- if (!r.docs.length) return 0
109
+ var q = { selector: query }
110
+ if (opts.sort) q.sort = normalizeSort(opts.sort)
111
+ if (opts.limit !== undefined) q.limit = opts.limit
112
+ if (opts.skip) q.skip = opts.skip
168
113
 
169
- var out = []
170
- for (var i = 0; i < r.docs.length; i++) {
171
- var d = r.docs[i]
172
- out.push({
173
- _id: d._id,
174
- _rev: d._rev,
175
- _deleted: true
176
- })
177
- }
114
+ var mf = opts.fields && normalizeFields(opts.fields)
115
+ if (mf) q.fields = mf
178
116
 
179
- await dbi.bulk({ docs: out })
180
- return out.length
117
+ var r = await db.find(q)
118
+ normalizeDocs(r.docs)
119
+ return r.docs[0] || null
181
120
  },
182
121
 
183
- //
184
- // FIND
185
- //
122
+ set: async function (arg, values) {
123
+ var db = await init()
186
124
 
187
- find: async function (query, opts) {
188
- var dbi = await ensure(name, server)
125
+ if (Array.isArray(arg)) {
126
+ var out = []
127
+ for (var i = 0; i < arg.length; i++) {
128
+ var d = arg[i]
129
+ var r = await db.insert(d)
130
+ d.id = r.id
131
+ out.push(d)
132
+ }
133
+ return out
134
+ }
189
135
 
190
- var q = { selector: query }
191
- if (opts) {
192
- if (opts.sort) q.sort = opts.sort
193
- if (opts.limit) q.limit = opts.limit
194
- if (opts.fields) q.fields = opts.fields
136
+ if (values === undefined) {
137
+ var r = await db.insert(arg)
138
+ arg.id = r.id
139
+ return arg
195
140
  }
196
141
 
197
- var r = await dbi.find(q)
198
- return r.docs
199
- },
142
+ var r = await db.find({ selector: arg })
143
+ if (!r.docs.length) return { n: 0 }
144
+
145
+ if (values === null) {
146
+ var del = []
147
+ for (var i = 0; i < r.docs.length; i++) {
148
+ del.push({
149
+ _id: r.docs[i]._id,
150
+ _rev: r.docs[i]._rev,
151
+ _deleted: true
152
+ })
153
+ }
154
+ await db.bulk({ docs: del })
155
+ return { n: del.length }
156
+ }
200
157
 
201
- //
202
- // INDEX
203
- //
158
+ var upd = []
159
+ for (var i = 0; i < r.docs.length; i++) {
160
+ var cur = r.docs[i]
161
+ var next = {}
162
+ for (var k in cur) next[k] = cur[k]
204
163
 
205
- index: async function (list) {
206
- var dbi = await ensure(name, server)
207
- for (var i = 0; i < list.length; i++) {
208
- await dbi.createIndex({ index: { fields: list[i] } })
164
+ for (var k in values) {
165
+ if (values[k] === undefined) delete next[k]
166
+ else next[k] = values[k]
167
+ }
168
+ upd.push(next)
209
169
  }
210
- },
211
170
 
212
- //
213
- // COUNT
214
- //
215
-
216
- count: async function (query) {
217
- var dbi = await ensure(name, server)
218
- var r = await dbi.find({ selector: query })
219
- return r.docs.length
171
+ await db.bulk({ docs: upd })
172
+ return { n: upd.length }
220
173
  },
221
174
 
222
- //
223
- // DROP (collection-level)
224
- //
225
-
226
175
  drop: async function () {
227
176
  try {
228
177
  await server.db.destroy(name)
229
178
  } catch (e) {}
230
- },
231
-
232
- //
233
- // BATCH
234
- //
235
-
236
- batch: async function (query, opt, fn) {
237
- var dbi = await ensure(name, server)
238
-
239
- var size = opt && opt.size ? opt.size : 100
240
- var limit = opt && opt.limit
241
- var sort = opt && opt.sort
242
- var fields = opt && opt.fields
243
-
244
- var bookmark = null
245
- var remaining = limit
246
-
247
- for (;;) {
248
- var effectiveSize = size
249
- if (remaining && remaining < effectiveSize) {
250
- effectiveSize = remaining
251
- }
252
-
253
- var q = {
254
- selector: query,
255
- limit: effectiveSize
256
- }
257
-
258
- if (sort) q.sort = sort
259
- if (fields) q.fields = fields
260
- if (bookmark) q.bookmark = bookmark
261
-
262
- var r = await dbi.find(q)
263
- var docs = r.docs
264
- if (!docs.length) break
265
-
266
- await fn(docs)
179
+ handle = null
180
+ initPromise = null
181
+ }
182
+ }
183
+ }
267
184
 
268
- if (remaining) {
269
- remaining -= docs.length
270
- if (remaining <= 0) break
271
- }
185
+ function normalizeSort(sort) {
186
+ var out = []
187
+ for (var k in sort) {
188
+ if (sort[k] === 1) out.push({ [k]: 'asc' })
189
+ else if (sort[k] === -1) out.push({ [k]: 'desc' })
190
+ }
191
+ return out
192
+ }
272
193
 
273
- if (!r.bookmark || docs.length < effectiveSize) break
274
- bookmark = r.bookmark
275
- }
194
+ function normalizeFields(fields) {
195
+ var include = []
196
+ for (var k in fields) {
197
+ if (fields[k]) {
198
+ include.push(k === 'id' ? '_id' : k)
276
199
  }
277
200
  }
201
+ if (include.length) {
202
+ if (fields.id !== false && include.indexOf('_id') === -1)
203
+ include.push('_id')
204
+ return include
205
+ }
206
+ return null
278
207
  }
279
208
 
280
- //
281
- // ENSURE DB EXISTS
282
- //
283
-
284
- async function ensure(name, server) {
285
- try {
286
- await server.db.get(name)
287
- } catch (e) {
288
- await server.db.create(name)
209
+ function normalizeDocs(docs) {
210
+ for (var i = 0; i < docs.length; i++) {
211
+ docs[i].id = docs[i]._id
212
+ delete docs[i]._id
213
+ delete docs[i]._rev
289
214
  }
290
- return server.db.use(name)
291
215
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eldoy/webdb",
3
- "version": "0.4.1",
3
+ "version": "0.5.0",
4
4
  "description": "Document database client powered by CouchDB.",
5
5
  "publishConfig": {
6
6
  "access": "public"