@twin.org/entity-storage-connector-gcp-firestore 0.0.1 → 0.0.2-next.10
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 +1 -1
- package/dist/cjs/index.cjs +33 -34
- package/dist/esm/index.mjs +34 -35
- package/dist/types/firestoreEntityStorageConnector.d.ts +6 -6
- package/dist/types/models/IFirestoreEntityStorageConnectorConfig.d.ts +1 -1
- package/dist/types/models/IFirestoreEntityStorageConnectorConstructorOptions.d.ts +2 -2
- package/docs/changelog.md +169 -0
- package/docs/reference/classes/FirestoreEntityStorageConnector.md +7 -11
- package/docs/reference/interfaces/IFirestoreEntityStorageConnectorConfig.md +1 -1
- package/docs/reference/interfaces/IFirestoreEntityStorageConnectorConstructorOptions.md +3 -3
- package/locales/en.json +1 -5
- package/package.json +27 -8
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@ npm install @twin.org/entity-storage-connector-gcp-firestore
|
|
|
13
13
|
The tests developed are functional tests and need an instance of Firestore up and running. To run Firestore locally:
|
|
14
14
|
|
|
15
15
|
```sh
|
|
16
|
-
docker run -d --name twin-entity-storage-firestore -p
|
|
16
|
+
docker run -d --name twin-entity-storage-firestore -p 8580:8080 gcr.io/google.com/cloudsdktool/cloud-sdk:emulators gcloud beta emulators firestore start --host-port=0.0.0.0:8080
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
Afterwards you can run the tests as follows:
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
var firestore = require('@google-cloud/firestore');
|
|
4
4
|
var core = require('@twin.org/core');
|
|
5
5
|
var entity = require('@twin.org/entity');
|
|
6
|
-
var loggingModels = require('@twin.org/logging-models');
|
|
7
6
|
|
|
8
7
|
// Copyright 2024 IOTA Stiftung.
|
|
9
8
|
// SPDX-License-Identifier: Apache-2.0.
|
|
@@ -12,14 +11,14 @@ var loggingModels = require('@twin.org/logging-models');
|
|
|
12
11
|
*/
|
|
13
12
|
class FirestoreEntityStorageConnector {
|
|
14
13
|
/**
|
|
15
|
-
*
|
|
16
|
-
* @internal
|
|
14
|
+
* Runtime name for the class.
|
|
17
15
|
*/
|
|
18
|
-
static
|
|
16
|
+
static CLASS_NAME = "FirestoreEntityStorageConnector";
|
|
19
17
|
/**
|
|
20
|
-
*
|
|
18
|
+
* Limit the number of entities when finding.
|
|
19
|
+
* @internal
|
|
21
20
|
*/
|
|
22
|
-
|
|
21
|
+
static _DEFAULT_LIMIT = 40;
|
|
23
22
|
/**
|
|
24
23
|
* The schema for the entity.
|
|
25
24
|
* @internal
|
|
@@ -50,14 +49,14 @@ class FirestoreEntityStorageConnector {
|
|
|
50
49
|
* @param options The options for the connector.
|
|
51
50
|
*/
|
|
52
51
|
constructor(options) {
|
|
53
|
-
core.Guards.object(
|
|
54
|
-
core.Guards.stringValue(
|
|
55
|
-
core.Guards.object(
|
|
56
|
-
core.Guards.stringValue(
|
|
57
|
-
core.Guards.stringValue(
|
|
52
|
+
core.Guards.object(FirestoreEntityStorageConnector.CLASS_NAME, "options", options);
|
|
53
|
+
core.Guards.stringValue(FirestoreEntityStorageConnector.CLASS_NAME, "options.entitySchema", options.entitySchema);
|
|
54
|
+
core.Guards.object(FirestoreEntityStorageConnector.CLASS_NAME, "options.config", options.config);
|
|
55
|
+
core.Guards.stringValue(FirestoreEntityStorageConnector.CLASS_NAME, "options.config.projectId", options.config.projectId);
|
|
56
|
+
core.Guards.stringValue(FirestoreEntityStorageConnector.CLASS_NAME, "options.config.collectionName", options.config.collectionName);
|
|
58
57
|
let credentials;
|
|
59
58
|
if (!core.Is.empty(options.config.credentials)) {
|
|
60
|
-
core.Guards.stringBase64(
|
|
59
|
+
core.Guards.stringBase64(FirestoreEntityStorageConnector.CLASS_NAME, "options.config.credentials", options.config.credentials);
|
|
61
60
|
credentials = core.ObjectHelper.fromBytes(core.Converter.base64ToBytes(options.config.credentials));
|
|
62
61
|
}
|
|
63
62
|
this._config = options.config;
|
|
@@ -80,15 +79,15 @@ class FirestoreEntityStorageConnector {
|
|
|
80
79
|
}
|
|
81
80
|
/**
|
|
82
81
|
* Bootstrap the component by creating and initializing any resources it needs.
|
|
83
|
-
* @param
|
|
82
|
+
* @param nodeLoggingComponentType The node logging component type.
|
|
84
83
|
* @returns True if the bootstrapping process was successful.
|
|
85
84
|
*/
|
|
86
|
-
async bootstrap(
|
|
87
|
-
const nodeLogging =
|
|
85
|
+
async bootstrap(nodeLoggingComponentType) {
|
|
86
|
+
const nodeLogging = core.ComponentFactory.getIfExists(nodeLoggingComponentType);
|
|
88
87
|
try {
|
|
89
88
|
await nodeLogging?.log({
|
|
90
89
|
level: "info",
|
|
91
|
-
source:
|
|
90
|
+
source: FirestoreEntityStorageConnector.CLASS_NAME,
|
|
92
91
|
ts: Date.now(),
|
|
93
92
|
message: "firestoreCreating",
|
|
94
93
|
data: {
|
|
@@ -103,7 +102,7 @@ class FirestoreEntityStorageConnector {
|
|
|
103
102
|
await testDoc.delete();
|
|
104
103
|
await nodeLogging?.log({
|
|
105
104
|
level: "info",
|
|
106
|
-
source:
|
|
105
|
+
source: FirestoreEntityStorageConnector.CLASS_NAME,
|
|
107
106
|
ts: Date.now(),
|
|
108
107
|
message: "firestoreCreated",
|
|
109
108
|
data: {
|
|
@@ -116,7 +115,7 @@ class FirestoreEntityStorageConnector {
|
|
|
116
115
|
catch (err) {
|
|
117
116
|
await nodeLogging?.log({
|
|
118
117
|
level: "error",
|
|
119
|
-
source:
|
|
118
|
+
source: FirestoreEntityStorageConnector.CLASS_NAME,
|
|
120
119
|
ts: Date.now(),
|
|
121
120
|
message: "firestoreCreationFailed",
|
|
122
121
|
error: core.BaseError.fromError(err),
|
|
@@ -143,7 +142,7 @@ class FirestoreEntityStorageConnector {
|
|
|
143
142
|
* @returns The object if it can be found or undefined.
|
|
144
143
|
*/
|
|
145
144
|
async get(id, secondaryIndex, conditions) {
|
|
146
|
-
core.Guards.stringValue(
|
|
145
|
+
core.Guards.stringValue(FirestoreEntityStorageConnector.CLASS_NAME, "id", id);
|
|
147
146
|
try {
|
|
148
147
|
if (!core.Is.stringValue(secondaryIndex) && !core.Is.arrayValue(conditions)) {
|
|
149
148
|
const docRef = this._collection.doc(id);
|
|
@@ -172,7 +171,7 @@ class FirestoreEntityStorageConnector {
|
|
|
172
171
|
}
|
|
173
172
|
}
|
|
174
173
|
catch (err) {
|
|
175
|
-
throw new core.GeneralError(
|
|
174
|
+
throw new core.GeneralError(FirestoreEntityStorageConnector.CLASS_NAME, "getEntityFailed", { id }, err);
|
|
176
175
|
}
|
|
177
176
|
}
|
|
178
177
|
/**
|
|
@@ -182,7 +181,7 @@ class FirestoreEntityStorageConnector {
|
|
|
182
181
|
* @returns Nothing.
|
|
183
182
|
*/
|
|
184
183
|
async set(entity$1, conditions) {
|
|
185
|
-
core.Guards.object(
|
|
184
|
+
core.Guards.object(FirestoreEntityStorageConnector.CLASS_NAME, "entity", entity$1);
|
|
186
185
|
entity.EntitySchemaHelper.validateEntity(entity$1, this.getSchema());
|
|
187
186
|
try {
|
|
188
187
|
const id = entity$1[this._primaryKey.property];
|
|
@@ -221,7 +220,7 @@ class FirestoreEntityStorageConnector {
|
|
|
221
220
|
}
|
|
222
221
|
}
|
|
223
222
|
catch (err) {
|
|
224
|
-
throw new core.GeneralError(
|
|
223
|
+
throw new core.GeneralError(FirestoreEntityStorageConnector.CLASS_NAME, "setEntityFailed", { id: entity$1.id }, err);
|
|
225
224
|
}
|
|
226
225
|
}
|
|
227
226
|
/**
|
|
@@ -231,7 +230,7 @@ class FirestoreEntityStorageConnector {
|
|
|
231
230
|
* @returns Nothing.
|
|
232
231
|
*/
|
|
233
232
|
async remove(id, conditions) {
|
|
234
|
-
core.Guards.stringValue(
|
|
233
|
+
core.Guards.stringValue(FirestoreEntityStorageConnector.CLASS_NAME, "id", id);
|
|
235
234
|
try {
|
|
236
235
|
const docRef = this._collection.doc(id);
|
|
237
236
|
if (!core.Is.arrayValue(conditions)) {
|
|
@@ -257,7 +256,7 @@ class FirestoreEntityStorageConnector {
|
|
|
257
256
|
}
|
|
258
257
|
}
|
|
259
258
|
catch (err) {
|
|
260
|
-
throw new core.GeneralError(
|
|
259
|
+
throw new core.GeneralError(FirestoreEntityStorageConnector.CLASS_NAME, "removeEntityFailed", { id }, err);
|
|
261
260
|
}
|
|
262
261
|
}
|
|
263
262
|
/**
|
|
@@ -265,11 +264,11 @@ class FirestoreEntityStorageConnector {
|
|
|
265
264
|
* @param conditions The conditions to match for the entities.
|
|
266
265
|
* @param sortProperties The optional sort order.
|
|
267
266
|
* @param properties The optional properties to return, defaults to all.
|
|
268
|
-
* @param cursor The cursor to request the next
|
|
269
|
-
* @param
|
|
267
|
+
* @param cursor The cursor to request the next chunk of entities.
|
|
268
|
+
* @param limit The suggested number of entities to return in each chunk.
|
|
270
269
|
* @returns The matching entities and a cursor for the next page.
|
|
271
270
|
*/
|
|
272
|
-
async query(conditions, sortProperties, properties, cursor,
|
|
271
|
+
async query(conditions, sortProperties, properties, cursor, limit) {
|
|
273
272
|
const queryDescription = [];
|
|
274
273
|
try {
|
|
275
274
|
let query = this._collection;
|
|
@@ -290,9 +289,9 @@ class FirestoreEntityStorageConnector {
|
|
|
290
289
|
}
|
|
291
290
|
queryDescription.push(`Cursor: ${cursor}`);
|
|
292
291
|
}
|
|
293
|
-
const
|
|
294
|
-
query = query.limit(
|
|
295
|
-
queryDescription.push(`Limit: ${
|
|
292
|
+
const finalLimit = limit ?? FirestoreEntityStorageConnector._DEFAULT_LIMIT;
|
|
293
|
+
query = query.limit(finalLimit);
|
|
294
|
+
queryDescription.push(`Limit: ${finalLimit}`);
|
|
296
295
|
if (properties) {
|
|
297
296
|
query = query.select(...properties);
|
|
298
297
|
queryDescription.push(`Properties: ${properties.join(", ")}`);
|
|
@@ -300,7 +299,7 @@ class FirestoreEntityStorageConnector {
|
|
|
300
299
|
const querySnapshot = await query.get();
|
|
301
300
|
const entities = querySnapshot.docs.map((doc) => doc.data());
|
|
302
301
|
let nextCursor;
|
|
303
|
-
if (entities.length ===
|
|
302
|
+
if (entities.length === finalLimit) {
|
|
304
303
|
nextCursor = querySnapshot.docs[querySnapshot.docs.length - 1].ref.path;
|
|
305
304
|
}
|
|
306
305
|
return {
|
|
@@ -309,7 +308,7 @@ class FirestoreEntityStorageConnector {
|
|
|
309
308
|
};
|
|
310
309
|
}
|
|
311
310
|
catch (err) {
|
|
312
|
-
throw new core.GeneralError(
|
|
311
|
+
throw new core.GeneralError(FirestoreEntityStorageConnector.CLASS_NAME, "queryFailed", { queryDescription: queryDescription.join("; ") }, err);
|
|
313
312
|
}
|
|
314
313
|
}
|
|
315
314
|
/**
|
|
@@ -325,7 +324,7 @@ class FirestoreEntityStorageConnector {
|
|
|
325
324
|
await this.deleteQueryBatch(query, batchSize);
|
|
326
325
|
}
|
|
327
326
|
catch (error) {
|
|
328
|
-
throw new core.GeneralError(
|
|
327
|
+
throw new core.GeneralError(FirestoreEntityStorageConnector.CLASS_NAME, "collectionDeleteFailed", { collectionName: this._config.collectionName }, error);
|
|
329
328
|
}
|
|
330
329
|
}
|
|
331
330
|
/**
|
|
@@ -363,7 +362,7 @@ class FirestoreEntityStorageConnector {
|
|
|
363
362
|
case entity.ComparisonOperator.Includes:
|
|
364
363
|
return query.where(property, "array-contains", value);
|
|
365
364
|
default:
|
|
366
|
-
throw new core.GeneralError(
|
|
365
|
+
throw new core.GeneralError(FirestoreEntityStorageConnector.CLASS_NAME, "unsupportedComparisonOperator", { comparison });
|
|
367
366
|
}
|
|
368
367
|
}
|
|
369
368
|
/**
|
package/dist/esm/index.mjs
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Firestore } from '@google-cloud/firestore';
|
|
2
|
-
import { Guards, Is, ObjectHelper, Converter, BaseError, GeneralError } from '@twin.org/core';
|
|
2
|
+
import { Guards, Is, ObjectHelper, Converter, ComponentFactory, BaseError, GeneralError } from '@twin.org/core';
|
|
3
3
|
import { EntitySchemaFactory, EntitySchemaHelper, SortDirection, ComparisonOperator } from '@twin.org/entity';
|
|
4
|
-
import { LoggingConnectorFactory } from '@twin.org/logging-models';
|
|
5
4
|
|
|
6
5
|
// Copyright 2024 IOTA Stiftung.
|
|
7
6
|
// SPDX-License-Identifier: Apache-2.0.
|
|
@@ -10,14 +9,14 @@ import { LoggingConnectorFactory } from '@twin.org/logging-models';
|
|
|
10
9
|
*/
|
|
11
10
|
class FirestoreEntityStorageConnector {
|
|
12
11
|
/**
|
|
13
|
-
*
|
|
14
|
-
* @internal
|
|
12
|
+
* Runtime name for the class.
|
|
15
13
|
*/
|
|
16
|
-
static
|
|
14
|
+
static CLASS_NAME = "FirestoreEntityStorageConnector";
|
|
17
15
|
/**
|
|
18
|
-
*
|
|
16
|
+
* Limit the number of entities when finding.
|
|
17
|
+
* @internal
|
|
19
18
|
*/
|
|
20
|
-
|
|
19
|
+
static _DEFAULT_LIMIT = 40;
|
|
21
20
|
/**
|
|
22
21
|
* The schema for the entity.
|
|
23
22
|
* @internal
|
|
@@ -48,14 +47,14 @@ class FirestoreEntityStorageConnector {
|
|
|
48
47
|
* @param options The options for the connector.
|
|
49
48
|
*/
|
|
50
49
|
constructor(options) {
|
|
51
|
-
Guards.object(
|
|
52
|
-
Guards.stringValue(
|
|
53
|
-
Guards.object(
|
|
54
|
-
Guards.stringValue(
|
|
55
|
-
Guards.stringValue(
|
|
50
|
+
Guards.object(FirestoreEntityStorageConnector.CLASS_NAME, "options", options);
|
|
51
|
+
Guards.stringValue(FirestoreEntityStorageConnector.CLASS_NAME, "options.entitySchema", options.entitySchema);
|
|
52
|
+
Guards.object(FirestoreEntityStorageConnector.CLASS_NAME, "options.config", options.config);
|
|
53
|
+
Guards.stringValue(FirestoreEntityStorageConnector.CLASS_NAME, "options.config.projectId", options.config.projectId);
|
|
54
|
+
Guards.stringValue(FirestoreEntityStorageConnector.CLASS_NAME, "options.config.collectionName", options.config.collectionName);
|
|
56
55
|
let credentials;
|
|
57
56
|
if (!Is.empty(options.config.credentials)) {
|
|
58
|
-
Guards.stringBase64(
|
|
57
|
+
Guards.stringBase64(FirestoreEntityStorageConnector.CLASS_NAME, "options.config.credentials", options.config.credentials);
|
|
59
58
|
credentials = ObjectHelper.fromBytes(Converter.base64ToBytes(options.config.credentials));
|
|
60
59
|
}
|
|
61
60
|
this._config = options.config;
|
|
@@ -78,15 +77,15 @@ class FirestoreEntityStorageConnector {
|
|
|
78
77
|
}
|
|
79
78
|
/**
|
|
80
79
|
* Bootstrap the component by creating and initializing any resources it needs.
|
|
81
|
-
* @param
|
|
80
|
+
* @param nodeLoggingComponentType The node logging component type.
|
|
82
81
|
* @returns True if the bootstrapping process was successful.
|
|
83
82
|
*/
|
|
84
|
-
async bootstrap(
|
|
85
|
-
const nodeLogging =
|
|
83
|
+
async bootstrap(nodeLoggingComponentType) {
|
|
84
|
+
const nodeLogging = ComponentFactory.getIfExists(nodeLoggingComponentType);
|
|
86
85
|
try {
|
|
87
86
|
await nodeLogging?.log({
|
|
88
87
|
level: "info",
|
|
89
|
-
source:
|
|
88
|
+
source: FirestoreEntityStorageConnector.CLASS_NAME,
|
|
90
89
|
ts: Date.now(),
|
|
91
90
|
message: "firestoreCreating",
|
|
92
91
|
data: {
|
|
@@ -101,7 +100,7 @@ class FirestoreEntityStorageConnector {
|
|
|
101
100
|
await testDoc.delete();
|
|
102
101
|
await nodeLogging?.log({
|
|
103
102
|
level: "info",
|
|
104
|
-
source:
|
|
103
|
+
source: FirestoreEntityStorageConnector.CLASS_NAME,
|
|
105
104
|
ts: Date.now(),
|
|
106
105
|
message: "firestoreCreated",
|
|
107
106
|
data: {
|
|
@@ -114,7 +113,7 @@ class FirestoreEntityStorageConnector {
|
|
|
114
113
|
catch (err) {
|
|
115
114
|
await nodeLogging?.log({
|
|
116
115
|
level: "error",
|
|
117
|
-
source:
|
|
116
|
+
source: FirestoreEntityStorageConnector.CLASS_NAME,
|
|
118
117
|
ts: Date.now(),
|
|
119
118
|
message: "firestoreCreationFailed",
|
|
120
119
|
error: BaseError.fromError(err),
|
|
@@ -141,7 +140,7 @@ class FirestoreEntityStorageConnector {
|
|
|
141
140
|
* @returns The object if it can be found or undefined.
|
|
142
141
|
*/
|
|
143
142
|
async get(id, secondaryIndex, conditions) {
|
|
144
|
-
Guards.stringValue(
|
|
143
|
+
Guards.stringValue(FirestoreEntityStorageConnector.CLASS_NAME, "id", id);
|
|
145
144
|
try {
|
|
146
145
|
if (!Is.stringValue(secondaryIndex) && !Is.arrayValue(conditions)) {
|
|
147
146
|
const docRef = this._collection.doc(id);
|
|
@@ -170,7 +169,7 @@ class FirestoreEntityStorageConnector {
|
|
|
170
169
|
}
|
|
171
170
|
}
|
|
172
171
|
catch (err) {
|
|
173
|
-
throw new GeneralError(
|
|
172
|
+
throw new GeneralError(FirestoreEntityStorageConnector.CLASS_NAME, "getEntityFailed", { id }, err);
|
|
174
173
|
}
|
|
175
174
|
}
|
|
176
175
|
/**
|
|
@@ -180,7 +179,7 @@ class FirestoreEntityStorageConnector {
|
|
|
180
179
|
* @returns Nothing.
|
|
181
180
|
*/
|
|
182
181
|
async set(entity, conditions) {
|
|
183
|
-
Guards.object(
|
|
182
|
+
Guards.object(FirestoreEntityStorageConnector.CLASS_NAME, "entity", entity);
|
|
184
183
|
EntitySchemaHelper.validateEntity(entity, this.getSchema());
|
|
185
184
|
try {
|
|
186
185
|
const id = entity[this._primaryKey.property];
|
|
@@ -219,7 +218,7 @@ class FirestoreEntityStorageConnector {
|
|
|
219
218
|
}
|
|
220
219
|
}
|
|
221
220
|
catch (err) {
|
|
222
|
-
throw new GeneralError(
|
|
221
|
+
throw new GeneralError(FirestoreEntityStorageConnector.CLASS_NAME, "setEntityFailed", { id: entity.id }, err);
|
|
223
222
|
}
|
|
224
223
|
}
|
|
225
224
|
/**
|
|
@@ -229,7 +228,7 @@ class FirestoreEntityStorageConnector {
|
|
|
229
228
|
* @returns Nothing.
|
|
230
229
|
*/
|
|
231
230
|
async remove(id, conditions) {
|
|
232
|
-
Guards.stringValue(
|
|
231
|
+
Guards.stringValue(FirestoreEntityStorageConnector.CLASS_NAME, "id", id);
|
|
233
232
|
try {
|
|
234
233
|
const docRef = this._collection.doc(id);
|
|
235
234
|
if (!Is.arrayValue(conditions)) {
|
|
@@ -255,7 +254,7 @@ class FirestoreEntityStorageConnector {
|
|
|
255
254
|
}
|
|
256
255
|
}
|
|
257
256
|
catch (err) {
|
|
258
|
-
throw new GeneralError(
|
|
257
|
+
throw new GeneralError(FirestoreEntityStorageConnector.CLASS_NAME, "removeEntityFailed", { id }, err);
|
|
259
258
|
}
|
|
260
259
|
}
|
|
261
260
|
/**
|
|
@@ -263,11 +262,11 @@ class FirestoreEntityStorageConnector {
|
|
|
263
262
|
* @param conditions The conditions to match for the entities.
|
|
264
263
|
* @param sortProperties The optional sort order.
|
|
265
264
|
* @param properties The optional properties to return, defaults to all.
|
|
266
|
-
* @param cursor The cursor to request the next
|
|
267
|
-
* @param
|
|
265
|
+
* @param cursor The cursor to request the next chunk of entities.
|
|
266
|
+
* @param limit The suggested number of entities to return in each chunk.
|
|
268
267
|
* @returns The matching entities and a cursor for the next page.
|
|
269
268
|
*/
|
|
270
|
-
async query(conditions, sortProperties, properties, cursor,
|
|
269
|
+
async query(conditions, sortProperties, properties, cursor, limit) {
|
|
271
270
|
const queryDescription = [];
|
|
272
271
|
try {
|
|
273
272
|
let query = this._collection;
|
|
@@ -288,9 +287,9 @@ class FirestoreEntityStorageConnector {
|
|
|
288
287
|
}
|
|
289
288
|
queryDescription.push(`Cursor: ${cursor}`);
|
|
290
289
|
}
|
|
291
|
-
const
|
|
292
|
-
query = query.limit(
|
|
293
|
-
queryDescription.push(`Limit: ${
|
|
290
|
+
const finalLimit = limit ?? FirestoreEntityStorageConnector._DEFAULT_LIMIT;
|
|
291
|
+
query = query.limit(finalLimit);
|
|
292
|
+
queryDescription.push(`Limit: ${finalLimit}`);
|
|
294
293
|
if (properties) {
|
|
295
294
|
query = query.select(...properties);
|
|
296
295
|
queryDescription.push(`Properties: ${properties.join(", ")}`);
|
|
@@ -298,7 +297,7 @@ class FirestoreEntityStorageConnector {
|
|
|
298
297
|
const querySnapshot = await query.get();
|
|
299
298
|
const entities = querySnapshot.docs.map((doc) => doc.data());
|
|
300
299
|
let nextCursor;
|
|
301
|
-
if (entities.length ===
|
|
300
|
+
if (entities.length === finalLimit) {
|
|
302
301
|
nextCursor = querySnapshot.docs[querySnapshot.docs.length - 1].ref.path;
|
|
303
302
|
}
|
|
304
303
|
return {
|
|
@@ -307,7 +306,7 @@ class FirestoreEntityStorageConnector {
|
|
|
307
306
|
};
|
|
308
307
|
}
|
|
309
308
|
catch (err) {
|
|
310
|
-
throw new GeneralError(
|
|
309
|
+
throw new GeneralError(FirestoreEntityStorageConnector.CLASS_NAME, "queryFailed", { queryDescription: queryDescription.join("; ") }, err);
|
|
311
310
|
}
|
|
312
311
|
}
|
|
313
312
|
/**
|
|
@@ -323,7 +322,7 @@ class FirestoreEntityStorageConnector {
|
|
|
323
322
|
await this.deleteQueryBatch(query, batchSize);
|
|
324
323
|
}
|
|
325
324
|
catch (error) {
|
|
326
|
-
throw new GeneralError(
|
|
325
|
+
throw new GeneralError(FirestoreEntityStorageConnector.CLASS_NAME, "collectionDeleteFailed", { collectionName: this._config.collectionName }, error);
|
|
327
326
|
}
|
|
328
327
|
}
|
|
329
328
|
/**
|
|
@@ -361,7 +360,7 @@ class FirestoreEntityStorageConnector {
|
|
|
361
360
|
case ComparisonOperator.Includes:
|
|
362
361
|
return query.where(property, "array-contains", value);
|
|
363
362
|
default:
|
|
364
|
-
throw new GeneralError(
|
|
363
|
+
throw new GeneralError(FirestoreEntityStorageConnector.CLASS_NAME, "unsupportedComparisonOperator", { comparison });
|
|
365
364
|
}
|
|
366
365
|
}
|
|
367
366
|
/**
|
|
@@ -8,7 +8,7 @@ export declare class FirestoreEntityStorageConnector<T = unknown> implements IEn
|
|
|
8
8
|
/**
|
|
9
9
|
* Runtime name for the class.
|
|
10
10
|
*/
|
|
11
|
-
readonly CLASS_NAME: string;
|
|
11
|
+
static readonly CLASS_NAME: string;
|
|
12
12
|
/**
|
|
13
13
|
* Create a new instance of FirestoreEntityStorageConnector.
|
|
14
14
|
* @param options The options for the connector.
|
|
@@ -16,10 +16,10 @@ export declare class FirestoreEntityStorageConnector<T = unknown> implements IEn
|
|
|
16
16
|
constructor(options: IFirestoreEntityStorageConnectorConstructorOptions);
|
|
17
17
|
/**
|
|
18
18
|
* Bootstrap the component by creating and initializing any resources it needs.
|
|
19
|
-
* @param
|
|
19
|
+
* @param nodeLoggingComponentType The node logging component type.
|
|
20
20
|
* @returns True if the bootstrapping process was successful.
|
|
21
21
|
*/
|
|
22
|
-
bootstrap(
|
|
22
|
+
bootstrap(nodeLoggingComponentType?: string): Promise<boolean>;
|
|
23
23
|
/**
|
|
24
24
|
* Get the schema for the entities.
|
|
25
25
|
* @returns The schema for the entities.
|
|
@@ -61,14 +61,14 @@ export declare class FirestoreEntityStorageConnector<T = unknown> implements IEn
|
|
|
61
61
|
* @param conditions The conditions to match for the entities.
|
|
62
62
|
* @param sortProperties The optional sort order.
|
|
63
63
|
* @param properties The optional properties to return, defaults to all.
|
|
64
|
-
* @param cursor The cursor to request the next
|
|
65
|
-
* @param
|
|
64
|
+
* @param cursor The cursor to request the next chunk of entities.
|
|
65
|
+
* @param limit The suggested number of entities to return in each chunk.
|
|
66
66
|
* @returns The matching entities and a cursor for the next page.
|
|
67
67
|
*/
|
|
68
68
|
query(conditions?: EntityCondition<T>, sortProperties?: {
|
|
69
69
|
property: keyof T;
|
|
70
70
|
sortDirection: SortDirection;
|
|
71
|
-
}[], properties?: (keyof T)[], cursor?: string,
|
|
71
|
+
}[], properties?: (keyof T)[], cursor?: string, limit?: number): Promise<{
|
|
72
72
|
/**
|
|
73
73
|
* The entities, which can be partial if a limited keys list was provided.
|
|
74
74
|
*/
|
|
@@ -19,7 +19,7 @@ export interface IFirestoreEntityStorageConnectorConfig {
|
|
|
19
19
|
*/
|
|
20
20
|
credentials?: string;
|
|
21
21
|
/**
|
|
22
|
-
* It's usually only used with an emulator (e.g., "localhost:
|
|
22
|
+
* It's usually only used with an emulator (e.g., "localhost:8580").
|
|
23
23
|
*/
|
|
24
24
|
endpoint?: string;
|
|
25
25
|
/**
|
|
@@ -8,9 +8,9 @@ export interface IFirestoreEntityStorageConnectorConstructorOptions {
|
|
|
8
8
|
*/
|
|
9
9
|
entitySchema: string;
|
|
10
10
|
/**
|
|
11
|
-
* The type of logging
|
|
11
|
+
* The type of logging component to use, defaults to no logging.
|
|
12
12
|
*/
|
|
13
|
-
|
|
13
|
+
loggingComponentType?: string;
|
|
14
14
|
/**
|
|
15
15
|
* The configuration for the connector.
|
|
16
16
|
*/
|
package/docs/changelog.md
CHANGED
|
@@ -1,5 +1,174 @@
|
|
|
1
1
|
# @twin.org/entity-storage-connector-gcp-firestore - Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.2-next.10](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-gcp-firestore-v0.0.2-next.9...entity-storage-connector-gcp-firestore-v0.0.2-next.10) (2025-10-09)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add validate-locales ([e66ef0d](https://github.com/twinfoundation/entity-storage/commit/e66ef0de26ca2f82b3fe89bb5c7a15a0978a9644))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @twin.org/entity-storage-models bumped from 0.0.2-next.9 to 0.0.2-next.10
|
|
16
|
+
* devDependencies
|
|
17
|
+
* @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.9 to 0.0.2-next.10
|
|
18
|
+
|
|
19
|
+
## [0.0.2-next.9](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-gcp-firestore-v0.0.2-next.8...entity-storage-connector-gcp-firestore-v0.0.2-next.9) (2025-10-02)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Miscellaneous Chores
|
|
23
|
+
|
|
24
|
+
* **entity-storage-connector-gcp-firestore:** Synchronize repo versions
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Dependencies
|
|
28
|
+
|
|
29
|
+
* The following workspace dependencies were updated
|
|
30
|
+
* dependencies
|
|
31
|
+
* @twin.org/entity-storage-models bumped from 0.0.2-next.8 to 0.0.2-next.9
|
|
32
|
+
* devDependencies
|
|
33
|
+
* @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.8 to 0.0.2-next.9
|
|
34
|
+
|
|
35
|
+
## [0.0.2-next.8](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-gcp-firestore-v0.0.2-next.7...entity-storage-connector-gcp-firestore-v0.0.2-next.8) (2025-08-29)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
### Features
|
|
39
|
+
|
|
40
|
+
* eslint migration to flat config ([f033b64](https://github.com/twinfoundation/entity-storage/commit/f033b64984c0e6a8129d929c9dd816dcc1b8dab0))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
### Dependencies
|
|
44
|
+
|
|
45
|
+
* The following workspace dependencies were updated
|
|
46
|
+
* dependencies
|
|
47
|
+
* @twin.org/entity-storage-models bumped from 0.0.2-next.7 to 0.0.2-next.8
|
|
48
|
+
* devDependencies
|
|
49
|
+
* @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.7 to 0.0.2-next.8
|
|
50
|
+
|
|
51
|
+
## [0.0.2-next.7](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-gcp-firestore-v0.0.2-next.6...entity-storage-connector-gcp-firestore-v0.0.2-next.7) (2025-08-20)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
### Features
|
|
55
|
+
|
|
56
|
+
* logging naming consistency ([f99d12d](https://github.com/twinfoundation/entity-storage/commit/f99d12dea04b6d4f2b5632ff5473e9ec7d5f9055))
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
### Dependencies
|
|
60
|
+
|
|
61
|
+
* The following workspace dependencies were updated
|
|
62
|
+
* dependencies
|
|
63
|
+
* @twin.org/entity-storage-models bumped from 0.0.2-next.6 to 0.0.2-next.7
|
|
64
|
+
* devDependencies
|
|
65
|
+
* @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.6 to 0.0.2-next.7
|
|
66
|
+
|
|
67
|
+
## [0.0.2-next.6](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-gcp-firestore-v0.0.2-next.5...entity-storage-connector-gcp-firestore-v0.0.2-next.6) (2025-08-19)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
### Features
|
|
71
|
+
|
|
72
|
+
* update framework core ([b59a380](https://github.com/twinfoundation/entity-storage/commit/b59a380bb7fba2b43610f69074dcdee24a4737da))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
### Dependencies
|
|
76
|
+
|
|
77
|
+
* The following workspace dependencies were updated
|
|
78
|
+
* dependencies
|
|
79
|
+
* @twin.org/entity-storage-models bumped from 0.0.2-next.5 to 0.0.2-next.6
|
|
80
|
+
* devDependencies
|
|
81
|
+
* @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.5 to 0.0.2-next.6
|
|
82
|
+
|
|
83
|
+
## [0.0.2-next.5](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-gcp-firestore-v0.0.2-next.4...entity-storage-connector-gcp-firestore-v0.0.2-next.5) (2025-08-11)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
### Miscellaneous Chores
|
|
87
|
+
|
|
88
|
+
* **entity-storage-connector-gcp-firestore:** Synchronize repo versions
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
### Dependencies
|
|
92
|
+
|
|
93
|
+
* The following workspace dependencies were updated
|
|
94
|
+
* dependencies
|
|
95
|
+
* @twin.org/entity-storage-models bumped from 0.0.2-next.4 to 0.0.2-next.5
|
|
96
|
+
* devDependencies
|
|
97
|
+
* @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.4 to 0.0.2-next.5
|
|
98
|
+
|
|
99
|
+
## [0.0.2-next.4](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-gcp-firestore-v0.0.2-next.3...entity-storage-connector-gcp-firestore-v0.0.2-next.4) (2025-08-08)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
### Miscellaneous Chores
|
|
103
|
+
|
|
104
|
+
* **entity-storage-connector-gcp-firestore:** Synchronize repo versions
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
### Dependencies
|
|
108
|
+
|
|
109
|
+
* The following workspace dependencies were updated
|
|
110
|
+
* dependencies
|
|
111
|
+
* @twin.org/entity-storage-models bumped from 0.0.2-next.3 to 0.0.2-next.4
|
|
112
|
+
* devDependencies
|
|
113
|
+
* @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.3 to 0.0.2-next.4
|
|
114
|
+
|
|
115
|
+
## [0.0.2-next.3](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-gcp-firestore-v0.0.2-next.2...entity-storage-connector-gcp-firestore-v0.0.2-next.3) (2025-07-25)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
### Miscellaneous Chores
|
|
119
|
+
|
|
120
|
+
* **entity-storage-connector-gcp-firestore:** Synchronize repo versions
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
### Dependencies
|
|
124
|
+
|
|
125
|
+
* The following workspace dependencies were updated
|
|
126
|
+
* dependencies
|
|
127
|
+
* @twin.org/entity-storage-models bumped from 0.0.2-next.2 to 0.0.2-next.3
|
|
128
|
+
* devDependencies
|
|
129
|
+
* @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.2 to 0.0.2-next.3
|
|
130
|
+
|
|
131
|
+
## [0.0.2-next.2](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-gcp-firestore-v0.0.2-next.1...entity-storage-connector-gcp-firestore-v0.0.2-next.2) (2025-07-24)
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
### Features
|
|
135
|
+
|
|
136
|
+
* synchronised storage ([#44](https://github.com/twinfoundation/entity-storage/issues/44)) ([94e10e2](https://github.com/twinfoundation/entity-storage/commit/94e10e26d1feec801449dc04af7a9757ac7495ff))
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
### Dependencies
|
|
140
|
+
|
|
141
|
+
* The following workspace dependencies were updated
|
|
142
|
+
* dependencies
|
|
143
|
+
* @twin.org/entity-storage-models bumped from 0.0.2-next.1 to 0.0.2-next.2
|
|
144
|
+
* devDependencies
|
|
145
|
+
* @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.1 to 0.0.2-next.2
|
|
146
|
+
|
|
147
|
+
## [0.0.2-next.1](https://github.com/twinfoundation/entity-storage/compare/entity-storage-connector-gcp-firestore-v0.0.2-next.0...entity-storage-connector-gcp-firestore-v0.0.2-next.1) (2025-07-17)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
### Features
|
|
151
|
+
|
|
152
|
+
* Add entity storage connector for GCP Firestore ([#21](https://github.com/twinfoundation/entity-storage/issues/21)) ([10bfbf0](https://github.com/twinfoundation/entity-storage/commit/10bfbf0ba7dfe1e9de14d8059426c370476749d4))
|
|
153
|
+
* add production release automation ([1eb4c8e](https://github.com/twinfoundation/entity-storage/commit/1eb4c8ee3eb099defdfc2d063ae44935276dcae8))
|
|
154
|
+
* CosmosDB Entity Storage Connector ([#20](https://github.com/twinfoundation/entity-storage/issues/20)) ([0ae8371](https://github.com/twinfoundation/entity-storage/commit/0ae8371d81ce7e20c0b0397144499dc3e17ffa0a))
|
|
155
|
+
* update dependencies ([7ccc0c4](https://github.com/twinfoundation/entity-storage/commit/7ccc0c429125d073dc60b3de6cf101abc8cc6cba))
|
|
156
|
+
* use shared store mechanism ([#34](https://github.com/twinfoundation/entity-storage/issues/34)) ([68b6b71](https://github.com/twinfoundation/entity-storage/commit/68b6b71e7a96d7d016cd57bfff36775b56bf3f93))
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
### Bug Fixes
|
|
160
|
+
|
|
161
|
+
* query params force coercion ([dd6aa87](https://github.com/twinfoundation/entity-storage/commit/dd6aa87efdfb60bab7d6756a86888863c45c51a7))
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
### Dependencies
|
|
165
|
+
|
|
166
|
+
* The following workspace dependencies were updated
|
|
167
|
+
* dependencies
|
|
168
|
+
* @twin.org/entity-storage-models bumped from 0.0.2-next.0 to 0.0.2-next.1
|
|
169
|
+
* devDependencies
|
|
170
|
+
* @twin.org/entity-storage-connector-memory bumped from 0.0.2-next.0 to 0.0.2-next.1
|
|
171
|
+
|
|
3
172
|
## 0.0.1 (2025-07-04)
|
|
4
173
|
|
|
5
174
|
|
|
@@ -36,29 +36,25 @@ The options for the connector.
|
|
|
36
36
|
|
|
37
37
|
### CLASS\_NAME
|
|
38
38
|
|
|
39
|
-
> `readonly` **CLASS\_NAME**: `string`
|
|
39
|
+
> `readonly` `static` **CLASS\_NAME**: `string`
|
|
40
40
|
|
|
41
41
|
Runtime name for the class.
|
|
42
42
|
|
|
43
|
-
#### Implementation of
|
|
44
|
-
|
|
45
|
-
`IEntityStorageConnector.CLASS_NAME`
|
|
46
|
-
|
|
47
43
|
## Methods
|
|
48
44
|
|
|
49
45
|
### bootstrap()
|
|
50
46
|
|
|
51
|
-
> **bootstrap**(`
|
|
47
|
+
> **bootstrap**(`nodeLoggingComponentType?`): `Promise`\<`boolean`\>
|
|
52
48
|
|
|
53
49
|
Bootstrap the component by creating and initializing any resources it needs.
|
|
54
50
|
|
|
55
51
|
#### Parameters
|
|
56
52
|
|
|
57
|
-
#####
|
|
53
|
+
##### nodeLoggingComponentType?
|
|
58
54
|
|
|
59
55
|
`string`
|
|
60
56
|
|
|
61
|
-
The node logging
|
|
57
|
+
The node logging component type.
|
|
62
58
|
|
|
63
59
|
#### Returns
|
|
64
60
|
|
|
@@ -194,7 +190,7 @@ Nothing.
|
|
|
194
190
|
|
|
195
191
|
### query()
|
|
196
192
|
|
|
197
|
-
> **query**(`conditions?`, `sortProperties?`, `properties?`, `cursor?`, `
|
|
193
|
+
> **query**(`conditions?`, `sortProperties?`, `properties?`, `cursor?`, `limit?`): `Promise`\<\{ `entities`: `Partial`\<`T`\>[]; `cursor?`: `string`; \}\>
|
|
198
194
|
|
|
199
195
|
Find all the entities which match the conditions.
|
|
200
196
|
|
|
@@ -222,9 +218,9 @@ The optional properties to return, defaults to all.
|
|
|
222
218
|
|
|
223
219
|
`string`
|
|
224
220
|
|
|
225
|
-
The cursor to request the next
|
|
221
|
+
The cursor to request the next chunk of entities.
|
|
226
222
|
|
|
227
|
-
#####
|
|
223
|
+
##### limit?
|
|
228
224
|
|
|
229
225
|
`number`
|
|
230
226
|
|
|
@@ -40,7 +40,7 @@ The GCP credentials, a base64 encoded version of the JWTInput data type.
|
|
|
40
40
|
|
|
41
41
|
> `optional` **endpoint**: `string`
|
|
42
42
|
|
|
43
|
-
It's usually only used with an emulator (e.g., "localhost:
|
|
43
|
+
It's usually only used with an emulator (e.g., "localhost:8580").
|
|
44
44
|
|
|
45
45
|
***
|
|
46
46
|
|
|
@@ -12,11 +12,11 @@ The schema for the entity.
|
|
|
12
12
|
|
|
13
13
|
***
|
|
14
14
|
|
|
15
|
-
###
|
|
15
|
+
### loggingComponentType?
|
|
16
16
|
|
|
17
|
-
> `optional` **
|
|
17
|
+
> `optional` **loggingComponentType**: `string`
|
|
18
18
|
|
|
19
|
-
The type of logging
|
|
19
|
+
The type of logging component to use, defaults to no logging.
|
|
20
20
|
|
|
21
21
|
***
|
|
22
22
|
|
package/locales/en.json
CHANGED
|
@@ -13,11 +13,7 @@
|
|
|
13
13
|
"removeEntityFailed": "Failed to remove entity \"{id}\"",
|
|
14
14
|
"queryFailed": "The query failed when issuing the following command \"{queryDescription}\"",
|
|
15
15
|
"collectionDeleteFailed": "Failed to delete collection \"{collectionName}\"",
|
|
16
|
-
"unsupportedComparisonOperator": "Comparison operator \"{comparison}\" is not supported"
|
|
17
|
-
"firestoreClientNotInitialized": "Firestore client not initialized",
|
|
18
|
-
"undefinedProperty": "Property \"{key}\" is undefined. Firestore does not support undefined values.",
|
|
19
|
-
"missingProjectId": "Project ID is required",
|
|
20
|
-
"documentDoesNotExist": "The document with id {id} does not exist."
|
|
16
|
+
"unsupportedComparisonOperator": "Comparison operator \"{comparison}\" is not supported"
|
|
21
17
|
}
|
|
22
18
|
}
|
|
23
19
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twin.org/entity-storage-connector-gcp-firestore",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2-next.10",
|
|
4
4
|
"description": "Entity Storage connector implementation using GCP Firestore storage",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
"node": ">=20.0.0"
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"@google-cloud/firestore": "7.11.
|
|
18
|
-
"@twin.org/core": "
|
|
19
|
-
"@twin.org/entity": "
|
|
20
|
-
"@twin.org/entity-storage-models": "
|
|
21
|
-
"@twin.org/logging-models": "
|
|
22
|
-
"@twin.org/nameof": "
|
|
17
|
+
"@google-cloud/firestore": "7.11.6",
|
|
18
|
+
"@twin.org/core": "next",
|
|
19
|
+
"@twin.org/entity": "next",
|
|
20
|
+
"@twin.org/entity-storage-models": "0.0.2-next.10",
|
|
21
|
+
"@twin.org/logging-models": "next",
|
|
22
|
+
"@twin.org/nameof": "next"
|
|
23
23
|
},
|
|
24
24
|
"main": "./dist/cjs/index.cjs",
|
|
25
25
|
"module": "./dist/esm/index.mjs",
|
|
@@ -38,5 +38,24 @@
|
|
|
38
38
|
"dist/types",
|
|
39
39
|
"locales",
|
|
40
40
|
"docs"
|
|
41
|
-
]
|
|
41
|
+
],
|
|
42
|
+
"keywords": [
|
|
43
|
+
"twin",
|
|
44
|
+
"trade",
|
|
45
|
+
"iota",
|
|
46
|
+
"framework",
|
|
47
|
+
"blockchain",
|
|
48
|
+
"entity-storage",
|
|
49
|
+
"entity",
|
|
50
|
+
"storage",
|
|
51
|
+
"persistence",
|
|
52
|
+
"database",
|
|
53
|
+
"connector",
|
|
54
|
+
"adapter",
|
|
55
|
+
"integration"
|
|
56
|
+
],
|
|
57
|
+
"bugs": {
|
|
58
|
+
"url": "git+https://github.com/twinfoundation/entity-storage/issues"
|
|
59
|
+
},
|
|
60
|
+
"homepage": "https://twindev.org"
|
|
42
61
|
}
|