@utaba/deep-memory-storage-cosmosdb 0.6.0 → 0.7.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/dist/index.cjs +143 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +143 -15
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -66,6 +66,10 @@ declare class CosmosDbProvider implements StorageProvider, GraphTraversalProvide
|
|
|
66
66
|
getEntities(repositoryId: string, entityIds: string[]): Promise<Map<string, StoredEntity>>;
|
|
67
67
|
updateEntity(repositoryId: string, entityId: string, updates: StoredEntityUpdate): Promise<StoredEntity>;
|
|
68
68
|
deleteEntity(repositoryId: string, entityId: string): Promise<void>;
|
|
69
|
+
deleteEntities(repositoryId: string, ids: string[]): Promise<{
|
|
70
|
+
deleted: string[];
|
|
71
|
+
notFound: string[];
|
|
72
|
+
}>;
|
|
69
73
|
deleteEntitiesByType(repositoryId: string, entityType: string): Promise<{
|
|
70
74
|
deletedEntities: number;
|
|
71
75
|
deletedRelationships: number;
|
|
@@ -75,6 +79,10 @@ declare class CosmosDbProvider implements StorageProvider, GraphTraversalProvide
|
|
|
75
79
|
getRelationship(repositoryId: string, relationshipId: string): Promise<StoredRelationship | null>;
|
|
76
80
|
getEntityRelationships(repositoryId: string, entityId: string, options?: RelationshipQueryOptions): Promise<PaginatedResult<StoredRelationship>>;
|
|
77
81
|
deleteRelationship(repositoryId: string, relationshipId: string): Promise<void>;
|
|
82
|
+
deleteRelationships(repositoryId: string, ids: string[]): Promise<{
|
|
83
|
+
deleted: string[];
|
|
84
|
+
notFound: string[];
|
|
85
|
+
}>;
|
|
78
86
|
deleteRelationshipsByType(repositoryId: string, relationshipType: string): Promise<{
|
|
79
87
|
deletedRelationships: number;
|
|
80
88
|
}>;
|
package/dist/index.d.ts
CHANGED
|
@@ -66,6 +66,10 @@ declare class CosmosDbProvider implements StorageProvider, GraphTraversalProvide
|
|
|
66
66
|
getEntities(repositoryId: string, entityIds: string[]): Promise<Map<string, StoredEntity>>;
|
|
67
67
|
updateEntity(repositoryId: string, entityId: string, updates: StoredEntityUpdate): Promise<StoredEntity>;
|
|
68
68
|
deleteEntity(repositoryId: string, entityId: string): Promise<void>;
|
|
69
|
+
deleteEntities(repositoryId: string, ids: string[]): Promise<{
|
|
70
|
+
deleted: string[];
|
|
71
|
+
notFound: string[];
|
|
72
|
+
}>;
|
|
69
73
|
deleteEntitiesByType(repositoryId: string, entityType: string): Promise<{
|
|
70
74
|
deletedEntities: number;
|
|
71
75
|
deletedRelationships: number;
|
|
@@ -75,6 +79,10 @@ declare class CosmosDbProvider implements StorageProvider, GraphTraversalProvide
|
|
|
75
79
|
getRelationship(repositoryId: string, relationshipId: string): Promise<StoredRelationship | null>;
|
|
76
80
|
getEntityRelationships(repositoryId: string, entityId: string, options?: RelationshipQueryOptions): Promise<PaginatedResult<StoredRelationship>>;
|
|
77
81
|
deleteRelationship(repositoryId: string, relationshipId: string): Promise<void>;
|
|
82
|
+
deleteRelationships(repositoryId: string, ids: string[]): Promise<{
|
|
83
|
+
deleted: string[];
|
|
84
|
+
notFound: string[];
|
|
85
|
+
}>;
|
|
78
86
|
deleteRelationshipsByType(repositoryId: string, relationshipType: string): Promise<{
|
|
79
87
|
deletedRelationships: number;
|
|
80
88
|
}>;
|
package/dist/index.js
CHANGED
|
@@ -635,12 +635,19 @@ async function updateEntity(conn, repositoryId, entityId, updates) {
|
|
|
635
635
|
bindings[paramName] = value;
|
|
636
636
|
propParts.push(`.property('${key}', ${paramName})`);
|
|
637
637
|
};
|
|
638
|
+
const dropProp = (key) => {
|
|
639
|
+
propParts.push(`.sideEffect(properties('${key}').drop())`);
|
|
640
|
+
};
|
|
641
|
+
if (updates.entityType !== void 0) addProp("entityType", updates.entityType);
|
|
638
642
|
if (updates.label !== void 0) addProp("entityLabel", updates.label);
|
|
639
643
|
if (updates.slug !== void 0) addProp("slug", updates.slug);
|
|
640
|
-
if (updates.summary
|
|
644
|
+
if (updates.summary === null) dropProp("summary");
|
|
645
|
+
else if (updates.summary !== void 0) addProp("summary", updates.summary);
|
|
641
646
|
if (updates.properties !== void 0) addProp("properties", JSON.stringify(updates.properties));
|
|
642
|
-
if (updates.data
|
|
643
|
-
if (updates.
|
|
647
|
+
if (updates.data === null) dropProp("data");
|
|
648
|
+
else if (updates.data !== void 0) addProp("data", updates.data);
|
|
649
|
+
if (updates.dataFormat === null) dropProp("dataFormat");
|
|
650
|
+
else if (updates.dataFormat !== void 0) addProp("dataFormat", updates.dataFormat);
|
|
644
651
|
if (updates.embedding !== void 0) addProp("embedding", JSON.stringify(updates.embedding));
|
|
645
652
|
addProp("modifiedBy", updates.provenance.modifiedBy);
|
|
646
653
|
addProp("modifiedByType", updates.provenance.modifiedByType);
|
|
@@ -688,9 +695,37 @@ async function findEntities(conn, repositoryId, query) {
|
|
|
688
695
|
});
|
|
689
696
|
filterClause += `.has('entityType', within(${typeParams.join(", ")}))`;
|
|
690
697
|
}
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
698
|
+
const hasPropertyFilter = query.properties != null && Object.keys(query.properties).length > 0;
|
|
699
|
+
const needsClientFilter = Boolean(query.searchTerm) || hasPropertyFilter;
|
|
700
|
+
if (needsClientFilter) {
|
|
701
|
+
const dataResult2 = await conn.submit(
|
|
702
|
+
`g.V()${filterClause}.valueMap(true)`,
|
|
703
|
+
bindings
|
|
704
|
+
);
|
|
705
|
+
let items2 = dataResult2.items.map(entityFromGremlin);
|
|
706
|
+
if (query.searchTerm) {
|
|
707
|
+
const term = query.searchTerm.toLowerCase();
|
|
708
|
+
items2 = items2.filter(
|
|
709
|
+
(e) => e.label.toLowerCase().includes(term) || e.slug.toLowerCase().includes(term) || e.summary != null && e.summary.toLowerCase().includes(term)
|
|
710
|
+
);
|
|
711
|
+
}
|
|
712
|
+
if (hasPropertyFilter) {
|
|
713
|
+
items2 = items2.filter((entity) => {
|
|
714
|
+
for (const [key, value] of Object.entries(query.properties)) {
|
|
715
|
+
if (entity.properties[key] !== value) return false;
|
|
716
|
+
}
|
|
717
|
+
return true;
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
const total2 = items2.length;
|
|
721
|
+
const paged = items2.slice(query.offset, query.offset + query.limit);
|
|
722
|
+
return {
|
|
723
|
+
items: paged,
|
|
724
|
+
total: total2,
|
|
725
|
+
hasMore: query.offset + query.limit < total2,
|
|
726
|
+
limit: query.limit,
|
|
727
|
+
offset: query.offset
|
|
728
|
+
};
|
|
694
729
|
}
|
|
695
730
|
const countResult = await conn.submit(
|
|
696
731
|
`g.V()${filterClause}.count()`,
|
|
@@ -703,15 +738,7 @@ async function findEntities(conn, repositoryId, query) {
|
|
|
703
738
|
`g.V()${filterClause}.range(rangeStart, rangeEnd).valueMap(true)`,
|
|
704
739
|
bindings
|
|
705
740
|
);
|
|
706
|
-
|
|
707
|
-
if (query.properties && Object.keys(query.properties).length > 0) {
|
|
708
|
-
items = items.filter((entity) => {
|
|
709
|
-
for (const [key, value] of Object.entries(query.properties)) {
|
|
710
|
-
if (entity.properties[key] !== value) return false;
|
|
711
|
-
}
|
|
712
|
-
return true;
|
|
713
|
-
});
|
|
714
|
-
}
|
|
741
|
+
const items = dataResult.items.map(entityFromGremlin);
|
|
715
742
|
return {
|
|
716
743
|
items,
|
|
717
744
|
total,
|
|
@@ -1448,6 +1475,45 @@ var CosmosDbProvider = class {
|
|
|
1448
1475
|
this.assertValidRepositoryId(repositoryId);
|
|
1449
1476
|
return deleteEntity(this.conn, repositoryId, entityId);
|
|
1450
1477
|
}
|
|
1478
|
+
async deleteEntities(repositoryId, ids) {
|
|
1479
|
+
if (ids.length === 0) return { deleted: [], notFound: [] };
|
|
1480
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1481
|
+
const deleted = [];
|
|
1482
|
+
const CHUNK = 100;
|
|
1483
|
+
for (let i = 0; i < ids.length; i += CHUNK) {
|
|
1484
|
+
const chunk = ids.slice(i, i + CHUNK);
|
|
1485
|
+
const bindings = { rid: repositoryId };
|
|
1486
|
+
const idParams = [];
|
|
1487
|
+
for (let j = 0; j < chunk.length; j++) {
|
|
1488
|
+
const p = `id${j}`;
|
|
1489
|
+
bindings[p] = chunk[j];
|
|
1490
|
+
idParams.push(p);
|
|
1491
|
+
}
|
|
1492
|
+
const withinExpr = `P.within(${idParams.join(", ")})`;
|
|
1493
|
+
const existResult = await this.conn.submit(
|
|
1494
|
+
`g.V().has('repositoryId', rid).has('id', ${withinExpr}).has('entityType').values('id')`,
|
|
1495
|
+
bindings
|
|
1496
|
+
);
|
|
1497
|
+
const found = existResult.items;
|
|
1498
|
+
if (found.length > 0) {
|
|
1499
|
+
const dropBindings = { rid: repositoryId };
|
|
1500
|
+
const dropIdParams = [];
|
|
1501
|
+
for (let j = 0; j < found.length; j++) {
|
|
1502
|
+
const p = `did${j}`;
|
|
1503
|
+
dropBindings[p] = found[j];
|
|
1504
|
+
dropIdParams.push(p);
|
|
1505
|
+
}
|
|
1506
|
+
const dropWithinExpr = `P.within(${dropIdParams.join(", ")})`;
|
|
1507
|
+
await this.conn.submit(
|
|
1508
|
+
`g.V().has('repositoryId', rid).has('id', ${dropWithinExpr}).has('entityType').drop()`,
|
|
1509
|
+
dropBindings
|
|
1510
|
+
);
|
|
1511
|
+
deleted.push(...found);
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1514
|
+
const deletedSet = new Set(deleted);
|
|
1515
|
+
return { deleted, notFound: ids.filter((id) => !deletedSet.has(id)) };
|
|
1516
|
+
}
|
|
1451
1517
|
async deleteEntitiesByType(repositoryId, entityType) {
|
|
1452
1518
|
this.assertValidRepositoryId(repositoryId);
|
|
1453
1519
|
return deleteEntitiesByType(this.conn, repositoryId, entityType);
|
|
@@ -1473,6 +1539,42 @@ var CosmosDbProvider = class {
|
|
|
1473
1539
|
this.assertValidRepositoryId(repositoryId);
|
|
1474
1540
|
return deleteRelationship(this.conn, repositoryId, relationshipId);
|
|
1475
1541
|
}
|
|
1542
|
+
async deleteRelationships(repositoryId, ids) {
|
|
1543
|
+
if (ids.length === 0) return { deleted: [], notFound: [] };
|
|
1544
|
+
this.assertValidRepositoryId(repositoryId);
|
|
1545
|
+
const deleted = [];
|
|
1546
|
+
const CHUNK = 100;
|
|
1547
|
+
for (let i = 0; i < ids.length; i += CHUNK) {
|
|
1548
|
+
const chunk = ids.slice(i, i + CHUNK);
|
|
1549
|
+
const bindings = { rid: repositoryId };
|
|
1550
|
+
const idParams = [];
|
|
1551
|
+
for (let j = 0; j < chunk.length; j++) {
|
|
1552
|
+
const p = `id${j}`;
|
|
1553
|
+
bindings[p] = chunk[j];
|
|
1554
|
+
idParams.push(p);
|
|
1555
|
+
}
|
|
1556
|
+
const withinExpr = `P.within(${idParams.join(", ")})`;
|
|
1557
|
+
const existResult = await this.conn.submit(
|
|
1558
|
+
`g.E().has('repositoryId', rid).has('id', ${withinExpr}).values('id')`,
|
|
1559
|
+
bindings
|
|
1560
|
+
);
|
|
1561
|
+
const found = existResult.items;
|
|
1562
|
+
if (found.length > 0) {
|
|
1563
|
+
await cosmosRestBatchDelete(
|
|
1564
|
+
this.getRestEndpoint(),
|
|
1565
|
+
this.config.key,
|
|
1566
|
+
this.config.database,
|
|
1567
|
+
this.config.container,
|
|
1568
|
+
repositoryId,
|
|
1569
|
+
found,
|
|
1570
|
+
this.config.rejectUnauthorized ?? true
|
|
1571
|
+
);
|
|
1572
|
+
deleted.push(...found);
|
|
1573
|
+
}
|
|
1574
|
+
}
|
|
1575
|
+
const deletedSet = new Set(deleted);
|
|
1576
|
+
return { deleted, notFound: ids.filter((id) => !deletedSet.has(id)) };
|
|
1577
|
+
}
|
|
1476
1578
|
async deleteRelationshipsByType(repositoryId, relationshipType) {
|
|
1477
1579
|
this.assertValidRepositoryId(repositoryId);
|
|
1478
1580
|
return deleteRelationshipsByType(this.conn, repositoryId, relationshipType);
|
|
@@ -1686,6 +1788,32 @@ async function cosmosRestPut(restBase, key, urlPath, resourceLink, resourceType,
|
|
|
1686
1788
|
const text = await response.text();
|
|
1687
1789
|
throw new Error(`CosmosDB REST ${response.status}: ${text}`);
|
|
1688
1790
|
}
|
|
1791
|
+
async function cosmosRestBatchDelete(restBase, key, database, container, partitionKeyValue, ids, rejectUnauthorized) {
|
|
1792
|
+
const resourceLink = `dbs/${database}/colls/${container}`;
|
|
1793
|
+
const date = (/* @__PURE__ */ new Date()).toUTCString();
|
|
1794
|
+
const token = cosmosAuthToken("post", "docs", resourceLink, date, key);
|
|
1795
|
+
if (!rejectUnauthorized) {
|
|
1796
|
+
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = "0";
|
|
1797
|
+
}
|
|
1798
|
+
const ops = ids.map((id) => ({ operationType: "Delete", id }));
|
|
1799
|
+
const response = await fetch(`${restBase}/${resourceLink}/docs`, {
|
|
1800
|
+
method: "POST",
|
|
1801
|
+
headers: {
|
|
1802
|
+
"Authorization": token,
|
|
1803
|
+
"x-ms-version": "2020-07-15",
|
|
1804
|
+
"x-ms-date": date,
|
|
1805
|
+
"Content-Type": "application/json",
|
|
1806
|
+
"x-ms-documentdb-partitionkey": JSON.stringify([partitionKeyValue]),
|
|
1807
|
+
"x-ms-cosmos-is-batch-request": "true",
|
|
1808
|
+
"x-ms-cosmos-batch-atomic": "true"
|
|
1809
|
+
},
|
|
1810
|
+
body: JSON.stringify(ops)
|
|
1811
|
+
});
|
|
1812
|
+
if (response.status !== 200 && response.status !== 207) {
|
|
1813
|
+
const text = await response.text();
|
|
1814
|
+
throw new ProviderError(`CosmosDB batch delete failed (${response.status}): ${text}`);
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1689
1817
|
export {
|
|
1690
1818
|
CosmosDbConnection,
|
|
1691
1819
|
CosmosDbProvider
|