@nicia-ai/typegraph 0.33.0 → 0.34.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 +20 -0
- package/dist/backend/postgres/index.cjs +26 -22
- package/dist/backend/postgres/index.d.cts +5 -5
- package/dist/backend/postgres/index.d.ts +5 -5
- package/dist/backend/postgres/index.js +13 -9
- package/dist/backend/postgres/pglite.cjs +17 -13
- package/dist/backend/postgres/pglite.cjs.map +1 -1
- package/dist/backend/postgres/pglite.d.cts +2 -2
- package/dist/backend/postgres/pglite.d.ts +2 -2
- package/dist/backend/postgres/pglite.js +13 -9
- package/dist/backend/postgres/pglite.js.map +1 -1
- package/dist/backend/sqlite/index.cjs +24 -20
- package/dist/backend/sqlite/index.d.cts +6 -6
- package/dist/backend/sqlite/index.d.ts +6 -6
- package/dist/backend/sqlite/index.js +12 -8
- package/dist/backend/sqlite/libsql.cjs +18 -14
- package/dist/backend/sqlite/libsql.cjs.map +1 -1
- package/dist/backend/sqlite/libsql.d.cts +11 -4
- package/dist/backend/sqlite/libsql.d.ts +11 -4
- package/dist/backend/sqlite/libsql.js +14 -10
- package/dist/backend/sqlite/libsql.js.map +1 -1
- package/dist/backend/sqlite/local.cjs +18 -14
- package/dist/backend/sqlite/local.cjs.map +1 -1
- package/dist/backend/sqlite/local.d.cts +2 -2
- package/dist/backend/sqlite/local.d.ts +2 -2
- package/dist/backend/sqlite/local.js +13 -9
- package/dist/backend/sqlite/local.js.map +1 -1
- package/dist/chunk-2EBMPJBO.js +16 -0
- package/dist/chunk-2EBMPJBO.js.map +1 -0
- package/dist/{chunk-CFNT3ITG.cjs → chunk-2JXB3NYJ.cjs} +15 -35
- package/dist/chunk-2JXB3NYJ.cjs.map +1 -0
- package/dist/{chunk-GYVBEZAO.js → chunk-2MRAX3UE.js} +3 -18
- package/dist/chunk-2MRAX3UE.js.map +1 -0
- package/dist/{chunk-D3EWZ67S.cjs → chunk-3BRVBQQD.cjs} +999 -2675
- package/dist/chunk-3BRVBQQD.cjs.map +1 -0
- package/dist/{chunk-FDN43KXV.cjs → chunk-3Z6TW3CT.cjs} +20 -19
- package/dist/chunk-3Z6TW3CT.cjs.map +1 -0
- package/dist/{chunk-6NRFUHMS.js → chunk-4DIBPQNJ.js} +5 -4
- package/dist/chunk-4DIBPQNJ.js.map +1 -0
- package/dist/chunk-4S2FXGBJ.js +9 -0
- package/dist/chunk-4S2FXGBJ.js.map +1 -0
- package/dist/chunk-5IQIX7LU.cjs +2070 -0
- package/dist/chunk-5IQIX7LU.cjs.map +1 -0
- package/dist/{chunk-CWFPJ3RC.js → chunk-6GNSY7AV.js} +3 -3
- package/dist/{chunk-CWFPJ3RC.js.map → chunk-6GNSY7AV.js.map} +1 -1
- package/dist/{chunk-NG5N7R45.cjs → chunk-6HVOHZHS.cjs} +184 -117
- package/dist/chunk-6HVOHZHS.cjs.map +1 -0
- package/dist/chunk-6SCVW4AS.js +20 -0
- package/dist/chunk-6SCVW4AS.js.map +1 -0
- package/dist/chunk-A7SZZFAG.js +2010 -0
- package/dist/chunk-A7SZZFAG.js.map +1 -0
- package/dist/chunk-ACSVZPK7.cjs +21 -0
- package/dist/chunk-ACSVZPK7.cjs.map +1 -0
- package/dist/{chunk-IZ4PCL47.js → chunk-BVTWD66D.js} +4 -66
- package/dist/chunk-BVTWD66D.js.map +1 -0
- package/dist/{chunk-QBYTJSAY.js → chunk-CHXTTSC6.js} +5 -39
- package/dist/chunk-CHXTTSC6.js.map +1 -0
- package/dist/{chunk-DJYRRDHA.js → chunk-CYX2JTDG.js} +3 -3
- package/dist/{chunk-DJYRRDHA.js.map → chunk-CYX2JTDG.js.map} +1 -1
- package/dist/{chunk-PRMKPFN5.js → chunk-DEQFL35G.js} +4 -3
- package/dist/chunk-DEQFL35G.js.map +1 -0
- package/dist/chunk-DI74SMXS.cjs +29 -0
- package/dist/chunk-DI74SMXS.cjs.map +1 -0
- package/dist/{chunk-WWVV44DY.cjs → chunk-G6SOJEDI.cjs} +11 -11
- package/dist/{chunk-WWVV44DY.cjs.map → chunk-G6SOJEDI.cjs.map} +1 -1
- package/dist/{chunk-LM2IC4ZJ.cjs → chunk-GQANNXXT.cjs} +15 -14
- package/dist/chunk-GQANNXXT.cjs.map +1 -0
- package/dist/chunk-GZCNZ7QW.js +24 -0
- package/dist/chunk-GZCNZ7QW.js.map +1 -0
- package/dist/{chunk-KTIEB7VH.cjs → chunk-HK5SATYM.cjs} +35 -58
- package/dist/chunk-HK5SATYM.cjs.map +1 -0
- package/dist/chunk-HMFK4BXR.cjs +12 -0
- package/dist/{chunk-6ZR4QC3O.cjs.map → chunk-HMFK4BXR.cjs.map} +1 -1
- package/dist/chunk-ITE4IXAK.js +25 -0
- package/dist/chunk-ITE4IXAK.js.map +1 -0
- package/dist/chunk-JJRCLAUN.cjs +155 -0
- package/dist/chunk-JJRCLAUN.cjs.map +1 -0
- package/dist/{chunk-ZFWNO3GE.cjs → chunk-JQGIPGVL.cjs} +66 -2
- package/dist/chunk-JQGIPGVL.cjs.map +1 -0
- package/dist/{chunk-XVUJY72M.js → chunk-K2TGS3EN.js} +105 -38
- package/dist/chunk-K2TGS3EN.js.map +1 -0
- package/dist/chunk-K34OPSJK.js +29 -0
- package/dist/chunk-K34OPSJK.js.map +1 -0
- package/dist/{chunk-YW7GHMF4.cjs → chunk-KGC4LY5T.cjs} +18 -17
- package/dist/chunk-KGC4LY5T.cjs.map +1 -0
- package/dist/{chunk-SST7XDY6.cjs → chunk-KNHYNQQ3.cjs} +111 -72
- package/dist/chunk-KNHYNQQ3.cjs.map +1 -0
- package/dist/{chunk-C4C4Q7A6.js → chunk-KUTNI6SI.js} +6 -21
- package/dist/chunk-KUTNI6SI.js.map +1 -0
- package/dist/{chunk-OS6KS3HV.js → chunk-LANHCOXB.js} +8 -7
- package/dist/chunk-LANHCOXB.js.map +1 -0
- package/dist/chunk-N6WTUSBV.cjs +23 -0
- package/dist/chunk-N6WTUSBV.cjs.map +1 -0
- package/dist/{chunk-73KASJGO.cjs → chunk-NAUA4PW5.cjs} +4 -28
- package/dist/chunk-NAUA4PW5.cjs.map +1 -0
- package/dist/chunk-QV245VMN.js +145 -0
- package/dist/chunk-QV245VMN.js.map +1 -0
- package/dist/{chunk-CEF2QOTO.js → chunk-RBV7YCQD.js} +4 -3
- package/dist/chunk-RBV7YCQD.js.map +1 -0
- package/dist/{chunk-OIE2UPVG.cjs → chunk-RHZWOJVA.cjs} +2 -19
- package/dist/chunk-RHZWOJVA.cjs.map +1 -0
- package/dist/{chunk-3IR2GEMJ.cjs → chunk-RRKQAKD6.cjs} +10 -9
- package/dist/chunk-RRKQAKD6.cjs.map +1 -0
- package/dist/{chunk-UPDMJEW6.js → chunk-RY2VIWAM.js} +11 -8
- package/dist/chunk-RY2VIWAM.js.map +1 -0
- package/dist/{chunk-PIHXFF73.js → chunk-SHLY4MCM.js} +3 -3
- package/dist/{chunk-PIHXFF73.js.map → chunk-SHLY4MCM.js.map} +1 -1
- package/dist/{chunk-SPT5JMME.js → chunk-T2DWPQNE.js} +103 -64
- package/dist/chunk-T2DWPQNE.js.map +1 -0
- package/dist/{chunk-WYTUF3QO.js → chunk-T46GR2VY.js} +3 -3
- package/dist/{chunk-WYTUF3QO.js.map → chunk-T46GR2VY.js.map} +1 -1
- package/dist/{chunk-MBLXCV2Y.cjs → chunk-T6SPUYLX.cjs} +5 -43
- package/dist/chunk-T6SPUYLX.cjs.map +1 -0
- package/dist/{chunk-3QRBXYT5.cjs → chunk-TGJE22RM.cjs} +6 -6
- package/dist/{chunk-3QRBXYT5.cjs.map → chunk-TGJE22RM.cjs.map} +1 -1
- package/dist/{chunk-BF3ZDEUE.cjs → chunk-TOTPVGOG.cjs} +70 -69
- package/dist/chunk-TOTPVGOG.cjs.map +1 -0
- package/dist/{chunk-KY5SDVA7.cjs → chunk-UJLOZYKT.cjs} +90 -87
- package/dist/chunk-UJLOZYKT.cjs.map +1 -0
- package/dist/{chunk-I4W7MKVG.cjs → chunk-UNNPKQUG.cjs} +19 -155
- package/dist/chunk-UNNPKQUG.cjs.map +1 -0
- package/dist/chunk-UR7W5YQK.js +18 -0
- package/dist/chunk-UR7W5YQK.js.map +1 -0
- package/dist/{chunk-PYD3UCDU.js → chunk-V3QNTB7Z.js} +19 -148
- package/dist/chunk-V3QNTB7Z.js.map +1 -0
- package/dist/{chunk-XKNAK27R.js → chunk-VCGO4V26.js} +4 -3
- package/dist/chunk-VCGO4V26.js.map +1 -0
- package/dist/{chunk-EF3Z645U.cjs → chunk-WL2SG7ZV.cjs} +6 -72
- package/dist/chunk-WL2SG7ZV.cjs.map +1 -0
- package/dist/{chunk-WLP6TKFB.js → chunk-WLRIWYHQ.js} +640 -2307
- package/dist/chunk-WLRIWYHQ.js.map +1 -0
- package/dist/{chunk-4RBAJVEC.cjs → chunk-WVC2Q2FD.cjs} +5 -5
- package/dist/{chunk-4RBAJVEC.cjs.map → chunk-WVC2Q2FD.cjs.map} +1 -1
- package/dist/chunk-XXVEULWX.js +39 -0
- package/dist/chunk-XXVEULWX.js.map +1 -0
- package/dist/chunk-YAZE7QZR.cjs +32 -0
- package/dist/chunk-YAZE7QZR.cjs.map +1 -0
- package/dist/chunk-YC6PWTHY.cjs +44 -0
- package/dist/chunk-YC6PWTHY.cjs.map +1 -0
- package/dist/chunk-Z5HBYM7U.cjs +11 -0
- package/dist/chunk-Z5HBYM7U.cjs.map +1 -0
- package/dist/{chunk-454I6GDF.js → chunk-Z5XBMDXU.js} +63 -3
- package/dist/chunk-Z5XBMDXU.js.map +1 -0
- package/dist/{chunk-3642VBVC.cjs → chunk-ZP5WHI4C.cjs} +106 -80
- package/dist/chunk-ZP5WHI4C.cjs.map +1 -0
- package/dist/{chunk-YCV72E6L.js → chunk-ZURTTSCM.js} +4 -25
- package/dist/chunk-ZURTTSCM.js.map +1 -0
- package/dist/{chunk-JHOBXD7O.js → chunk-ZV5N4DBG.js} +46 -20
- package/dist/chunk-ZV5N4DBG.js.map +1 -0
- package/dist/chunk-ZY4GXIVN.cjs +32 -0
- package/dist/chunk-ZY4GXIVN.cjs.map +1 -0
- package/dist/{ddl-CVnHJcar.d.ts → ddl-BrmPg61z.d.ts} +3 -3
- package/dist/{ddl-Dxt_fBHr.d.cts → ddl-j1-sH6lE.d.cts} +3 -3
- package/dist/graph-extension/index.cjs +18 -17
- package/dist/graph-extension/index.js +3 -2
- package/dist/graph-merge/index.cjs +294 -146
- package/dist/graph-merge/index.cjs.map +1 -1
- package/dist/graph-merge/index.d.cts +3 -3
- package/dist/graph-merge/index.d.ts +3 -3
- package/dist/graph-merge/index.js +172 -24
- package/dist/graph-merge/index.js.map +1 -1
- package/dist/index.cjs +181 -172
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -7
- package/dist/index.d.ts +7 -7
- package/dist/index.js +30 -22
- package/dist/index.js.map +1 -1
- package/dist/indexes/index.cjs +27 -25
- package/dist/indexes/index.d.cts +4 -4
- package/dist/indexes/index.d.ts +4 -4
- package/dist/indexes/index.js +9 -7
- package/dist/interchange/index.cjs +25 -16
- package/dist/interchange/index.d.cts +3 -3
- package/dist/interchange/index.d.ts +3 -3
- package/dist/interchange/index.js +12 -3
- package/dist/{manager-C0_r0ALf.d.ts → manager-BZUeN_BU.d.ts} +1 -1
- package/dist/{manager-BYl_zyZR.d.cts → manager-ms9cKdc6.d.cts} +1 -1
- package/dist/{postgres-MzBPkYzq.d.ts → postgres-BhpxGMC5.d.cts} +1 -1
- package/dist/{postgres-_9psmVGm.d.cts → postgres-CWHLwNl1.d.ts} +1 -1
- package/dist/profiler/index.cjs +3 -3
- package/dist/profiler/index.d.cts +5 -5
- package/dist/profiler/index.d.ts +5 -5
- package/dist/profiler/index.js +2 -2
- package/dist/provenance/index.cjs +591 -0
- package/dist/provenance/index.cjs.map +1 -0
- package/dist/provenance/index.d.cts +73 -0
- package/dist/provenance/index.d.ts +73 -0
- package/dist/provenance/index.js +589 -0
- package/dist/provenance/index.js.map +1 -0
- package/dist/schema/index.cjs +36 -32
- package/dist/schema/index.cjs.map +1 -1
- package/dist/schema/index.d.cts +4 -4
- package/dist/schema/index.d.ts +4 -4
- package/dist/schema/index.js +13 -9
- package/dist/schema/index.js.map +1 -1
- package/dist/{sqlite-gm44dShb.d.ts → sqlite-CGu5SLsw.d.ts} +1 -1
- package/dist/{sqlite-BfksSb45.d.cts → sqlite-XrDxNaa7.d.cts} +1 -1
- package/dist/{store-view-FfE5_7eo.d.ts → store-view-BlgnhEYf.d.ts} +33 -5
- package/dist/{store-view-9jQ2rPum.d.cts → store-view-D09po4H6.d.cts} +33 -5
- package/dist/{types-CdWxK-nD.d.ts → types-B1TbZJYS.d.ts} +1 -1
- package/dist/{types-DGylBhWo.d.ts → types-D1Sqeyxy.d.ts} +7 -3
- package/dist/{types-B6mhrcLv.d.cts → types-DiE1AO7p.d.cts} +1 -1
- package/dist/{types-C_UnQOQp.d.cts → types-DkNnF-7K.d.cts} +7 -3
- package/dist/{where-Bpp2ul_z.d.cts → where-DKjuofPr.d.cts} +1 -1
- package/dist/{where-BsEXraKW.d.ts → where-DrUIIWHb.d.ts} +1 -1
- package/package.json +8 -2
- package/dist/chunk-2YMGNYXY.js +0 -40
- package/dist/chunk-2YMGNYXY.js.map +0 -1
- package/dist/chunk-3642VBVC.cjs.map +0 -1
- package/dist/chunk-3IR2GEMJ.cjs.map +0 -1
- package/dist/chunk-454I6GDF.js.map +0 -1
- package/dist/chunk-6NRFUHMS.js.map +0 -1
- package/dist/chunk-6ZR4QC3O.cjs +0 -12
- package/dist/chunk-73KASJGO.cjs.map +0 -1
- package/dist/chunk-BF3ZDEUE.cjs.map +0 -1
- package/dist/chunk-C4C4Q7A6.js.map +0 -1
- package/dist/chunk-CEF2QOTO.js.map +0 -1
- package/dist/chunk-CFNT3ITG.cjs.map +0 -1
- package/dist/chunk-D3EWZ67S.cjs.map +0 -1
- package/dist/chunk-EF3Z645U.cjs.map +0 -1
- package/dist/chunk-FDN43KXV.cjs.map +0 -1
- package/dist/chunk-GYVBEZAO.js.map +0 -1
- package/dist/chunk-I4W7MKVG.cjs.map +0 -1
- package/dist/chunk-IZ4PCL47.js.map +0 -1
- package/dist/chunk-JHOBXD7O.js.map +0 -1
- package/dist/chunk-KTIEB7VH.cjs.map +0 -1
- package/dist/chunk-KY5SDVA7.cjs.map +0 -1
- package/dist/chunk-LM2IC4ZJ.cjs.map +0 -1
- package/dist/chunk-MBLXCV2Y.cjs.map +0 -1
- package/dist/chunk-NG5N7R45.cjs.map +0 -1
- package/dist/chunk-OIE2UPVG.cjs.map +0 -1
- package/dist/chunk-OS6KS3HV.js.map +0 -1
- package/dist/chunk-PRMKPFN5.js.map +0 -1
- package/dist/chunk-PYD3UCDU.js.map +0 -1
- package/dist/chunk-QBYTJSAY.js.map +0 -1
- package/dist/chunk-SPT5JMME.js.map +0 -1
- package/dist/chunk-SST7XDY6.cjs.map +0 -1
- package/dist/chunk-UPDMJEW6.js.map +0 -1
- package/dist/chunk-WLP6TKFB.js.map +0 -1
- package/dist/chunk-XKNAK27R.js.map +0 -1
- package/dist/chunk-XVUJY72M.js.map +0 -1
- package/dist/chunk-YCV72E6L.js.map +0 -1
- package/dist/chunk-YW7GHMF4.cjs.map +0 -1
- package/dist/chunk-ZFWNO3GE.cjs.map +0 -1
|
@@ -1,307 +1,25 @@
|
|
|
1
1
|
import { quoteIdentifier, EMPTY_REQUIRED_COLUMNS, addRequiredColumn, markSelectiveFieldAsRequired, markFieldRefAsRequired, NODE_COLUMNS, shouldProjectColumn, mapSelectiveSystemFieldToColumn, isIdFieldRef, isAggregateExpr, EDGE_COLUMNS } from './chunk-3EUKJEQ3.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
2
|
+
import { createEdgeRowMapper, createNodeRowMapper, POSTGRES_ROW_MAPPER_CONFIG, SQLITE_ROW_MAPPER_CONFIG } from './chunk-QV245VMN.js';
|
|
3
|
+
import { runHookedWriteOperation, runInWriteTransaction } from './chunk-6SCVW4AS.js';
|
|
4
|
+
import { loadAndMergeGraphExtensionDocument, ensureSchema, loadAndVerifyGraph, mergeGraphExtension, commitNewSchemaVersion, applyDeprecatedKinds, loadActiveSchemaWithBootstrap, parseSerializedSchema, computeClosuresFromOntology, createEmptyClosures, KindRegistry, extensionKindNames, serializeSchemaProperties, buildGraphExtensionOntologyKeySet, compileTimeOntologyKey, getTypeName, validateNodeProps, validateEdgeProps } from './chunk-K2TGS3EN.js';
|
|
5
|
+
import { sortedReplacer, canonicalEqual } from './chunk-UR7W5YQK.js';
|
|
6
|
+
import { isKnownKind, getNodeKinds, getEdgeKinds } from './chunk-CHXTTSC6.js';
|
|
7
|
+
import { generateIndexDDL } from './chunk-SHLY4MCM.js';
|
|
8
|
+
import { getDialect, assertVectorMinScore, compileNodeIndexFieldKeys, compileIndexWhere, vectorScoreExpression, vectorMinScoreCondition } from './chunk-KUTNI6SI.js';
|
|
9
|
+
import { NODE_META_KEYS, EDGE_META_KEYS } from './chunk-4DIBPQNJ.js';
|
|
10
|
+
import { sha256Hex, fnv1aBase36 } from './chunk-K34OPSJK.js';
|
|
11
|
+
import { createSchemaIntrospector } from './chunk-BVTWD66D.js';
|
|
12
|
+
import { IncompatibleChangeError, filterReservedKeys, RESERVED_NODE_KEYS, RESERVED_EDGE_KEYS, RemoveCompileTimeKindError, KindHasReferentsError, validateProjectionField } from './chunk-ZURTTSCM.js';
|
|
13
|
+
import { compareStrings } from './chunk-4S2FXGBJ.js';
|
|
14
|
+
import { resolveReadCoordinate, withRecordedCoordinate, describeCoordinate, coordinateContext, DEFAULT_SQL_SCHEMA, requireSqlSchema, recordedReadSchemaFor, asCompiledSelectSql, getSearchableFields, createSqlSchema, requireExternalRecordedReadSource, createRecordedReadBinding, createRecordedBackend, readRecordedClock, asRecordedInstant, recordedCaptureRequiresCallbackTransactionError, assertRecordedCaptureTransactionIsolation, createRecordedTransactionScope, lockRecordedGraphWrite, createHistoryUnsafeSqlRef, generateId, vectorSlotKey, getEmbeddingFields, computeFulltextContent, recordedReadSqlSchema, requireRecordedReadBinding, asCompiledRowsSql, getKindsForUniquenessCheck, checkWherePredicate, computeUniqueKey, applyNodeHardDelete, createNodeWriteContext, applyNodeSoftDelete, runInsertBatch, nodeInsertDispatch, runInsertBatchReturning, edgeInsertDispatch, getNodeRowsByIds, getEdgeRowsByIds, applyNodeUpdate, applyNodeInsertSideEffects, checkCardinality, checkUniqueEdge, validateEdgeEndpoints, assertValidRecordedInstant, checkUniquenessConstraints, createUniquenessContext, recordedBindParamBudget, checkDisjointness, closeRecordedHardDeletedKind, asCompiledStatementSql, EMBEDDINGS_CTE_ALIAS, FULLTEXT_CTE_ALIAS, HYBRID_CANDIDATES_CTE_ALIAS, ALIAS_CTE_PREFIX } from './chunk-A7SZZFAG.js';
|
|
15
|
+
import { isParameterRef, fieldRef, buildFieldBuilderForTypeInfo, stringField, createFulltextAccessor, runOptionallyInTransaction, baseField, objectField, arrayField, dateField, numberField, isLiveNodeRow, createBackendOverlay, compileKindFilter, chunk, sqlValueList, buildPredicateIndex, compileFieldValue, extractVectorSimilarityPredicates, extractFulltextMatchPredicates, compilePredicateExpression, getPredicatesForAlias, getNodeKindsForAlias, getHybridTargetAlias, compilePredicateClauses } from './chunk-V3QNTB7Z.js';
|
|
16
|
+
import { nowIso, validateOptionalCanonicalIsoDate } from './chunk-XXVEULWX.js';
|
|
17
|
+
import { withRecordedRelationsPrecondition, isMissingTableError } from './chunk-2MRAX3UE.js';
|
|
18
|
+
import { DEFAULT_PAGINATION_LIMIT, DEFAULT_STREAM_BATCH_SIZE, SQLITE_PATH_DELIMITER, PG_ARRAY_START, PG_ARRAY_END, PG_PATH_ELEMENT_SEPARATOR, MAX_PG_IDENTIFIER_LENGTH } from './chunk-2EBMPJBO.js';
|
|
19
|
+
import { resolveEmbeddingFields } from './chunk-Z5XBMDXU.js';
|
|
20
|
+
import { ConfigurationError, UnsupportedPredicateError, ValidationError, KindNotFoundError, EndpointError, EagerMaterializationError, CompilerInvariantError, UniquenessError, DatabaseOperationError, CardinalityError, EdgeNotFoundError, NodeIndexNotFoundError, NodeConstraintNotFoundError, NodeNotFoundError, EndpointNotFoundError } from './chunk-TQOYM4LN.js';
|
|
14
21
|
import { jsonPointer, parseJsonPointer, resolveJsonPointer } from './chunk-K5P5OZXS.js';
|
|
15
|
-
import {
|
|
16
|
-
import { nanoid } from 'nanoid';
|
|
17
|
-
|
|
18
|
-
// src/core/temporal.ts
|
|
19
|
-
var RECORDED_MAX = "9999-12-31T23:59:59.999Z";
|
|
20
|
-
function assertValidRecordedInstant(value, path) {
|
|
21
|
-
validateCanonicalIsoDate(value, path);
|
|
22
|
-
if (value >= RECORDED_MAX) {
|
|
23
|
-
throw new ValidationError(
|
|
24
|
-
`${path} must be before the recorded-time open sentinel ${RECORDED_MAX}.`,
|
|
25
|
-
{
|
|
26
|
-
issues: [
|
|
27
|
-
{
|
|
28
|
-
path,
|
|
29
|
-
message: `Expected a timestamp before ${RECORDED_MAX}, got "${value}"`
|
|
30
|
-
}
|
|
31
|
-
]
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
suggestion: "Use a real recorded-time commit instant, not the open-interval sentinel."
|
|
35
|
-
}
|
|
36
|
-
);
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
function asRecordedInstant(value) {
|
|
40
|
-
assertValidRecordedInstant(value, "asRecordedInstant");
|
|
41
|
-
return value;
|
|
42
|
-
}
|
|
43
|
-
function resolveReadCoordinate(mode, asOf, suggestion) {
|
|
44
|
-
if (mode !== "asOf" && asOf !== void 0) {
|
|
45
|
-
throw new ValidationError(
|
|
46
|
-
`Temporal mode "${mode}" does not take an asOf timestamp.`,
|
|
47
|
-
{
|
|
48
|
-
issues: [
|
|
49
|
-
{
|
|
50
|
-
path: "asOf",
|
|
51
|
-
message: `asOf is only valid with mode "asOf", not "${mode}"`
|
|
52
|
-
}
|
|
53
|
-
]
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
suggestion: 'Pin an instant with store.asOf(timestamp) or store.view({ mode: "asOf", asOf }); drop asOf for other modes.'
|
|
57
|
-
}
|
|
58
|
-
);
|
|
59
|
-
}
|
|
60
|
-
assertValidAsOf(
|
|
61
|
-
mode,
|
|
62
|
-
asOf,
|
|
63
|
-
suggestion === void 0 ? void 0 : { suggestion }
|
|
64
|
-
);
|
|
65
|
-
return { valid: asOf === void 0 ? { mode } : { mode, asOf } };
|
|
66
|
-
}
|
|
67
|
-
function withRecordedCoordinate(coordinate, recordedAsOf) {
|
|
68
|
-
assertValidRecordedInstant(recordedAsOf, "asOfRecorded");
|
|
69
|
-
return {
|
|
70
|
-
...coordinate,
|
|
71
|
-
recorded: { asOf: recordedAsOf }
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
function assertValidAsOf(mode, asOf, options) {
|
|
75
|
-
if (mode === "asOf" && asOf === void 0) {
|
|
76
|
-
throw new ValidationError(
|
|
77
|
-
'Temporal mode "asOf" requires a timestamp',
|
|
78
|
-
{
|
|
79
|
-
issues: [
|
|
80
|
-
{ path: "asOf", message: "Timestamp is required for asOf mode" }
|
|
81
|
-
]
|
|
82
|
-
},
|
|
83
|
-
{
|
|
84
|
-
suggestion: options?.suggestion ?? 'Provide an ISO-8601 timestamp for asOf mode, e.g. "2026-01-01T00:00:00.000Z".'
|
|
85
|
-
}
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
if (asOf !== void 0) {
|
|
89
|
-
validateCanonicalIsoDate(asOf, "asOf");
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
function describeCoordinate(coordinate) {
|
|
93
|
-
const { mode, asOf } = coordinate.valid;
|
|
94
|
-
const valid = asOf === void 0 ? `mode "${mode}"` : `mode "${mode}" asOf ${asOf}`;
|
|
95
|
-
return coordinate.recorded === void 0 ? valid : `${valid}, recorded asOf ${coordinate.recorded.asOf}`;
|
|
96
|
-
}
|
|
97
|
-
function coordinateContext(coordinate) {
|
|
98
|
-
const { mode, asOf } = coordinate.valid;
|
|
99
|
-
return {
|
|
100
|
-
temporalMode: mode,
|
|
101
|
-
...asOf !== void 0 && { asOf },
|
|
102
|
-
...coordinate.recorded === void 0 ? {} : { recordedAsOf: coordinate.recorded.asOf }
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// src/query/sql-intent.ts
|
|
107
|
-
function asCompiledRowsSql(query) {
|
|
108
|
-
return query;
|
|
109
|
-
}
|
|
110
|
-
function asCompiledSelectSql(query) {
|
|
111
|
-
return asCompiledRowsSql(query);
|
|
112
|
-
}
|
|
113
|
-
function asCompiledStatementSql(query) {
|
|
114
|
-
return query;
|
|
115
|
-
}
|
|
116
|
-
var SqlSchemaDescriptor = class {
|
|
117
|
-
// Private field gives SqlSchema nominal identity; runtime checks use instanceof.
|
|
118
|
-
#brand = true;
|
|
119
|
-
tables;
|
|
120
|
-
nodesTable;
|
|
121
|
-
edgesTable;
|
|
122
|
-
recordedNodesTable;
|
|
123
|
-
recordedEdgesTable;
|
|
124
|
-
recordedClockTable;
|
|
125
|
-
fulltextTable;
|
|
126
|
-
constructor(fields) {
|
|
127
|
-
this.tables = fields.tables;
|
|
128
|
-
this.nodesTable = fields.nodesTable;
|
|
129
|
-
this.edgesTable = fields.edgesTable;
|
|
130
|
-
this.recordedNodesTable = fields.recordedNodesTable;
|
|
131
|
-
this.recordedEdgesTable = fields.recordedEdgesTable;
|
|
132
|
-
this.recordedClockTable = fields.recordedClockTable;
|
|
133
|
-
this.fulltextTable = fields.fulltextTable;
|
|
134
|
-
void this.#brand;
|
|
135
|
-
Object.freeze(this);
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
var DEFAULT_TABLE_NAMES = {
|
|
139
|
-
nodes: "typegraph_nodes",
|
|
140
|
-
edges: "typegraph_edges",
|
|
141
|
-
recordedNodes: "typegraph_recorded_nodes",
|
|
142
|
-
recordedEdges: "typegraph_recorded_edges",
|
|
143
|
-
recordedClock: "typegraph_recorded_clock",
|
|
144
|
-
fulltext: "typegraph_node_fulltext",
|
|
145
|
-
uniques: "typegraph_node_uniques"
|
|
146
|
-
};
|
|
147
|
-
function resolveTableNames(names) {
|
|
148
|
-
return {
|
|
149
|
-
nodes: names.nodes ?? DEFAULT_TABLE_NAMES.nodes,
|
|
150
|
-
edges: names.edges ?? DEFAULT_TABLE_NAMES.edges,
|
|
151
|
-
recordedNodes: names.recordedNodes ?? DEFAULT_TABLE_NAMES.recordedNodes,
|
|
152
|
-
recordedEdges: names.recordedEdges ?? DEFAULT_TABLE_NAMES.recordedEdges,
|
|
153
|
-
recordedClock: names.recordedClock ?? DEFAULT_TABLE_NAMES.recordedClock,
|
|
154
|
-
fulltext: names.fulltext ?? DEFAULT_TABLE_NAMES.fulltext,
|
|
155
|
-
uniques: names.uniques ?? DEFAULT_TABLE_NAMES.uniques
|
|
156
|
-
};
|
|
157
|
-
}
|
|
158
|
-
var VALID_IDENTIFIER_PATTERN = /^[a-z_][a-z0-9_$]*$/i;
|
|
159
|
-
function validateTableName(name, label) {
|
|
160
|
-
if (!name || name.length === 0) {
|
|
161
|
-
throw new ConfigurationError(`${label} table name cannot be empty`);
|
|
162
|
-
}
|
|
163
|
-
if (name.length > MAX_PG_IDENTIFIER_LENGTH) {
|
|
164
|
-
throw new ConfigurationError(
|
|
165
|
-
`${label} table name exceeds maximum length of ${MAX_PG_IDENTIFIER_LENGTH} characters`
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
if (!VALID_IDENTIFIER_PATTERN.test(name)) {
|
|
169
|
-
throw new ConfigurationError(
|
|
170
|
-
`${label} table name "${name}" is not a valid SQL identifier. Table names must start with a letter or underscore and contain only letters, digits, underscores, or dollar signs.`
|
|
171
|
-
);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
function quoteIdentifier2(name) {
|
|
175
|
-
return `"${name.replaceAll('"', '""')}"`;
|
|
176
|
-
}
|
|
177
|
-
function freezeSqlSchema(fields) {
|
|
178
|
-
return new SqlSchemaDescriptor(fields);
|
|
179
|
-
}
|
|
180
|
-
function isSqlSchema(schema) {
|
|
181
|
-
return schema instanceof SqlSchemaDescriptor && Object.isFrozen(schema);
|
|
182
|
-
}
|
|
183
|
-
function requireSqlSchema(schema, surface = "SqlSchema") {
|
|
184
|
-
if (isSqlSchema(schema)) return schema;
|
|
185
|
-
throw new ConfigurationError(
|
|
186
|
-
`${surface} must be created with createSqlSchema(...).`,
|
|
187
|
-
{ code: "INVALID_SQL_SCHEMA", surface },
|
|
188
|
-
{
|
|
189
|
-
suggestion: "Pass the result of createSqlSchema(...) instead of a plain schema-shaped object."
|
|
190
|
-
}
|
|
191
|
-
);
|
|
192
|
-
}
|
|
193
|
-
function createSqlSchema(names = {}) {
|
|
194
|
-
const tables = resolveTableNames(names);
|
|
195
|
-
validateTableName(tables.nodes, "nodes");
|
|
196
|
-
validateTableName(tables.edges, "edges");
|
|
197
|
-
validateTableName(tables.recordedNodes, "recordedNodes");
|
|
198
|
-
validateTableName(tables.recordedEdges, "recordedEdges");
|
|
199
|
-
validateTableName(tables.recordedClock, "recordedClock");
|
|
200
|
-
validateTableName(tables.fulltext, "fulltext");
|
|
201
|
-
validateTableName(tables.uniques, "uniques");
|
|
202
|
-
return freezeSqlSchema({
|
|
203
|
-
tables: Object.freeze(tables),
|
|
204
|
-
nodesTable: sql.raw(quoteIdentifier2(tables.nodes)),
|
|
205
|
-
edgesTable: sql.raw(quoteIdentifier2(tables.edges)),
|
|
206
|
-
recordedNodesTable: sql.raw(quoteIdentifier2(tables.recordedNodes)),
|
|
207
|
-
recordedEdgesTable: sql.raw(quoteIdentifier2(tables.recordedEdges)),
|
|
208
|
-
recordedClockTable: sql.raw(quoteIdentifier2(tables.recordedClock)),
|
|
209
|
-
fulltextTable: sql.raw(quoteIdentifier2(tables.fulltext))
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
var EXTERNAL_RECORDED_READ_SOURCE = /* @__PURE__ */ Symbol(
|
|
213
|
-
"ExternalRecordedReadSource"
|
|
214
|
-
);
|
|
215
|
-
var TYPEGRAPH_RECORDED_READ_SOURCE = /* @__PURE__ */ Symbol(
|
|
216
|
-
"TypeGraphRecordedReadSource"
|
|
217
|
-
);
|
|
218
|
-
function recordedRelation(options) {
|
|
219
|
-
const schema = requireSqlSchema(options.schema, "recordedRelation schema");
|
|
220
|
-
return Object.freeze({
|
|
221
|
-
source: "external",
|
|
222
|
-
schema,
|
|
223
|
-
[EXTERNAL_RECORDED_READ_SOURCE]: true
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
function requireExternalRecordedReadSource(source) {
|
|
227
|
-
if (source === void 0) return void 0;
|
|
228
|
-
if (isExternalRecordedReadSource(source)) return source;
|
|
229
|
-
throw new ConfigurationError(
|
|
230
|
-
"recordedRead must be created with recordedRelation({ schema }).",
|
|
231
|
-
{ code: "INVALID_RECORDED_READ_SOURCE" },
|
|
232
|
-
{
|
|
233
|
-
suggestion: "Pass { recordedRead: recordedRelation({ schema }) } for an externally populated recorded relation. Use { history: true } when TypeGraph should capture writes."
|
|
234
|
-
}
|
|
235
|
-
);
|
|
236
|
-
}
|
|
237
|
-
function isExternalRecordedReadSource(source) {
|
|
238
|
-
if (typeof source !== "object" || source === null) return false;
|
|
239
|
-
const candidate = source;
|
|
240
|
-
return candidate.source === "external" && candidate[EXTERNAL_RECORDED_READ_SOURCE] === true && isSqlSchema(candidate.schema) && Object.isFrozen(candidate);
|
|
241
|
-
}
|
|
242
|
-
function createRecordedReadBinding(schema) {
|
|
243
|
-
const readSchema = requireSqlSchema(schema, "recorded read binding schema");
|
|
244
|
-
return Object.freeze({
|
|
245
|
-
source: "typegraph-capture",
|
|
246
|
-
schema: readSchema,
|
|
247
|
-
[TYPEGRAPH_RECORDED_READ_SOURCE]: true
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
function requireRecordedReadBinding(binding, surface) {
|
|
251
|
-
if (isRecordedReadBinding(binding)) return binding;
|
|
252
|
-
if (binding !== void 0) {
|
|
253
|
-
throw new ConfigurationError(
|
|
254
|
-
"Recorded-time reads require a recorded read relation created by TypeGraph.",
|
|
255
|
-
{ code: "INVALID_RECORDED_READ_BINDING", surface },
|
|
256
|
-
{
|
|
257
|
-
suggestion: "Use createStore(graph, backend, { history: true }) or { recordedRead: recordedRelation({ schema }) } instead of passing a plain object."
|
|
258
|
-
}
|
|
259
|
-
);
|
|
260
|
-
}
|
|
261
|
-
throw new ConfigurationError(
|
|
262
|
-
"Recorded-time reads require a recorded read relation.",
|
|
263
|
-
{ code: "RECORDED_READ_REQUIRES_BINDING", surface },
|
|
264
|
-
{
|
|
265
|
-
suggestion: "Create the store with createStore(graph, backend, { history: true }) to bind TypeGraph's built-in captured relation, or pass { recordedRead: recordedRelation({ schema }) } for an externally populated recorded relation."
|
|
266
|
-
}
|
|
267
|
-
);
|
|
268
|
-
}
|
|
269
|
-
function isTypeGraphRecordedReadSource(source) {
|
|
270
|
-
if (typeof source !== "object" || source === null) return false;
|
|
271
|
-
const candidate = source;
|
|
272
|
-
return candidate.source === "typegraph-capture" && candidate[TYPEGRAPH_RECORDED_READ_SOURCE] === true && isSqlSchema(candidate.schema) && Object.isFrozen(candidate);
|
|
273
|
-
}
|
|
274
|
-
function isRecordedReadBinding(binding) {
|
|
275
|
-
return isExternalRecordedReadSource(binding) || isTypeGraphRecordedReadSource(binding);
|
|
276
|
-
}
|
|
277
|
-
function recordedReadSqlSchema(binding) {
|
|
278
|
-
const { schema } = requireRecordedReadBinding(
|
|
279
|
-
binding,
|
|
280
|
-
"recorded-read-schema"
|
|
281
|
-
);
|
|
282
|
-
return freezeSqlSchema({
|
|
283
|
-
tables: schema.tables,
|
|
284
|
-
nodesTable: schema.recordedNodesTable,
|
|
285
|
-
edgesTable: schema.recordedEdgesTable,
|
|
286
|
-
recordedNodesTable: schema.recordedNodesTable,
|
|
287
|
-
recordedEdgesTable: schema.recordedEdgesTable,
|
|
288
|
-
recordedClockTable: schema.recordedClockTable,
|
|
289
|
-
fulltextTable: schema.fulltextTable
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
function recordedReadSchemaFor(schema, recordedAsOf, binding, surface) {
|
|
293
|
-
const baseSchema = requireSqlSchema(schema, `${surface} schema`);
|
|
294
|
-
if (recordedAsOf === void 0) return baseSchema;
|
|
295
|
-
return recordedReadSqlSchema(requireRecordedReadBinding(binding, surface));
|
|
296
|
-
}
|
|
297
|
-
var DEFAULT_SQL_SCHEMA = createSqlSchema();
|
|
298
|
-
function vectorSlotKey(nodeKind, fieldPath) {
|
|
299
|
-
return `${nodeKind}\0${fieldPath}`;
|
|
300
|
-
}
|
|
301
|
-
var ALIAS_CTE_PREFIX = "cte_";
|
|
302
|
-
var EMBEDDINGS_CTE_ALIAS = "cte_embeddings";
|
|
303
|
-
var FULLTEXT_CTE_ALIAS = "cte_fulltext";
|
|
304
|
-
var HYBRID_CANDIDATES_CTE_ALIAS = "cte_relevance_candidates";
|
|
22
|
+
import { Placeholder, sql } from 'drizzle-orm';
|
|
305
23
|
|
|
306
24
|
// src/store/collection-surface.ts
|
|
307
25
|
var CURRENT_ONLY_READ_NAMES = [
|
|
@@ -4632,7 +4350,7 @@ function compileStandardQueryWithCteStrategy(ast, graphId, ctx) {
|
|
|
4632
4350
|
...vectorPredicate === void 0 ? {} : { vectorPredicate },
|
|
4633
4351
|
...fulltextPredicate === void 0 ? {} : { fulltextPredicate }
|
|
4634
4352
|
});
|
|
4635
|
-
const
|
|
4353
|
+
const groupBy = buildStandardGroupBy({ ast, dialect });
|
|
4636
4354
|
const having2 = buildStandardHaving({ ast, ctx });
|
|
4637
4355
|
const orderBy = selectStandardOrderBy({
|
|
4638
4356
|
ast,
|
|
@@ -4649,7 +4367,7 @@ function compileStandardQueryWithCteStrategy(ast, graphId, ctx) {
|
|
|
4649
4367
|
return emitStandardQuerySql({
|
|
4650
4368
|
ctes,
|
|
4651
4369
|
fromClause,
|
|
4652
|
-
...
|
|
4370
|
+
...groupBy === void 0 ? {} : { groupBy },
|
|
4653
4371
|
...having2 === void 0 ? {} : { having: having2 },
|
|
4654
4372
|
...orderBy === void 0 ? {} : { orderBy },
|
|
4655
4373
|
...limitOffset === void 0 ? {} : { limitOffset },
|
|
@@ -4657,9 +4375,6 @@ function compileStandardQueryWithCteStrategy(ast, graphId, ctx) {
|
|
|
4657
4375
|
projection
|
|
4658
4376
|
});
|
|
4659
4377
|
}
|
|
4660
|
-
function generateId() {
|
|
4661
|
-
return nanoid();
|
|
4662
|
-
}
|
|
4663
4378
|
|
|
4664
4379
|
// src/utils/path.ts
|
|
4665
4380
|
function parseSqlitePath(path) {
|
|
@@ -5249,9 +4964,9 @@ function buildSelectiveFields(accessedFields, options) {
|
|
|
5249
4964
|
valueType: typeInfo?.valueType
|
|
5250
4965
|
};
|
|
5251
4966
|
}).toSorted((a, b) => {
|
|
5252
|
-
const aliasCompare = a.alias
|
|
4967
|
+
const aliasCompare = compareStrings(a.alias, b.alias);
|
|
5253
4968
|
if (aliasCompare !== 0) return aliasCompare;
|
|
5254
|
-
return a.field
|
|
4969
|
+
return compareStrings(a.field, b.field);
|
|
5255
4970
|
});
|
|
5256
4971
|
}
|
|
5257
4972
|
function buildAliasKindMap(state) {
|
|
@@ -5471,7 +5186,7 @@ function buildAliasPlans(state, selectiveFields, schemaIntrospector) {
|
|
|
5471
5186
|
systemOutputNames: new Set(systemFields.map((f) => f.outputName))
|
|
5472
5187
|
});
|
|
5473
5188
|
}
|
|
5474
|
-
return plans.toSorted((a, b) => a.alias
|
|
5189
|
+
return plans.toSorted((a, b) => compareStrings(a.alias, b.alias));
|
|
5475
5190
|
}
|
|
5476
5191
|
function buildSelectiveContext(row, plans, traversals) {
|
|
5477
5192
|
const context = {};
|
|
@@ -6896,9 +6611,9 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
6896
6611
|
add(traversal.edgeAlias);
|
|
6897
6612
|
}
|
|
6898
6613
|
return result.toSorted((a, b) => {
|
|
6899
|
-
const aliasCompare = a.alias
|
|
6614
|
+
const aliasCompare = compareStrings(a.alias, b.alias);
|
|
6900
6615
|
if (aliasCompare !== 0) return aliasCompare;
|
|
6901
|
-
return a.field
|
|
6616
|
+
return compareStrings(a.field, b.field);
|
|
6902
6617
|
});
|
|
6903
6618
|
}
|
|
6904
6619
|
async #tryOptimizedPaginate(cursorData, direction, pageLimit, fetchLimit, cursor, isBackward) {
|
|
@@ -6979,7 +6694,7 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
6979
6694
|
};
|
|
6980
6695
|
}
|
|
6981
6696
|
#recordOrderByFieldsForPagination(tracker) {
|
|
6982
|
-
for (const spec of this.#
|
|
6697
|
+
for (const spec of this.#paginationOrderBy()) {
|
|
6983
6698
|
const field2 = spec.field;
|
|
6984
6699
|
if (field2.path.length === 1 && field2.path[0] !== "props" && field2.jsonPointer === void 0) {
|
|
6985
6700
|
tracker.record(field2.alias, field2.path[0], true);
|
|
@@ -7004,7 +6719,7 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
7004
6719
|
row,
|
|
7005
6720
|
selectiveFields
|
|
7006
6721
|
);
|
|
7007
|
-
return buildCursorFromRow(contextRow, this.#
|
|
6722
|
+
return buildCursorFromRow(contextRow, this.#paginationOrderBy(), direction);
|
|
7008
6723
|
}
|
|
7009
6724
|
#buildCursorContextFromSelectiveRow(row, selectiveFields) {
|
|
7010
6725
|
const outputNameByAliasField = /* @__PURE__ */ new Map();
|
|
@@ -7021,7 +6736,7 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
7021
6736
|
}
|
|
7022
6737
|
}
|
|
7023
6738
|
const cursorContext = {};
|
|
7024
|
-
for (const spec of this.#
|
|
6739
|
+
for (const spec of this.#paginationOrderBy()) {
|
|
7025
6740
|
const alias = spec.field.alias;
|
|
7026
6741
|
const jsonPointer2 = spec.field.jsonPointer;
|
|
7027
6742
|
if (jsonPointer2 === void 0) {
|
|
@@ -7102,6 +6817,32 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
7102
6817
|
}
|
|
7103
6818
|
return this.#state.traversals.find((t) => t.nodeAlias === alias)?.nodeKinds;
|
|
7104
6819
|
}
|
|
6820
|
+
/**
|
|
6821
|
+
* The ORDER BY used for keyset pagination: the caller's ORDER BY plus a final
|
|
6822
|
+
* unique tiebreaker on the start alias's `id`. Without a unique final key, a
|
|
6823
|
+
* non-unique sort (e.g. `orderBy("p", "age")` with many equal ages) makes the
|
|
6824
|
+
* keyset predicate `age > lastAge` skip every not-yet-returned equal-age row,
|
|
6825
|
+
* silently losing data across pages. The start node's `id` is unique and
|
|
6826
|
+
* always projected, so appending it gives a total order that page boundaries
|
|
6827
|
+
* can split cleanly. Skipped when the caller already orders by the start
|
|
6828
|
+
* alias's `id` (the sort is already total). Every pagination read of ORDER BY
|
|
6829
|
+
* — the emitted sort, the cursor predicate, cursor encoding, and cursor
|
|
6830
|
+
* validation — routes through here so the extra column stays consistent across
|
|
6831
|
+
* the standard and selective-field-optimized paths.
|
|
6832
|
+
*/
|
|
6833
|
+
#paginationOrderBy() {
|
|
6834
|
+
const orderBy = this.#state.orderBy;
|
|
6835
|
+
const startAlias = this.#state.startAlias;
|
|
6836
|
+
const alreadyTotal = orderBy.some(
|
|
6837
|
+
(spec) => spec.field.alias === startAlias && spec.field.path.length === 1 && spec.field.path[0] === "id" && spec.field.jsonPointer === void 0
|
|
6838
|
+
);
|
|
6839
|
+
if (alreadyTotal) return orderBy;
|
|
6840
|
+
const tiebreaker = {
|
|
6841
|
+
field: { __type: "field_ref", alias: startAlias, path: ["id"] },
|
|
6842
|
+
direction: "asc"
|
|
6843
|
+
};
|
|
6844
|
+
return [...orderBy, tiebreaker];
|
|
6845
|
+
}
|
|
7105
6846
|
/**
|
|
7106
6847
|
* Executes a paginated query using cursor-based keyset pagination.
|
|
7107
6848
|
*
|
|
@@ -7140,7 +6881,7 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
7140
6881
|
let cursorData;
|
|
7141
6882
|
if (cursor) {
|
|
7142
6883
|
cursorData = decodeCursor(cursor);
|
|
7143
|
-
validateCursorColumns(cursorData, this.#
|
|
6884
|
+
validateCursorColumns(cursorData, this.#paginationOrderBy());
|
|
7144
6885
|
}
|
|
7145
6886
|
const fetchLimit = limit + 1;
|
|
7146
6887
|
const direction = isBackward ? "backward" : "forward";
|
|
@@ -7172,7 +6913,7 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
7172
6913
|
return buildPaginatedResult(
|
|
7173
6914
|
data,
|
|
7174
6915
|
orderedRows,
|
|
7175
|
-
this.#
|
|
6916
|
+
this.#paginationOrderBy(),
|
|
7176
6917
|
limit,
|
|
7177
6918
|
hasMore,
|
|
7178
6919
|
isBackward,
|
|
@@ -7218,7 +6959,7 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
7218
6959
|
*/
|
|
7219
6960
|
async #executeWithCursor(cursorData, direction, limit, options) {
|
|
7220
6961
|
const ast = this.toAst();
|
|
7221
|
-
let orderBy = this.#
|
|
6962
|
+
let orderBy = this.#paginationOrderBy();
|
|
7222
6963
|
if (direction === "backward") {
|
|
7223
6964
|
orderBy = orderBy.map((spec) => ({
|
|
7224
6965
|
...spec,
|
|
@@ -7229,7 +6970,7 @@ var ExecutableQuery = class _ExecutableQuery {
|
|
|
7229
6970
|
if (cursorData) {
|
|
7230
6971
|
const cursorPredicate = buildCursorPredicate(
|
|
7231
6972
|
cursorData,
|
|
7232
|
-
this.#
|
|
6973
|
+
this.#paginationOrderBy(),
|
|
7233
6974
|
direction,
|
|
7234
6975
|
this.#state.startAlias
|
|
7235
6976
|
);
|
|
@@ -8947,101 +8688,6 @@ function createQueryBuilderWithContext(graphId, registry, options) {
|
|
|
8947
8688
|
return new QueryBuilder(config, initialState);
|
|
8948
8689
|
}
|
|
8949
8690
|
|
|
8950
|
-
// src/store/fulltext-sync.ts
|
|
8951
|
-
var searchableFieldsCache = /* @__PURE__ */ new WeakMap();
|
|
8952
|
-
function getSearchableFields(schema) {
|
|
8953
|
-
const cached = searchableFieldsCache.get(schema);
|
|
8954
|
-
if (cached) return cached;
|
|
8955
|
-
const fields = computeSearchableFields(schema);
|
|
8956
|
-
searchableFieldsCache.set(schema, fields);
|
|
8957
|
-
return fields;
|
|
8958
|
-
}
|
|
8959
|
-
function computeSearchableFields(schema) {
|
|
8960
|
-
if (schema.type !== "object") return [];
|
|
8961
|
-
const def = schema.def;
|
|
8962
|
-
const shape = def.shape;
|
|
8963
|
-
if (!shape) return [];
|
|
8964
|
-
const fields = [];
|
|
8965
|
-
for (const [fieldPath, fieldSchema] of Object.entries(shape)) {
|
|
8966
|
-
const metadata = getSearchableMetadata(fieldSchema);
|
|
8967
|
-
if (metadata !== void 0) {
|
|
8968
|
-
fields.push({ fieldPath, metadata });
|
|
8969
|
-
}
|
|
8970
|
-
}
|
|
8971
|
-
warnIfConflictingLanguages(fields);
|
|
8972
|
-
return fields;
|
|
8973
|
-
}
|
|
8974
|
-
function warnIfConflictingLanguages(fields) {
|
|
8975
|
-
if (fields.length < 2) return;
|
|
8976
|
-
const languages = new Set(fields.map((field2) => field2.metadata.language));
|
|
8977
|
-
if (languages.size < 2) return;
|
|
8978
|
-
if (typeof console === "undefined" || typeof console.warn !== "function") {
|
|
8979
|
-
return;
|
|
8980
|
-
}
|
|
8981
|
-
const fieldSummary = fields.map((field2) => `${field2.fieldPath}=${field2.metadata.language}`).join(", ");
|
|
8982
|
-
const winning = fields[0]?.metadata.language ?? DEFAULT_SEARCHABLE_LANGUAGE;
|
|
8983
|
-
console.warn(
|
|
8984
|
-
`[typegraph] searchable() fields declare conflicting languages (${fieldSummary}). The first field's language ("${winning}") is recorded on the fulltext row; true multilingual indexing requires a dedicated node kind per language.`
|
|
8985
|
-
);
|
|
8986
|
-
}
|
|
8987
|
-
var FIELD_SEPARATOR = "\n";
|
|
8988
|
-
function resolveCombinedLanguage(fields) {
|
|
8989
|
-
return fields[0]?.metadata.language ?? DEFAULT_SEARCHABLE_LANGUAGE;
|
|
8990
|
-
}
|
|
8991
|
-
function computeFulltextContent(schema, props) {
|
|
8992
|
-
const searchableFields = getSearchableFields(schema);
|
|
8993
|
-
if (searchableFields.length === 0) return void 0;
|
|
8994
|
-
const parts = [];
|
|
8995
|
-
for (const field2 of searchableFields) {
|
|
8996
|
-
const value = props[field2.fieldPath];
|
|
8997
|
-
if (typeof value === "string" && value.length > 0) {
|
|
8998
|
-
parts.push(value);
|
|
8999
|
-
}
|
|
9000
|
-
}
|
|
9001
|
-
if (parts.length === 0) return void 0;
|
|
9002
|
-
return {
|
|
9003
|
-
content: parts.join(FIELD_SEPARATOR),
|
|
9004
|
-
language: resolveCombinedLanguage(searchableFields)
|
|
9005
|
-
};
|
|
9006
|
-
}
|
|
9007
|
-
async function syncFulltext(ctx, schema, props) {
|
|
9008
|
-
const { backend } = ctx;
|
|
9009
|
-
if (!backend.upsertFulltext || !backend.deleteFulltext) {
|
|
9010
|
-
return;
|
|
9011
|
-
}
|
|
9012
|
-
const computed = computeFulltextContent(schema, props);
|
|
9013
|
-
if (computed !== void 0) {
|
|
9014
|
-
await backend.upsertFulltext({
|
|
9015
|
-
graphId: ctx.graphId,
|
|
9016
|
-
nodeKind: ctx.nodeKind,
|
|
9017
|
-
nodeId: ctx.nodeId,
|
|
9018
|
-
content: computed.content,
|
|
9019
|
-
language: computed.language
|
|
9020
|
-
});
|
|
9021
|
-
return;
|
|
9022
|
-
}
|
|
9023
|
-
if (getSearchableFields(schema).length === 0) return;
|
|
9024
|
-
await backend.deleteFulltext({
|
|
9025
|
-
graphId: ctx.graphId,
|
|
9026
|
-
nodeKind: ctx.nodeKind,
|
|
9027
|
-
nodeId: ctx.nodeId
|
|
9028
|
-
});
|
|
9029
|
-
}
|
|
9030
|
-
async function deleteNodeFulltext(ctx, schema) {
|
|
9031
|
-
const { backend } = ctx;
|
|
9032
|
-
if (!backend.deleteFulltext) {
|
|
9033
|
-
return;
|
|
9034
|
-
}
|
|
9035
|
-
if (getSearchableFields(schema).length === 0) {
|
|
9036
|
-
return;
|
|
9037
|
-
}
|
|
9038
|
-
await backend.deleteFulltext({
|
|
9039
|
-
graphId: ctx.graphId,
|
|
9040
|
-
nodeKind: ctx.nodeKind,
|
|
9041
|
-
nodeId: ctx.nodeId
|
|
9042
|
-
});
|
|
9043
|
-
}
|
|
9044
|
-
|
|
9045
8691
|
// src/store/fulltext-rebuild.ts
|
|
9046
8692
|
var DEFAULT_PAGE_SIZE = 500;
|
|
9047
8693
|
var DEFAULT_MAX_SKIPPED_IDS = 1e4;
|
|
@@ -9215,78 +8861,6 @@ function processPage(schema, rows) {
|
|
|
9215
8861
|
return { toUpsert, toDelete, skipped, skippedIds };
|
|
9216
8862
|
}
|
|
9217
8863
|
|
|
9218
|
-
// src/store/embedding-sync.ts
|
|
9219
|
-
var embeddingFieldsCache = /* @__PURE__ */ new WeakMap();
|
|
9220
|
-
function getEmbeddingFields(schema) {
|
|
9221
|
-
const cached = embeddingFieldsCache.get(schema);
|
|
9222
|
-
if (cached) return cached;
|
|
9223
|
-
const fields = resolveEmbeddingFields(schema);
|
|
9224
|
-
embeddingFieldsCache.set(schema, fields);
|
|
9225
|
-
return fields;
|
|
9226
|
-
}
|
|
9227
|
-
async function syncEmbeddings(ctx, schema, props) {
|
|
9228
|
-
const { backend } = ctx;
|
|
9229
|
-
if (!backend.upsertEmbedding || !backend.deleteEmbedding) {
|
|
9230
|
-
return;
|
|
9231
|
-
}
|
|
9232
|
-
const embeddingFields = getEmbeddingFields(schema);
|
|
9233
|
-
if (embeddingFields.length === 0) {
|
|
9234
|
-
return;
|
|
9235
|
-
}
|
|
9236
|
-
for (const field2 of embeddingFields) {
|
|
9237
|
-
const value = props[field2.fieldPath];
|
|
9238
|
-
if (isValidEmbeddingValue(value)) {
|
|
9239
|
-
await backend.upsertEmbedding({
|
|
9240
|
-
graphId: ctx.graphId,
|
|
9241
|
-
nodeKind: ctx.nodeKind,
|
|
9242
|
-
nodeId: ctx.nodeId,
|
|
9243
|
-
fieldPath: field2.fieldPath,
|
|
9244
|
-
embedding: value,
|
|
9245
|
-
dimensions: field2.dimensions,
|
|
9246
|
-
metric: field2.metric,
|
|
9247
|
-
indexType: field2.indexType
|
|
9248
|
-
});
|
|
9249
|
-
} else if (value === void 0) {
|
|
9250
|
-
await backend.deleteEmbedding({
|
|
9251
|
-
graphId: ctx.graphId,
|
|
9252
|
-
nodeKind: ctx.nodeKind,
|
|
9253
|
-
nodeId: ctx.nodeId,
|
|
9254
|
-
fieldPath: field2.fieldPath,
|
|
9255
|
-
dimensions: field2.dimensions,
|
|
9256
|
-
metric: field2.metric,
|
|
9257
|
-
indexType: field2.indexType
|
|
9258
|
-
});
|
|
9259
|
-
}
|
|
9260
|
-
}
|
|
9261
|
-
}
|
|
9262
|
-
async function deleteNodeEmbeddings(ctx, schema) {
|
|
9263
|
-
const { backend } = ctx;
|
|
9264
|
-
if (!backend.deleteEmbedding) {
|
|
9265
|
-
return;
|
|
9266
|
-
}
|
|
9267
|
-
const embeddingFields = getEmbeddingFields(schema);
|
|
9268
|
-
if (embeddingFields.length === 0) {
|
|
9269
|
-
return;
|
|
9270
|
-
}
|
|
9271
|
-
for (const field2 of embeddingFields) {
|
|
9272
|
-
await backend.deleteEmbedding({
|
|
9273
|
-
graphId: ctx.graphId,
|
|
9274
|
-
nodeKind: ctx.nodeKind,
|
|
9275
|
-
nodeId: ctx.nodeId,
|
|
9276
|
-
fieldPath: field2.fieldPath,
|
|
9277
|
-
dimensions: field2.dimensions,
|
|
9278
|
-
metric: field2.metric,
|
|
9279
|
-
indexType: field2.indexType
|
|
9280
|
-
});
|
|
9281
|
-
}
|
|
9282
|
-
}
|
|
9283
|
-
function isValidEmbeddingValue(value) {
|
|
9284
|
-
if (!Array.isArray(value)) {
|
|
9285
|
-
return false;
|
|
9286
|
-
}
|
|
9287
|
-
return value.every((n) => typeof n === "number" && Number.isFinite(n));
|
|
9288
|
-
}
|
|
9289
|
-
|
|
9290
8864
|
// src/store/search.ts
|
|
9291
8865
|
function resolveSearchSlot(ctx, nodeKind, fieldPath) {
|
|
9292
8866
|
const nodeType = ctx.registry.getNodeType(nodeKind);
|
|
@@ -9512,7 +9086,7 @@ async function executeHybridSearch(ctx, nodeKind, options) {
|
|
|
9512
9086
|
fused.set(row.nodeId, entry2);
|
|
9513
9087
|
}
|
|
9514
9088
|
const ranked = [...fused.values()].toSorted(
|
|
9515
|
-
(a, b) => b.fusedScore - a.fusedScore || a.nodeId
|
|
9089
|
+
(a, b) => b.fusedScore - a.fusedScore || compareStrings(a.nodeId, b.nodeId)
|
|
9516
9090
|
).slice(0, options.limit);
|
|
9517
9091
|
const ids = ranked.map((entry2) => entry2.nodeId);
|
|
9518
9092
|
const nodeMap = await fetchNodesByIds(backend, graphId, nodeKind, ids);
|
|
@@ -10631,33 +10205,6 @@ function createGraphAlgorithms(params) {
|
|
|
10631
10205
|
};
|
|
10632
10206
|
}
|
|
10633
10207
|
|
|
10634
|
-
// src/store/row-fetch.ts
|
|
10635
|
-
async function getRowsByIds(ids, policy) {
|
|
10636
|
-
const rowsById = /* @__PURE__ */ new Map();
|
|
10637
|
-
if (ids.length === 0) return rowsById;
|
|
10638
|
-
if (policy.batch !== void 0) {
|
|
10639
|
-
const rows2 = await policy.batch(ids);
|
|
10640
|
-
for (const row of rows2) {
|
|
10641
|
-
rowsById.set(row.id, row);
|
|
10642
|
-
}
|
|
10643
|
-
return rowsById;
|
|
10644
|
-
}
|
|
10645
|
-
const uniqueIds = [...new Set(ids)];
|
|
10646
|
-
const rows = await Promise.all(uniqueIds.map((id) => policy.one(id)));
|
|
10647
|
-
for (const row of rows) {
|
|
10648
|
-
if (row !== void 0) rowsById.set(row.id, row);
|
|
10649
|
-
}
|
|
10650
|
-
return rowsById;
|
|
10651
|
-
}
|
|
10652
|
-
|
|
10653
|
-
// src/store/edge-fetch.ts
|
|
10654
|
-
async function getEdgeRowsByIds(backend, graphId, ids) {
|
|
10655
|
-
return getRowsByIds(ids, {
|
|
10656
|
-
batch: backend.getEdges === void 0 ? void 0 : (batchIds) => backend.getEdges(graphId, batchIds),
|
|
10657
|
-
one: (id) => backend.getEdge(graphId, id)
|
|
10658
|
-
});
|
|
10659
|
-
}
|
|
10660
|
-
|
|
10661
10208
|
// src/store/collections/edge-collection.ts
|
|
10662
10209
|
function narrowEdge(edge) {
|
|
10663
10210
|
return edge;
|
|
@@ -10989,14 +10536,6 @@ function createEdgeCollection(config) {
|
|
|
10989
10536
|
};
|
|
10990
10537
|
}
|
|
10991
10538
|
|
|
10992
|
-
// src/store/node-fetch.ts
|
|
10993
|
-
async function getNodeRowsByIds(backend, graphId, kind, ids) {
|
|
10994
|
-
return getRowsByIds(ids, {
|
|
10995
|
-
batch: backend.getNodes === void 0 ? void 0 : (batchIds) => backend.getNodes(graphId, kind, batchIds),
|
|
10996
|
-
one: (id) => backend.getNode(graphId, kind, id)
|
|
10997
|
-
});
|
|
10998
|
-
}
|
|
10999
|
-
|
|
11000
10539
|
// src/store/collections/node-collection.ts
|
|
11001
10540
|
function narrowNode(node) {
|
|
11002
10541
|
return node;
|
|
@@ -11269,20 +10808,14 @@ function createNodeCollection(config) {
|
|
|
11269
10808
|
return results.map((bucket) => narrowNodes(bucket));
|
|
11270
10809
|
},
|
|
11271
10810
|
async getOrCreateByConstraint(constraintName, props, options) {
|
|
11272
|
-
const
|
|
11273
|
-
|
|
11274
|
-
|
|
11275
|
-
|
|
11276
|
-
|
|
11277
|
-
|
|
11278
|
-
|
|
11279
|
-
|
|
11280
|
-
return result;
|
|
11281
|
-
};
|
|
11282
|
-
if (backend.capabilities.transactions && "transaction" in backend) {
|
|
11283
|
-
return backend.transaction(async (txBackend) => execute(txBackend));
|
|
11284
|
-
}
|
|
11285
|
-
return execute(backend);
|
|
10811
|
+
const result = await executeGetOrCreateByConstraint(
|
|
10812
|
+
kind,
|
|
10813
|
+
constraintName,
|
|
10814
|
+
props,
|
|
10815
|
+
backend,
|
|
10816
|
+
options
|
|
10817
|
+
);
|
|
10818
|
+
return result;
|
|
11286
10819
|
},
|
|
11287
10820
|
async bulkGetOrCreateByConstraint(constraintName, items, options) {
|
|
11288
10821
|
if (items.length === 0) return [];
|
|
@@ -11734,990 +11267,25 @@ async function computeIndexSignature(dialect, targetTableName, declaration) {
|
|
|
11734
11267
|
const json = JSON.stringify(hashable, sortedReplacer);
|
|
11735
11268
|
return sha256Hex(json, 16);
|
|
11736
11269
|
}
|
|
11737
|
-
|
|
11738
|
-
|
|
11739
|
-
|
|
11740
|
-
return {
|
|
11741
|
-
one: (params) => backend.insertNode(params),
|
|
11742
|
-
oneNoReturn: backend.insertNodeNoReturn === void 0 ? void 0 : (params) => backend.insertNodeNoReturn(params),
|
|
11743
|
-
batch: backend.insertNodesBatch === void 0 ? void 0 : (params) => backend.insertNodesBatch(params),
|
|
11744
|
-
batchReturning: backend.insertNodesBatchReturning === void 0 ? void 0 : (params) => backend.insertNodesBatchReturning(params)
|
|
11745
|
-
};
|
|
11746
|
-
}
|
|
11747
|
-
function edgeInsertDispatch(backend) {
|
|
11748
|
-
return {
|
|
11749
|
-
one: (params) => backend.insertEdge(params),
|
|
11750
|
-
oneNoReturn: backend.insertEdgeNoReturn === void 0 ? void 0 : (params) => backend.insertEdgeNoReturn(params),
|
|
11751
|
-
batch: backend.insertEdgesBatch === void 0 ? void 0 : (params) => backend.insertEdgesBatch(params),
|
|
11752
|
-
batchReturning: backend.insertEdgesBatchReturning === void 0 ? void 0 : (params) => backend.insertEdgesBatchReturning(params)
|
|
11753
|
-
};
|
|
11754
|
-
}
|
|
11755
|
-
async function runInsertNoReturn(dispatch, params) {
|
|
11756
|
-
if (dispatch.oneNoReturn !== void 0) {
|
|
11757
|
-
await dispatch.oneNoReturn(params);
|
|
11758
|
-
return;
|
|
11759
|
-
}
|
|
11760
|
-
await dispatch.one(params);
|
|
11761
|
-
}
|
|
11762
|
-
async function runInsertBatch(dispatch, params) {
|
|
11763
|
-
if (params.length === 0) return;
|
|
11764
|
-
if (dispatch.batch !== void 0) {
|
|
11765
|
-
await dispatch.batch(params);
|
|
11766
|
-
return;
|
|
11767
|
-
}
|
|
11768
|
-
for (const insertParams of params) {
|
|
11769
|
-
await runInsertNoReturn(dispatch, insertParams);
|
|
11770
|
-
}
|
|
11771
|
-
}
|
|
11772
|
-
async function runInsertBatchReturning(dispatch, params) {
|
|
11773
|
-
if (dispatch.batchReturning !== void 0) {
|
|
11774
|
-
return dispatch.batchReturning(params);
|
|
11775
|
-
}
|
|
11776
|
-
const rows = [];
|
|
11777
|
-
for (const insertParams of params) {
|
|
11778
|
-
rows.push(await dispatch.one(insertParams));
|
|
11779
|
-
}
|
|
11780
|
-
return rows;
|
|
11781
|
-
}
|
|
11782
|
-
function requireRecordedSchema(target) {
|
|
11783
|
-
if (target.tableNames === void 0) {
|
|
11784
|
-
throw new ConfigurationError(
|
|
11785
|
-
"Recorded-time capture requires the backend to expose tableNames.",
|
|
11786
|
-
{ dialect: target.dialect },
|
|
11787
|
-
{
|
|
11788
|
-
suggestion: "Use a built-in SQLite/PostgreSQL backend, or set tableNames on the custom backend so recorded-time capture targets the configured relations."
|
|
11789
|
-
}
|
|
11790
|
-
);
|
|
11791
|
-
}
|
|
11792
|
-
return createSqlSchema(target.tableNames);
|
|
11270
|
+
var ENTITY_KINDS = ["node", "edge"];
|
|
11271
|
+
function buildPendingKindRemoval(args) {
|
|
11272
|
+
return { ...args, removedAt: void 0, error: void 0 };
|
|
11793
11273
|
}
|
|
11794
|
-
function
|
|
11795
|
-
|
|
11274
|
+
async function materializeRemovals(context, options = {}) {
|
|
11275
|
+
const { backend, graphId } = context;
|
|
11276
|
+
if (backend.executeDdl === void 0 || backend.recordKindRemoval === void 0 || backend.getPendingKindRemovals === void 0) {
|
|
11796
11277
|
throw new ConfigurationError(
|
|
11797
|
-
"
|
|
11798
|
-
{
|
|
11799
|
-
{
|
|
11800
|
-
suggestion: "Use the built-in SQLite/PostgreSQL backends or provide executeStatement on the custom backend's transaction target."
|
|
11801
|
-
}
|
|
11278
|
+
"store.materializeRemovals() requires a backend with kind-removal primitives (executeDdl, recordKindRemoval, getPendingKindRemovals). The bundled SQLite and Postgres backends provide them.",
|
|
11279
|
+
{ code: "MATERIALIZE_REMOVALS_BACKEND_UNSUPPORTED" }
|
|
11802
11280
|
);
|
|
11803
11281
|
}
|
|
11804
|
-
|
|
11805
|
-
|
|
11806
|
-
|
|
11807
|
-
await
|
|
11808
|
-
|
|
11809
|
-
|
|
11810
|
-
|
|
11811
|
-
"Recorded-time capture on PostgreSQL requires read_committed isolation.",
|
|
11812
|
-
{ isolationLevel: isolationLevel ?? "unknown" },
|
|
11813
|
-
{
|
|
11814
|
-
suggestion: "Omit the transaction isolation option or use read_committed. PostgreSQL repeatable_read/serializable snapshots cannot safely allocate the per-graph recorded clock inside the captured transaction."
|
|
11815
|
-
}
|
|
11816
|
-
);
|
|
11817
|
-
}
|
|
11818
|
-
function isSupportedRecordedIsolationLevel(isolationLevel) {
|
|
11819
|
-
return isolationLevel === void 0 || isolationLevel === "read_committed" || isolationLevel === "read_uncommitted";
|
|
11820
|
-
}
|
|
11821
|
-
function assertRequestedRecordedIsolation(backend, options) {
|
|
11822
|
-
if (backend.dialect !== "postgres") return;
|
|
11823
|
-
const isolationLevel = options?.isolationLevel;
|
|
11824
|
-
if (isSupportedRecordedIsolationLevel(isolationLevel)) return;
|
|
11825
|
-
throw unsupportedPostgresIsolationError(isolationLevel);
|
|
11826
|
-
}
|
|
11827
|
-
function normalizeIsolationLevel(value) {
|
|
11828
|
-
if (typeof value !== "string") return void 0;
|
|
11829
|
-
return value.replaceAll(" ", "_").toLowerCase();
|
|
11830
|
-
}
|
|
11831
|
-
async function assertRecordedCaptureTransactionIsolation(target) {
|
|
11832
|
-
if (target.dialect !== "postgres") return;
|
|
11833
|
-
const rows = await target.execute(
|
|
11834
|
-
asCompiledRowsSql(sql`
|
|
11835
|
-
SELECT current_setting('transaction_isolation') AS transaction_isolation
|
|
11836
|
-
`)
|
|
11837
|
-
);
|
|
11838
|
-
const isolationLevel = normalizeIsolationLevel(
|
|
11839
|
-
rows[0]?.transaction_isolation
|
|
11840
|
-
);
|
|
11841
|
-
if (isSupportedRecordedIsolationLevel(isolationLevel)) return;
|
|
11842
|
-
throw unsupportedPostgresIsolationError(isolationLevel);
|
|
11843
|
-
}
|
|
11844
|
-
function recordedCaptureRequiresCallbackTransactionError(details) {
|
|
11845
|
-
return new ConfigurationError(
|
|
11846
|
-
"withTransaction() has no recorded-time capture flush point when history is enabled.",
|
|
11847
|
-
details,
|
|
11848
|
-
{
|
|
11849
|
-
suggestion: "Use store.withRecordedTransaction(externalTx, async (tx) => ...) so TypeGraph can flush capture before the caller commits."
|
|
11850
|
-
}
|
|
11851
|
-
);
|
|
11852
|
-
}
|
|
11853
|
-
function historyUnsafeRawWriteError(surface) {
|
|
11854
|
-
return new ConfigurationError(
|
|
11855
|
-
`${surface} is not available when history capture is enabled because raw SQL writes bypass recorded-time capture.`,
|
|
11856
|
-
{ code: "RECORDED_CAPTURE_RAW_SQL_DISABLED" },
|
|
11857
|
-
{
|
|
11858
|
-
suggestion: "Run graph writes through store.nodes/store.edges (or tx.nodes/tx.edges inside a transaction), or perform raw relational writes outside a history-enabled TypeGraph store."
|
|
11859
|
-
}
|
|
11860
|
-
);
|
|
11861
|
-
}
|
|
11862
|
-
function failHistoryUnsafeSqlRef() {
|
|
11863
|
-
throw historyUnsafeRawWriteError("tx.sql");
|
|
11864
|
-
}
|
|
11865
|
-
function createHistoryUnsafeSqlRef() {
|
|
11866
|
-
return new Proxy(
|
|
11867
|
-
function historyUnsafeSqlRef() {
|
|
11868
|
-
return failHistoryUnsafeSqlRef();
|
|
11869
|
-
},
|
|
11870
|
-
{
|
|
11871
|
-
get() {
|
|
11872
|
-
return failHistoryUnsafeSqlRef();
|
|
11873
|
-
},
|
|
11874
|
-
apply() {
|
|
11875
|
-
return failHistoryUnsafeSqlRef();
|
|
11876
|
-
},
|
|
11877
|
-
set() {
|
|
11878
|
-
return failHistoryUnsafeSqlRef();
|
|
11879
|
-
},
|
|
11880
|
-
defineProperty() {
|
|
11881
|
-
return failHistoryUnsafeSqlRef();
|
|
11882
|
-
},
|
|
11883
|
-
deleteProperty() {
|
|
11884
|
-
return failHistoryUnsafeSqlRef();
|
|
11885
|
-
},
|
|
11886
|
-
// Enumeration / inspection traps too, so spreading (`{...tx.sql}`),
|
|
11887
|
-
// `Object.keys`, `in`, and prototype reads also fail loudly rather than
|
|
11888
|
-
// silently yielding an empty object that reads as "no raw handle".
|
|
11889
|
-
has() {
|
|
11890
|
-
return failHistoryUnsafeSqlRef();
|
|
11891
|
-
},
|
|
11892
|
-
ownKeys() {
|
|
11893
|
-
return failHistoryUnsafeSqlRef();
|
|
11894
|
-
},
|
|
11895
|
-
getOwnPropertyDescriptor() {
|
|
11896
|
-
return failHistoryUnsafeSqlRef();
|
|
11897
|
-
},
|
|
11898
|
-
getPrototypeOf() {
|
|
11899
|
-
return failHistoryUnsafeSqlRef();
|
|
11900
|
-
}
|
|
11901
|
-
}
|
|
11902
|
-
);
|
|
11903
|
-
}
|
|
11904
|
-
function rawWriteGuards(target, prefix) {
|
|
11905
|
-
return {
|
|
11906
|
-
...target.executeStatement === void 0 ? {} : {
|
|
11907
|
-
executeStatement(_query) {
|
|
11908
|
-
return Promise.reject(
|
|
11909
|
-
historyUnsafeRawWriteError(`${prefix}.executeStatement`)
|
|
11910
|
-
);
|
|
11911
|
-
}
|
|
11912
|
-
},
|
|
11913
|
-
...target.executeDdl === void 0 ? {} : {
|
|
11914
|
-
executeDdl(_ddl) {
|
|
11915
|
-
return Promise.reject(
|
|
11916
|
-
historyUnsafeRawWriteError(`${prefix}.executeDdl`)
|
|
11917
|
-
);
|
|
11918
|
-
}
|
|
11919
|
-
}
|
|
11920
|
-
};
|
|
11921
|
-
}
|
|
11922
|
-
function assertCapturableBackend(backend) {
|
|
11923
|
-
if (!backend.capabilities.transactions) {
|
|
11924
|
-
throw new ConfigurationError(
|
|
11925
|
-
"history: true requires a backend with transaction support.",
|
|
11926
|
-
{ dialect: backend.dialect },
|
|
11927
|
-
{
|
|
11928
|
-
suggestion: "Use a transactional SQLite/PostgreSQL backend or disable recorded-time capture for this store."
|
|
11929
|
-
}
|
|
11930
|
-
);
|
|
11931
|
-
}
|
|
11932
|
-
if (backend.executeStatement === void 0) {
|
|
11933
|
-
throw new ConfigurationError(
|
|
11934
|
-
"history: true requires a backend that supports executeStatement.",
|
|
11935
|
-
{ dialect: backend.dialect },
|
|
11936
|
-
{
|
|
11937
|
-
suggestion: "Use a built-in SQLite/PostgreSQL backend, or implement executeStatement on the custom backend so recorded-time capture can write history rows."
|
|
11938
|
-
}
|
|
11939
|
-
);
|
|
11940
|
-
}
|
|
11941
|
-
if (backend.capabilities.returning === false) {
|
|
11942
|
-
throw new ConfigurationError(
|
|
11943
|
-
"history: true requires a backend that supports UPDATE \u2026 RETURNING.",
|
|
11944
|
-
{ dialect: backend.dialect },
|
|
11945
|
-
{
|
|
11946
|
-
suggestion: "Use a built-in SQLite/PostgreSQL backend, or run recorded-time capture on a backend whose engine supports UPDATE \u2026 RETURNING \u2014 capture closes recorded intervals with a RETURNING statement on its hot path."
|
|
11947
|
-
}
|
|
11948
|
-
);
|
|
11949
|
-
}
|
|
11950
|
-
if (backend.tableNames === void 0) {
|
|
11951
|
-
throw new ConfigurationError(
|
|
11952
|
-
"history: true requires a backend that exposes tableNames.",
|
|
11953
|
-
{ dialect: backend.dialect },
|
|
11954
|
-
{
|
|
11955
|
-
suggestion: "Use a built-in SQLite/PostgreSQL backend, or set tableNames on the custom backend so recorded-time capture can resolve the recorded relations instead of silently falling back to defaults."
|
|
11956
|
-
}
|
|
11957
|
-
);
|
|
11958
|
-
}
|
|
11959
|
-
}
|
|
11960
|
-
|
|
11961
|
-
// src/store/recorded-capture/clock.ts
|
|
11962
|
-
var RECORDED_MIN = "1970-01-01T00:00:00.000Z";
|
|
11963
|
-
var RECORDED_MAX_TIME = new Date(RECORDED_MAX).getTime();
|
|
11964
|
-
var RECORDED_CLOCK_ADVISORY_LOCK_NAMESPACE = "typegraph:recorded-clock";
|
|
11965
|
-
function recordedClockAdvisoryLockSql(graphId) {
|
|
11966
|
-
return sql`
|
|
11967
|
-
SELECT pg_advisory_xact_lock(
|
|
11968
|
-
hashtext(${RECORDED_CLOCK_ADVISORY_LOCK_NAMESPACE}),
|
|
11969
|
-
hashtext(${graphId})
|
|
11970
|
-
)
|
|
11971
|
-
`;
|
|
11972
|
-
}
|
|
11973
|
-
function failInvalidClockTimestamp(value) {
|
|
11974
|
-
throw new ConfigurationError(
|
|
11975
|
-
"Recorded clock row contained an invalid timestamp",
|
|
11976
|
-
{ value }
|
|
11977
|
-
);
|
|
11978
|
-
}
|
|
11979
|
-
var ZONELESS_DATETIME_PATTERN = /^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?$/;
|
|
11980
|
-
var OFFSET_DATETIME_PATTERN = /^(\d{4}-\d{2}-\d{2})[ T](\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?)(Z|[+-]\d{2}(?::?\d{2})?)$/i;
|
|
11981
|
-
function normalizeOffsetDesignator(offset) {
|
|
11982
|
-
if (offset.toUpperCase() === "Z") return "Z";
|
|
11983
|
-
if (/^[+-]\d{2}$/.test(offset)) return `${offset}:00`;
|
|
11984
|
-
if (/^[+-]\d{4}$/.test(offset)) {
|
|
11985
|
-
return `${offset.slice(0, 3)}:${offset.slice(3)}`;
|
|
11986
|
-
}
|
|
11987
|
-
return offset;
|
|
11988
|
-
}
|
|
11989
|
-
function clockTimestampMs(value) {
|
|
11990
|
-
if (ZONELESS_DATETIME_PATTERN.test(value)) {
|
|
11991
|
-
return Date.parse(`${value.replace(" ", "T")}Z`);
|
|
11992
|
-
}
|
|
11993
|
-
const offsetMatch = OFFSET_DATETIME_PATTERN.exec(value);
|
|
11994
|
-
if (offsetMatch) {
|
|
11995
|
-
const [, date, time, offset] = offsetMatch;
|
|
11996
|
-
return Date.parse(`${date}T${time}${normalizeOffsetDesignator(offset)}`);
|
|
11997
|
-
}
|
|
11998
|
-
return Date.parse(value);
|
|
11999
|
-
}
|
|
12000
|
-
function toCanonicalIso(value) {
|
|
12001
|
-
if (value instanceof Date) {
|
|
12002
|
-
if (Number.isNaN(value.getTime())) return failInvalidClockTimestamp(value);
|
|
12003
|
-
return value.toISOString();
|
|
12004
|
-
}
|
|
12005
|
-
if (typeof value === "string") {
|
|
12006
|
-
const timestamp = clockTimestampMs(value);
|
|
12007
|
-
if (Number.isNaN(timestamp)) return failInvalidClockTimestamp(value);
|
|
12008
|
-
return new Date(timestamp).toISOString();
|
|
12009
|
-
}
|
|
12010
|
-
return failInvalidClockTimestamp(value);
|
|
12011
|
-
}
|
|
12012
|
-
function nextRecordedCommitTime(previous) {
|
|
12013
|
-
const wallTime = Date.parse(nowIso());
|
|
12014
|
-
return previous === void 0 ? wallTime : Math.max(wallTime, Date.parse(previous) + 1);
|
|
12015
|
-
}
|
|
12016
|
-
async function readRecordedClock(target, schema, graphId) {
|
|
12017
|
-
const rows = await target.execute(
|
|
12018
|
-
asCompiledRowsSql(sql`
|
|
12019
|
-
SELECT recorded_at
|
|
12020
|
-
FROM ${schema.recordedClockTable}
|
|
12021
|
-
WHERE graph_id = ${graphId}
|
|
12022
|
-
`)
|
|
12023
|
-
);
|
|
12024
|
-
const first = rows[0];
|
|
12025
|
-
return first === void 0 ? void 0 : toCanonicalIso(first.recorded_at);
|
|
12026
|
-
}
|
|
12027
|
-
async function writeRecordedClock(target, schema, graphId, recordedAt) {
|
|
12028
|
-
await executeStatement(
|
|
12029
|
-
target,
|
|
12030
|
-
sql`
|
|
12031
|
-
INSERT INTO ${schema.recordedClockTable} (graph_id, recorded_at)
|
|
12032
|
-
VALUES (${graphId}, ${recordedAt})
|
|
12033
|
-
ON CONFLICT (graph_id) DO UPDATE SET recorded_at = ${recordedAt}
|
|
12034
|
-
`
|
|
12035
|
-
);
|
|
12036
|
-
}
|
|
12037
|
-
async function lockRecordedClock(target, schema, graphId, ownsWriteLock) {
|
|
12038
|
-
if (target.dialect === "postgres") {
|
|
12039
|
-
await target.execute(
|
|
12040
|
-
asCompiledRowsSql(recordedClockAdvisoryLockSql(graphId))
|
|
12041
|
-
);
|
|
12042
|
-
return;
|
|
12043
|
-
}
|
|
12044
|
-
if (ownsWriteLock) return;
|
|
12045
|
-
await executeStatement(
|
|
12046
|
-
target,
|
|
12047
|
-
sql`
|
|
12048
|
-
INSERT INTO ${schema.recordedClockTable} (graph_id, recorded_at)
|
|
12049
|
-
VALUES (${graphId}, ${RECORDED_MIN})
|
|
12050
|
-
ON CONFLICT (graph_id) DO UPDATE SET recorded_at = recorded_at
|
|
12051
|
-
`
|
|
12052
|
-
);
|
|
12053
|
-
}
|
|
12054
|
-
async function allocateRecordedCommit(target, schema, graphId, ownsWriteLock) {
|
|
12055
|
-
await lockRecordedClock(target, schema, graphId, ownsWriteLock);
|
|
12056
|
-
const previous = await readRecordedClock(target, schema, graphId);
|
|
12057
|
-
const recordedCommitTime = nextRecordedCommitTime(previous);
|
|
12058
|
-
if (!Number.isFinite(recordedCommitTime) || recordedCommitTime >= RECORDED_MAX_TIME) {
|
|
12059
|
-
throw new ConfigurationError(
|
|
12060
|
-
`Recorded commit clock reached the open sentinel ${RECORDED_MAX}`,
|
|
12061
|
-
{ graphId, recordedCommitTime },
|
|
12062
|
-
{
|
|
12063
|
-
suggestion: "Use a graph with a normal recorded-time clock; the open sentinel is reserved for relation intervals."
|
|
12064
|
-
}
|
|
12065
|
-
);
|
|
12066
|
-
}
|
|
12067
|
-
const recordedCommit = new Date(recordedCommitTime).toISOString();
|
|
12068
|
-
await writeRecordedClock(target, schema, graphId, recordedCommit);
|
|
12069
|
-
return recordedCommit;
|
|
12070
|
-
}
|
|
12071
|
-
var RECORDED_HISTORY_META = "{}";
|
|
12072
|
-
var RECORDED_NODE_COLUMNS = [
|
|
12073
|
-
"history_id",
|
|
12074
|
-
"graph_id",
|
|
12075
|
-
"kind",
|
|
12076
|
-
"id",
|
|
12077
|
-
"props",
|
|
12078
|
-
"version",
|
|
12079
|
-
"valid_from",
|
|
12080
|
-
"valid_to",
|
|
12081
|
-
"created_at",
|
|
12082
|
-
"updated_at",
|
|
12083
|
-
"deleted_at",
|
|
12084
|
-
"recorded_from",
|
|
12085
|
-
"recorded_to",
|
|
12086
|
-
"op",
|
|
12087
|
-
"schema_version",
|
|
12088
|
-
"tx_id",
|
|
12089
|
-
"meta"
|
|
12090
|
-
];
|
|
12091
|
-
var RECORDED_EDGE_COLUMNS = [
|
|
12092
|
-
"history_id",
|
|
12093
|
-
"graph_id",
|
|
12094
|
-
"id",
|
|
12095
|
-
"kind",
|
|
12096
|
-
"from_kind",
|
|
12097
|
-
"from_id",
|
|
12098
|
-
"to_kind",
|
|
12099
|
-
"to_id",
|
|
12100
|
-
"props",
|
|
12101
|
-
"valid_from",
|
|
12102
|
-
"valid_to",
|
|
12103
|
-
"created_at",
|
|
12104
|
-
"updated_at",
|
|
12105
|
-
"deleted_at",
|
|
12106
|
-
"recorded_from",
|
|
12107
|
-
"recorded_to",
|
|
12108
|
-
"op",
|
|
12109
|
-
"schema_version",
|
|
12110
|
-
"tx_id",
|
|
12111
|
-
"meta"
|
|
12112
|
-
];
|
|
12113
|
-
var RECORDED_NODE_COLUMN_LIST = sql.raw(RECORDED_NODE_COLUMNS.join(", "));
|
|
12114
|
-
var RECORDED_EDGE_COLUMN_LIST = sql.raw(RECORDED_EDGE_COLUMNS.join(", "));
|
|
12115
|
-
var RECORDED_BIND_PARAM_BUDGET = 900;
|
|
12116
|
-
function recordedBindParamBudget(target) {
|
|
12117
|
-
const budget = target.capabilities.maxBindParameters ?? RECORDED_BIND_PARAM_BUDGET;
|
|
12118
|
-
if (!Number.isSafeInteger(budget) || budget < 1) {
|
|
12119
|
-
throw new ConfigurationError(
|
|
12120
|
-
`backend capabilities.maxBindParameters must be a positive integer, got: ${String(budget)}`,
|
|
12121
|
-
{
|
|
12122
|
-
code: "INVALID_BACKEND_CAPABILITY",
|
|
12123
|
-
capability: "maxBindParameters",
|
|
12124
|
-
value: budget
|
|
12125
|
-
}
|
|
12126
|
-
);
|
|
12127
|
-
}
|
|
12128
|
-
return budget;
|
|
12129
|
-
}
|
|
12130
|
-
function recordedChunkSize(target, columnCount) {
|
|
12131
|
-
const budget = recordedBindParamBudget(target);
|
|
12132
|
-
return Math.max(1, Math.floor(budget / columnCount));
|
|
12133
|
-
}
|
|
12134
|
-
function recordedCommonCells() {
|
|
12135
|
-
return {
|
|
12136
|
-
history_id: () => sql`${generateId()}`,
|
|
12137
|
-
graph_id: (row) => sql`${row.graph_id}`,
|
|
12138
|
-
id: (row) => sql`${row.id}`,
|
|
12139
|
-
kind: (row) => sql`${row.kind}`,
|
|
12140
|
-
props: (row) => sql`${row.props}`,
|
|
12141
|
-
valid_from: (row) => sql`${sqlNull(row.valid_from)}`,
|
|
12142
|
-
valid_to: (row) => sql`${sqlNull(row.valid_to)}`,
|
|
12143
|
-
created_at: (row) => sql`${row.created_at}`,
|
|
12144
|
-
updated_at: (row) => sql`${row.updated_at}`,
|
|
12145
|
-
deleted_at: (row) => sql`${sqlNull(row.deleted_at)}`,
|
|
12146
|
-
recorded_from: (_row, recordedCommit) => sql`${recordedCommit}`,
|
|
12147
|
-
recorded_to: () => sql`${RECORDED_MAX}`,
|
|
12148
|
-
op: (_row, _recordedCommit, operation) => sql`${operation}`,
|
|
12149
|
-
schema_version: () => sql`NULL`,
|
|
12150
|
-
tx_id: () => sql`NULL`,
|
|
12151
|
-
meta: () => sql`${RECORDED_HISTORY_META}`
|
|
12152
|
-
};
|
|
12153
|
-
}
|
|
12154
|
-
var recordedNodeCells = {
|
|
12155
|
-
...recordedCommonCells(),
|
|
12156
|
-
version: (row) => sql`${row.version}`
|
|
12157
|
-
};
|
|
12158
|
-
var recordedEdgeCells = {
|
|
12159
|
-
...recordedCommonCells(),
|
|
12160
|
-
from_kind: (row) => sql`${row.from_kind}`,
|
|
12161
|
-
from_id: (row) => sql`${row.from_id}`,
|
|
12162
|
-
to_kind: (row) => sql`${row.to_kind}`,
|
|
12163
|
-
to_id: (row) => sql`${row.to_id}`
|
|
12164
|
-
};
|
|
12165
|
-
function recordedValuesTuple(columns, cells, row, recordedCommit, operation) {
|
|
12166
|
-
const tuple = columns.map(
|
|
12167
|
-
(column) => cells[column](row, recordedCommit, operation)
|
|
12168
|
-
);
|
|
12169
|
-
return sql`(${sql.join(tuple, sql`, `)})`;
|
|
12170
|
-
}
|
|
12171
|
-
async function insertRecordedRows(target, table, columnList, columns, cells, inserts, recordedCommit) {
|
|
12172
|
-
if (inserts.length === 0) return;
|
|
12173
|
-
const values = inserts.map(
|
|
12174
|
-
(insert) => recordedValuesTuple(
|
|
12175
|
-
columns,
|
|
12176
|
-
cells,
|
|
12177
|
-
insert.row,
|
|
12178
|
-
recordedCommit,
|
|
12179
|
-
insert.operation
|
|
12180
|
-
)
|
|
12181
|
-
);
|
|
12182
|
-
await executeStatement(
|
|
12183
|
-
target,
|
|
12184
|
-
sql`
|
|
12185
|
-
INSERT INTO ${table} (${columnList})
|
|
12186
|
-
VALUES ${sql.join(values, sql`, `)}
|
|
12187
|
-
`
|
|
12188
|
-
);
|
|
12189
|
-
}
|
|
12190
|
-
function recordedNodeChunkSize(target) {
|
|
12191
|
-
return recordedChunkSize(target, RECORDED_NODE_COLUMNS.length);
|
|
12192
|
-
}
|
|
12193
|
-
function recordedEdgeChunkSize(target) {
|
|
12194
|
-
return recordedChunkSize(target, RECORDED_EDGE_COLUMNS.length);
|
|
12195
|
-
}
|
|
12196
|
-
function insertRecordedNodeRows(target, table, inserts, recordedCommit) {
|
|
12197
|
-
return insertRecordedRows(
|
|
12198
|
-
target,
|
|
12199
|
-
table,
|
|
12200
|
-
RECORDED_NODE_COLUMN_LIST,
|
|
12201
|
-
RECORDED_NODE_COLUMNS,
|
|
12202
|
-
recordedNodeCells,
|
|
12203
|
-
inserts,
|
|
12204
|
-
recordedCommit
|
|
12205
|
-
);
|
|
12206
|
-
}
|
|
12207
|
-
function insertRecordedEdgeRows(target, table, inserts, recordedCommit) {
|
|
12208
|
-
return insertRecordedRows(
|
|
12209
|
-
target,
|
|
12210
|
-
table,
|
|
12211
|
-
RECORDED_EDGE_COLUMN_LIST,
|
|
12212
|
-
RECORDED_EDGE_COLUMNS,
|
|
12213
|
-
recordedEdgeCells,
|
|
12214
|
-
inserts,
|
|
12215
|
-
recordedCommit
|
|
12216
|
-
);
|
|
12217
|
-
}
|
|
12218
|
-
|
|
12219
|
-
// src/store/recorded-capture/flush.ts
|
|
12220
|
-
function entityKey(entity) {
|
|
12221
|
-
switch (entity.entity) {
|
|
12222
|
-
case "node": {
|
|
12223
|
-
return `node\0${entity.graphId}\0${entity.kind}\0${entity.id}`;
|
|
12224
|
-
}
|
|
12225
|
-
case "edge": {
|
|
12226
|
-
return `edge\0${entity.graphId}\0${entity.id}`;
|
|
12227
|
-
}
|
|
12228
|
-
}
|
|
12229
|
-
}
|
|
12230
|
-
async function closeOpenReturning(target, table, graphId, ids, recordedCommit, kind) {
|
|
12231
|
-
const kindFilter = kind === void 0 ? sql`` : sql`AND kind = ${kind}`;
|
|
12232
|
-
const rows = await target.execute(
|
|
12233
|
-
asCompiledRowsSql(sql`
|
|
12234
|
-
UPDATE ${table}
|
|
12235
|
-
SET recorded_to = ${recordedCommit}
|
|
12236
|
-
WHERE graph_id = ${graphId}
|
|
12237
|
-
${kindFilter}
|
|
12238
|
-
AND recorded_to = ${RECORDED_MAX}
|
|
12239
|
-
AND id IN (${sqlValueList(ids)})
|
|
12240
|
-
RETURNING id, deleted_at
|
|
12241
|
-
`)
|
|
12242
|
-
);
|
|
12243
|
-
return new Map(rows.map((row) => [row.id, isPresent(row.deleted_at)]));
|
|
12244
|
-
}
|
|
12245
|
-
function recordedOp(hadOpenRow, priorRowWasTombstone, after) {
|
|
12246
|
-
if (isPresent(after.deleted_at)) return "delete";
|
|
12247
|
-
if (!hadOpenRow || priorRowWasTombstone) return "create";
|
|
12248
|
-
return "update";
|
|
12249
|
-
}
|
|
12250
|
-
function groupNodesByKind(entities) {
|
|
12251
|
-
const byKind = /* @__PURE__ */ new Map();
|
|
12252
|
-
for (const entity of entities) {
|
|
12253
|
-
const group = byKind.get(entity.kind) ?? [];
|
|
12254
|
-
group.push(entity);
|
|
12255
|
-
byKind.set(entity.kind, group);
|
|
12256
|
-
}
|
|
12257
|
-
return byKind;
|
|
12258
|
-
}
|
|
12259
|
-
async function resolveAfterImages(entities, readMissing) {
|
|
12260
|
-
const afterById = /* @__PURE__ */ new Map();
|
|
12261
|
-
const needRead = [];
|
|
12262
|
-
for (const entity of entities) {
|
|
12263
|
-
if (entity.afterImage === void 0) {
|
|
12264
|
-
needRead.push(entity.id);
|
|
12265
|
-
} else {
|
|
12266
|
-
afterById.set(entity.id, entity.afterImage);
|
|
12267
|
-
}
|
|
12268
|
-
}
|
|
12269
|
-
if (needRead.length > 0) {
|
|
12270
|
-
for (const [id, row] of await readMissing(needRead)) afterById.set(id, row);
|
|
12271
|
-
}
|
|
12272
|
-
return afterById;
|
|
12273
|
-
}
|
|
12274
|
-
function recordedInsertsFor(afterById, closed) {
|
|
12275
|
-
return [...afterById.values()].map((row) => ({
|
|
12276
|
-
row,
|
|
12277
|
-
operation: recordedOp(closed.has(row.id), closed.get(row.id) ?? false, row)
|
|
12278
|
-
}));
|
|
12279
|
-
}
|
|
12280
|
-
async function flushNodes(target, schema, graphId, entities, recordedCommit) {
|
|
12281
|
-
const chunkSize = recordedNodeChunkSize(target);
|
|
12282
|
-
for (const [kind, group] of groupNodesByKind(entities)) {
|
|
12283
|
-
for (const entityChunk of chunk(group, chunkSize)) {
|
|
12284
|
-
const ids = entityChunk.map((entity) => entity.id);
|
|
12285
|
-
const closed = await closeOpenReturning(
|
|
12286
|
-
target,
|
|
12287
|
-
schema.recordedNodesTable,
|
|
12288
|
-
graphId,
|
|
12289
|
-
ids,
|
|
12290
|
-
recordedCommit,
|
|
12291
|
-
kind
|
|
12292
|
-
);
|
|
12293
|
-
const afterById = await resolveAfterImages(
|
|
12294
|
-
entityChunk,
|
|
12295
|
-
(missing) => getNodeRowsByIds(target, graphId, kind, missing)
|
|
12296
|
-
);
|
|
12297
|
-
await insertRecordedNodeRows(
|
|
12298
|
-
target,
|
|
12299
|
-
schema.recordedNodesTable,
|
|
12300
|
-
recordedInsertsFor(afterById, closed),
|
|
12301
|
-
recordedCommit
|
|
12302
|
-
);
|
|
12303
|
-
}
|
|
12304
|
-
}
|
|
12305
|
-
}
|
|
12306
|
-
async function flushEdges(target, schema, graphId, entities, recordedCommit) {
|
|
12307
|
-
const chunkSize = recordedEdgeChunkSize(target);
|
|
12308
|
-
for (const entityChunk of chunk(entities, chunkSize)) {
|
|
12309
|
-
const ids = entityChunk.map((entity) => entity.id);
|
|
12310
|
-
const closed = await closeOpenReturning(
|
|
12311
|
-
target,
|
|
12312
|
-
schema.recordedEdgesTable,
|
|
12313
|
-
graphId,
|
|
12314
|
-
ids,
|
|
12315
|
-
recordedCommit
|
|
12316
|
-
);
|
|
12317
|
-
const afterById = await resolveAfterImages(
|
|
12318
|
-
entityChunk,
|
|
12319
|
-
(missing) => getEdgeRowsByIds(target, graphId, missing)
|
|
12320
|
-
);
|
|
12321
|
-
await insertRecordedEdgeRows(
|
|
12322
|
-
target,
|
|
12323
|
-
schema.recordedEdgesTable,
|
|
12324
|
-
recordedInsertsFor(afterById, closed),
|
|
12325
|
-
recordedCommit
|
|
12326
|
-
);
|
|
12327
|
-
}
|
|
12328
|
-
}
|
|
12329
|
-
async function closeOpenByKind(target, table, graphId, kind, recordedCommit) {
|
|
12330
|
-
await executeStatement(
|
|
12331
|
-
target,
|
|
12332
|
-
sql`
|
|
12333
|
-
UPDATE ${table}
|
|
12334
|
-
SET recorded_to = ${recordedCommit}
|
|
12335
|
-
WHERE graph_id = ${graphId}
|
|
12336
|
-
AND kind = ${kind}
|
|
12337
|
-
AND recorded_to = ${RECORDED_MAX}
|
|
12338
|
-
`
|
|
12339
|
-
);
|
|
12340
|
-
}
|
|
12341
|
-
async function closeOpenEdgesByNodeKind(target, schema, graphId, nodeKind, recordedCommit) {
|
|
12342
|
-
await executeStatement(
|
|
12343
|
-
target,
|
|
12344
|
-
sql`
|
|
12345
|
-
UPDATE ${schema.recordedEdgesTable}
|
|
12346
|
-
SET recorded_to = ${recordedCommit}
|
|
12347
|
-
WHERE graph_id = ${graphId}
|
|
12348
|
-
AND (from_kind = ${nodeKind} OR to_kind = ${nodeKind})
|
|
12349
|
-
AND recorded_to = ${RECORDED_MAX}
|
|
12350
|
-
`
|
|
12351
|
-
);
|
|
12352
|
-
}
|
|
12353
|
-
async function closeRecordedHardDeletedKind(target, schema, graphId, removal, ownsWriteLock) {
|
|
12354
|
-
const recordedCommit = await allocateRecordedCommit(
|
|
12355
|
-
target,
|
|
12356
|
-
schema,
|
|
12357
|
-
graphId,
|
|
12358
|
-
ownsWriteLock
|
|
12359
|
-
);
|
|
12360
|
-
if (removal.entity === "node") {
|
|
12361
|
-
await closeOpenByKind(
|
|
12362
|
-
target,
|
|
12363
|
-
schema.recordedNodesTable,
|
|
12364
|
-
graphId,
|
|
12365
|
-
removal.kind,
|
|
12366
|
-
recordedCommit
|
|
12367
|
-
);
|
|
12368
|
-
await closeOpenEdgesByNodeKind(
|
|
12369
|
-
target,
|
|
12370
|
-
schema,
|
|
12371
|
-
graphId,
|
|
12372
|
-
removal.kind,
|
|
12373
|
-
recordedCommit
|
|
12374
|
-
);
|
|
12375
|
-
return;
|
|
12376
|
-
}
|
|
12377
|
-
await closeOpenByKind(
|
|
12378
|
-
target,
|
|
12379
|
-
schema.recordedEdgesTable,
|
|
12380
|
-
graphId,
|
|
12381
|
-
removal.kind,
|
|
12382
|
-
recordedCommit
|
|
12383
|
-
);
|
|
12384
|
-
}
|
|
12385
|
-
async function queryConnectedEdgeIds(target, schema, params) {
|
|
12386
|
-
const rows = await target.execute(
|
|
12387
|
-
asCompiledRowsSql(sql`
|
|
12388
|
-
SELECT id
|
|
12389
|
-
FROM ${schema.edgesTable}
|
|
12390
|
-
WHERE graph_id = ${params.graphId}
|
|
12391
|
-
AND (
|
|
12392
|
-
(from_kind = ${params.kind} AND from_id = ${params.id})
|
|
12393
|
-
OR (to_kind = ${params.kind} AND to_id = ${params.id})
|
|
12394
|
-
)
|
|
12395
|
-
`)
|
|
12396
|
-
);
|
|
12397
|
-
return rows.map((row) => row.id);
|
|
12398
|
-
}
|
|
12399
|
-
|
|
12400
|
-
// src/store/recorded-capture.ts
|
|
12401
|
-
function nodeIdentityKey(graphId, kind, id) {
|
|
12402
|
-
return `${graphId}\0${kind}\0${id}`;
|
|
12403
|
-
}
|
|
12404
|
-
function nodeParamsIdentityKey(params) {
|
|
12405
|
-
return nodeIdentityKey(params.graphId, params.kind, params.id);
|
|
12406
|
-
}
|
|
12407
|
-
function nodeRowIdentityKey(row) {
|
|
12408
|
-
return nodeIdentityKey(row.graph_id, row.kind, row.id);
|
|
12409
|
-
}
|
|
12410
|
-
function edgeIdentityKey(graphId, id) {
|
|
12411
|
-
return `${graphId}\0${id}`;
|
|
12412
|
-
}
|
|
12413
|
-
function edgeParamsIdentityKey(params) {
|
|
12414
|
-
return edgeIdentityKey(params.graphId, params.id);
|
|
12415
|
-
}
|
|
12416
|
-
function edgeRowIdentityKey(row) {
|
|
12417
|
-
return edgeIdentityKey(row.graph_id, row.id);
|
|
12418
|
-
}
|
|
12419
|
-
function createRecordedCaptureSession() {
|
|
12420
|
-
const touched = /* @__PURE__ */ new Map();
|
|
12421
|
-
let sealed = false;
|
|
12422
|
-
function touch(entity) {
|
|
12423
|
-
if (sealed) {
|
|
12424
|
-
throw new ConfigurationError(
|
|
12425
|
-
"Recorded-time capture session is sealed: a graph write happened after the transaction's capture was flushed.",
|
|
12426
|
-
{ entity: entity.entity, graphId: entity.graphId, id: entity.id },
|
|
12427
|
-
{
|
|
12428
|
-
suggestion: "Perform all writes inside the withRecordedTransaction callback; do not reuse the transaction context after it returns."
|
|
12429
|
-
}
|
|
12430
|
-
);
|
|
12431
|
-
}
|
|
12432
|
-
touched.set(entityKey(entity), entity);
|
|
12433
|
-
}
|
|
12434
|
-
return {
|
|
12435
|
-
touchNode(graphId, kind, id, afterImage) {
|
|
12436
|
-
touch({ entity: "node", graphId, kind, id, afterImage });
|
|
12437
|
-
},
|
|
12438
|
-
touchEdge(graphId, id, afterImage) {
|
|
12439
|
-
touch({ entity: "edge", graphId, id, afterImage });
|
|
12440
|
-
},
|
|
12441
|
-
async flush(target, schema, ownsWriteLock) {
|
|
12442
|
-
if (sealed) {
|
|
12443
|
-
throw new ConfigurationError(
|
|
12444
|
-
"Recorded-time capture session was already flushed.",
|
|
12445
|
-
{},
|
|
12446
|
-
{
|
|
12447
|
-
suggestion: "A capture scope flushes once at its terminal point; do not flush it twice."
|
|
12448
|
-
}
|
|
12449
|
-
);
|
|
12450
|
-
}
|
|
12451
|
-
sealed = true;
|
|
12452
|
-
if (touched.size === 0) return;
|
|
12453
|
-
const byGraph = groupBy(touched.values(), (entity) => entity.graphId);
|
|
12454
|
-
for (const [graphId, entities] of byGraph) {
|
|
12455
|
-
const recordedCommit = await allocateRecordedCommit(
|
|
12456
|
-
target,
|
|
12457
|
-
schema,
|
|
12458
|
-
graphId,
|
|
12459
|
-
ownsWriteLock
|
|
12460
|
-
);
|
|
12461
|
-
const nodes = entities.filter(
|
|
12462
|
-
(entity) => entity.entity === "node"
|
|
12463
|
-
);
|
|
12464
|
-
const edges = entities.filter(
|
|
12465
|
-
(entity) => entity.entity === "edge"
|
|
12466
|
-
);
|
|
12467
|
-
await flushNodes(target, schema, graphId, nodes, recordedCommit);
|
|
12468
|
-
await flushEdges(target, schema, graphId, edges, recordedCommit);
|
|
12469
|
-
}
|
|
12470
|
-
touched.clear();
|
|
12471
|
-
}
|
|
12472
|
-
};
|
|
12473
|
-
}
|
|
12474
|
-
function createRecordedTransactionBackend(target, session, schema) {
|
|
12475
|
-
const nodeDispatch = nodeInsertDispatch(target);
|
|
12476
|
-
const edgeDispatch = edgeInsertDispatch(target);
|
|
12477
|
-
return createBackendOverlay(target, {
|
|
12478
|
-
...rawWriteGuards(target, "tx.backend"),
|
|
12479
|
-
async insertNode(params) {
|
|
12480
|
-
const row = await target.insertNode(params);
|
|
12481
|
-
session.touchNode(params.graphId, params.kind, params.id, row);
|
|
12482
|
-
return row;
|
|
12483
|
-
},
|
|
12484
|
-
...target.insertNodeNoReturn === void 0 ? {} : {
|
|
12485
|
-
async insertNodeNoReturn(params) {
|
|
12486
|
-
await runInsertNoReturn(nodeDispatch, params);
|
|
12487
|
-
session.touchNode(params.graphId, params.kind, params.id);
|
|
12488
|
-
}
|
|
12489
|
-
},
|
|
12490
|
-
...target.insertNodesBatch === void 0 ? {} : {
|
|
12491
|
-
async insertNodesBatch(params) {
|
|
12492
|
-
await runInsertBatch(nodeDispatch, params);
|
|
12493
|
-
for (const node of params) {
|
|
12494
|
-
session.touchNode(node.graphId, node.kind, node.id);
|
|
12495
|
-
}
|
|
12496
|
-
}
|
|
12497
|
-
},
|
|
12498
|
-
...target.insertNodesBatchReturning === void 0 ? {} : {
|
|
12499
|
-
async insertNodesBatchReturning(params) {
|
|
12500
|
-
const rows = await runInsertBatchReturning(nodeDispatch, params);
|
|
12501
|
-
const rowsByIdentity = new Map(
|
|
12502
|
-
rows.map((row) => [nodeRowIdentityKey(row), row])
|
|
12503
|
-
);
|
|
12504
|
-
for (const node of params) {
|
|
12505
|
-
session.touchNode(
|
|
12506
|
-
node.graphId,
|
|
12507
|
-
node.kind,
|
|
12508
|
-
node.id,
|
|
12509
|
-
rowsByIdentity.get(nodeParamsIdentityKey(node))
|
|
12510
|
-
);
|
|
12511
|
-
}
|
|
12512
|
-
return rows;
|
|
12513
|
-
}
|
|
12514
|
-
},
|
|
12515
|
-
async updateNode(params) {
|
|
12516
|
-
const row = await target.updateNode(params);
|
|
12517
|
-
session.touchNode(params.graphId, params.kind, params.id, row);
|
|
12518
|
-
return row;
|
|
12519
|
-
},
|
|
12520
|
-
async deleteNode(params) {
|
|
12521
|
-
await target.deleteNode(params);
|
|
12522
|
-
session.touchNode(params.graphId, params.kind, params.id);
|
|
12523
|
-
},
|
|
12524
|
-
async hardDeleteNode(params) {
|
|
12525
|
-
const connectedEdgeIds = await queryConnectedEdgeIds(
|
|
12526
|
-
target,
|
|
12527
|
-
schema,
|
|
12528
|
-
params
|
|
12529
|
-
);
|
|
12530
|
-
await target.hardDeleteNode(params);
|
|
12531
|
-
session.touchNode(params.graphId, params.kind, params.id);
|
|
12532
|
-
for (const edgeId of connectedEdgeIds) {
|
|
12533
|
-
session.touchEdge(params.graphId, edgeId);
|
|
12534
|
-
}
|
|
12535
|
-
},
|
|
12536
|
-
async insertEdge(params) {
|
|
12537
|
-
const row = await target.insertEdge(params);
|
|
12538
|
-
session.touchEdge(params.graphId, params.id, row);
|
|
12539
|
-
return row;
|
|
12540
|
-
},
|
|
12541
|
-
...target.insertEdgeNoReturn === void 0 ? {} : {
|
|
12542
|
-
async insertEdgeNoReturn(params) {
|
|
12543
|
-
await runInsertNoReturn(edgeDispatch, params);
|
|
12544
|
-
session.touchEdge(params.graphId, params.id);
|
|
12545
|
-
}
|
|
12546
|
-
},
|
|
12547
|
-
...target.insertEdgesBatch === void 0 ? {} : {
|
|
12548
|
-
async insertEdgesBatch(params) {
|
|
12549
|
-
await runInsertBatch(edgeDispatch, params);
|
|
12550
|
-
for (const edge of params) {
|
|
12551
|
-
session.touchEdge(edge.graphId, edge.id);
|
|
12552
|
-
}
|
|
12553
|
-
}
|
|
12554
|
-
},
|
|
12555
|
-
...target.insertEdgesBatchReturning === void 0 ? {} : {
|
|
12556
|
-
async insertEdgesBatchReturning(params) {
|
|
12557
|
-
const rows = await runInsertBatchReturning(edgeDispatch, params);
|
|
12558
|
-
const rowsByIdentity = new Map(
|
|
12559
|
-
rows.map((row) => [edgeRowIdentityKey(row), row])
|
|
12560
|
-
);
|
|
12561
|
-
for (const edge of params) {
|
|
12562
|
-
session.touchEdge(
|
|
12563
|
-
edge.graphId,
|
|
12564
|
-
edge.id,
|
|
12565
|
-
rowsByIdentity.get(edgeParamsIdentityKey(edge))
|
|
12566
|
-
);
|
|
12567
|
-
}
|
|
12568
|
-
return rows;
|
|
12569
|
-
}
|
|
12570
|
-
},
|
|
12571
|
-
async updateEdge(params) {
|
|
12572
|
-
const row = await target.updateEdge(params);
|
|
12573
|
-
session.touchEdge(params.graphId, params.id, row);
|
|
12574
|
-
return row;
|
|
12575
|
-
},
|
|
12576
|
-
async deleteEdge(params) {
|
|
12577
|
-
await target.deleteEdge(params);
|
|
12578
|
-
session.touchEdge(params.graphId, params.id);
|
|
12579
|
-
},
|
|
12580
|
-
async hardDeleteEdge(params) {
|
|
12581
|
-
await target.hardDeleteEdge(params);
|
|
12582
|
-
session.touchEdge(params.graphId, params.id);
|
|
12583
|
-
}
|
|
12584
|
-
});
|
|
12585
|
-
}
|
|
12586
|
-
function createRecordedTransactionScope(target, schema, ownsWriteLock = false) {
|
|
12587
|
-
requireCaptureStatements(target);
|
|
12588
|
-
const session = createRecordedCaptureSession();
|
|
12589
|
-
const resolvedSchema = schema ?? requireRecordedSchema(target);
|
|
12590
|
-
return {
|
|
12591
|
-
backend: createRecordedTransactionBackend(target, session, resolvedSchema),
|
|
12592
|
-
async flush() {
|
|
12593
|
-
await withRecordedRelationsPrecondition(
|
|
12594
|
-
session.flush(target, resolvedSchema, ownsWriteLock),
|
|
12595
|
-
{ dialect: target.dialect, surface: "capture-flush" }
|
|
12596
|
-
);
|
|
12597
|
-
}
|
|
12598
|
-
};
|
|
12599
|
-
}
|
|
12600
|
-
async function runCapturedAutocommit(backend, schema, fn, options) {
|
|
12601
|
-
assertRequestedRecordedIsolation(backend, options);
|
|
12602
|
-
return backend.transaction(async (target) => {
|
|
12603
|
-
await assertRecordedCaptureTransactionIsolation(target);
|
|
12604
|
-
const scope = createRecordedTransactionScope(target, schema, true);
|
|
12605
|
-
const result = await fn(scope.backend);
|
|
12606
|
-
await scope.flush();
|
|
12607
|
-
return result;
|
|
12608
|
-
}, options);
|
|
12609
|
-
}
|
|
12610
|
-
function createRecordedBackend(backend, schema) {
|
|
12611
|
-
assertCapturableBackend(backend);
|
|
12612
|
-
const capture = (fn) => runCapturedAutocommit(backend, schema, fn);
|
|
12613
|
-
return createBackendOverlay(backend, {
|
|
12614
|
-
...rawWriteGuards(backend, "backend"),
|
|
12615
|
-
async insertNode(params) {
|
|
12616
|
-
return capture((target) => target.insertNode(params));
|
|
12617
|
-
},
|
|
12618
|
-
...backend.insertNodeNoReturn === void 0 ? {} : {
|
|
12619
|
-
async insertNodeNoReturn(params) {
|
|
12620
|
-
await capture(
|
|
12621
|
-
(target) => runInsertNoReturn(nodeInsertDispatch(target), params)
|
|
12622
|
-
);
|
|
12623
|
-
}
|
|
12624
|
-
},
|
|
12625
|
-
...backend.insertNodesBatch === void 0 ? {} : {
|
|
12626
|
-
async insertNodesBatch(params) {
|
|
12627
|
-
await capture(
|
|
12628
|
-
(target) => runInsertBatch(nodeInsertDispatch(target), params)
|
|
12629
|
-
);
|
|
12630
|
-
}
|
|
12631
|
-
},
|
|
12632
|
-
...backend.insertNodesBatchReturning === void 0 ? {} : {
|
|
12633
|
-
async insertNodesBatchReturning(params) {
|
|
12634
|
-
return capture(
|
|
12635
|
-
(target) => runInsertBatchReturning(nodeInsertDispatch(target), params)
|
|
12636
|
-
);
|
|
12637
|
-
}
|
|
12638
|
-
},
|
|
12639
|
-
async updateNode(params) {
|
|
12640
|
-
return capture((target) => target.updateNode(params));
|
|
12641
|
-
},
|
|
12642
|
-
async deleteNode(params) {
|
|
12643
|
-
await capture((target) => target.deleteNode(params));
|
|
12644
|
-
},
|
|
12645
|
-
async hardDeleteNode(params) {
|
|
12646
|
-
await capture((target) => target.hardDeleteNode(params));
|
|
12647
|
-
},
|
|
12648
|
-
async insertEdge(params) {
|
|
12649
|
-
return capture((target) => target.insertEdge(params));
|
|
12650
|
-
},
|
|
12651
|
-
...backend.insertEdgeNoReturn === void 0 ? {} : {
|
|
12652
|
-
async insertEdgeNoReturn(params) {
|
|
12653
|
-
await capture(
|
|
12654
|
-
(target) => runInsertNoReturn(edgeInsertDispatch(target), params)
|
|
12655
|
-
);
|
|
12656
|
-
}
|
|
12657
|
-
},
|
|
12658
|
-
...backend.insertEdgesBatch === void 0 ? {} : {
|
|
12659
|
-
async insertEdgesBatch(params) {
|
|
12660
|
-
await capture(
|
|
12661
|
-
(target) => runInsertBatch(edgeInsertDispatch(target), params)
|
|
12662
|
-
);
|
|
12663
|
-
}
|
|
12664
|
-
},
|
|
12665
|
-
...backend.insertEdgesBatchReturning === void 0 ? {} : {
|
|
12666
|
-
async insertEdgesBatchReturning(params) {
|
|
12667
|
-
return capture(
|
|
12668
|
-
(target) => runInsertBatchReturning(edgeInsertDispatch(target), params)
|
|
12669
|
-
);
|
|
12670
|
-
}
|
|
12671
|
-
},
|
|
12672
|
-
async updateEdge(params) {
|
|
12673
|
-
return capture((target) => target.updateEdge(params));
|
|
12674
|
-
},
|
|
12675
|
-
async deleteEdge(params) {
|
|
12676
|
-
await capture((target) => target.deleteEdge(params));
|
|
12677
|
-
},
|
|
12678
|
-
async hardDeleteEdge(params) {
|
|
12679
|
-
await capture((target) => target.hardDeleteEdge(params));
|
|
12680
|
-
},
|
|
12681
|
-
async transaction(fn, options) {
|
|
12682
|
-
assertRequestedRecordedIsolation(backend, options);
|
|
12683
|
-
return backend.transaction(async (target) => {
|
|
12684
|
-
await assertRecordedCaptureTransactionIsolation(target);
|
|
12685
|
-
const scope = createRecordedTransactionScope(target, schema, true);
|
|
12686
|
-
const result = await fn(scope.backend, createHistoryUnsafeSqlRef());
|
|
12687
|
-
await scope.flush();
|
|
12688
|
-
return result;
|
|
12689
|
-
}, options);
|
|
12690
|
-
},
|
|
12691
|
-
...backend.adoptTransaction === void 0 ? {} : {
|
|
12692
|
-
adoptTransaction(externalTx) {
|
|
12693
|
-
throw recordedCaptureRequiresCallbackTransactionError({
|
|
12694
|
-
externalTxType: typeof externalTx
|
|
12695
|
-
});
|
|
12696
|
-
}
|
|
12697
|
-
}
|
|
12698
|
-
});
|
|
12699
|
-
}
|
|
12700
|
-
|
|
12701
|
-
// src/store/materialize-removals.ts
|
|
12702
|
-
var ENTITY_KINDS = ["node", "edge"];
|
|
12703
|
-
function buildPendingKindRemoval(args) {
|
|
12704
|
-
return { ...args, removedAt: void 0, error: void 0 };
|
|
12705
|
-
}
|
|
12706
|
-
async function materializeRemovals(context, options = {}) {
|
|
12707
|
-
const { backend, graphId } = context;
|
|
12708
|
-
if (backend.executeDdl === void 0 || backend.recordKindRemoval === void 0 || backend.getPendingKindRemovals === void 0) {
|
|
12709
|
-
throw new ConfigurationError(
|
|
12710
|
-
"store.materializeRemovals() requires a backend with kind-removal primitives (executeDdl, recordKindRemoval, getPendingKindRemovals). The bundled SQLite and Postgres backends provide them.",
|
|
12711
|
-
{ code: "MATERIALIZE_REMOVALS_BACKEND_UNSUPPORTED" }
|
|
12712
|
-
);
|
|
12713
|
-
}
|
|
12714
|
-
await ensureFocusedStatusTable(backend, backend.ensureKindRemovalsTable);
|
|
12715
|
-
await reconcilePendingRemovals(context);
|
|
12716
|
-
const reclaimedVectorFields = await reclaimRemovedVectorFieldTables(context);
|
|
12717
|
-
const pending = await backend.getPendingKindRemovals(graphId);
|
|
12718
|
-
const kindFilter = options.kinds === void 0 ? void 0 : new Set(options.kinds);
|
|
12719
|
-
const candidates = pending.filter(
|
|
12720
|
-
(row) => kindFilter === void 0 ? true : kindFilter.has(row.kindName)
|
|
11282
|
+
await ensureFocusedStatusTable(backend, backend.ensureKindRemovalsTable);
|
|
11283
|
+
await reconcilePendingRemovals(context);
|
|
11284
|
+
const reclaimedVectorFields = await reclaimRemovedVectorFieldTables(context);
|
|
11285
|
+
const pending = await backend.getPendingKindRemovals(graphId);
|
|
11286
|
+
const kindFilter = options.kinds === void 0 ? void 0 : new Set(options.kinds);
|
|
11287
|
+
const candidates = pending.filter(
|
|
11288
|
+
(row) => kindFilter === void 0 ? true : kindFilter.has(row.kindName)
|
|
12721
11289
|
);
|
|
12722
11290
|
if (candidates.length === 0) return { results: [], reclaimedVectorFields };
|
|
12723
11291
|
const tableNames = backend.tableNames;
|
|
@@ -13023,180 +11591,20 @@ async function reclaimRemovedVectorFieldTables(context) {
|
|
|
13023
11591
|
}
|
|
13024
11592
|
}
|
|
13025
11593
|
if (results.every((entry2) => entry2.status === "reclaimed")) {
|
|
13026
|
-
if (perBackend === void 0) {
|
|
13027
|
-
perBackend = /* @__PURE__ */ new Map();
|
|
13028
|
-
reclaimCache.set(backend, perBackend);
|
|
13029
|
-
}
|
|
13030
|
-
perBackend.set(cacheKey, results);
|
|
13031
|
-
}
|
|
13032
|
-
return results;
|
|
13033
|
-
}
|
|
13034
|
-
var reclaimCache = /* @__PURE__ */ new WeakMap();
|
|
13035
|
-
function quote(identifier) {
|
|
13036
|
-
return `"${identifier.replaceAll('"', '""')}"`;
|
|
13037
|
-
}
|
|
13038
|
-
function literal(value) {
|
|
13039
|
-
return `'${value.replaceAll("'", "''")}'`;
|
|
13040
|
-
}
|
|
13041
|
-
|
|
13042
|
-
// src/constraints/index.ts
|
|
13043
|
-
var UNIQUE_KEY_SEPARATOR = "";
|
|
13044
|
-
var UNIQUE_KEY_NULL_MARKER = "";
|
|
13045
|
-
function computeUniqueKey(props, fields, collation) {
|
|
13046
|
-
const values = fields.map((field2) => {
|
|
13047
|
-
const value = props[field2];
|
|
13048
|
-
if (value === void 0 || value === null) {
|
|
13049
|
-
return UNIQUE_KEY_NULL_MARKER;
|
|
13050
|
-
}
|
|
13051
|
-
const stringValue = typeof value === "string" ? value : typeof value === "number" || typeof value === "boolean" ? value.toString() : JSON.stringify(value);
|
|
13052
|
-
return collation === "caseInsensitive" ? stringValue.toLowerCase() : stringValue;
|
|
13053
|
-
});
|
|
13054
|
-
return values.join(UNIQUE_KEY_SEPARATOR);
|
|
13055
|
-
}
|
|
13056
|
-
function checkWherePredicate(constraint, props) {
|
|
13057
|
-
if (!constraint.where) {
|
|
13058
|
-
return true;
|
|
13059
|
-
}
|
|
13060
|
-
const predicateBuilder = buildPredicateContext(props);
|
|
13061
|
-
const predicate = constraint.where(predicateBuilder);
|
|
13062
|
-
return evaluatePredicate(predicate, props);
|
|
13063
|
-
}
|
|
13064
|
-
function buildPredicateContext(props) {
|
|
13065
|
-
const context = {};
|
|
13066
|
-
for (const key of Object.keys(props)) {
|
|
13067
|
-
context[key] = {
|
|
13068
|
-
isNull: () => ({
|
|
13069
|
-
__type: "unique_predicate",
|
|
13070
|
-
field: key,
|
|
13071
|
-
op: "isNull"
|
|
13072
|
-
}),
|
|
13073
|
-
isNotNull: () => ({
|
|
13074
|
-
__type: "unique_predicate",
|
|
13075
|
-
field: key,
|
|
13076
|
-
op: "isNotNull"
|
|
13077
|
-
})
|
|
13078
|
-
};
|
|
13079
|
-
}
|
|
13080
|
-
return context;
|
|
13081
|
-
}
|
|
13082
|
-
function evaluatePredicate(predicate, props) {
|
|
13083
|
-
if (typeof predicate !== "object" || predicate === null || !("__type" in predicate)) {
|
|
13084
|
-
return true;
|
|
13085
|
-
}
|
|
13086
|
-
const pred = predicate;
|
|
13087
|
-
if (pred.__type !== "unique_predicate") {
|
|
13088
|
-
return true;
|
|
13089
|
-
}
|
|
13090
|
-
const value = props[pred.field];
|
|
13091
|
-
if (pred.op === "isNull") {
|
|
13092
|
-
return value === null || value === void 0;
|
|
13093
|
-
}
|
|
13094
|
-
return isPresent(value);
|
|
13095
|
-
}
|
|
13096
|
-
function getKindsForUniquenessCheck(baseKind, scope, registry) {
|
|
13097
|
-
if (scope === "kind") {
|
|
13098
|
-
return [baseKind];
|
|
13099
|
-
}
|
|
13100
|
-
const root = findRootAncestor(baseKind, registry);
|
|
13101
|
-
return registry.expandSubClasses(root);
|
|
13102
|
-
}
|
|
13103
|
-
function findRootAncestor(kind, registry) {
|
|
13104
|
-
const ancestors = registry.getAncestors(kind);
|
|
13105
|
-
if (ancestors.size === 0) {
|
|
13106
|
-
return kind;
|
|
13107
|
-
}
|
|
13108
|
-
for (const ancestor of ancestors) {
|
|
13109
|
-
if (registry.getAncestors(ancestor).size === 0) {
|
|
13110
|
-
return ancestor;
|
|
13111
|
-
}
|
|
13112
|
-
}
|
|
13113
|
-
const firstAncestor = [...ancestors][0];
|
|
13114
|
-
return firstAncestor ? findRootAncestor(firstAncestor, registry) : kind;
|
|
13115
|
-
}
|
|
13116
|
-
function checkCardinality(edgeKind, fromKind, fromId, cardinality, existingEdgeCount, hasActiveEdge) {
|
|
13117
|
-
switch (cardinality) {
|
|
13118
|
-
case "many": {
|
|
13119
|
-
return void 0;
|
|
13120
|
-
}
|
|
13121
|
-
case "one": {
|
|
13122
|
-
if (existingEdgeCount > 0) {
|
|
13123
|
-
return new CardinalityError({
|
|
13124
|
-
edgeKind,
|
|
13125
|
-
fromKind,
|
|
13126
|
-
fromId,
|
|
13127
|
-
cardinality: "one",
|
|
13128
|
-
existingCount: existingEdgeCount
|
|
13129
|
-
});
|
|
13130
|
-
}
|
|
13131
|
-
return void 0;
|
|
13132
|
-
}
|
|
13133
|
-
case "unique": {
|
|
13134
|
-
return void 0;
|
|
13135
|
-
}
|
|
13136
|
-
case "oneActive": {
|
|
13137
|
-
if (hasActiveEdge) {
|
|
13138
|
-
return new CardinalityError({
|
|
13139
|
-
edgeKind,
|
|
13140
|
-
fromKind,
|
|
13141
|
-
fromId,
|
|
13142
|
-
cardinality: "oneActive",
|
|
13143
|
-
existingCount: 1
|
|
13144
|
-
});
|
|
13145
|
-
}
|
|
13146
|
-
return void 0;
|
|
13147
|
-
}
|
|
13148
|
-
}
|
|
13149
|
-
}
|
|
13150
|
-
function checkUniqueEdge(edgeKind, fromKind, fromId, _toKind, _toId, existingCount) {
|
|
13151
|
-
if (existingCount > 0) {
|
|
13152
|
-
return new CardinalityError({
|
|
13153
|
-
edgeKind,
|
|
13154
|
-
fromKind,
|
|
13155
|
-
fromId,
|
|
13156
|
-
cardinality: "unique",
|
|
13157
|
-
existingCount
|
|
13158
|
-
});
|
|
13159
|
-
}
|
|
13160
|
-
return void 0;
|
|
13161
|
-
}
|
|
13162
|
-
function validateEdgeEndpoints(edgeKind, fromKind, toKind, registration, registry) {
|
|
13163
|
-
const validFromKinds = registration.from.map((node) => node.kind);
|
|
13164
|
-
const fromValid = validFromKinds.some(
|
|
13165
|
-
(validKind) => registry.isAssignableTo(fromKind, validKind)
|
|
13166
|
-
);
|
|
13167
|
-
if (!fromValid) {
|
|
13168
|
-
return new EndpointError({
|
|
13169
|
-
edgeKind,
|
|
13170
|
-
endpoint: "from",
|
|
13171
|
-
actualKind: fromKind,
|
|
13172
|
-
expectedKinds: validFromKinds
|
|
13173
|
-
});
|
|
13174
|
-
}
|
|
13175
|
-
const validToKinds = registration.to.map((node) => node.kind);
|
|
13176
|
-
const toValid = validToKinds.some(
|
|
13177
|
-
(validKind) => registry.isAssignableTo(toKind, validKind)
|
|
13178
|
-
);
|
|
13179
|
-
if (!toValid) {
|
|
13180
|
-
return new EndpointError({
|
|
13181
|
-
edgeKind,
|
|
13182
|
-
endpoint: "to",
|
|
13183
|
-
actualKind: toKind,
|
|
13184
|
-
expectedKinds: validToKinds
|
|
13185
|
-
});
|
|
13186
|
-
}
|
|
13187
|
-
return void 0;
|
|
13188
|
-
}
|
|
13189
|
-
function checkDisjointness(nodeId, nodeKind, existingKinds, registry) {
|
|
13190
|
-
for (const existingKind of existingKinds) {
|
|
13191
|
-
if (registry.areDisjoint(nodeKind, existingKind)) {
|
|
13192
|
-
return new DisjointError({
|
|
13193
|
-
nodeId,
|
|
13194
|
-
attemptedKind: nodeKind,
|
|
13195
|
-
conflictingKind: existingKind
|
|
13196
|
-
});
|
|
11594
|
+
if (perBackend === void 0) {
|
|
11595
|
+
perBackend = /* @__PURE__ */ new Map();
|
|
11596
|
+
reclaimCache.set(backend, perBackend);
|
|
13197
11597
|
}
|
|
11598
|
+
perBackend.set(cacheKey, results);
|
|
13198
11599
|
}
|
|
13199
|
-
return
|
|
11600
|
+
return results;
|
|
11601
|
+
}
|
|
11602
|
+
var reclaimCache = /* @__PURE__ */ new WeakMap();
|
|
11603
|
+
function quote(identifier) {
|
|
11604
|
+
return `"${identifier.replaceAll('"', '""')}"`;
|
|
11605
|
+
}
|
|
11606
|
+
function literal(value) {
|
|
11607
|
+
return `'${value.replaceAll("'", "''")}'`;
|
|
13200
11608
|
}
|
|
13201
11609
|
|
|
13202
11610
|
// src/store/constraints.ts
|
|
@@ -13483,16 +11891,11 @@ async function executeEdgeCreateInternal(ctx, input, backend, options) {
|
|
|
13483
11891
|
const kind = input.kind;
|
|
13484
11892
|
const id = input.id ?? generateId();
|
|
13485
11893
|
const opContext = ctx.createOperationContext("create", "edge", kind, id);
|
|
13486
|
-
return ctx
|
|
13487
|
-
const prepared = await validateAndPrepareEdgeCreate(
|
|
13488
|
-
ctx,
|
|
13489
|
-
input,
|
|
13490
|
-
id,
|
|
13491
|
-
backend
|
|
13492
|
-
);
|
|
11894
|
+
return runHookedWriteOperation(ctx, opContext, backend, async (target) => {
|
|
11895
|
+
const prepared = await validateAndPrepareEdgeCreate(ctx, input, id, target);
|
|
13493
11896
|
let row;
|
|
13494
11897
|
{
|
|
13495
|
-
row = await
|
|
11898
|
+
row = await target.insertEdge(prepared.insertParams);
|
|
13496
11899
|
}
|
|
13497
11900
|
if (row === void 0) return;
|
|
13498
11901
|
return rowToEdge(row);
|
|
@@ -13512,93 +11915,64 @@ async function executeEdgeCreateNoReturnBatch(ctx, inputs, backend) {
|
|
|
13512
11915
|
if (inputs.length === 0) {
|
|
13513
11916
|
return;
|
|
13514
11917
|
}
|
|
13515
|
-
|
|
13516
|
-
|
|
13517
|
-
|
|
13518
|
-
const
|
|
13519
|
-
|
|
13520
|
-
|
|
13521
|
-
|
|
13522
|
-
|
|
13523
|
-
|
|
13524
|
-
|
|
13525
|
-
|
|
13526
|
-
|
|
13527
|
-
|
|
13528
|
-
|
|
11918
|
+
await runInWriteTransaction(ctx, backend, async (target) => {
|
|
11919
|
+
const { backend: validationBackend, registerPendingEdgeForCardinality } = createEdgeBatchValidationBackend(target);
|
|
11920
|
+
const preparedCreates = [];
|
|
11921
|
+
for (const input of inputs) {
|
|
11922
|
+
const id = input.id ?? generateId();
|
|
11923
|
+
const prepared = await validateAndPrepareEdgeCreate(
|
|
11924
|
+
ctx,
|
|
11925
|
+
input,
|
|
11926
|
+
id,
|
|
11927
|
+
validationBackend
|
|
11928
|
+
);
|
|
11929
|
+
preparedCreates.push(prepared);
|
|
11930
|
+
registerPendingEdgeForCardinality(
|
|
11931
|
+
prepared.insertParams,
|
|
11932
|
+
prepared.cardinality
|
|
11933
|
+
);
|
|
11934
|
+
}
|
|
11935
|
+
const batchInsertParams = preparedCreates.map(
|
|
11936
|
+
(prepared) => prepared.insertParams
|
|
13529
11937
|
);
|
|
13530
|
-
|
|
13531
|
-
|
|
13532
|
-
(prepared) => prepared.insertParams
|
|
13533
|
-
);
|
|
13534
|
-
await runInsertBatch(edgeInsertDispatch(backend), batchInsertParams);
|
|
11938
|
+
await runInsertBatch(edgeInsertDispatch(target), batchInsertParams);
|
|
11939
|
+
});
|
|
13535
11940
|
}
|
|
13536
11941
|
async function executeEdgeCreateBatch(ctx, inputs, backend) {
|
|
13537
11942
|
if (inputs.length === 0) {
|
|
13538
11943
|
return [];
|
|
13539
11944
|
}
|
|
13540
|
-
|
|
13541
|
-
|
|
13542
|
-
|
|
13543
|
-
const
|
|
13544
|
-
|
|
13545
|
-
|
|
13546
|
-
|
|
13547
|
-
|
|
13548
|
-
|
|
11945
|
+
return runInWriteTransaction(ctx, backend, async (target) => {
|
|
11946
|
+
const { backend: validationBackend, registerPendingEdgeForCardinality } = createEdgeBatchValidationBackend(target);
|
|
11947
|
+
const preparedCreates = [];
|
|
11948
|
+
for (const input of inputs) {
|
|
11949
|
+
const id = input.id ?? generateId();
|
|
11950
|
+
const prepared = await validateAndPrepareEdgeCreate(
|
|
11951
|
+
ctx,
|
|
11952
|
+
input,
|
|
11953
|
+
id,
|
|
11954
|
+
validationBackend
|
|
11955
|
+
);
|
|
11956
|
+
preparedCreates.push(prepared);
|
|
11957
|
+
registerPendingEdgeForCardinality(
|
|
11958
|
+
prepared.insertParams,
|
|
11959
|
+
prepared.cardinality
|
|
11960
|
+
);
|
|
11961
|
+
}
|
|
11962
|
+
const batchInsertParams = preparedCreates.map(
|
|
11963
|
+
(prepared) => prepared.insertParams
|
|
13549
11964
|
);
|
|
13550
|
-
|
|
13551
|
-
|
|
13552
|
-
|
|
13553
|
-
prepared.cardinality
|
|
11965
|
+
const rows = await runInsertBatchReturning(
|
|
11966
|
+
edgeInsertDispatch(target),
|
|
11967
|
+
batchInsertParams
|
|
13554
11968
|
);
|
|
13555
|
-
|
|
13556
|
-
const batchInsertParams = preparedCreates.map(
|
|
13557
|
-
(prepared) => prepared.insertParams
|
|
13558
|
-
);
|
|
13559
|
-
const rows = await runInsertBatchReturning(
|
|
13560
|
-
edgeInsertDispatch(backend),
|
|
13561
|
-
batchInsertParams
|
|
13562
|
-
);
|
|
13563
|
-
return rows.map((row) => rowToEdge(row));
|
|
13564
|
-
}
|
|
13565
|
-
async function executeEdgeUpdate(ctx, input, backend) {
|
|
13566
|
-
const id = input.id;
|
|
13567
|
-
const existing = await backend.getEdge(ctx.graphId, id);
|
|
13568
|
-
if (!existing || existing.deleted_at) {
|
|
13569
|
-
throw new EdgeNotFoundError("unknown", id);
|
|
13570
|
-
}
|
|
13571
|
-
const opContext = ctx.createOperationContext(
|
|
13572
|
-
"update",
|
|
13573
|
-
"edge",
|
|
13574
|
-
existing.kind,
|
|
13575
|
-
id
|
|
13576
|
-
);
|
|
13577
|
-
return ctx.withOperationHooks(opContext, async () => {
|
|
13578
|
-
const registration = getEdgeRegistration(ctx.graph, existing.kind);
|
|
13579
|
-
const edgeKind = registration.type;
|
|
13580
|
-
const existingProps = JSON.parse(existing.props);
|
|
13581
|
-
const mergedProps = { ...existingProps, ...input.props };
|
|
13582
|
-
const validatedProps = validateEdgeProps(edgeKind.schema, mergedProps, {
|
|
13583
|
-
kind: existing.kind,
|
|
13584
|
-
operation: "update",
|
|
13585
|
-
id
|
|
13586
|
-
});
|
|
13587
|
-
const validTo = validateOptionalCanonicalIsoDate(input.validTo, "validTo");
|
|
13588
|
-
const updateParams = {
|
|
13589
|
-
graphId: ctx.graphId,
|
|
13590
|
-
id,
|
|
13591
|
-
props: validatedProps
|
|
13592
|
-
};
|
|
13593
|
-
if (validTo !== void 0) updateParams.validTo = validTo;
|
|
13594
|
-
const row = await backend.updateEdge(updateParams);
|
|
13595
|
-
return rowToEdge(row);
|
|
11969
|
+
return rows.map((row) => rowToEdge(row));
|
|
13596
11970
|
});
|
|
13597
11971
|
}
|
|
13598
|
-
async function
|
|
11972
|
+
async function performEdgeUpdate(ctx, input, target, options) {
|
|
13599
11973
|
const id = input.id;
|
|
13600
|
-
const existing = await
|
|
13601
|
-
if (!existing) {
|
|
11974
|
+
const existing = await target.getEdge(ctx.graphId, id);
|
|
11975
|
+
if (!existing || !options?.clearDeleted && existing.deleted_at) {
|
|
13602
11976
|
throw new EdgeNotFoundError("unknown", id);
|
|
13603
11977
|
}
|
|
13604
11978
|
const registration = getEdgeRegistration(ctx.graph, existing.kind);
|
|
@@ -13618,40 +11992,55 @@ async function executeEdgeUpsertUpdate(ctx, input, backend, options) {
|
|
|
13618
11992
|
};
|
|
13619
11993
|
if (validTo !== void 0) updateParams.validTo = validTo;
|
|
13620
11994
|
if (options?.clearDeleted) updateParams.clearDeleted = true;
|
|
13621
|
-
const row = await
|
|
11995
|
+
const row = await target.updateEdge(updateParams);
|
|
13622
11996
|
return rowToEdge(row);
|
|
13623
11997
|
}
|
|
13624
|
-
async function
|
|
13625
|
-
const
|
|
13626
|
-
|
|
13627
|
-
|
|
11998
|
+
async function executeEdgeUpdate(ctx, input, backend) {
|
|
11999
|
+
const id = input.id;
|
|
12000
|
+
const gate = await backend.getEdge(ctx.graphId, id);
|
|
12001
|
+
if (!gate || gate.deleted_at) {
|
|
12002
|
+
throw new EdgeNotFoundError("unknown", id);
|
|
13628
12003
|
}
|
|
13629
|
-
const opContext = ctx.createOperationContext(
|
|
13630
|
-
|
|
13631
|
-
|
|
13632
|
-
|
|
13633
|
-
|
|
12004
|
+
const opContext = ctx.createOperationContext("update", "edge", gate.kind, id);
|
|
12005
|
+
return runHookedWriteOperation(
|
|
12006
|
+
ctx,
|
|
12007
|
+
opContext,
|
|
12008
|
+
backend,
|
|
12009
|
+
(target) => performEdgeUpdate(ctx, input, target)
|
|
12010
|
+
);
|
|
12011
|
+
}
|
|
12012
|
+
async function executeEdgeUpsertUpdate(ctx, input, backend, options) {
|
|
12013
|
+
return runInWriteTransaction(
|
|
12014
|
+
ctx,
|
|
12015
|
+
backend,
|
|
12016
|
+
(target) => performEdgeUpdate(ctx, input, target, options)
|
|
13634
12017
|
);
|
|
13635
|
-
|
|
13636
|
-
|
|
12018
|
+
}
|
|
12019
|
+
async function executeEdgeDelete(ctx, id, backend) {
|
|
12020
|
+
const gate = await backend.getEdge(ctx.graphId, id);
|
|
12021
|
+
if (!gate || gate.deleted_at) return;
|
|
12022
|
+
const opContext = ctx.createOperationContext("delete", "edge", gate.kind, id);
|
|
12023
|
+
return runHookedWriteOperation(ctx, opContext, backend, async (target) => {
|
|
12024
|
+
const existing = await target.getEdge(ctx.graphId, id);
|
|
12025
|
+
if (!existing || existing.deleted_at) {
|
|
12026
|
+
return;
|
|
12027
|
+
}
|
|
12028
|
+
await target.deleteEdge({
|
|
13637
12029
|
graphId: ctx.graphId,
|
|
13638
12030
|
id
|
|
13639
12031
|
});
|
|
13640
12032
|
});
|
|
13641
12033
|
}
|
|
13642
12034
|
async function executeEdgeHardDelete(ctx, id, backend) {
|
|
13643
|
-
const
|
|
13644
|
-
if (!
|
|
13645
|
-
|
|
13646
|
-
|
|
13647
|
-
|
|
13648
|
-
|
|
13649
|
-
|
|
13650
|
-
|
|
13651
|
-
|
|
13652
|
-
);
|
|
13653
|
-
return ctx.withOperationHooks(opContext, async () => {
|
|
13654
|
-
await backend.hardDeleteEdge({
|
|
12035
|
+
const gate = await backend.getEdge(ctx.graphId, id);
|
|
12036
|
+
if (!gate) return;
|
|
12037
|
+
const opContext = ctx.createOperationContext("delete", "edge", gate.kind, id);
|
|
12038
|
+
return runHookedWriteOperation(ctx, opContext, backend, async (target) => {
|
|
12039
|
+
const existing = await target.getEdge(ctx.graphId, id);
|
|
12040
|
+
if (!existing) {
|
|
12041
|
+
return;
|
|
12042
|
+
}
|
|
12043
|
+
await target.hardDeleteEdge({
|
|
13655
12044
|
graphId: ctx.graphId,
|
|
13656
12045
|
id
|
|
13657
12046
|
});
|
|
@@ -13771,72 +12160,100 @@ async function executeEdgeGetOrCreateByEndpoints(ctx, kind, fromKind, fromId, to
|
|
|
13771
12160
|
operation: "create"
|
|
13772
12161
|
});
|
|
13773
12162
|
validateMatchOnFields(edgeKind.schema, matchOn, kind);
|
|
13774
|
-
|
|
13775
|
-
|
|
13776
|
-
|
|
13777
|
-
fromKind,
|
|
13778
|
-
fromId,
|
|
13779
|
-
toKind,
|
|
13780
|
-
toId,
|
|
13781
|
-
excludeDeleted: false,
|
|
13782
|
-
temporalMode: "includeTombstones"
|
|
13783
|
-
});
|
|
13784
|
-
const { liveRow, deletedRow } = findMatchingEdge(
|
|
13785
|
-
candidateRows,
|
|
13786
|
-
matchOn,
|
|
13787
|
-
validatedProps
|
|
13788
|
-
);
|
|
13789
|
-
if (liveRow === void 0 && deletedRow === void 0) {
|
|
13790
|
-
const input = {
|
|
12163
|
+
if (ifExists === "return") {
|
|
12164
|
+
const probeRows = await backend.findEdgesByKind({
|
|
12165
|
+
graphId: ctx.graphId,
|
|
13791
12166
|
kind,
|
|
13792
12167
|
fromKind,
|
|
13793
12168
|
fromId,
|
|
13794
12169
|
toKind,
|
|
13795
12170
|
toId,
|
|
13796
|
-
|
|
13797
|
-
|
|
13798
|
-
|
|
13799
|
-
|
|
12171
|
+
excludeDeleted: false,
|
|
12172
|
+
temporalMode: "includeTombstones"
|
|
12173
|
+
});
|
|
12174
|
+
const { liveRow: probedLiveRow } = findMatchingEdge(
|
|
12175
|
+
probeRows,
|
|
12176
|
+
matchOn,
|
|
12177
|
+
validatedProps
|
|
12178
|
+
);
|
|
12179
|
+
if (probedLiveRow !== void 0) {
|
|
12180
|
+
return { edge: rowToEdge(probedLiveRow), action: "found" };
|
|
12181
|
+
}
|
|
13800
12182
|
}
|
|
13801
|
-
|
|
13802
|
-
|
|
13803
|
-
|
|
12183
|
+
async function attempt() {
|
|
12184
|
+
const candidateRows = await backend.findEdgesByKind({
|
|
12185
|
+
graphId: ctx.graphId,
|
|
12186
|
+
kind,
|
|
12187
|
+
fromKind,
|
|
12188
|
+
fromId,
|
|
12189
|
+
toKind,
|
|
12190
|
+
toId,
|
|
12191
|
+
excludeDeleted: false,
|
|
12192
|
+
temporalMode: "includeTombstones"
|
|
12193
|
+
});
|
|
12194
|
+
const { liveRow, deletedRow } = findMatchingEdge(
|
|
12195
|
+
candidateRows,
|
|
12196
|
+
matchOn,
|
|
12197
|
+
validatedProps
|
|
12198
|
+
);
|
|
12199
|
+
if (liveRow === void 0 && deletedRow === void 0) {
|
|
12200
|
+
const input = {
|
|
12201
|
+
kind,
|
|
12202
|
+
fromKind,
|
|
12203
|
+
fromId,
|
|
12204
|
+
toKind,
|
|
12205
|
+
toId,
|
|
12206
|
+
props: validatedProps
|
|
12207
|
+
};
|
|
12208
|
+
const edge2 = await executeEdgeCreate(ctx, input, backend);
|
|
12209
|
+
return { edge: edge2, action: "created" };
|
|
13804
12210
|
}
|
|
13805
|
-
|
|
13806
|
-
|
|
13807
|
-
|
|
12211
|
+
if (liveRow !== void 0) {
|
|
12212
|
+
if (ifExists === "return") {
|
|
12213
|
+
return { edge: rowToEdge(liveRow), action: "found" };
|
|
12214
|
+
}
|
|
12215
|
+
const edge2 = await executeEdgeUpsertUpdate(
|
|
12216
|
+
ctx,
|
|
12217
|
+
{ id: liveRow.id, props: validatedProps },
|
|
12218
|
+
backend
|
|
12219
|
+
);
|
|
12220
|
+
return { edge: edge2, action: "updated" };
|
|
12221
|
+
}
|
|
12222
|
+
const cardinality = registration.cardinality ?? "many";
|
|
12223
|
+
if (deletedRow === void 0) {
|
|
12224
|
+
throw new Error("Expected deletedRow to be defined");
|
|
12225
|
+
}
|
|
12226
|
+
const matchedDeletedRow = deletedRow;
|
|
12227
|
+
const effectiveValidTo = matchedDeletedRow.valid_to;
|
|
12228
|
+
const constraintContext = {
|
|
12229
|
+
graphId: ctx.graphId,
|
|
12230
|
+
registry: ctx.registry,
|
|
13808
12231
|
backend
|
|
12232
|
+
};
|
|
12233
|
+
await checkCardinalityConstraint(
|
|
12234
|
+
constraintContext,
|
|
12235
|
+
kind,
|
|
12236
|
+
cardinality,
|
|
12237
|
+
fromKind,
|
|
12238
|
+
fromId,
|
|
12239
|
+
toKind,
|
|
12240
|
+
toId,
|
|
12241
|
+
effectiveValidTo
|
|
13809
12242
|
);
|
|
13810
|
-
|
|
12243
|
+
const edge = await executeEdgeUpsertUpdate(
|
|
12244
|
+
ctx,
|
|
12245
|
+
{ id: matchedDeletedRow.id, props: validatedProps },
|
|
12246
|
+
backend,
|
|
12247
|
+
{ clearDeleted: true }
|
|
12248
|
+
);
|
|
12249
|
+
return { edge, action: "resurrected" };
|
|
13811
12250
|
}
|
|
13812
|
-
|
|
13813
|
-
|
|
13814
|
-
|
|
12251
|
+
try {
|
|
12252
|
+
return await attempt();
|
|
12253
|
+
} catch (error) {
|
|
12254
|
+
if (!(error instanceof CardinalityError)) throw error;
|
|
12255
|
+
return attempt();
|
|
13815
12256
|
}
|
|
13816
|
-
const matchedDeletedRow = deletedRow;
|
|
13817
|
-
const effectiveValidTo = matchedDeletedRow.valid_to;
|
|
13818
|
-
const constraintContext = {
|
|
13819
|
-
graphId: ctx.graphId,
|
|
13820
|
-
registry: ctx.registry,
|
|
13821
|
-
backend
|
|
13822
|
-
};
|
|
13823
|
-
await checkCardinalityConstraint(
|
|
13824
|
-
constraintContext,
|
|
13825
|
-
kind,
|
|
13826
|
-
cardinality,
|
|
13827
|
-
fromKind,
|
|
13828
|
-
fromId,
|
|
13829
|
-
toKind,
|
|
13830
|
-
toId,
|
|
13831
|
-
effectiveValidTo
|
|
13832
|
-
);
|
|
13833
|
-
const edge = await executeEdgeUpsertUpdate(
|
|
13834
|
-
ctx,
|
|
13835
|
-
{ id: matchedDeletedRow.id, props: validatedProps },
|
|
13836
|
-
backend,
|
|
13837
|
-
{ clearDeleted: true }
|
|
13838
|
-
);
|
|
13839
|
-
return { edge, action: "resurrected" };
|
|
13840
12257
|
}
|
|
13841
12258
|
async function executeEdgeBulkGetOrCreateByEndpoints(ctx, kind, items, backend, options) {
|
|
13842
12259
|
if (items.length === 0) return [];
|
|
@@ -13882,258 +12299,153 @@ async function executeEdgeBulkGetOrCreateByEndpoints(ctx, kind, items, backend,
|
|
|
13882
12299
|
uniqueEndpoints.set(entry2.endpointKey, {
|
|
13883
12300
|
fromKind: entry2.fromKind,
|
|
13884
12301
|
fromId: entry2.fromId,
|
|
13885
|
-
toKind: entry2.toKind,
|
|
13886
|
-
toId: entry2.toId
|
|
13887
|
-
});
|
|
13888
|
-
}
|
|
13889
|
-
}
|
|
13890
|
-
const rowsByEndpoint = /* @__PURE__ */ new Map();
|
|
13891
|
-
for (const [endpointKey, endpoint] of uniqueEndpoints) {
|
|
13892
|
-
const rows = await backend.findEdgesByKind({
|
|
13893
|
-
graphId: ctx.graphId,
|
|
13894
|
-
kind,
|
|
13895
|
-
fromKind: endpoint.fromKind,
|
|
13896
|
-
fromId: endpoint.fromId,
|
|
13897
|
-
toKind: endpoint.toKind,
|
|
13898
|
-
toId: endpoint.toId,
|
|
13899
|
-
excludeDeleted: false,
|
|
13900
|
-
temporalMode: "includeTombstones"
|
|
13901
|
-
});
|
|
13902
|
-
rowsByEndpoint.set(endpointKey, rows);
|
|
13903
|
-
}
|
|
13904
|
-
const toCreate = [];
|
|
13905
|
-
const toFetch = [];
|
|
13906
|
-
const duplicateOf = [];
|
|
13907
|
-
const seenKeys = /* @__PURE__ */ new Map();
|
|
13908
|
-
for (const [index, entry2] of validated.entries()) {
|
|
13909
|
-
const previousIndex = seenKeys.get(entry2.compositeKey);
|
|
13910
|
-
if (previousIndex !== void 0) {
|
|
13911
|
-
duplicateOf.push({ index, sourceIndex: previousIndex });
|
|
13912
|
-
continue;
|
|
13913
|
-
}
|
|
13914
|
-
seenKeys.set(entry2.compositeKey, index);
|
|
13915
|
-
const candidateRows = rowsByEndpoint.get(entry2.endpointKey) ?? [];
|
|
13916
|
-
const { liveRow, deletedRow } = findMatchingEdge(
|
|
13917
|
-
candidateRows,
|
|
13918
|
-
matchOn,
|
|
13919
|
-
entry2.validatedProps
|
|
13920
|
-
);
|
|
13921
|
-
if (liveRow === void 0 && deletedRow === void 0) {
|
|
13922
|
-
toCreate.push({
|
|
13923
|
-
index,
|
|
13924
|
-
input: {
|
|
13925
|
-
kind,
|
|
13926
|
-
fromKind: entry2.fromKind,
|
|
13927
|
-
fromId: entry2.fromId,
|
|
13928
|
-
toKind: entry2.toKind,
|
|
13929
|
-
toId: entry2.toId,
|
|
13930
|
-
props: entry2.validatedProps
|
|
13931
|
-
}
|
|
13932
|
-
});
|
|
13933
|
-
} else {
|
|
13934
|
-
const bestRow = liveRow ?? deletedRow;
|
|
13935
|
-
if (bestRow === void 0) {
|
|
13936
|
-
throw new Error("Expected at least one of liveRow or deletedRow");
|
|
13937
|
-
}
|
|
13938
|
-
toFetch.push({
|
|
13939
|
-
index,
|
|
13940
|
-
row: bestRow,
|
|
13941
|
-
isDeleted: liveRow === void 0,
|
|
13942
|
-
validatedProps: entry2.validatedProps,
|
|
13943
|
-
fromKind: entry2.fromKind,
|
|
13944
|
-
fromId: entry2.fromId,
|
|
13945
|
-
toKind: entry2.toKind,
|
|
13946
|
-
toId: entry2.toId
|
|
13947
|
-
});
|
|
13948
|
-
}
|
|
13949
|
-
}
|
|
13950
|
-
const results = Array.from({ length: items.length });
|
|
13951
|
-
if (toCreate.length > 0) {
|
|
13952
|
-
const createInputs = toCreate.map((entry2) => entry2.input);
|
|
13953
|
-
const createdEdges = await executeEdgeCreateBatch(
|
|
13954
|
-
ctx,
|
|
13955
|
-
createInputs,
|
|
13956
|
-
backend
|
|
13957
|
-
);
|
|
13958
|
-
for (const [batchIndex, entry2] of toCreate.entries()) {
|
|
13959
|
-
results[entry2.index] = {
|
|
13960
|
-
edge: createdEdges[batchIndex],
|
|
13961
|
-
action: "created"
|
|
13962
|
-
};
|
|
13963
|
-
}
|
|
13964
|
-
}
|
|
13965
|
-
for (const entry2 of toFetch) {
|
|
13966
|
-
if (entry2.isDeleted) {
|
|
13967
|
-
const effectiveValidTo = entry2.row.valid_to;
|
|
13968
|
-
const constraintContext = {
|
|
13969
|
-
graphId: ctx.graphId,
|
|
13970
|
-
registry: ctx.registry,
|
|
13971
|
-
backend
|
|
13972
|
-
};
|
|
13973
|
-
await checkCardinalityConstraint(
|
|
13974
|
-
constraintContext,
|
|
13975
|
-
kind,
|
|
13976
|
-
cardinality,
|
|
13977
|
-
entry2.fromKind,
|
|
13978
|
-
entry2.fromId,
|
|
13979
|
-
entry2.toKind,
|
|
13980
|
-
entry2.toId,
|
|
13981
|
-
effectiveValidTo
|
|
13982
|
-
);
|
|
13983
|
-
const edge = await executeEdgeUpsertUpdate(
|
|
13984
|
-
ctx,
|
|
13985
|
-
{ id: entry2.row.id, props: entry2.validatedProps },
|
|
13986
|
-
backend,
|
|
13987
|
-
{ clearDeleted: true }
|
|
13988
|
-
);
|
|
13989
|
-
results[entry2.index] = { edge, action: "resurrected" };
|
|
13990
|
-
} else if (ifExists === "update") {
|
|
13991
|
-
const edge = await executeEdgeUpsertUpdate(
|
|
13992
|
-
ctx,
|
|
13993
|
-
{ id: entry2.row.id, props: entry2.validatedProps },
|
|
13994
|
-
backend
|
|
13995
|
-
);
|
|
13996
|
-
results[entry2.index] = { edge, action: "updated" };
|
|
13997
|
-
} else {
|
|
13998
|
-
results[entry2.index] = { edge: rowToEdge(entry2.row), action: "found" };
|
|
13999
|
-
}
|
|
14000
|
-
}
|
|
14001
|
-
for (const { index, sourceIndex } of duplicateOf) {
|
|
14002
|
-
const sourceResult = results[sourceIndex];
|
|
14003
|
-
results[index] = { edge: sourceResult.edge, action: "found" };
|
|
14004
|
-
}
|
|
14005
|
-
return results;
|
|
14006
|
-
}
|
|
14007
|
-
|
|
14008
|
-
// src/store/uniqueness.ts
|
|
14009
|
-
async function checkUniquenessConstraints(ctx, kind, id, props, constraints) {
|
|
14010
|
-
for (const constraint of constraints) {
|
|
14011
|
-
if (!checkWherePredicate(constraint, props)) {
|
|
14012
|
-
continue;
|
|
12302
|
+
toKind: entry2.toKind,
|
|
12303
|
+
toId: entry2.toId
|
|
12304
|
+
});
|
|
14013
12305
|
}
|
|
14014
|
-
|
|
14015
|
-
|
|
14016
|
-
|
|
14017
|
-
|
|
14018
|
-
|
|
14019
|
-
const kindsToCheck = getKindsForUniquenessCheck(
|
|
14020
|
-
kind,
|
|
14021
|
-
constraint.scope,
|
|
14022
|
-
ctx.registry
|
|
14023
|
-
);
|
|
14024
|
-
for (const kindToCheck of kindsToCheck) {
|
|
14025
|
-
const existing = await ctx.backend.checkUnique({
|
|
12306
|
+
}
|
|
12307
|
+
async function fetchRowsByEndpoint(reader) {
|
|
12308
|
+
const rowsByEndpoint = /* @__PURE__ */ new Map();
|
|
12309
|
+
for (const [endpointKey, endpoint] of uniqueEndpoints) {
|
|
12310
|
+
const rows = await reader.findEdgesByKind({
|
|
14026
12311
|
graphId: ctx.graphId,
|
|
14027
|
-
|
|
14028
|
-
|
|
14029
|
-
|
|
12312
|
+
kind,
|
|
12313
|
+
fromKind: endpoint.fromKind,
|
|
12314
|
+
fromId: endpoint.fromId,
|
|
12315
|
+
toKind: endpoint.toKind,
|
|
12316
|
+
toId: endpoint.toId,
|
|
12317
|
+
excludeDeleted: false,
|
|
12318
|
+
temporalMode: "includeTombstones"
|
|
14030
12319
|
});
|
|
14031
|
-
|
|
14032
|
-
|
|
14033
|
-
|
|
14034
|
-
|
|
14035
|
-
|
|
14036
|
-
|
|
14037
|
-
|
|
12320
|
+
rowsByEndpoint.set(endpointKey, rows);
|
|
12321
|
+
}
|
|
12322
|
+
return rowsByEndpoint;
|
|
12323
|
+
}
|
|
12324
|
+
function partitionEntries(rowsByEndpoint) {
|
|
12325
|
+
const toCreate = [];
|
|
12326
|
+
const toFetch = [];
|
|
12327
|
+
const duplicateOf = [];
|
|
12328
|
+
const seenKeys = /* @__PURE__ */ new Map();
|
|
12329
|
+
for (const [index, entry2] of validated.entries()) {
|
|
12330
|
+
const previousIndex = seenKeys.get(entry2.compositeKey);
|
|
12331
|
+
if (previousIndex !== void 0) {
|
|
12332
|
+
duplicateOf.push({ index, sourceIndex: previousIndex });
|
|
12333
|
+
continue;
|
|
12334
|
+
}
|
|
12335
|
+
seenKeys.set(entry2.compositeKey, index);
|
|
12336
|
+
const candidateRows = rowsByEndpoint.get(entry2.endpointKey) ?? [];
|
|
12337
|
+
const { liveRow, deletedRow } = findMatchingEdge(
|
|
12338
|
+
candidateRows,
|
|
12339
|
+
matchOn,
|
|
12340
|
+
entry2.validatedProps
|
|
12341
|
+
);
|
|
12342
|
+
if (liveRow === void 0 && deletedRow === void 0) {
|
|
12343
|
+
toCreate.push({
|
|
12344
|
+
index,
|
|
12345
|
+
input: {
|
|
12346
|
+
kind,
|
|
12347
|
+
fromKind: entry2.fromKind,
|
|
12348
|
+
fromId: entry2.fromId,
|
|
12349
|
+
toKind: entry2.toKind,
|
|
12350
|
+
toId: entry2.toId,
|
|
12351
|
+
props: entry2.validatedProps
|
|
12352
|
+
}
|
|
12353
|
+
});
|
|
12354
|
+
} else {
|
|
12355
|
+
const bestRow = liveRow ?? deletedRow;
|
|
12356
|
+
if (bestRow === void 0) {
|
|
12357
|
+
throw new Error("Expected at least one of liveRow or deletedRow");
|
|
12358
|
+
}
|
|
12359
|
+
toFetch.push({
|
|
12360
|
+
index,
|
|
12361
|
+
row: bestRow,
|
|
12362
|
+
isDeleted: liveRow === void 0,
|
|
12363
|
+
validatedProps: entry2.validatedProps,
|
|
12364
|
+
fromKind: entry2.fromKind,
|
|
12365
|
+
fromId: entry2.fromId,
|
|
12366
|
+
toKind: entry2.toKind,
|
|
12367
|
+
toId: entry2.toId
|
|
14038
12368
|
});
|
|
14039
12369
|
}
|
|
14040
12370
|
}
|
|
12371
|
+
return { toCreate, toFetch, duplicateOf };
|
|
14041
12372
|
}
|
|
14042
|
-
|
|
14043
|
-
|
|
14044
|
-
|
|
14045
|
-
if (
|
|
14046
|
-
|
|
12373
|
+
if (ifExists === "return") {
|
|
12374
|
+
const probe = partitionEntries(await fetchRowsByEndpoint(backend));
|
|
12375
|
+
const allFoundLive = probe.toCreate.length === 0 && probe.toFetch.every((entry2) => !entry2.isDeleted);
|
|
12376
|
+
if (allFoundLive) {
|
|
12377
|
+
const found = Array.from({ length: items.length });
|
|
12378
|
+
for (const entry2 of probe.toFetch) {
|
|
12379
|
+
found[entry2.index] = { edge: rowToEdge(entry2.row), action: "found" };
|
|
12380
|
+
}
|
|
12381
|
+
for (const { index, sourceIndex } of probe.duplicateOf) {
|
|
12382
|
+
found[index] = { edge: found[sourceIndex].edge, action: "found" };
|
|
12383
|
+
}
|
|
12384
|
+
return found;
|
|
14047
12385
|
}
|
|
14048
|
-
const key = computeUniqueKey(
|
|
14049
|
-
props,
|
|
14050
|
-
constraint.fields,
|
|
14051
|
-
constraint.collation
|
|
14052
|
-
);
|
|
14053
|
-
await ctx.backend.insertUnique({
|
|
14054
|
-
graphId: ctx.graphId,
|
|
14055
|
-
nodeKind: kind,
|
|
14056
|
-
constraintName: constraint.name,
|
|
14057
|
-
key,
|
|
14058
|
-
nodeId: id,
|
|
14059
|
-
concreteKind: kind
|
|
14060
|
-
});
|
|
14061
12386
|
}
|
|
14062
|
-
|
|
14063
|
-
|
|
14064
|
-
|
|
14065
|
-
if (!checkWherePredicate(constraint, props)) {
|
|
14066
|
-
continue;
|
|
14067
|
-
}
|
|
14068
|
-
const key = computeUniqueKey(
|
|
14069
|
-
props,
|
|
14070
|
-
constraint.fields,
|
|
14071
|
-
constraint.collation
|
|
12387
|
+
return runInWriteTransaction(ctx, backend, async (target) => {
|
|
12388
|
+
const { toCreate, toFetch, duplicateOf } = partitionEntries(
|
|
12389
|
+
await fetchRowsByEndpoint(target)
|
|
14072
12390
|
);
|
|
14073
|
-
|
|
14074
|
-
|
|
14075
|
-
|
|
14076
|
-
|
|
14077
|
-
|
|
14078
|
-
|
|
14079
|
-
|
|
14080
|
-
}
|
|
14081
|
-
async function updateUniquenessEntries(ctx, kind, id, oldProps, newProps, constraints) {
|
|
14082
|
-
for (const constraint of constraints) {
|
|
14083
|
-
const oldApplies = checkWherePredicate(constraint, oldProps);
|
|
14084
|
-
const newApplies = checkWherePredicate(constraint, newProps);
|
|
14085
|
-
const oldKey = oldApplies ? computeUniqueKey(oldProps, constraint.fields, constraint.collation) : void 0;
|
|
14086
|
-
const newKey = newApplies ? computeUniqueKey(newProps, constraint.fields, constraint.collation) : void 0;
|
|
14087
|
-
if (!oldApplies && !newApplies) {
|
|
14088
|
-
continue;
|
|
14089
|
-
}
|
|
14090
|
-
if (oldApplies && newApplies && oldKey === newKey) {
|
|
14091
|
-
continue;
|
|
14092
|
-
}
|
|
14093
|
-
if (oldApplies && oldKey !== void 0) {
|
|
14094
|
-
await ctx.backend.deleteUnique({
|
|
14095
|
-
graphId: ctx.graphId,
|
|
14096
|
-
nodeKind: kind,
|
|
14097
|
-
constraintName: constraint.name,
|
|
14098
|
-
key: oldKey
|
|
14099
|
-
});
|
|
14100
|
-
}
|
|
14101
|
-
if (newApplies && newKey !== void 0) {
|
|
14102
|
-
const kindsToCheck = getKindsForUniquenessCheck(
|
|
14103
|
-
kind,
|
|
14104
|
-
constraint.scope,
|
|
14105
|
-
ctx.registry
|
|
12391
|
+
const results = Array.from({ length: items.length });
|
|
12392
|
+
if (toCreate.length > 0) {
|
|
12393
|
+
const createInputs = toCreate.map((entry2) => entry2.input);
|
|
12394
|
+
const createdEdges = await executeEdgeCreateBatch(
|
|
12395
|
+
ctx,
|
|
12396
|
+
createInputs,
|
|
12397
|
+
target
|
|
14106
12398
|
);
|
|
14107
|
-
for (const
|
|
14108
|
-
|
|
12399
|
+
for (const [batchIndex, entry2] of toCreate.entries()) {
|
|
12400
|
+
results[entry2.index] = {
|
|
12401
|
+
edge: createdEdges[batchIndex],
|
|
12402
|
+
action: "created"
|
|
12403
|
+
};
|
|
12404
|
+
}
|
|
12405
|
+
}
|
|
12406
|
+
for (const entry2 of toFetch) {
|
|
12407
|
+
if (entry2.isDeleted) {
|
|
12408
|
+
const effectiveValidTo = entry2.row.valid_to;
|
|
12409
|
+
const constraintContext = {
|
|
14109
12410
|
graphId: ctx.graphId,
|
|
14110
|
-
|
|
14111
|
-
|
|
14112
|
-
|
|
14113
|
-
|
|
14114
|
-
|
|
14115
|
-
|
|
14116
|
-
|
|
14117
|
-
|
|
14118
|
-
|
|
14119
|
-
|
|
14120
|
-
|
|
14121
|
-
|
|
14122
|
-
|
|
12411
|
+
registry: ctx.registry,
|
|
12412
|
+
backend: target
|
|
12413
|
+
};
|
|
12414
|
+
await checkCardinalityConstraint(
|
|
12415
|
+
constraintContext,
|
|
12416
|
+
kind,
|
|
12417
|
+
cardinality,
|
|
12418
|
+
entry2.fromKind,
|
|
12419
|
+
entry2.fromId,
|
|
12420
|
+
entry2.toKind,
|
|
12421
|
+
entry2.toId,
|
|
12422
|
+
effectiveValidTo
|
|
12423
|
+
);
|
|
12424
|
+
const edge = await executeEdgeUpsertUpdate(
|
|
12425
|
+
ctx,
|
|
12426
|
+
{ id: entry2.row.id, props: entry2.validatedProps },
|
|
12427
|
+
target,
|
|
12428
|
+
{ clearDeleted: true }
|
|
12429
|
+
);
|
|
12430
|
+
results[entry2.index] = { edge, action: "resurrected" };
|
|
12431
|
+
} else if (ifExists === "update") {
|
|
12432
|
+
const edge = await executeEdgeUpsertUpdate(
|
|
12433
|
+
ctx,
|
|
12434
|
+
{ id: entry2.row.id, props: entry2.validatedProps },
|
|
12435
|
+
target
|
|
12436
|
+
);
|
|
12437
|
+
results[entry2.index] = { edge, action: "updated" };
|
|
12438
|
+
} else {
|
|
12439
|
+
results[entry2.index] = { edge: rowToEdge(entry2.row), action: "found" };
|
|
14123
12440
|
}
|
|
14124
|
-
await ctx.backend.insertUnique({
|
|
14125
|
-
graphId: ctx.graphId,
|
|
14126
|
-
nodeKind: kind,
|
|
14127
|
-
constraintName: constraint.name,
|
|
14128
|
-
key: newKey,
|
|
14129
|
-
nodeId: id,
|
|
14130
|
-
concreteKind: kind
|
|
14131
|
-
});
|
|
14132
12441
|
}
|
|
14133
|
-
|
|
12442
|
+
for (const { index, sourceIndex } of duplicateOf) {
|
|
12443
|
+
const sourceResult = results[sourceIndex];
|
|
12444
|
+
results[index] = { edge: sourceResult.edge, action: "found" };
|
|
12445
|
+
}
|
|
12446
|
+
return results;
|
|
12447
|
+
});
|
|
14134
12448
|
}
|
|
14135
|
-
|
|
14136
|
-
// src/store/operations/node-operations.ts
|
|
14137
12449
|
function getNodeRegistration(graph, kind) {
|
|
14138
12450
|
const registration = graph.nodes[kind];
|
|
14139
12451
|
if (registration === void 0) throw new KindNotFoundError(kind, "node");
|
|
@@ -14143,9 +12455,6 @@ var CACHE_KEY_SEPARATOR = "\0";
|
|
|
14143
12455
|
function buildNodeCacheKey(graphId, kind, id) {
|
|
14144
12456
|
return `${graphId}${CACHE_KEY_SEPARATOR}${kind}${CACHE_KEY_SEPARATOR}${id}`;
|
|
14145
12457
|
}
|
|
14146
|
-
function runInTopLevelTransactionForHistory(ctx, backend, fn) {
|
|
14147
|
-
return ctx.historyEnabled ? runOptionallyInTransaction(backend, fn) : fn(backend);
|
|
14148
|
-
}
|
|
14149
12458
|
function buildUniqueCacheKey(graphId, nodeKind, constraintName, key) {
|
|
14150
12459
|
return `${graphId}${CACHE_KEY_SEPARATOR}${nodeKind}${CACHE_KEY_SEPARATOR}${constraintName}${CACHE_KEY_SEPARATOR}${key}`;
|
|
14151
12460
|
}
|
|
@@ -14195,15 +12504,6 @@ function resolveConstraint(graph, kind, constraintName) {
|
|
|
14195
12504
|
}
|
|
14196
12505
|
return constraint;
|
|
14197
12506
|
}
|
|
14198
|
-
function createUniquenessContext(graphId, registry, backend) {
|
|
14199
|
-
return { graphId, registry, backend };
|
|
14200
|
-
}
|
|
14201
|
-
function createEmbeddingSyncContext(graphId, nodeKind, nodeId, backend) {
|
|
14202
|
-
return { graphId, nodeKind, nodeId, backend };
|
|
14203
|
-
}
|
|
14204
|
-
function createFulltextSyncContext(graphId, nodeKind, nodeId, backend) {
|
|
14205
|
-
return { graphId, nodeKind, nodeId, backend };
|
|
14206
|
-
}
|
|
14207
12507
|
function createNodeBatchValidationBackend(graphId, registry, backend) {
|
|
14208
12508
|
const nodeCache = /* @__PURE__ */ new Map();
|
|
14209
12509
|
const pendingNodes = /* @__PURE__ */ new Map();
|
|
@@ -14345,37 +12645,24 @@ async function validateAndPrepareNodeCreate(ctx, input, id, backend) {
|
|
|
14345
12645
|
)
|
|
14346
12646
|
};
|
|
14347
12647
|
}
|
|
14348
|
-
async function finalizeNodeCreate(ctx, prepared, backend) {
|
|
14349
|
-
await
|
|
14350
|
-
|
|
14351
|
-
|
|
14352
|
-
|
|
14353
|
-
|
|
14354
|
-
|
|
14355
|
-
|
|
14356
|
-
|
|
14357
|
-
|
|
14358
|
-
|
|
14359
|
-
prepared.kind,
|
|
14360
|
-
prepared.id,
|
|
14361
|
-
backend
|
|
14362
|
-
),
|
|
14363
|
-
prepared.nodeKind.schema,
|
|
14364
|
-
prepared.validatedProps
|
|
14365
|
-
);
|
|
14366
|
-
await syncFulltext(
|
|
14367
|
-
createFulltextSyncContext(ctx.graphId, prepared.kind, prepared.id, backend),
|
|
14368
|
-
prepared.nodeKind.schema,
|
|
14369
|
-
prepared.validatedProps
|
|
12648
|
+
async function finalizeNodeCreate(ctx, prepared, backend, lock) {
|
|
12649
|
+
await applyNodeInsertSideEffects(
|
|
12650
|
+
createNodeWriteContext(ctx.graphId, ctx.registry, lock),
|
|
12651
|
+
{
|
|
12652
|
+
kind: prepared.kind,
|
|
12653
|
+
id: prepared.id,
|
|
12654
|
+
schema: prepared.nodeKind.schema,
|
|
12655
|
+
props: prepared.validatedProps,
|
|
12656
|
+
uniqueConstraints: prepared.uniqueConstraints
|
|
12657
|
+
},
|
|
12658
|
+
backend
|
|
14370
12659
|
);
|
|
14371
12660
|
}
|
|
14372
|
-
async function performNodeUpdate(ctx, input, backend, options) {
|
|
12661
|
+
async function performNodeUpdate(ctx, input, backend, lock, options) {
|
|
14373
12662
|
const { kind, id } = input;
|
|
14374
12663
|
const registration = getNodeRegistration(ctx.graph, kind);
|
|
14375
12664
|
const existing = await backend.getNode(ctx.graphId, kind, id);
|
|
14376
|
-
if (!existing
|
|
14377
|
-
throw new NodeNotFoundError(kind, id);
|
|
14378
|
-
}
|
|
12665
|
+
if (!existing) throw new NodeNotFoundError(kind, id);
|
|
14379
12666
|
const existingProps = JSON.parse(existing.props);
|
|
14380
12667
|
const mergedProps = { ...existingProps, ...input.props };
|
|
14381
12668
|
const nodeKind = registration.type;
|
|
@@ -14385,69 +12672,29 @@ async function performNodeUpdate(ctx, input, backend, options) {
|
|
|
14385
12672
|
id
|
|
14386
12673
|
});
|
|
14387
12674
|
const validTo = validateOptionalCanonicalIsoDate(input.validTo, "validTo");
|
|
14388
|
-
|
|
14389
|
-
|
|
14390
|
-
|
|
14391
|
-
id,
|
|
14392
|
-
existingProps,
|
|
12675
|
+
const writeContext = createNodeWriteContext(ctx.graphId, ctx.registry, lock);
|
|
12676
|
+
const shared = {
|
|
12677
|
+
schema: nodeKind.schema,
|
|
14393
12678
|
validatedProps,
|
|
14394
|
-
registration.unique ?? []
|
|
14395
|
-
|
|
14396
|
-
const updateParams = {
|
|
14397
|
-
graphId: ctx.graphId,
|
|
14398
|
-
kind,
|
|
14399
|
-
id,
|
|
14400
|
-
props: validatedProps,
|
|
14401
|
-
incrementVersion: true
|
|
12679
|
+
uniqueConstraints: registration.unique ?? [],
|
|
12680
|
+
...validTo !== void 0 && { validTo }
|
|
14402
12681
|
};
|
|
14403
|
-
if (
|
|
14404
|
-
|
|
14405
|
-
|
|
14406
|
-
|
|
14407
|
-
|
|
14408
|
-
|
|
14409
|
-
|
|
14410
|
-
|
|
14411
|
-
|
|
14412
|
-
|
|
14413
|
-
|
|
14414
|
-
|
|
12682
|
+
if (options?.clearDeleted) {
|
|
12683
|
+
const row2 = await applyNodeUpdate(
|
|
12684
|
+
writeContext,
|
|
12685
|
+
{ ...shared, existing, clearDeleted: true },
|
|
12686
|
+
backend
|
|
12687
|
+
);
|
|
12688
|
+
return rowToNode(row2);
|
|
12689
|
+
}
|
|
12690
|
+
if (!isLiveNodeRow(existing)) throw new NodeNotFoundError(kind, id);
|
|
12691
|
+
const row = await applyNodeUpdate(
|
|
12692
|
+
writeContext,
|
|
12693
|
+
{ ...shared, existing },
|
|
12694
|
+
backend
|
|
14415
12695
|
);
|
|
14416
12696
|
return rowToNode(row);
|
|
14417
12697
|
}
|
|
14418
|
-
async function enforceDeleteBehavior(ctx, kind, id, mode, backend, registration) {
|
|
14419
|
-
const deleteBehavior = registration.onDelete ?? "restrict";
|
|
14420
|
-
const connectedEdges = await backend.findEdgesConnectedTo({
|
|
14421
|
-
graphId: ctx.graphId,
|
|
14422
|
-
nodeKind: kind,
|
|
14423
|
-
nodeId: id
|
|
14424
|
-
});
|
|
14425
|
-
if (connectedEdges.length === 0) return;
|
|
14426
|
-
switch (deleteBehavior) {
|
|
14427
|
-
case "restrict": {
|
|
14428
|
-
const edgeKinds = [...new Set(connectedEdges.map((edge) => edge.kind))];
|
|
14429
|
-
throw new RestrictedDeleteError({
|
|
14430
|
-
nodeKind: kind,
|
|
14431
|
-
nodeId: id,
|
|
14432
|
-
edgeCount: connectedEdges.length,
|
|
14433
|
-
edgeKinds
|
|
14434
|
-
});
|
|
14435
|
-
}
|
|
14436
|
-
case "cascade":
|
|
14437
|
-
case "disconnect": {
|
|
14438
|
-
for (const edge of connectedEdges) {
|
|
14439
|
-
await (mode === "hard" ? backend.hardDeleteEdge({
|
|
14440
|
-
graphId: ctx.graphId,
|
|
14441
|
-
id: edge.id
|
|
14442
|
-
}) : backend.deleteEdge({
|
|
14443
|
-
graphId: ctx.graphId,
|
|
14444
|
-
id: edge.id
|
|
14445
|
-
}));
|
|
14446
|
-
}
|
|
14447
|
-
break;
|
|
14448
|
-
}
|
|
14449
|
-
}
|
|
14450
|
-
}
|
|
14451
12698
|
async function prepareBatchCreates(ctx, inputs, backend) {
|
|
14452
12699
|
const {
|
|
14453
12700
|
backend: validationBackend,
|
|
@@ -14528,9 +12775,11 @@ async function executeNodeCreateInternal(ctx, input, backend, options) {
|
|
|
14528
12775
|
const kind = input.kind;
|
|
14529
12776
|
const id = input.id ?? generateId();
|
|
14530
12777
|
const opContext = ctx.createOperationContext("create", "node", kind, id);
|
|
14531
|
-
return
|
|
12778
|
+
return runHookedWriteOperation(
|
|
12779
|
+
ctx,
|
|
14532
12780
|
opContext,
|
|
14533
|
-
|
|
12781
|
+
backend,
|
|
12782
|
+
async (target, lock) => {
|
|
14534
12783
|
const prepared = await validateAndPrepareNodeCreate(
|
|
14535
12784
|
ctx,
|
|
14536
12785
|
input,
|
|
@@ -14541,10 +12790,10 @@ async function executeNodeCreateInternal(ctx, input, backend, options) {
|
|
|
14541
12790
|
{
|
|
14542
12791
|
row = await target.insertNode(prepared.insertParams);
|
|
14543
12792
|
}
|
|
14544
|
-
await finalizeNodeCreate(ctx, prepared, target);
|
|
12793
|
+
await finalizeNodeCreate(ctx, prepared, target, lock);
|
|
14545
12794
|
if (row === void 0) return;
|
|
14546
12795
|
return rowToNode(row);
|
|
14547
|
-
}
|
|
12796
|
+
}
|
|
14548
12797
|
);
|
|
14549
12798
|
}
|
|
14550
12799
|
async function executeNodeCreate(ctx, input, backend) {
|
|
@@ -14559,7 +12808,7 @@ async function executeNodeCreate(ctx, input, backend) {
|
|
|
14559
12808
|
}
|
|
14560
12809
|
async function executeNodeCreateNoReturnBatch(ctx, inputs, backend) {
|
|
14561
12810
|
if (inputs.length === 0) return;
|
|
14562
|
-
await
|
|
12811
|
+
await runInWriteTransaction(ctx, backend, async (target, lock) => {
|
|
14563
12812
|
const { preparedCreates, batchInsertParams } = await prepareBatchCreates(
|
|
14564
12813
|
ctx,
|
|
14565
12814
|
inputs,
|
|
@@ -14567,13 +12816,13 @@ async function executeNodeCreateNoReturnBatch(ctx, inputs, backend) {
|
|
|
14567
12816
|
);
|
|
14568
12817
|
await runInsertBatch(nodeInsertDispatch(target), batchInsertParams);
|
|
14569
12818
|
for (const prepared of preparedCreates) {
|
|
14570
|
-
await finalizeNodeCreate(ctx, prepared, target);
|
|
12819
|
+
await finalizeNodeCreate(ctx, prepared, target, lock);
|
|
14571
12820
|
}
|
|
14572
12821
|
});
|
|
14573
12822
|
}
|
|
14574
12823
|
async function executeNodeCreateBatch(ctx, inputs, backend) {
|
|
14575
12824
|
if (inputs.length === 0) return [];
|
|
14576
|
-
return
|
|
12825
|
+
return runInWriteTransaction(ctx, backend, async (target, lock) => {
|
|
14577
12826
|
const { preparedCreates, batchInsertParams } = await prepareBatchCreates(
|
|
14578
12827
|
ctx,
|
|
14579
12828
|
inputs,
|
|
@@ -14584,7 +12833,7 @@ async function executeNodeCreateBatch(ctx, inputs, backend) {
|
|
|
14584
12833
|
batchInsertParams
|
|
14585
12834
|
);
|
|
14586
12835
|
for (const prepared of preparedCreates) {
|
|
14587
|
-
await finalizeNodeCreate(ctx, prepared, target);
|
|
12836
|
+
await finalizeNodeCreate(ctx, prepared, target, lock);
|
|
14588
12837
|
}
|
|
14589
12838
|
return rows.map((row) => rowToNode(row));
|
|
14590
12839
|
});
|
|
@@ -14596,71 +12845,69 @@ async function executeNodeUpdate(ctx, input, backend, options) {
|
|
|
14596
12845
|
input.kind,
|
|
14597
12846
|
input.id
|
|
14598
12847
|
);
|
|
14599
|
-
return
|
|
12848
|
+
return runHookedWriteOperation(
|
|
12849
|
+
ctx,
|
|
14600
12850
|
opContext,
|
|
14601
|
-
|
|
14602
|
-
|
|
14603
|
-
backend,
|
|
14604
|
-
(target) => performNodeUpdate(ctx, input, target, options)
|
|
14605
|
-
)
|
|
12851
|
+
backend,
|
|
12852
|
+
(target, lock) => performNodeUpdate(ctx, input, target, lock, options)
|
|
14606
12853
|
);
|
|
14607
12854
|
}
|
|
14608
12855
|
async function executeNodeUpsertUpdate(ctx, input, backend, options) {
|
|
14609
|
-
return
|
|
12856
|
+
return runInWriteTransaction(
|
|
14610
12857
|
ctx,
|
|
14611
12858
|
backend,
|
|
14612
|
-
(target) => performNodeUpdate(ctx, input, target, options)
|
|
12859
|
+
(target, lock) => performNodeUpdate(ctx, input, target, lock, options)
|
|
14613
12860
|
);
|
|
14614
12861
|
}
|
|
14615
12862
|
async function executeNodeDelete(ctx, kind, id, backend) {
|
|
12863
|
+
const gate = await backend.getNode(ctx.graphId, kind, id);
|
|
12864
|
+
if (!gate || gate.deleted_at) return;
|
|
14616
12865
|
const opContext = ctx.createOperationContext("delete", "node", kind, id);
|
|
14617
|
-
return
|
|
14618
|
-
|
|
14619
|
-
|
|
14620
|
-
|
|
14621
|
-
|
|
14622
|
-
const
|
|
14623
|
-
|
|
14624
|
-
|
|
14625
|
-
await
|
|
14626
|
-
|
|
14627
|
-
|
|
14628
|
-
|
|
14629
|
-
|
|
14630
|
-
|
|
14631
|
-
|
|
14632
|
-
|
|
14633
|
-
|
|
14634
|
-
await deleteNodeEmbeddings(
|
|
14635
|
-
createEmbeddingSyncContext(ctx.graphId, kind, id, target),
|
|
14636
|
-
nodeKind.schema
|
|
14637
|
-
);
|
|
14638
|
-
await deleteNodeFulltext(
|
|
14639
|
-
createFulltextSyncContext(ctx.graphId, kind, id, target),
|
|
14640
|
-
nodeKind.schema
|
|
12866
|
+
return runHookedWriteOperation(
|
|
12867
|
+
ctx,
|
|
12868
|
+
opContext,
|
|
12869
|
+
backend,
|
|
12870
|
+
async (target, lock) => {
|
|
12871
|
+
const registration = getNodeRegistration(ctx.graph, kind);
|
|
12872
|
+
const preflight = await target.getNode(ctx.graphId, kind, id);
|
|
12873
|
+
if (!preflight || !isLiveNodeRow(preflight)) return;
|
|
12874
|
+
await applyNodeSoftDelete(
|
|
12875
|
+
createNodeWriteContext(ctx.graphId, ctx.registry, lock),
|
|
12876
|
+
{
|
|
12877
|
+
existing: preflight,
|
|
12878
|
+
schema: registration.type.schema,
|
|
12879
|
+
uniqueConstraints: registration.unique ?? [],
|
|
12880
|
+
onDelete: registration.onDelete
|
|
12881
|
+
},
|
|
12882
|
+
target
|
|
14641
12883
|
);
|
|
14642
|
-
}
|
|
14643
|
-
|
|
14644
|
-
});
|
|
12884
|
+
}
|
|
12885
|
+
);
|
|
14645
12886
|
}
|
|
14646
12887
|
async function executeNodeHardDelete(ctx, kind, id, backend) {
|
|
12888
|
+
const gate = await backend.getNode(ctx.graphId, kind, id);
|
|
12889
|
+
if (!gate) return;
|
|
14647
12890
|
const opContext = ctx.createOperationContext("delete", "node", kind, id);
|
|
14648
|
-
return
|
|
14649
|
-
|
|
14650
|
-
|
|
14651
|
-
|
|
14652
|
-
|
|
14653
|
-
const
|
|
14654
|
-
|
|
14655
|
-
|
|
14656
|
-
await
|
|
14657
|
-
|
|
14658
|
-
|
|
14659
|
-
|
|
12891
|
+
return runHookedWriteOperation(
|
|
12892
|
+
ctx,
|
|
12893
|
+
opContext,
|
|
12894
|
+
backend,
|
|
12895
|
+
async (target, lock) => {
|
|
12896
|
+
const registration = getNodeRegistration(ctx.graph, kind);
|
|
12897
|
+
const preflight = await target.getNode(ctx.graphId, kind, id);
|
|
12898
|
+
if (!preflight) return;
|
|
12899
|
+
await applyNodeHardDelete(
|
|
12900
|
+
createNodeWriteContext(ctx.graphId, ctx.registry, lock),
|
|
12901
|
+
{
|
|
12902
|
+
kind,
|
|
12903
|
+
id,
|
|
12904
|
+
schema: registration.type.schema,
|
|
12905
|
+
onDelete: registration.onDelete
|
|
12906
|
+
},
|
|
12907
|
+
target
|
|
14660
12908
|
);
|
|
14661
|
-
}
|
|
14662
|
-
|
|
14663
|
-
});
|
|
12909
|
+
}
|
|
12910
|
+
);
|
|
14664
12911
|
}
|
|
14665
12912
|
async function executeNodeGetOrCreateByConstraint(ctx, kind, constraintName, props, backend, options) {
|
|
14666
12913
|
const ifExists = options?.ifExists ?? "return";
|
|
@@ -14689,51 +12936,59 @@ async function executeNodeGetOrCreateByConstraint(ctx, kind, constraintName, pro
|
|
|
14689
12936
|
constraint.scope,
|
|
14690
12937
|
ctx.registry
|
|
14691
12938
|
);
|
|
14692
|
-
|
|
14693
|
-
|
|
14694
|
-
|
|
14695
|
-
|
|
14696
|
-
|
|
14697
|
-
|
|
14698
|
-
|
|
14699
|
-
|
|
14700
|
-
if (existingUniqueRow === void 0) {
|
|
14701
|
-
const node = await executeNodeCreate(
|
|
14702
|
-
ctx,
|
|
14703
|
-
{ kind, props: validatedProps },
|
|
14704
|
-
backend
|
|
12939
|
+
async function attempt() {
|
|
12940
|
+
const existingUniqueRow = await findUniqueRowAcrossKinds(
|
|
12941
|
+
backend,
|
|
12942
|
+
ctx.graphId,
|
|
12943
|
+
constraint.name,
|
|
12944
|
+
key,
|
|
12945
|
+
kindsToCheck,
|
|
12946
|
+
true
|
|
14705
12947
|
);
|
|
14706
|
-
|
|
14707
|
-
|
|
14708
|
-
|
|
14709
|
-
|
|
14710
|
-
|
|
14711
|
-
|
|
14712
|
-
|
|
14713
|
-
|
|
14714
|
-
const
|
|
14715
|
-
ctx,
|
|
14716
|
-
|
|
14717
|
-
|
|
12948
|
+
if (existingUniqueRow === void 0) {
|
|
12949
|
+
const node = await executeNodeCreate(
|
|
12950
|
+
ctx,
|
|
12951
|
+
{ kind, props: validatedProps },
|
|
12952
|
+
backend
|
|
12953
|
+
);
|
|
12954
|
+
return { node, action: "created" };
|
|
12955
|
+
}
|
|
12956
|
+
const existingRow = await backend.getNode(
|
|
12957
|
+
ctx.graphId,
|
|
12958
|
+
existingUniqueRow.concrete_kind,
|
|
12959
|
+
existingUniqueRow.node_id
|
|
14718
12960
|
);
|
|
14719
|
-
|
|
12961
|
+
if (existingRow === void 0) {
|
|
12962
|
+
const node = await executeNodeCreate(
|
|
12963
|
+
ctx,
|
|
12964
|
+
{ kind, props: validatedProps },
|
|
12965
|
+
backend
|
|
12966
|
+
);
|
|
12967
|
+
return { node, action: "created" };
|
|
12968
|
+
}
|
|
12969
|
+
const isSoftDeleted = existingRow.deleted_at !== void 0;
|
|
12970
|
+
if (isSoftDeleted || ifExists === "update") {
|
|
12971
|
+
const concreteKind = existingUniqueRow.concrete_kind;
|
|
12972
|
+
const node = await executeNodeUpsertUpdate(
|
|
12973
|
+
ctx,
|
|
12974
|
+
{
|
|
12975
|
+
kind: concreteKind,
|
|
12976
|
+
id: existingRow.id,
|
|
12977
|
+
props: validatedProps
|
|
12978
|
+
},
|
|
12979
|
+
backend,
|
|
12980
|
+
{ clearDeleted: isSoftDeleted }
|
|
12981
|
+
);
|
|
12982
|
+
return { node, action: isSoftDeleted ? "resurrected" : "updated" };
|
|
12983
|
+
}
|
|
12984
|
+
return { node: rowToNode(existingRow), action: "found" };
|
|
14720
12985
|
}
|
|
14721
|
-
|
|
14722
|
-
|
|
14723
|
-
|
|
14724
|
-
|
|
14725
|
-
|
|
14726
|
-
{
|
|
14727
|
-
kind: concreteKind,
|
|
14728
|
-
id: existingRow.id,
|
|
14729
|
-
props: validatedProps
|
|
14730
|
-
},
|
|
14731
|
-
backend,
|
|
14732
|
-
{ clearDeleted: isSoftDeleted }
|
|
14733
|
-
);
|
|
14734
|
-
return { node, action: isSoftDeleted ? "resurrected" : "updated" };
|
|
12986
|
+
try {
|
|
12987
|
+
return await attempt();
|
|
12988
|
+
} catch (error) {
|
|
12989
|
+
if (!(error instanceof UniquenessError)) throw error;
|
|
12990
|
+
return attempt();
|
|
14735
12991
|
}
|
|
14736
|
-
return { node: rowToNode(existingRow), action: "found" };
|
|
14737
12992
|
}
|
|
14738
12993
|
async function executeNodeFindByConstraint(ctx, kind, constraintName, props, backend) {
|
|
14739
12994
|
const registration = getNodeRegistration(ctx.graph, kind);
|
|
@@ -15347,6 +13602,9 @@ var CAUGHT_UP_VERB_DETAILS = {
|
|
|
15347
13602
|
function rowMapperConfigFor(backend) {
|
|
15348
13603
|
return backend.dialect === "postgres" ? POSTGRES_ROW_MAPPER_CONFIG : SQLITE_ROW_MAPPER_CONFIG;
|
|
15349
13604
|
}
|
|
13605
|
+
function asError(error) {
|
|
13606
|
+
return error instanceof Error ? error : new Error(String(error));
|
|
13607
|
+
}
|
|
15350
13608
|
var Store = class _Store {
|
|
15351
13609
|
#graph;
|
|
15352
13610
|
/**
|
|
@@ -15660,7 +13918,9 @@ var Store = class _Store {
|
|
|
15660
13918
|
* Node operations bound to this store instance.
|
|
15661
13919
|
*/
|
|
15662
13920
|
get #nodeOperations() {
|
|
15663
|
-
|
|
13921
|
+
return this.#buildNodeOperations(this.#createNodeOperationContext());
|
|
13922
|
+
}
|
|
13923
|
+
#buildNodeOperations(ctx) {
|
|
15664
13924
|
return {
|
|
15665
13925
|
defaultTemporalMode: this.#graph.defaults.temporalMode,
|
|
15666
13926
|
rowToNode: (row) => rowToNode(row),
|
|
@@ -15716,7 +13976,9 @@ var Store = class _Store {
|
|
|
15716
13976
|
* Edge operations bound to this store instance.
|
|
15717
13977
|
*/
|
|
15718
13978
|
get #edgeOperations() {
|
|
15719
|
-
|
|
13979
|
+
return this.#buildEdgeOperations(this.#createEdgeOperationContext());
|
|
13980
|
+
}
|
|
13981
|
+
#buildEdgeOperations(ctx) {
|
|
15720
13982
|
return {
|
|
15721
13983
|
defaultTemporalMode: this.#graph.defaults.temporalMode,
|
|
15722
13984
|
rowToEdge: (row) => rowToEdge(row),
|
|
@@ -16128,13 +14390,36 @@ var Store = class _Store {
|
|
|
16128
14390
|
return invoke({
|
|
16129
14391
|
nodes: this.nodes,
|
|
16130
14392
|
edges: this.edges,
|
|
16131
|
-
backend: this.#backend
|
|
14393
|
+
backend: this.#backend,
|
|
14394
|
+
getNodeCollection: (kind) => this.getNodeCollection(kind),
|
|
14395
|
+
// No transaction, no deferral: operations apply as they happen, so
|
|
14396
|
+
// their hooks fire immediately.
|
|
14397
|
+
runNodeOperationHooks: (operation, kind, id, hookedFunction) => this.#withOperationHooks(
|
|
14398
|
+
this.#createOperationContext(operation, "node", kind, id),
|
|
14399
|
+
hookedFunction
|
|
14400
|
+
)
|
|
16132
14401
|
});
|
|
16133
14402
|
}
|
|
16134
|
-
|
|
16135
|
-
|
|
16136
|
-
|
|
16137
|
-
|
|
14403
|
+
const pending = [];
|
|
14404
|
+
const runHooks = this.#createBufferedHookRunner(pending);
|
|
14405
|
+
try {
|
|
14406
|
+
const result = await this.#backend.transaction(
|
|
14407
|
+
async (txBackend, sql17) => invoke(this.#buildTransactionContext(txBackend, sql17, runHooks)),
|
|
14408
|
+
options
|
|
14409
|
+
);
|
|
14410
|
+
for (const outcome of pending) {
|
|
14411
|
+
this.#hooks.onOperationEnd?.(outcome.ctx, {
|
|
14412
|
+
durationMs: outcome.durationMs
|
|
14413
|
+
});
|
|
14414
|
+
}
|
|
14415
|
+
return result;
|
|
14416
|
+
} catch (error) {
|
|
14417
|
+
const failure = asError(error);
|
|
14418
|
+
for (const outcome of pending) {
|
|
14419
|
+
this.#hooks.onError?.(outcome.ctx, failure);
|
|
14420
|
+
}
|
|
14421
|
+
throw error;
|
|
14422
|
+
}
|
|
16138
14423
|
}
|
|
16139
14424
|
/**
|
|
16140
14425
|
* Adopts a caller-owned, already-open Drizzle transaction so the graph
|
|
@@ -16234,6 +14519,9 @@ var Store = class _Store {
|
|
|
16234
14519
|
backend: txBackend,
|
|
16235
14520
|
flush: () => Promise.resolve()
|
|
16236
14521
|
};
|
|
14522
|
+
if (this.#captureEnabled) {
|
|
14523
|
+
await lockRecordedGraphWrite(scope.backend, this.graphId);
|
|
14524
|
+
}
|
|
16237
14525
|
const invoke = fn;
|
|
16238
14526
|
const result = await invoke(
|
|
16239
14527
|
this.#buildTransactionContext(scope.backend, externalTx)
|
|
@@ -16251,15 +14539,16 @@ var Store = class _Store {
|
|
|
16251
14539
|
* (#140); when history capture is enabled it is replaced with a fail-loud
|
|
16252
14540
|
* guard because raw graph writes would bypass recorded-time capture.
|
|
16253
14541
|
*/
|
|
16254
|
-
#buildTransactionContext(txBackend,
|
|
14542
|
+
#buildTransactionContext(txBackend, sql17, runHooks = this.#immediateHookRunner()) {
|
|
16255
14543
|
const txNodeOperations = {
|
|
16256
|
-
...this.#
|
|
14544
|
+
...this.#buildNodeOperations(this.#createNodeOperationContext(runHooks)),
|
|
16257
14545
|
createQuery: () => this.#createQueryForBackend(txBackend)
|
|
16258
14546
|
};
|
|
16259
14547
|
const txEdgeOperations = {
|
|
16260
|
-
...this.#
|
|
14548
|
+
...this.#buildEdgeOperations(this.#createEdgeOperationContext(runHooks)),
|
|
16261
14549
|
createQuery: () => this.#createQueryForBackend(txBackend)
|
|
16262
14550
|
};
|
|
14551
|
+
const runNodeOperationHooks = (operation, kind, id, fn) => runHooks(this.#createOperationContext(operation, "node", kind, id), fn);
|
|
16263
14552
|
const nodes = createNodeCollectionsProxy(
|
|
16264
14553
|
this.#graph,
|
|
16265
14554
|
this.graphId,
|
|
@@ -16274,9 +14563,28 @@ var Store = class _Store {
|
|
|
16274
14563
|
txBackend,
|
|
16275
14564
|
txEdgeOperations
|
|
16276
14565
|
);
|
|
16277
|
-
|
|
16278
|
-
|
|
16279
|
-
|
|
14566
|
+
const getNodeCollection = (kind) => {
|
|
14567
|
+
if (!Object.hasOwn(this.#graph.nodes, kind)) return void 0;
|
|
14568
|
+
return nodes[kind];
|
|
14569
|
+
};
|
|
14570
|
+
if (sql17 === void 0) {
|
|
14571
|
+
return {
|
|
14572
|
+
nodes,
|
|
14573
|
+
edges,
|
|
14574
|
+
backend: txBackend,
|
|
14575
|
+
getNodeCollection,
|
|
14576
|
+
runNodeOperationHooks
|
|
14577
|
+
};
|
|
14578
|
+
}
|
|
14579
|
+
const exposedSql = this.#captureEnabled ? createHistoryUnsafeSqlRef() : sql17;
|
|
14580
|
+
return {
|
|
14581
|
+
nodes,
|
|
14582
|
+
edges,
|
|
14583
|
+
sql: exposedSql,
|
|
14584
|
+
backend: txBackend,
|
|
14585
|
+
getNodeCollection,
|
|
14586
|
+
runNodeOperationHooks
|
|
14587
|
+
};
|
|
16280
14588
|
}
|
|
16281
14589
|
// === Graph Lifecycle ===
|
|
16282
14590
|
/**
|
|
@@ -16937,23 +15245,27 @@ var Store = class _Store {
|
|
|
16937
15245
|
await this.#backend.close();
|
|
16938
15246
|
}
|
|
16939
15247
|
// === Internal: Operation Contexts ===
|
|
16940
|
-
#
|
|
15248
|
+
#immediateHookRunner() {
|
|
15249
|
+
return (ctx, fn) => this.#withOperationHooks(ctx, fn);
|
|
15250
|
+
}
|
|
15251
|
+
#createNodeOperationContext(runHooks = this.#immediateHookRunner()) {
|
|
16941
15252
|
return {
|
|
16942
15253
|
graph: this.#graph,
|
|
16943
15254
|
graphId: this.graphId,
|
|
16944
15255
|
historyEnabled: this.#captureEnabled,
|
|
16945
15256
|
registry: this.#registry,
|
|
16946
15257
|
createOperationContext: (operation, entity, kind, id) => this.#createOperationContext(operation, entity, kind, id),
|
|
16947
|
-
withOperationHooks:
|
|
15258
|
+
withOperationHooks: runHooks
|
|
16948
15259
|
};
|
|
16949
15260
|
}
|
|
16950
|
-
#createEdgeOperationContext() {
|
|
15261
|
+
#createEdgeOperationContext(runHooks = this.#immediateHookRunner()) {
|
|
16951
15262
|
return {
|
|
16952
15263
|
graph: this.#graph,
|
|
16953
15264
|
graphId: this.graphId,
|
|
15265
|
+
historyEnabled: this.#captureEnabled,
|
|
16954
15266
|
registry: this.#registry,
|
|
16955
15267
|
createOperationContext: (operation, entity, kind, id) => this.#createOperationContext(operation, entity, kind, id),
|
|
16956
|
-
withOperationHooks:
|
|
15268
|
+
withOperationHooks: runHooks
|
|
16957
15269
|
};
|
|
16958
15270
|
}
|
|
16959
15271
|
// === Internal: Hook Helpers ===
|
|
@@ -16983,13 +15295,34 @@ var Store = class _Store {
|
|
|
16983
15295
|
});
|
|
16984
15296
|
return result;
|
|
16985
15297
|
} catch (error) {
|
|
16986
|
-
this.#hooks.onError?.(
|
|
16987
|
-
ctx,
|
|
16988
|
-
error instanceof Error ? error : new Error(String(error))
|
|
16989
|
-
);
|
|
15298
|
+
this.#hooks.onError?.(ctx, asError(error));
|
|
16990
15299
|
throw error;
|
|
16991
15300
|
}
|
|
16992
15301
|
}
|
|
15302
|
+
/**
|
|
15303
|
+
* A hook runner for operations that execute INSIDE an explicit
|
|
15304
|
+
* `store.transaction`: `onOperationStart` (and a failed operation's
|
|
15305
|
+
* `onError`) fire immediately — the attempt and the failure are real when
|
|
15306
|
+
* they happen — but a successful operation's `onOperationEnd` is only
|
|
15307
|
+
* BUFFERED. `transaction()` flushes the buffer after the backend COMMIT
|
|
15308
|
+
* succeeds, or converts every buffered success into `onError` when the
|
|
15309
|
+
* transaction fails, so `onOperationEnd` always means durably committed
|
|
15310
|
+
* even for operations nested in a caller-controlled transaction.
|
|
15311
|
+
*/
|
|
15312
|
+
#createBufferedHookRunner(pending) {
|
|
15313
|
+
return async (ctx, fn) => {
|
|
15314
|
+
this.#hooks.onOperationStart?.(ctx);
|
|
15315
|
+
const startTime = Date.now();
|
|
15316
|
+
try {
|
|
15317
|
+
const result = await fn();
|
|
15318
|
+
pending.push({ ctx, durationMs: Date.now() - startTime });
|
|
15319
|
+
return result;
|
|
15320
|
+
} catch (error) {
|
|
15321
|
+
this.#hooks.onError?.(ctx, asError(error));
|
|
15322
|
+
throw error;
|
|
15323
|
+
}
|
|
15324
|
+
};
|
|
15325
|
+
}
|
|
16993
15326
|
// === Internal: Temporal Filtering ===
|
|
16994
15327
|
#temporalRowMatcher(options) {
|
|
16995
15328
|
const { temporalMode, asOf } = resolveTemporalReadParams(
|
|
@@ -17100,6 +15433,6 @@ async function createVerifiedStore(graph, backend, options) {
|
|
|
17100
15433
|
return [store, result];
|
|
17101
15434
|
}
|
|
17102
15435
|
|
|
17103
|
-
export {
|
|
17104
|
-
//# sourceMappingURL=chunk-
|
|
17105
|
-
//# sourceMappingURL=chunk-
|
|
15436
|
+
export { ExecutableAggregateQuery, ExecutableQuery, MAX_EXPLICIT_RECURSIVE_DEPTH, MAX_RECURSIVE_DEPTH, PreparedQuery, QueryBuilder, RecordedStoreView, StoreSearch, StoreView, UnionableQuery, avg, composeFragments, count, countDistinct, countDistinctEdges, countEdges, createFragment, createQueryBuilder, createStore, createStoreWithSchema, createVerifiedStore, defineSubgraphProject, field, having, havingEq, havingGt, havingGte, havingLt, havingLte, limitFragment, max, min, offsetFragment, orderByFragment, sum };
|
|
15437
|
+
//# sourceMappingURL=chunk-WLRIWYHQ.js.map
|
|
15438
|
+
//# sourceMappingURL=chunk-WLRIWYHQ.js.map
|