@utaba/deep-memory-storage-cosmosdb 0.18.0 → 0.19.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 +19 -12
- package/dist/index.cjs +374 -57
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +350 -33
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -88,35 +88,42 @@ All data is partitioned by `repositoryId` — every vertex and edge stores it. T
|
|
|
88
88
|
|
|
89
89
|
### Edge Types
|
|
90
90
|
|
|
91
|
-
Edge labels are relationship types. Each edge stores `sourceEntityId`, `targetEntityId`, `bidirectional`, properties (
|
|
91
|
+
Edge labels are relationship types. Each edge stores `sourceEntityId`, `targetEntityId`, `bidirectional`, user properties (dual-written — see [Property Storage](#property-storage)), and provenance.
|
|
92
92
|
|
|
93
93
|
### Property Storage
|
|
94
94
|
|
|
95
|
+
User-supplied properties on entities and relationships are **dual-written**: the full payload is JSON-stringified into the `properties` slot (round-trip authoritative — every shape JS can serialise survives), and every key whose value is natively Cosmos-storable (`string`, finite `number`, `boolean`, homogeneous arrays of those) is mirrored as a per-key native vertex/edge scalar so it can be reached by server-side Gremlin predicates (`has('orgType', 'company')`, `values('orgType')`, `group().by(...)`) and the exact-path `findEntities` SQL prefilter. Nested objects, `null`, mixed arrays, and arrays of objects live only in the blob and are not predicate-queryable. Schema-slot collisions on user keys (`entityType`, `id`, `'label'` on edges, …) throw `ProviderError` synchronously on every write path AND on `findEntities` property filters. See the [Properties model section in the Gremlin compatibility doc](https://github.com/TjWheeler/deep-memory/blob/main/docs/cosmosdb-gremlin-compatibility.md#properties-model) for the full contract.
|
|
96
|
+
|
|
95
97
|
| Data | Storage | Notes |
|
|
96
98
|
|------|---------|-------|
|
|
97
|
-
| Entity properties | JSON
|
|
99
|
+
| Entity / relationship user properties | JSON blob in `properties` + per-key native vertex/edge scalars for native-storable values | Blob is authoritative on read. The scalars are a write-only mirror that powers server-side predicates and aggregation; the read path never consumes them. |
|
|
98
100
|
| Embeddings | JSON string in `embedding` vertex property | Stored for export/import fidelity; not searchable via Gremlin |
|
|
99
101
|
| Governance config | JSON string in `governanceConfig` vertex property | On `_repository` vertices |
|
|
100
102
|
| Vocabulary | JSON string in `vocabulary` vertex property | On `_vocabulary` vertices |
|
|
101
103
|
|
|
102
104
|
## Capabilities
|
|
103
105
|
|
|
104
|
-
`findEntities()`
|
|
106
|
+
`findEntities()` runs against the Cosmos NoSQL (Document) endpoint over the same backing container the Gremlin reads use — a separate code path because the Gremlin subset cannot express case-insensitive substring search server-side (`TextP.containing()` silently returns zero rows in the Cosmos Gremlin subset). The two paths share the container; `CosmosDocumentClient` issues raw HTTPS + HMAC requests with no SDK dependency. Supports:
|
|
105
107
|
|
|
106
|
-
- **Type filter** —
|
|
107
|
-
- **Text search** — case-insensitive
|
|
108
|
-
- **
|
|
108
|
+
- **Type filter** — `c.entityType[0]._value IN (@etype0, …)`
|
|
109
|
+
- **Text search** — case-insensitive substring via `CONTAINS(<field>, @term, true)` across `entityLabel` / `slug` / `summary`
|
|
110
|
+
- **Property filter** — three modes set by the filter values:
|
|
111
|
+
- no filter → `PaginatedResult.total` is an exact `number`
|
|
112
|
+
- every value native-storable → exact prefilter (`c.<key>[0]._value = @val` per clause against the dual-written scalar column); `total` is an exact `number`
|
|
113
|
+
- any value non-storable → fallback `CONTAINS` substring on the JSON blob; `total: undefined` (the count branch is skipped because the substring prefilter over-reports)
|
|
114
|
+
- Reserved-key collisions in `query.properties` throw `ProviderError` synchronously
|
|
115
|
+
- **Pagination** — SQL `ORDER BY c.id OFFSET @off LIMIT @lim`; data and count queries share one `WHERE` clause so `total` is consistent with the data page by construction
|
|
109
116
|
|
|
110
117
|
`GraphTraversalProvider` capabilities:
|
|
111
118
|
|
|
112
119
|
| Capability | Supported |
|
|
113
120
|
|-----------|-----------|
|
|
114
121
|
| Native Gremlin queries | Yes |
|
|
115
|
-
| Relationship property filters | Yes |
|
|
116
|
-
| Entity property filters | Yes |
|
|
122
|
+
| Relationship property filters | Yes (server-side `has('<userKey>', value)` against the dual-written edge scalar) |
|
|
123
|
+
| Entity property filters | Yes (server-side `has('<userKey>', value)` against the dual-written vertex scalar) |
|
|
117
124
|
| Repeat/loop traversals | Yes |
|
|
118
125
|
| Dedup | Yes |
|
|
119
|
-
|
|
|
126
|
+
| Server-side aggregation over user properties | Yes — `group().by(values('<userKey>')).by(count())` and `dedup().by(values('<userKey>'))` resolve through the dual-written scalars |
|
|
120
127
|
| Relationship summaries | No |
|
|
121
128
|
|
|
122
129
|
RU cost is reported in `QueryMetadata.resourceCost` for graph traversal operations.
|
|
@@ -125,11 +132,11 @@ RU cost is reported in `QueryMetadata.resourceCost` for graph traversal operatio
|
|
|
125
132
|
|
|
126
133
|
| Limitation | Impact |
|
|
127
134
|
|-----------|--------|
|
|
128
|
-
| No
|
|
135
|
+
| No ranked / fuzzy / phrase text search | `findEntities()` text matching is substring `CONTAINS` over `entityLabel` / `slug` / `summary` only — pair with a separate `SearchProvider` for ranked, fuzzy, or multi-token search |
|
|
129
136
|
| No vector similarity | Embeddings stored for portability but not searchable |
|
|
130
|
-
|
|
|
137
|
+
| `group().by(values('<key>'))` cost scales with partition size | Server-side aggregation over user-property scalars works but touches every matching vertex in the partition — costly at millions of vertices. Mitigation options (write-side counter vertex, scheduled stats refresh) are deferred |
|
|
131
138
|
| No lambda steps | Cannot use closures in Gremlin queries |
|
|
132
|
-
|
|
|
139
|
+
| Nested-shape user properties are blob-only | Nested objects, `null`, mixed-type arrays, and arrays of objects survive via the JSON blob but get no native scalar mirror — so they are not server-side predicate-queryable. Homogeneous arrays of native-storable values *are* dual-written as multi-cardinality native properties. |
|
|
133
140
|
|
|
134
141
|
## Bulk Operations
|
|
135
142
|
|