s3db.js 1.0.6 → 2.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 +385 -186
- package/build/cache/s3-cache.class.js +7 -5
- package/build/cache/s3-resource-cache.class.js +6 -8
- package/build/cache/serializers.type.js +1 -0
- package/build/index.js +23 -6
- package/build/plugins/costs.plugin.js +65 -0
- package/build/plugins/index.js +8 -0
- package/build/{plugin.interface.js → plugins/plugin.interface.js} +0 -0
- package/build/s3-client.class.js +52 -21
- package/build/{resource.interface.js → s3-database-config.interface.js} +0 -0
- package/build/{s3db.class.js → s3-database.class.js} +20 -15
- package/build/{resource.class.js → s3-resource.class.js} +73 -77
- package/build/{s3db-config.interface.js → s3-resource.interface.js} +0 -0
- package/build/stream/index.js +19 -0
- package/build/stream/resource-ids-read-stream.class.js +3 -1
- package/build/stream/resource-ids-transformer.class.js +3 -1
- package/build/stream/resource-write-stream.class.js +4 -2
- package/package.json +16 -9
- package/.github/workflows/pipeline.yml +0 -16
- package/examples/1-bulk-insert.js +0 -64
- package/examples/2-read-stream.js +0 -61
- package/examples/3-read-stream-to-csv.js +0 -57
- package/examples/4-read-stream-to-zip.js +0 -56
- package/examples/5-write-stream.js +0 -98
- package/examples/6-jwt-tokens.js +0 -124
- package/examples/concerns/index.js +0 -64
- package/src/cache/avro.serializer.ts +0 -12
- package/src/cache/json.serializer.ts +0 -4
- package/src/cache/s3-cache.class.ts +0 -155
- package/src/cache/s3-resource-cache.class.ts +0 -75
- package/src/cache/serializers.type.ts +0 -8
- package/src/errors.ts +0 -96
- package/src/index.ts +0 -4
- package/src/metadata.interface.ts +0 -4
- package/src/plugin.interface.ts +0 -4
- package/src/resource.class.ts +0 -529
- package/src/resource.interface.ts +0 -21
- package/src/s3-client.class.ts +0 -297
- package/src/s3db-config.interface.ts +0 -9
- package/src/s3db.class.ts +0 -215
- package/src/stream/resource-ids-read-stream.class.ts +0 -90
- package/src/stream/resource-ids-transformer.class.ts +0 -38
- package/src/stream/resource-write-stream.class.ts +0 -78
- package/src/validator.ts +0 -39
- package/tests/cache.spec.ts +0 -187
- package/tests/concerns/index.ts +0 -16
- package/tests/config.spec.ts +0 -29
- package/tests/resources.spec.ts +0 -197
package/README.md
CHANGED
|
@@ -1,34 +1,49 @@
|
|
|
1
1
|
# s3db.js
|
|
2
2
|
|
|
3
|
+
[](http://unlicense.org/) [](https://www.npmjs.com/package/s3db.js) [](https://codeclimate.com/github/forattini-dev/s3db.js/maintainability) [](https://coveralls.io/github/forattini-dev/s3db.js?branch=main)
|
|
4
|
+
|
|
3
5
|
Another way to create a cheap document-base database with an easy ORM to handle your dataset!
|
|
4
6
|
|
|
7
|
+
<table width="100%">
|
|
8
|
+
<tr>
|
|
9
|
+
<td>
|
|
10
|
+
|
|
5
11
|
1. <a href="#motivation">Motivation</a>
|
|
6
|
-
1. <a href="#install">Install</a>
|
|
7
12
|
1. <a href="#usage">Usage</a>
|
|
13
|
+
1. <a href="#install">Install</a>
|
|
8
14
|
1. <a href="#quick-setup">Quick Setup</a>
|
|
9
15
|
1. <a href="#insights">Insights</a>
|
|
10
16
|
1. <a href="#database">Database</a>
|
|
11
17
|
1. <a href="#create-a-resource">Create a resource</a>
|
|
12
18
|
1. <a href="#resource-methods">Resource methods</a>
|
|
13
|
-
1. <a href="#insert">Insert</a>
|
|
14
|
-
1. <a href="#
|
|
15
|
-
1. <a href="#
|
|
16
|
-
1. <a href="#
|
|
17
|
-
1. <a href="#delete">Delete</a>
|
|
19
|
+
1. <a href="#insert-one">Insert one</a>
|
|
20
|
+
1. <a href="#get-one">Get one</a>
|
|
21
|
+
1. <a href="#update-one">Update one</a>
|
|
22
|
+
1. <a href="#delete-one">Delete one</a>
|
|
18
23
|
1. <a href="#count">Count</a>
|
|
19
|
-
1. <a href="#
|
|
20
|
-
1. <a href="#get-
|
|
21
|
-
1. <a href="#delete-all">Delete all</a>
|
|
24
|
+
1. <a href="#insert-many">Insert many</a>
|
|
25
|
+
1. <a href="#get-many">Get many</a>
|
|
22
26
|
1. <a href="#get-all">Get all</a>
|
|
27
|
+
1. <a href="#delete-many">Delete many</a>
|
|
28
|
+
1. <a href="#delete-all">Delete all</a>
|
|
29
|
+
1. <a href="#list-ids">List ids</a>
|
|
23
30
|
1. <a href="#resource-streams">Resource streams</a>
|
|
24
31
|
1. <a href="#readable-stream">Readable stream</a>
|
|
25
32
|
1. <a href="#writable-stream">Writable stream</a>
|
|
26
|
-
1. <a href="#events">Events</a>
|
|
27
33
|
1. <a href="#s3-client">S3 Client</a>
|
|
34
|
+
1. <a href="#events">Events</a>
|
|
35
|
+
1. <a href="#plugins">Plugins</a>
|
|
28
36
|
1. <a href="#examples">Examples</a>
|
|
29
37
|
1. <a href="#cost-simulation">Cost Simulation</a>
|
|
30
38
|
1. <a href="#big-example">Big Example</a>
|
|
31
39
|
1. <a href="#small-example">Small example</a>
|
|
40
|
+
1. <a href="#roadmap">Roadmap</a>
|
|
41
|
+
|
|
42
|
+
</td>
|
|
43
|
+
</tr>
|
|
44
|
+
</table>
|
|
45
|
+
|
|
46
|
+
---
|
|
32
47
|
|
|
33
48
|
## Motivation
|
|
34
49
|
|
|
@@ -52,24 +67,28 @@ Check the <a href="#cost-simulation">cost simulation</a> section below for a dee
|
|
|
52
67
|
|
|
53
68
|
Lets give it a try! :)
|
|
54
69
|
|
|
55
|
-
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## Usage
|
|
73
|
+
|
|
74
|
+
You may check the snippets bellow or go straight to the <a href="#examples">Examples</a> section!
|
|
75
|
+
|
|
76
|
+
### Install
|
|
56
77
|
|
|
57
78
|
```bash
|
|
58
79
|
npm i s3db.js
|
|
80
|
+
|
|
59
81
|
# or
|
|
82
|
+
|
|
60
83
|
yarn add s3db.js
|
|
61
84
|
```
|
|
62
85
|
|
|
63
|
-
## Usage
|
|
64
|
-
|
|
65
|
-
You may check the snippets bellow or go straight to the <a href="#examples">Examples</a> section!
|
|
66
|
-
|
|
67
86
|
### Quick setup
|
|
68
87
|
|
|
69
88
|
Our S3db client use connection string params.
|
|
70
89
|
|
|
71
90
|
```javascript
|
|
72
|
-
import S3db from "s3db.js";
|
|
91
|
+
import { S3db } from "s3db.js";
|
|
73
92
|
|
|
74
93
|
const {
|
|
75
94
|
AWS_BUCKET,
|
|
@@ -92,14 +111,14 @@ If you do use `dotenv` package:
|
|
|
92
111
|
import * as dotenv from "dotenv";
|
|
93
112
|
dotenv.config();
|
|
94
113
|
|
|
95
|
-
import S3db from "s3db.js";
|
|
114
|
+
import { S3db } from "s3db.js";
|
|
96
115
|
```
|
|
97
116
|
|
|
98
117
|
### Insights
|
|
99
118
|
|
|
100
119
|
- This implementation of ORM simulates a document repository. Due to the fact that `s3db.js` uses `aws-sdk`'s' S3 api; all requests are GET/PUT as `key=value` resources. So the best case scenario is to access like a document implementation.
|
|
101
120
|
|
|
102
|
-
- For better use of the <a href="#cache"
|
|
121
|
+
- 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. But you will need to manage this incremental ID by your own.
|
|
103
122
|
|
|
104
123
|
### Database
|
|
105
124
|
|
|
@@ -113,7 +132,7 @@ Your `s3db.js` client can be initiated with options:
|
|
|
113
132
|
| ttl | true | (Coming soon) TTL to your cache duration in seconds | `number` | 86400 |
|
|
114
133
|
| uri | false | A url as your S3 connection string | `string` | `undefined` |
|
|
115
134
|
|
|
116
|
-
|
|
135
|
+
Config example:
|
|
117
136
|
|
|
118
137
|
```javascript
|
|
119
138
|
const {
|
|
@@ -124,11 +143,7 @@ const {
|
|
|
124
143
|
} = process.env;
|
|
125
144
|
|
|
126
145
|
const uri = `s3://${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}@${AWS_BUCKET}/${AWS_BUCKET_PREFIX}`;
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
Config example:
|
|
130
146
|
|
|
131
|
-
```javascript
|
|
132
147
|
const options = {
|
|
133
148
|
uri,
|
|
134
149
|
parallelism: 25,
|
|
@@ -136,19 +151,21 @@ const options = {
|
|
|
136
151
|
};
|
|
137
152
|
```
|
|
138
153
|
|
|
139
|
-
|
|
154
|
+
#### s3db.connect()
|
|
140
155
|
|
|
141
|
-
|
|
156
|
+
This method must always be invoked before any operation take place. This will interact with AWS' S3 api and check the itens below:
|
|
142
157
|
|
|
143
|
-
1.
|
|
144
|
-
|
|
145
|
-
|
|
158
|
+
1. With current credentials:
|
|
159
|
+
- Check if client has access to the S3 bucket.
|
|
160
|
+
- Check if client has access to bucket life-cycle policies.
|
|
161
|
+
1. With defined database:
|
|
162
|
+
- Check if there is already a database in this connection string.
|
|
163
|
+
- If any database is found, downloads it's medatada and loads each `Resource` definition.
|
|
164
|
+
- Else, it will generate an empty <a href="#metadata-file">`metadata`</a> file into this prefix and mark that this is a new database from scratch.
|
|
146
165
|
|
|
147
166
|
#### Metadata file
|
|
148
167
|
|
|
149
|
-
`s3db.js` will generate a file
|
|
150
|
-
|
|
151
|
-
It has this structure:
|
|
168
|
+
`s3db.js` will generate a file `/s3db.json` at the pre-defined prefix with this structure:
|
|
152
169
|
|
|
153
170
|
```javascript
|
|
154
171
|
{
|
|
@@ -180,7 +197,7 @@ It has this structure:
|
|
|
180
197
|
}
|
|
181
198
|
```
|
|
182
199
|
|
|
183
|
-
|
|
200
|
+
### Create a resource
|
|
184
201
|
|
|
185
202
|
Resources are definitions of data collections.
|
|
186
203
|
|
|
@@ -200,13 +217,13 @@ const attributes = {
|
|
|
200
217
|
},
|
|
201
218
|
};
|
|
202
219
|
|
|
203
|
-
await s3db.createResource({
|
|
204
|
-
|
|
220
|
+
const resource = await s3db.createResource({
|
|
221
|
+
name: "leads",
|
|
205
222
|
attributes,
|
|
206
223
|
});
|
|
207
224
|
```
|
|
208
225
|
|
|
209
|
-
Resources' names **cannot** prefix each other, like: `leads` and `leads-copy`! S3's api
|
|
226
|
+
Resources' names **cannot** prefix each other, like: `leads` and `leads-copy`! S3's api lists keys using prefix notation, so every time you list `leads`, all keys of `leads-copy` will appear as well.
|
|
210
227
|
|
|
211
228
|
##### Attributes
|
|
212
229
|
|
|
@@ -240,11 +257,19 @@ const attributes = {
|
|
|
240
257
|
};
|
|
241
258
|
```
|
|
242
259
|
|
|
260
|
+
##### Reference:
|
|
261
|
+
|
|
262
|
+
You may just use the reference:
|
|
263
|
+
|
|
264
|
+
```javascript
|
|
265
|
+
const Leads = s3db.resource("leads");
|
|
266
|
+
```
|
|
267
|
+
|
|
243
268
|
##### Limitations:
|
|
244
269
|
|
|
245
270
|
As we need to store the resource definition within a JSON file, to keep your definitions intact the best way is to use the [string-based shorthand definitions](https://github.com/icebob/fastest-validator#shorthand-definitions) in your resource definition.
|
|
246
271
|
|
|
247
|
-
By design,
|
|
272
|
+
By design, the resource definition **will will strip all functions** in attributes to avoid `eval()` calls.
|
|
248
273
|
|
|
249
274
|
The `fastest-validator` starts with the params below:
|
|
250
275
|
|
|
@@ -260,15 +285,9 @@ The `fastest-validator` starts with the params below:
|
|
|
260
285
|
}
|
|
261
286
|
```
|
|
262
287
|
|
|
263
|
-
|
|
288
|
+
---
|
|
264
289
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
```javascript
|
|
268
|
-
const Leads = s3db.resource("leads");
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
### Resources methods
|
|
290
|
+
## Resources methods
|
|
272
291
|
|
|
273
292
|
Consider `resource` as:
|
|
274
293
|
|
|
@@ -276,11 +295,11 @@ Consider `resource` as:
|
|
|
276
295
|
const resource = s3db.resource("leads");
|
|
277
296
|
```
|
|
278
297
|
|
|
279
|
-
|
|
298
|
+
### Insert one
|
|
280
299
|
|
|
281
300
|
```javascript
|
|
282
301
|
// data
|
|
283
|
-
const
|
|
302
|
+
const insertedData = await resource.insert({
|
|
284
303
|
id: "mypersonal@email.com", // if not defined a id will be generated!
|
|
285
304
|
utm: {
|
|
286
305
|
source: "abc",
|
|
@@ -291,44 +310,28 @@ const data = {
|
|
|
291
310
|
mobileNumber: "+5511234567890",
|
|
292
311
|
},
|
|
293
312
|
invalidAttr: "this attribute will disappear",
|
|
294
|
-
};
|
|
313
|
+
});
|
|
295
314
|
|
|
296
|
-
|
|
315
|
+
// {
|
|
316
|
+
// id: "mypersonal@email.com",
|
|
317
|
+
// utm: {
|
|
318
|
+
// source: "abc",
|
|
319
|
+
// },
|
|
320
|
+
// lead: {
|
|
321
|
+
// fullName: "My Complex Name",
|
|
322
|
+
// personalEmail: "mypersonal@email.com",
|
|
323
|
+
// mobileNumber: "+5511234567890",
|
|
324
|
+
// },
|
|
325
|
+
// invalidAttr: "this attribute will disappear",
|
|
326
|
+
// }
|
|
297
327
|
```
|
|
298
328
|
|
|
299
329
|
If not defined an id attribute, `s3db.js` will use [`nanoid`](https://github.com/ai/nanoid) to generate a random unique id!
|
|
300
330
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
You may bulk insert data with a friendly method.
|
|
304
|
-
|
|
305
|
-
This method uses [`supercharge/promise-pool`](https://github.com/supercharge/promise-pool) to organize the parallelism of your promises.
|
|
331
|
+
### Get one
|
|
306
332
|
|
|
307
333
|
```javascript
|
|
308
|
-
const
|
|
309
|
-
parallelism: 10, // default
|
|
310
|
-
});
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
Bulk insert:
|
|
314
|
-
|
|
315
|
-
```javascript
|
|
316
|
-
const objects = new Array(100).fill(0).map((v, k) => ({
|
|
317
|
-
id: `bulk-${k}@mymail.com`,
|
|
318
|
-
lead: {
|
|
319
|
-
fullName: "My Test Name",
|
|
320
|
-
personalEmail: `bulk-${k}@mymail.com`,
|
|
321
|
-
mobileNumber: "+55 11 1234567890",
|
|
322
|
-
},
|
|
323
|
-
}));
|
|
324
|
-
|
|
325
|
-
await resource.bulkInsert(objects);
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
#### Get
|
|
329
|
-
|
|
330
|
-
```javascript
|
|
331
|
-
const obj = await resource.getById("mypersonal@email.com");
|
|
334
|
+
const obj = await resource.get("mypersonal@email.com");
|
|
332
335
|
|
|
333
336
|
// {
|
|
334
337
|
// id: "mypersonal@email.com",
|
|
@@ -343,11 +346,12 @@ const obj = await resource.getById("mypersonal@email.com");
|
|
|
343
346
|
// }
|
|
344
347
|
```
|
|
345
348
|
|
|
346
|
-
|
|
349
|
+
### Update one
|
|
347
350
|
|
|
348
351
|
```javascript
|
|
349
|
-
const obj = await resource.
|
|
352
|
+
const obj = await resource.update("mypersonal@email.com", {
|
|
350
353
|
lead: {
|
|
354
|
+
fullName: "My New Name",
|
|
351
355
|
mobileNumber: "+5511999999999",
|
|
352
356
|
},
|
|
353
357
|
});
|
|
@@ -358,20 +362,20 @@ const obj = await resource.updateById("mypersonal@email.com", {
|
|
|
358
362
|
// source: "abc",
|
|
359
363
|
// },
|
|
360
364
|
// lead: {
|
|
361
|
-
// fullName: "My
|
|
365
|
+
// fullName: "My New Name",
|
|
362
366
|
// personalEmail: "mypersonal@email.com",
|
|
363
367
|
// mobileNumber: "+5511999999999",
|
|
364
368
|
// },
|
|
365
369
|
// }
|
|
366
370
|
```
|
|
367
371
|
|
|
368
|
-
|
|
372
|
+
### Delete one
|
|
369
373
|
|
|
370
374
|
```javascript
|
|
371
|
-
await resource.
|
|
375
|
+
await resource.delete(id);
|
|
372
376
|
```
|
|
373
377
|
|
|
374
|
-
|
|
378
|
+
### Count
|
|
375
379
|
|
|
376
380
|
```javascript
|
|
377
381
|
await resource.count();
|
|
@@ -379,38 +383,88 @@ await resource.count();
|
|
|
379
383
|
// 101
|
|
380
384
|
```
|
|
381
385
|
|
|
382
|
-
|
|
386
|
+
### Insert many
|
|
387
|
+
|
|
388
|
+
You may bulk insert data with a friendly method that receives a list of objects.
|
|
389
|
+
|
|
390
|
+
```javascript
|
|
391
|
+
const objects = new Array(100).fill(0).map((v, k) => ({
|
|
392
|
+
id: `bulk-${k}@mymail.com`,
|
|
393
|
+
lead: {
|
|
394
|
+
fullName: "My Test Name",
|
|
395
|
+
personalEmail: `bulk-${k}@mymail.com`,
|
|
396
|
+
mobileNumber: "+55 11 1234567890",
|
|
397
|
+
},
|
|
398
|
+
}));
|
|
399
|
+
|
|
400
|
+
await resource.insertMany(objects);
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
Keep in mind that we need to send a request to each object to be created. There is an option to change the amount of simultaneos connections that your client will handle.
|
|
383
404
|
|
|
384
405
|
```javascript
|
|
385
|
-
|
|
406
|
+
const s3db = new S3db({
|
|
407
|
+
parallelism: 100, // default = 10
|
|
408
|
+
});
|
|
386
409
|
```
|
|
387
410
|
|
|
388
|
-
|
|
411
|
+
This method uses [`supercharge/promise-pool`](https://github.com/supercharge/promise-pool) to organize the parallel promises.
|
|
412
|
+
|
|
413
|
+
### Get many
|
|
389
414
|
|
|
390
415
|
```javascript
|
|
391
|
-
|
|
416
|
+
await resource.getMany(["id1", "id2", "id3 "]);
|
|
417
|
+
|
|
392
418
|
// [
|
|
393
|
-
//
|
|
394
|
-
//
|
|
395
|
-
//
|
|
419
|
+
// obj1,
|
|
420
|
+
// obj2,
|
|
421
|
+
// obj3,
|
|
422
|
+
// ]
|
|
423
|
+
```
|
|
424
|
+
|
|
425
|
+
### Get all
|
|
426
|
+
|
|
427
|
+
```javascript
|
|
428
|
+
const data = await resource.getAll();
|
|
429
|
+
|
|
430
|
+
// [
|
|
431
|
+
// obj1,
|
|
432
|
+
// obj2,
|
|
433
|
+
// ...
|
|
396
434
|
// ]
|
|
397
435
|
```
|
|
398
436
|
|
|
399
|
-
|
|
437
|
+
### Delete many
|
|
438
|
+
|
|
439
|
+
```javascript
|
|
440
|
+
await resource.deleteMany(["id1", "id2", "id3 "]);
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
### Delete all
|
|
400
444
|
|
|
401
445
|
```javascript
|
|
402
446
|
await resource.deleteAll();
|
|
403
447
|
```
|
|
404
448
|
|
|
405
|
-
|
|
449
|
+
### List ids
|
|
406
450
|
|
|
407
451
|
```javascript
|
|
408
|
-
const
|
|
452
|
+
const ids = await resource.listIds();
|
|
453
|
+
|
|
454
|
+
// [
|
|
455
|
+
// 'id1',
|
|
456
|
+
// 'id2',
|
|
457
|
+
// 'id3',
|
|
458
|
+
// ]
|
|
409
459
|
```
|
|
410
460
|
|
|
411
|
-
|
|
461
|
+
---
|
|
412
462
|
|
|
413
|
-
|
|
463
|
+
## Resource streams
|
|
464
|
+
|
|
465
|
+
As we need to request the metadata for each id to return it's attributes, a better way to handle a huge amount off data might be using streams.
|
|
466
|
+
|
|
467
|
+
### Readable stream
|
|
414
468
|
|
|
415
469
|
```javascript
|
|
416
470
|
const readableStream = await resource.readable();
|
|
@@ -420,7 +474,7 @@ readableStream.on("data", (lead) => console.log("lead.id =", lead.id));
|
|
|
420
474
|
readableStream.on("end", console.log("end"));
|
|
421
475
|
```
|
|
422
476
|
|
|
423
|
-
|
|
477
|
+
### Writable stream
|
|
424
478
|
|
|
425
479
|
```javascript
|
|
426
480
|
const writableStream = await resource.writable();
|
|
@@ -434,178 +488,317 @@ writableStream.write({
|
|
|
434
488
|
});
|
|
435
489
|
```
|
|
436
490
|
|
|
437
|
-
|
|
491
|
+
---
|
|
492
|
+
|
|
493
|
+
## S3 Client
|
|
494
|
+
|
|
495
|
+
`s3db.js` has a S3 proxied client named [`S3Client`](https://github.com/forattini-dev/s3db.js/blob/main/src/s3-client.class.ts). It brings a few handy and less verbose functions to deal with AWS S3's api.
|
|
496
|
+
|
|
497
|
+
```javascript
|
|
498
|
+
import { S3Client } from "s3db.js";
|
|
438
499
|
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
- resource.created
|
|
442
|
-
- resource.inserted
|
|
443
|
-
- resource.deleted
|
|
444
|
-
- error
|
|
445
|
-
1. client
|
|
446
|
-
- action
|
|
447
|
-
- error
|
|
448
|
-
1. resource
|
|
449
|
-
- id
|
|
450
|
-
- inserted
|
|
451
|
-
- deleted
|
|
452
|
-
- error
|
|
453
|
-
1. stream
|
|
454
|
-
- resource.id
|
|
455
|
-
- resource.data
|
|
456
|
-
- error
|
|
500
|
+
const client = new S3Client({ connectionString });
|
|
501
|
+
```
|
|
457
502
|
|
|
458
|
-
|
|
503
|
+
Each method has a **[:link:](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html) link** to the official `aws-sdk` docs.
|
|
459
504
|
|
|
460
|
-
#####
|
|
505
|
+
##### getObject [:link:](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#getObject-property)
|
|
461
506
|
|
|
462
507
|
```javascript
|
|
463
|
-
|
|
508
|
+
const { Body, Metadata } = await client.getObject({
|
|
509
|
+
key: `my-prefixed-file.csv`,
|
|
510
|
+
});
|
|
511
|
+
|
|
512
|
+
// AWS.Response
|
|
464
513
|
```
|
|
465
514
|
|
|
466
|
-
#####
|
|
515
|
+
##### putObject [:link:](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property)
|
|
467
516
|
|
|
468
517
|
```javascript
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
518
|
+
const response = await client.putObject({
|
|
519
|
+
key: `my-prefixed-file.csv`,
|
|
520
|
+
contentType: "text/csv",
|
|
521
|
+
metadata: { a: "1", b: "2", c: "3" },
|
|
522
|
+
body: "a;b;c\n1;2;3\n4;5;6",
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
// AWS.Response
|
|
472
526
|
```
|
|
473
527
|
|
|
474
|
-
#####
|
|
528
|
+
##### headObject [:link:](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#headObject-property)
|
|
475
529
|
|
|
476
530
|
```javascript
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
);
|
|
531
|
+
const { Metadata } = await client.headObject({
|
|
532
|
+
key: `my-prefixed-file.csv`,
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
// AWS.Response
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
##### deleteObject [:link:](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#deleteObject-property)
|
|
539
|
+
|
|
540
|
+
```javascript
|
|
541
|
+
const response = await client.deleteObject({
|
|
542
|
+
key: `my-prefixed-file.csv`,
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
// AWS.Response
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
##### deleteObjects [:link:](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#deleteObjects-property)
|
|
549
|
+
|
|
550
|
+
```javascript
|
|
551
|
+
const response = await client.deleteObjects({
|
|
552
|
+
keys: [`my-prefixed-file.csv`, `my-other-prefixed-file.csv`],
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
// AWS.Response
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
##### listObjects [:link:](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#listObjects-property)
|
|
559
|
+
|
|
560
|
+
```javascript
|
|
561
|
+
const response = await client.listObjects({
|
|
562
|
+
prefix: `my-subdir`,
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
// AWS.Response
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
##### count
|
|
569
|
+
|
|
570
|
+
Custom made method to make it easier to count keys within a listObjects loop.
|
|
571
|
+
|
|
572
|
+
```javascript
|
|
573
|
+
const count = await client.count({
|
|
574
|
+
prefix: `my-subdir`,
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
// 10
|
|
480
578
|
```
|
|
481
579
|
|
|
482
|
-
#####
|
|
580
|
+
##### getAllKeys
|
|
581
|
+
|
|
582
|
+
Custom made method to make it easier to return all keys in a subpath within a listObjects loop.
|
|
583
|
+
|
|
584
|
+
All returned keys will have the it's fullpath replaced with the current "scope" path.
|
|
483
585
|
|
|
484
586
|
```javascript
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
);
|
|
587
|
+
const keys = await client.getAllKeys({
|
|
588
|
+
prefix: `my-subdir`,
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
// [
|
|
592
|
+
// key1,
|
|
593
|
+
// key2,
|
|
594
|
+
// ...
|
|
595
|
+
// ]
|
|
488
596
|
```
|
|
489
597
|
|
|
490
|
-
|
|
598
|
+
---
|
|
599
|
+
|
|
600
|
+
## Events
|
|
601
|
+
|
|
602
|
+
The 3 main classes `S3db`, `Resource` and `S3Client` are extensions of Javascript's `EventEmitter`.
|
|
603
|
+
|
|
604
|
+
| S3Database | S3Client | S3Resource | S3Resource Readable Stream |
|
|
605
|
+
| ---------- | ------------- | ---------- | -------------------------- |
|
|
606
|
+
| error | error | error | error |
|
|
607
|
+
| connected | request | insert | id |
|
|
608
|
+
| | response | get | data |
|
|
609
|
+
| | response | update | |
|
|
610
|
+
| | getObject | delete | |
|
|
611
|
+
| | putObject | count | |
|
|
612
|
+
| | headObject | insertMany | |
|
|
613
|
+
| | deleteObject | deleteAll | |
|
|
614
|
+
| | deleteObjects | listIds | |
|
|
615
|
+
| | listObjects | getMany | |
|
|
616
|
+
| | count | getAll | |
|
|
617
|
+
| | getAllKeys | | |
|
|
618
|
+
|
|
619
|
+
### S3Database
|
|
620
|
+
|
|
621
|
+
#### error
|
|
491
622
|
|
|
492
623
|
```javascript
|
|
493
624
|
s3db.on("error", (error) => console.error(error));
|
|
494
625
|
```
|
|
495
626
|
|
|
496
|
-
####
|
|
627
|
+
#### connected
|
|
628
|
+
|
|
629
|
+
```javascript
|
|
630
|
+
s3db.on("connected", () => {});
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
### S3Client
|
|
497
634
|
|
|
498
|
-
|
|
635
|
+
Using this reference for the events:
|
|
499
636
|
|
|
500
637
|
```javascript
|
|
501
|
-
s3db.client
|
|
502
|
-
console.log(`resource ${resourceName} created`)
|
|
503
|
-
);
|
|
638
|
+
const client = s3db.client;
|
|
504
639
|
```
|
|
505
640
|
|
|
506
|
-
|
|
641
|
+
#### error
|
|
507
642
|
|
|
508
643
|
```javascript
|
|
509
|
-
|
|
644
|
+
client.on("error", (error) => console.error(error));
|
|
510
645
|
```
|
|
511
646
|
|
|
512
|
-
####
|
|
647
|
+
#### request
|
|
513
648
|
|
|
514
|
-
|
|
649
|
+
Emitted when a request is generated to AWS.
|
|
515
650
|
|
|
516
651
|
```javascript
|
|
517
|
-
|
|
652
|
+
client.on("request", (action, params) => {});
|
|
653
|
+
```
|
|
654
|
+
|
|
655
|
+
#### response
|
|
656
|
+
|
|
657
|
+
Emitted when a response is received from AWS.
|
|
518
658
|
|
|
519
|
-
|
|
659
|
+
```javascript
|
|
660
|
+
client.on("response", (action, params, response) => {});
|
|
520
661
|
```
|
|
521
662
|
|
|
522
|
-
####
|
|
663
|
+
#### getObject
|
|
523
664
|
|
|
524
665
|
```javascript
|
|
525
|
-
|
|
666
|
+
client.on("getObject", (options, response) => {});
|
|
667
|
+
```
|
|
526
668
|
|
|
527
|
-
|
|
669
|
+
#### putObject
|
|
670
|
+
|
|
671
|
+
```javascript
|
|
672
|
+
client.on("putObject", (options, response) => {});
|
|
528
673
|
```
|
|
529
674
|
|
|
530
|
-
|
|
675
|
+
#### headObject
|
|
531
676
|
|
|
532
|
-
|
|
677
|
+
```javascript
|
|
678
|
+
client.on("headObject", (options, response) => {});
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
#### deleteObject
|
|
533
682
|
|
|
534
683
|
```javascript
|
|
535
|
-
|
|
684
|
+
client.on("deleteObject", (options, response) => {});
|
|
685
|
+
```
|
|
536
686
|
|
|
537
|
-
|
|
687
|
+
#### deleteObjects
|
|
688
|
+
|
|
689
|
+
```javascript
|
|
690
|
+
client.on("deleteObjects", (options, response) => {});
|
|
538
691
|
```
|
|
539
692
|
|
|
540
|
-
|
|
693
|
+
#### listObjects
|
|
541
694
|
|
|
542
695
|
```javascript
|
|
543
|
-
|
|
544
|
-
key: `my-prefixed-file.csv`,
|
|
545
|
-
});
|
|
696
|
+
client.on("listObjects", (options, response) => {});
|
|
546
697
|
```
|
|
547
698
|
|
|
548
|
-
|
|
699
|
+
#### count
|
|
549
700
|
|
|
550
701
|
```javascript
|
|
551
|
-
|
|
552
|
-
key: `my-prefixed-file.csv`,
|
|
553
|
-
contentType: "text/csv",
|
|
554
|
-
metadata: { a: "1", b: "2", c: "3" },
|
|
555
|
-
body: "a;b;c\n1;2;3\n4;5;6",
|
|
556
|
-
});
|
|
702
|
+
client.on("count", (options, response) => {});
|
|
557
703
|
```
|
|
558
704
|
|
|
559
|
-
|
|
705
|
+
#### getAllKeys
|
|
560
706
|
|
|
561
707
|
```javascript
|
|
562
|
-
|
|
563
|
-
key: `my-prefixed-file.csv`,
|
|
564
|
-
});
|
|
708
|
+
client.on("getAllKeys", (options, response) => {});
|
|
565
709
|
```
|
|
566
710
|
|
|
567
|
-
|
|
711
|
+
### S3Resource
|
|
712
|
+
|
|
713
|
+
Using this reference for the events:
|
|
568
714
|
|
|
569
715
|
```javascript
|
|
570
|
-
const
|
|
571
|
-
key: `my-prefixed-file.csv`,
|
|
572
|
-
});
|
|
716
|
+
const resource = s3db.resource("leads");
|
|
573
717
|
```
|
|
574
718
|
|
|
575
|
-
|
|
719
|
+
#### error
|
|
576
720
|
|
|
577
721
|
```javascript
|
|
578
|
-
|
|
579
|
-
keys: [`my-prefixed-file.csv`, `my-other-prefixed-file.csv`],
|
|
580
|
-
});
|
|
722
|
+
resource.on("error", (err) => console.error(err));
|
|
581
723
|
```
|
|
582
724
|
|
|
583
|
-
|
|
725
|
+
#### insert
|
|
584
726
|
|
|
585
727
|
```javascript
|
|
586
|
-
|
|
587
|
-
prefix: `my-subdir`,
|
|
588
|
-
});
|
|
728
|
+
resource.on("insert", (data) => {});
|
|
589
729
|
```
|
|
590
730
|
|
|
591
|
-
|
|
731
|
+
#### get
|
|
592
732
|
|
|
593
733
|
```javascript
|
|
594
|
-
|
|
595
|
-
prefix: `my-subdir`,
|
|
596
|
-
});
|
|
734
|
+
resource.on("get", (data) => {});
|
|
597
735
|
```
|
|
598
736
|
|
|
599
|
-
|
|
737
|
+
#### update
|
|
600
738
|
|
|
601
|
-
|
|
739
|
+
```javascript
|
|
740
|
+
resource.on("update", (attrs, data) => {});
|
|
741
|
+
```
|
|
742
|
+
|
|
743
|
+
#### delete
|
|
602
744
|
|
|
603
745
|
```javascript
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
746
|
+
resource.on("delete", (id) => {});
|
|
747
|
+
```
|
|
748
|
+
|
|
749
|
+
#### count
|
|
750
|
+
|
|
751
|
+
```javascript
|
|
752
|
+
resource.on("count", (count) => {});
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
#### insertMany
|
|
756
|
+
|
|
757
|
+
```javascript
|
|
758
|
+
resource.on("insertMany", (count) => {});
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
#### getMany
|
|
762
|
+
|
|
763
|
+
```javascript
|
|
764
|
+
resource.on("getMany", (count) => {});
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
#### getAll
|
|
768
|
+
|
|
769
|
+
```javascript
|
|
770
|
+
resource.on("getAll", (count) => {});
|
|
771
|
+
```
|
|
772
|
+
|
|
773
|
+
#### deleteAll
|
|
774
|
+
|
|
775
|
+
```javascript
|
|
776
|
+
resource.on("deleteAll", (count) => {});
|
|
777
|
+
```
|
|
778
|
+
|
|
779
|
+
#### listIds
|
|
780
|
+
|
|
781
|
+
```javascript
|
|
782
|
+
resource.on("listIds", (count) => {});
|
|
607
783
|
```
|
|
608
784
|
|
|
785
|
+
---
|
|
786
|
+
|
|
787
|
+
## Plugins
|
|
788
|
+
|
|
789
|
+
Anatomy of a plugin:
|
|
790
|
+
|
|
791
|
+
```javascript
|
|
792
|
+
const MyPlugin = {
|
|
793
|
+
setup(s3db: S3db) {},
|
|
794
|
+
start() {},
|
|
795
|
+
};
|
|
796
|
+
```
|
|
797
|
+
|
|
798
|
+
We have an example of a _costs simulator plugin_ [here!](https://github.com/forattini-dev/s3db.js/blob/main/src/plugins/costs.plugin.js)
|
|
799
|
+
|
|
800
|
+
---
|
|
801
|
+
|
|
609
802
|
## Examples
|
|
610
803
|
|
|
611
804
|
The processing power here was not the priority, just used my little nodebook Dell XPS. Check the `./examples` directory to get some ideas on how to use this package and the code of the examples below.
|
|
@@ -784,7 +977,7 @@ Lets save some JWT tokens using the [RFC:7519](https://www.rfc-editor.org/rfc/rf
|
|
|
784
977
|
|
|
785
978
|
```javascript
|
|
786
979
|
await s3db.createResource({
|
|
787
|
-
|
|
980
|
+
name: "tokens",
|
|
788
981
|
attributes: {
|
|
789
982
|
iss: 'url|max:256',
|
|
790
983
|
sub: 'string',
|
|
@@ -818,3 +1011,9 @@ function validateToken (token) {
|
|
|
818
1011
|
return resource.getById(id)
|
|
819
1012
|
}
|
|
820
1013
|
```
|
|
1014
|
+
|
|
1015
|
+
## Roadmap
|
|
1016
|
+
|
|
1017
|
+
Tasks board can be found at [this link](https://github.com/orgs/forattini-dev/projects/5/views/1)!
|
|
1018
|
+
|
|
1019
|
+
Feel free to interact and PRs are welcome! :)
|