@eldoy/webdb 0.4.0 → 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 +148 -220
  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++) {
@@ -22,266 +18,198 @@ module.exports = function (url) {
22
18
  await server.db.compact(name)
23
19
  }
24
20
 
21
+ db.info = async function () {
22
+ return server.info()
23
+ }
24
+
25
25
  return db
26
26
  }
27
27
 
28
- //
29
- // COLLECTION-LEVEL API (ordered to match test suite)
30
- //
28
+ function collection(name, server) {
29
+ var handle = null
30
+ var initPromise = null
31
31
 
32
- function api(name, server) {
33
- return {
34
- //
35
- // CRUD
36
- //
32
+ function init() {
33
+ if (initPromise) return initPromise
37
34
 
38
- create: async function (doc) {
39
- var db = await ensure(name, server)
40
- return db.insert(doc)
41
- },
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
+ })()
42
46
 
43
- bulk: async function (docs) {
44
- var db = await ensure(name, server)
45
- await db.bulk({ docs: docs })
46
- return docs.length
47
- },
47
+ return initPromise
48
+ }
48
49
 
49
- put: async function (query, update) {
50
- var dbi = await ensure(name, server)
51
-
52
- // find one match
53
- var r = await dbi.find({
54
- selector: query,
55
- limit: 1
56
- })
57
-
58
- // create if not found
59
- if (!r.docs.length) {
60
- var created = await dbi.insert(update)
61
- return {
62
- _id: created.id,
63
- _rev: created.rev,
64
- ...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)
65
57
  }
66
58
  }
59
+ }
60
+ )
67
61
 
68
- // update existing
69
- var cur = r.docs[0]
70
- var next = {}
71
-
72
- for (var k in cur) next[k] = cur[k]
73
- for (var k in update) next[k] = update[k]
74
-
75
- var res = await dbi.insert(next)
76
-
77
- next._id = res.id
78
- next._rev = res.rev
79
- return next
80
- },
62
+ return {
63
+ data: data,
81
64
 
82
- update: async function (query, update) {
83
- var db = await ensure(name, server)
84
- var r = await db.find({ selector: query })
85
- if (!r.docs.length) return 0
65
+ get: async function (query, opts, onBatch) {
66
+ var db = await init()
67
+ opts = opts || {}
86
68
 
87
- var out = []
88
- for (var i = 0; i < r.docs.length; i++) {
89
- var cur = r.docs[i]
90
- var next = {}
91
- for (var k in cur) next[k] = cur[k]
92
- for (var k in update) next[k] = update[k]
93
- out.push(next)
69
+ if (opts.count) {
70
+ var r = await db.find({ selector: query })
71
+ return { count: r.docs.length }
94
72
  }
95
73
 
96
- await db.bulk({ docs: out })
97
- return out.length
98
- },
99
-
100
- get: async function (query) {
101
- var dbi = await ensure(name, server)
102
- var r = await dbi.find({ selector: query, limit: 1 })
103
- return r.docs[0] || null
104
- },
105
-
106
- set: async function (query, update) {
107
- var dbi = await ensure(name, server)
108
-
109
- // find one
110
- var r = await dbi.find({
111
- selector: query,
112
- limit: 1
113
- })
114
-
115
- if (!r.docs.length) return null
116
-
117
- var cur = r.docs[0]
118
- var next = {}
74
+ if (onBatch) {
75
+ var batch = opts.batch || 100
76
+ var remaining = opts.limit
77
+ var bookmark = null
119
78
 
120
- // merge current doc + update
121
- for (var k in cur) next[k] = cur[k]
122
- for (var k in update) next[k] = update[k]
79
+ for (;;) {
80
+ var limit = batch
81
+ if (remaining !== undefined && remaining < limit) {
82
+ limit = remaining
83
+ }
123
84
 
124
- // write updated doc
125
- var res = await dbi.insert(next)
85
+ var q = { selector: query, limit: limit }
86
+ if (opts.sort) q.sort = normalizeSort(opts.sort)
126
87
 
127
- // return updated document shape
128
- next._id = res.id
129
- next._rev = res.rev
130
- return next
131
- },
132
-
133
- remove: async function (query) {
134
- var dbi = await ensure(name, server)
135
-
136
- // find one
137
- var r = await dbi.find({
138
- selector: query,
139
- limit: 1
140
- })
88
+ var mf = opts.fields && normalizeFields(opts.fields)
89
+ if (mf) q.fields = mf
90
+ if (bookmark) q.bookmark = bookmark
141
91
 
142
- if (!r.docs.length) return null
92
+ var r = await db.find(q)
93
+ if (!r.docs.length) break
143
94
 
144
- var doc = r.docs[0]
95
+ normalizeDocs(r.docs)
96
+ await onBatch(r.docs)
145
97
 
146
- // mark as deleted
147
- var res = await dbi.insert({
148
- _id: doc._id,
149
- _rev: doc._rev,
150
- _deleted: true
151
- })
98
+ if (remaining !== undefined) {
99
+ remaining -= r.docs.length
100
+ if (remaining <= 0) break
101
+ }
152
102
 
153
- return {
154
- _id: res.id,
155
- _rev: res.rev
103
+ if (!r.bookmark || r.docs.length < limit) break
104
+ bookmark = r.bookmark
105
+ }
106
+ return
156
107
  }
157
- },
158
108
 
159
- delete: async function (query) {
160
- var dbi = await ensure(name, server)
161
-
162
- var r = await dbi.find({ selector: query })
163
- 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
164
113
 
165
- var out = []
166
- for (var i = 0; i < r.docs.length; i++) {
167
- var d = r.docs[i]
168
- out.push({
169
- _id: d._id,
170
- _rev: d._rev,
171
- _deleted: true
172
- })
173
- }
114
+ var mf = opts.fields && normalizeFields(opts.fields)
115
+ if (mf) q.fields = mf
174
116
 
175
- await dbi.bulk({ docs: out })
176
- return out.length
117
+ var r = await db.find(q)
118
+ normalizeDocs(r.docs)
119
+ return r.docs[0] || null
177
120
  },
178
121
 
179
- //
180
- // FIND
181
- //
122
+ set: async function (arg, values) {
123
+ var db = await init()
182
124
 
183
- find: async function (query, opts) {
184
- 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
+ }
185
135
 
186
- var q = { selector: query }
187
- if (opts) {
188
- if (opts.sort) q.sort = opts.sort
189
- if (opts.limit) q.limit = opts.limit
190
- 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
191
140
  }
192
141
 
193
- var r = await dbi.find(q)
194
- return r.docs
195
- },
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
+ }
196
157
 
197
- //
198
- // INDEX
199
- //
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]
200
163
 
201
- index: async function (list) {
202
- var dbi = await ensure(name, server)
203
- for (var i = 0; i < list.length; i++) {
204
- 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)
205
169
  }
206
- },
207
-
208
- //
209
- // COUNT
210
- //
211
170
 
212
- count: async function (query) {
213
- var dbi = await ensure(name, server)
214
- var r = await dbi.find({ selector: query })
215
- return r.docs.length
171
+ await db.bulk({ docs: upd })
172
+ return { n: upd.length }
216
173
  },
217
174
 
218
- //
219
- // DROP (collection-level)
220
- //
221
-
222
175
  drop: async function () {
223
176
  try {
224
177
  await server.db.destroy(name)
225
178
  } catch (e) {}
226
- },
227
-
228
- //
229
- // BATCH
230
- //
231
-
232
- batch: async function (query, opt, fn) {
233
- var dbi = await ensure(name, server)
234
-
235
- var size = opt && opt.size ? opt.size : 100
236
- var limit = opt && opt.limit
237
- var sort = opt && opt.sort
238
- var fields = opt && opt.fields
239
-
240
- var bookmark = null
241
- var remaining = limit
242
-
243
- for (;;) {
244
- var effectiveSize = size
245
- if (remaining && remaining < effectiveSize) {
246
- effectiveSize = remaining
247
- }
248
-
249
- var q = {
250
- selector: query,
251
- limit: effectiveSize
252
- }
253
-
254
- if (sort) q.sort = sort
255
- if (fields) q.fields = fields
256
- if (bookmark) q.bookmark = bookmark
257
-
258
- var r = await dbi.find(q)
259
- var docs = r.docs
260
- if (!docs.length) break
261
-
262
- await fn(docs)
179
+ handle = null
180
+ initPromise = null
181
+ }
182
+ }
183
+ }
263
184
 
264
- if (remaining) {
265
- remaining -= docs.length
266
- if (remaining <= 0) break
267
- }
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
+ }
268
193
 
269
- if (!r.bookmark || docs.length < effectiveSize) break
270
- bookmark = r.bookmark
271
- }
194
+ function normalizeFields(fields) {
195
+ var include = []
196
+ for (var k in fields) {
197
+ if (fields[k]) {
198
+ include.push(k === 'id' ? '_id' : k)
272
199
  }
273
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
274
207
  }
275
208
 
276
- //
277
- // ENSURE DB EXISTS
278
- //
279
-
280
- async function ensure(name, server) {
281
- try {
282
- await server.db.get(name)
283
- } catch (e) {
284
- 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
285
214
  }
286
- return server.db.use(name)
287
215
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eldoy/webdb",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Document database client powered by CouchDB.",
5
5
  "publishConfig": {
6
6
  "access": "public"