s3db.js 1.0.0 → 1.0.2
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 +115 -37
- package/UNLICENSE +24 -0
- package/package.json +26 -7
- package/src/resource.class.ts +4 -6
package/README.md
CHANGED
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
# s3db.js
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Another way to create a cheap document-base database with an easy ORM to handle your dataset!
|
|
4
4
|
|
|
5
5
|
1. <a href="#motivation">Motivation</a>
|
|
6
6
|
1. <a href="#install">Install</a>
|
|
7
7
|
1. <a href="#usage">Usage</a>
|
|
8
8
|
1. <a href="#quick-setup">Quick Setup</a>
|
|
9
9
|
1. <a href="#insights">Insights</a>
|
|
10
|
-
1. <a href="#
|
|
11
|
-
1. <a href="#
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
1. <a href="#
|
|
21
|
-
1. <a href="#
|
|
10
|
+
1. <a href="#database">Database</a>
|
|
11
|
+
1. <a href="#create-a-resource">Create a resource</a>
|
|
12
|
+
1. <a href="#resource-methods">Resource methods</a>
|
|
13
|
+
1. <a href="#insert">Insert</a>
|
|
14
|
+
1. <a href="#bulk-insert">Bulk insert</a>
|
|
15
|
+
1. <a href="#get">Get</a>
|
|
16
|
+
1. <a href="#update">Update</a>
|
|
17
|
+
1. <a href="#delete">Delete</a>
|
|
18
|
+
1. <a href="#count">Count</a>
|
|
19
|
+
1. <a href="#bulk-delete">Bulk delete</a>
|
|
20
|
+
1. <a href="#get-all-ids">Get all ids</a>
|
|
21
|
+
1. <a href="#delete-all">Delete all</a>
|
|
22
|
+
1. <a href="#get-all">Get all</a>
|
|
23
|
+
1. <a href="#resource-streams">Resource streams</a>
|
|
24
|
+
1. <a href="#readable-stream">Readable stream</a>
|
|
25
|
+
1. <a href="#writable-stream">Writable stream</a>
|
|
26
|
+
1. <a href="#events">Events</a>
|
|
27
|
+
1. <a href="#s3-client">S3 Client</a>
|
|
22
28
|
1. <a href="#examples">Examples</a>
|
|
23
29
|
1. <a href="#cost-simulation">Cost Simulation</a>
|
|
24
30
|
1. <a href="#big-example">Big Example</a>
|
|
@@ -95,13 +101,13 @@ import S3db from "s3db.js";
|
|
|
95
101
|
|
|
96
102
|
- For better use of the <a href="#cache">`cache`</a> (and listing), the best ID format is to use sequential ids with leading zeros (eq: 00001, 00002, 00003) due to S3 internal keys sorting method.
|
|
97
103
|
|
|
98
|
-
###
|
|
104
|
+
### Database
|
|
99
105
|
|
|
100
106
|
Your `s3db.js` client can be initiated with options:
|
|
101
107
|
|
|
102
108
|
| option | optional | description | type | default |
|
|
103
109
|
| :---------: | :------: | :-------------------------------------------------: | :-------: | :---------: |
|
|
104
|
-
| cache | true |
|
|
110
|
+
| cache | true | Persist searched data to reduce repeated requests | `boolean` | `undefined` |
|
|
105
111
|
| parallelism | true | Number of simultaneous tasks | `number` | 10 |
|
|
106
112
|
| passphrase | true | Your encryption secret | `string` | `undefined` |
|
|
107
113
|
| ttl | true | (Coming soon) TTL to your cache duration in seconds | `number` | 86400 |
|
|
@@ -174,8 +180,6 @@ It has this structure:
|
|
|
174
180
|
}
|
|
175
181
|
```
|
|
176
182
|
|
|
177
|
-
### Resources
|
|
178
|
-
|
|
179
183
|
#### Create a resource
|
|
180
184
|
|
|
181
185
|
Resources are definitions of data collections.
|
|
@@ -230,6 +234,9 @@ const attributes = {
|
|
|
230
234
|
long: "number",
|
|
231
235
|
city: "string",
|
|
232
236
|
},
|
|
237
|
+
|
|
238
|
+
// may have multiple definitions.
|
|
239
|
+
address_number: ["string", "number"],
|
|
233
240
|
};
|
|
234
241
|
```
|
|
235
242
|
|
|
@@ -261,11 +268,19 @@ You may just use the reference:
|
|
|
261
268
|
const Leads = s3db.resource("leads");
|
|
262
269
|
```
|
|
263
270
|
|
|
264
|
-
|
|
271
|
+
### Resources methods
|
|
272
|
+
|
|
273
|
+
Consider `resource` as:
|
|
274
|
+
|
|
275
|
+
```javascript
|
|
276
|
+
const resource = s3db.resource("leads");
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
#### Insert
|
|
265
280
|
|
|
266
281
|
```javascript
|
|
267
282
|
// data
|
|
268
|
-
const
|
|
283
|
+
const data = {
|
|
269
284
|
id: "mypersonal@email.com", // if not defined a id will be generated!
|
|
270
285
|
utm: {
|
|
271
286
|
source: "abc",
|
|
@@ -278,12 +293,12 @@ const attributes = {
|
|
|
278
293
|
invalidAttr: "this attribute will disappear",
|
|
279
294
|
};
|
|
280
295
|
|
|
281
|
-
const insertedData = await
|
|
296
|
+
const insertedData = await resource.insert(data);
|
|
282
297
|
```
|
|
283
298
|
|
|
284
299
|
If not defined an id attribute, `s3db.js` will use [`nanoid`](https://github.com/ai/nanoid) to generate a random unique id!
|
|
285
300
|
|
|
286
|
-
#### Bulk insert
|
|
301
|
+
#### Bulk insert
|
|
287
302
|
|
|
288
303
|
You may bulk insert data with a friendly method.
|
|
289
304
|
|
|
@@ -291,7 +306,7 @@ This method uses [`supercharge/promise-pool`](https://github.com/supercharge/pro
|
|
|
291
306
|
|
|
292
307
|
```javascript
|
|
293
308
|
const s3db = new S3db({
|
|
294
|
-
parallelism: 10,
|
|
309
|
+
parallelism: 10, // default
|
|
295
310
|
});
|
|
296
311
|
```
|
|
297
312
|
|
|
@@ -303,17 +318,17 @@ const objects = new Array(100).fill(0).map((v, k) => ({
|
|
|
303
318
|
lead: {
|
|
304
319
|
fullName: "My Test Name",
|
|
305
320
|
personalEmail: `bulk-${k}@mymail.com`,
|
|
306
|
-
mobileNumber: "+55
|
|
321
|
+
mobileNumber: "+55 11 1234567890",
|
|
307
322
|
},
|
|
308
323
|
}));
|
|
309
324
|
|
|
310
|
-
await
|
|
325
|
+
await resource.bulkInsert(objects);
|
|
311
326
|
```
|
|
312
327
|
|
|
313
|
-
#### Get
|
|
328
|
+
#### Get
|
|
314
329
|
|
|
315
330
|
```javascript
|
|
316
|
-
const obj = await
|
|
331
|
+
const obj = await resource.getById("mypersonal@email.com");
|
|
317
332
|
|
|
318
333
|
// {
|
|
319
334
|
// id: "mypersonal@email.com",
|
|
@@ -328,32 +343,95 @@ const obj = await s3db.resource("leads").get("mypersonal@email.com");
|
|
|
328
343
|
// }
|
|
329
344
|
```
|
|
330
345
|
|
|
331
|
-
####
|
|
346
|
+
#### Update
|
|
347
|
+
|
|
348
|
+
```javascript
|
|
349
|
+
const obj = await resource.updateById("mypersonal@email.com", {
|
|
350
|
+
lead: {
|
|
351
|
+
mobileNumber: "+5511999999999",
|
|
352
|
+
},
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
// {
|
|
356
|
+
// id: "mypersonal@email.com",
|
|
357
|
+
// utm: {
|
|
358
|
+
// source: "abc",
|
|
359
|
+
// },
|
|
360
|
+
// lead: {
|
|
361
|
+
// fullName: "My Complex Name",
|
|
362
|
+
// personalEmail: "mypersonal@email.com",
|
|
363
|
+
// mobileNumber: "+5511999999999",
|
|
364
|
+
// },
|
|
365
|
+
// }
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
#### Delete
|
|
332
369
|
|
|
333
370
|
```javascript
|
|
334
|
-
|
|
371
|
+
await resource.deleteById(id);
|
|
372
|
+
```
|
|
335
373
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
374
|
+
#### Count
|
|
375
|
+
|
|
376
|
+
```javascript
|
|
377
|
+
await resource.count();
|
|
378
|
+
|
|
379
|
+
// 101
|
|
339
380
|
```
|
|
340
381
|
|
|
341
|
-
#### Delete
|
|
382
|
+
#### Bulk Delete
|
|
342
383
|
|
|
343
384
|
```javascript
|
|
344
|
-
await
|
|
385
|
+
await resource.bulkDelete(["id1", "id2", "id3 "]);
|
|
345
386
|
```
|
|
346
387
|
|
|
347
|
-
####
|
|
388
|
+
#### Get all Ids
|
|
348
389
|
|
|
349
390
|
```javascript
|
|
350
|
-
await
|
|
391
|
+
const ids = await resource.getAllIds();
|
|
392
|
+
// [
|
|
393
|
+
// 'id1',
|
|
394
|
+
// 'id2',
|
|
395
|
+
// 'id3',
|
|
396
|
+
// ]
|
|
351
397
|
```
|
|
352
398
|
|
|
353
|
-
####
|
|
399
|
+
#### Delete all
|
|
354
400
|
|
|
355
401
|
```javascript
|
|
356
|
-
|
|
402
|
+
await resource.deleteAll();
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
#### Get all
|
|
406
|
+
|
|
407
|
+
```javascript
|
|
408
|
+
const data = await resource.getAll();
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
### Resource streams
|
|
412
|
+
|
|
413
|
+
#### Readable stream
|
|
414
|
+
|
|
415
|
+
```javascript
|
|
416
|
+
const readableStream = await resource.readable();
|
|
417
|
+
|
|
418
|
+
readableStream.on("id", (id) => console.log("id =", id));
|
|
419
|
+
readableStream.on("data", (lead) => console.log("lead.id =", lead.id));
|
|
420
|
+
readableStream.on("end", console.log("end"));
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
#### Writable stream
|
|
424
|
+
|
|
425
|
+
```javascript
|
|
426
|
+
const writableStream = await resource.writable();
|
|
427
|
+
|
|
428
|
+
writableStream.write({
|
|
429
|
+
lead: {
|
|
430
|
+
fullName: "My Test Name",
|
|
431
|
+
personalEmail: `bulk-${k}@mymail.com`,
|
|
432
|
+
mobileNumber: "+55 11 1234567890",
|
|
433
|
+
},
|
|
434
|
+
});
|
|
357
435
|
```
|
|
358
436
|
|
|
359
437
|
### Events
|
package/UNLICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
|
2
|
+
|
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
4
|
+
distribute this software, either in source code form or as a compiled
|
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
|
6
|
+
means.
|
|
7
|
+
|
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
|
9
|
+
of this software dedicate any and all copyright interest in the
|
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
|
11
|
+
of the public at large and to the detriment of our heirs and
|
|
12
|
+
successors. We intend this dedication to be an overt act of
|
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
|
14
|
+
software under copyright law.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
+
|
|
24
|
+
For more information, please refer to <https://unlicense.org>
|
package/package.json
CHANGED
|
@@ -1,22 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "s3db.js",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Use AWS S3 as a database",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Use AWS S3 as a cheap document database.",
|
|
5
5
|
"main": "build/index.js",
|
|
6
|
+
"author": "filipeforattini",
|
|
7
|
+
"license": "UNLICENSE",
|
|
6
8
|
"scripts": {
|
|
7
9
|
"build": "rimraf ./build && tsc",
|
|
8
10
|
"test": "jest --coverage",
|
|
11
|
+
"coverage": "coveralls < coverage/lcov.info",
|
|
12
|
+
"coverage:serve": "npx http-server ./coverage/lcov-report",
|
|
9
13
|
"test:cache": "jest --coverage ./tests/cache.spec.ts",
|
|
10
14
|
"example:1": "cd examples; node 1-bulk-insert.js",
|
|
11
15
|
"example:2": "cd examples; node 2-read-stream.js",
|
|
12
16
|
"example:3": "cd examples; node 3-read-stream-to-csv.js",
|
|
13
17
|
"example:4": "cd examples; node 4-read-stream-to-zip.js",
|
|
14
18
|
"example:5": "cd examples; node 5-write-stream.js",
|
|
15
|
-
"example:6": "cd examples; node 6-jwt-tokens.js"
|
|
16
|
-
"coverage": "npx http-server ./coverage/lcov-report"
|
|
19
|
+
"example:6": "cd examples; node 6-jwt-tokens.js"
|
|
17
20
|
},
|
|
18
|
-
"author": "filipeforattini",
|
|
19
|
-
"license": "ISC",
|
|
20
21
|
"devDependencies": {
|
|
21
22
|
"@types/crypto-js": "^4.1.1",
|
|
22
23
|
"@types/flat": "^5.0.2",
|
|
@@ -25,6 +26,7 @@
|
|
|
25
26
|
"@types/node": "^18.11.9",
|
|
26
27
|
"@types/pako": "^2.0.0",
|
|
27
28
|
"@types/progress": "^2.0.5",
|
|
29
|
+
"coveralls": "^3.1.1",
|
|
28
30
|
"dotenv": "^16.0.3",
|
|
29
31
|
"esm": "^3.2.25",
|
|
30
32
|
"fakerator": "^0.3.6",
|
|
@@ -47,5 +49,22 @@
|
|
|
47
49
|
"lodash": "^4.17.21",
|
|
48
50
|
"nanoid": "3.3.4",
|
|
49
51
|
"ts-mixer": "^6.0.2"
|
|
50
|
-
}
|
|
52
|
+
},
|
|
53
|
+
"directories": {
|
|
54
|
+
"example": "examples",
|
|
55
|
+
"test": "tests"
|
|
56
|
+
},
|
|
57
|
+
"repository": {
|
|
58
|
+
"type": "git",
|
|
59
|
+
"url": "git+https://github.com/filipeforattini/s3db.js.git"
|
|
60
|
+
},
|
|
61
|
+
"keywords": [
|
|
62
|
+
"s3",
|
|
63
|
+
"aws",
|
|
64
|
+
"database"
|
|
65
|
+
],
|
|
66
|
+
"bugs": {
|
|
67
|
+
"url": "https://github.com/filipeforattini/s3db.js/issues"
|
|
68
|
+
},
|
|
69
|
+
"homepage": "https://github.com/filipeforattini/s3db.js#readme"
|
|
51
70
|
}
|
package/src/resource.class.ts
CHANGED
|
@@ -225,7 +225,7 @@ export default class Resource
|
|
|
225
225
|
});
|
|
226
226
|
|
|
227
227
|
// validate
|
|
228
|
-
|
|
228
|
+
let { isValid, errors, data: validated } = this.check(attrs);
|
|
229
229
|
|
|
230
230
|
if (!isValid) {
|
|
231
231
|
return Promise.reject(
|
|
@@ -239,18 +239,16 @@ export default class Resource
|
|
|
239
239
|
}
|
|
240
240
|
|
|
241
241
|
if (!id && id !== 0) id = nanoid();
|
|
242
|
+
validated = this.map(validated);
|
|
242
243
|
|
|
243
244
|
// save
|
|
244
245
|
await this.s3Client.putObject({
|
|
245
246
|
key: path.join(`resource=${this.name}`, `id=${id}`),
|
|
246
247
|
body: "",
|
|
247
|
-
metadata:
|
|
248
|
+
metadata: validated,
|
|
248
249
|
});
|
|
249
250
|
|
|
250
|
-
const final = {
|
|
251
|
-
id,
|
|
252
|
-
...(unflatten(validated) as object),
|
|
253
|
-
};
|
|
251
|
+
const final = { id, ...(unflatten(this.unmap(validated)) as object) };
|
|
254
252
|
|
|
255
253
|
this.emit("inserted", final);
|
|
256
254
|
this.s3db.emit("inserted", this.name, final);
|