BatchEngine
Executes save, update, delete, and saveAll operations using LOGGED batch statements.
BATCH-consistency lookups are included in the atomic batch. EVENTUAL-consistency lookups fire asynchronously via scope after the batch commits, but are routed through the same executeWithRetry/executeWithRetrySuspend path as every other write: they retry on transient failures per retryConfig.retryOn, are counted in inFlightCount so graceful shutdown drains them before closing the session, and are rejected once isShuttingDown is set — same as any synchronous query. Failures (including "rejected due to shutdown") are forwarded to eventListener (if set) then logged.
Transient failures listed in retryConfig.retryOn are retried with linear backoff — except the @Version LWT update statement (see update/updateSuspend), which is executed exactly once via executeOnce/executeOnceSuspend to avoid a blind retry masking a real success as a spurious KandraOptimisticLockException. When isShuttingDown is set, all new queries — eventual lookups included — are rejected with KandraQueryException.
Constructors
Properties
Functions
Uses StatementBuilder.appendToCollectionSuspend (async prepare) — see GH #27 / ISS-049.
Uses StatementBuilder.counterUpdateSuspend (async prepare) — see GH #27 / ISS-049.
Deletes a row by full primary key without looking up the entity first — used by io.kandra.runtime.repository.KandraRepository.deleteById's "not found" branch (nothing to diff against, so there's no lookup-table cleanup possible here; unlike delete this never touches lookup rows). Routed through executeWithRetry so it gets the same shutdown gate, retry-on-transient-error, and inFlightCount tracking as every other write.
Suspend counterpart of deleteById — see its doc. Uses StatementBuilder.deleteByIdSuspend (async prepare) rather than the blocking StatementBuilder.deleteById (GH #27 / ISS-049).
Uses StatementBuilder.counterUpdateSuspend (async prepare) — see GH #27 / ISS-049.
Despite the name, this is a map merge/overwrite-by-key (col = col + ?) — see StatementBuilder.appendToCollection's doc.
Uses StatementBuilder.appendToCollectionSuspend (async prepare) — see GH #27 / ISS-049.
Uses StatementBuilder.removeFromCollectionSuspend (async prepare) — see GH #27 / ISS-049.
Same write path as save, but returns the entity actually persisted — with any @GeneratedUuid/@CreatedAt/@UpdatedAt/@Version values injectTimestamps/ injectInitialVersion generated before the write, instead of discarding that copy the way save does. See GH #132 / ISS-096: callers who relied on save()'s Unit return and then reused their original entity (e.g. to build an HTTP response) were silently working with placeholder values — UUID(0, 0), Instant.EPOCH — while the row that actually landed in Scylla carried the real generated ones.
Suspend counterpart of saveAndGet — see its doc for why this exists (GH #132 / ISS-096).
Same LWT write path as saveIfNotExists, but returns the entity actually persisted — with any @GeneratedUuid/@CreatedAt/@UpdatedAt values injectTimestamps computed before the write — instead of discarding that copy behind a bare Boolean the way saveIfNotExists does. Returns null when the IF NOT EXISTS check did not apply (a row already existed under this key) — the same "nothing was written" signal saveIfNotExists reports as false. See GH #138: same root-cause shape as GH #132 (save(), fixed by saveAndGet()) and GH #136 (update(), fixed by updateAndGet()) — a third instance of the same gap in this file.
Suspend counterpart of saveIfNotExistsAndGet — see its doc for why this exists (GH #138).
Same write path as update, but returns the entity actually persisted — with the post-update @Version (and @UpdatedAt) injectVersion/injectTimestamps computed for the write, instead of discarding that copy the way update does. See GH #136: a caller who relied on update()'s Unit return and then reused the pre-update version it already had for a subsequent optimistic-locked update got a spurious KandraOptimisticLockException against a write that had actually succeeded — it never learned its own prior write's resulting version.
Suspend counterpart of updateAndGet — see its doc for why this exists (GH #136).