Skip to main content

IStreamDataRepository

Namespace: Meshmakers.Octo.Runtime.Contracts.StreamData

Repository for stream data operations against a tenant-scoped, CrateDB-backed time-series store organised by CkArchive instances. Accessed via ITenantContext.GetStreamDataRepository(). Every operation is scoped to a single archive, addressed by its runtime id.

public interface IStreamDataRepository

Methods

EnsureDatabaseCreatedAsync()

Ensures the tenant's stream data namespace (e.g. CrateDB schema) exists. Idempotent. Called when a tenant opts into stream data; per-archive tables are created later via IStreamDataRepository.EnsureArchiveCreatedAsync(ArchiveSnapshot).

Task EnsureDatabaseCreatedAsync()

Returns

Task

DeleteDatabaseAsync()

Drops the tenant's entire stream data namespace including every archive table. Idempotent.

Task DeleteDatabaseAsync()

Returns

Task

EnsureArchiveCreatedAsync(ArchiveSnapshot)

Creates the storage table for the archive described by according to its current CkArchive definition. The snapshot carries the target CK type and user-picked columns the data store needs to generate DDL — passing it directly avoids a round-trip through IArchiveRuntimeStore from inside the repository. Idempotent (uses CREATE TABLE IF NOT EXISTS) so retries after a transient Mongo update failure converge cleanly.

Task EnsureArchiveCreatedAsync(ArchiveSnapshot snapshot)

Parameters

snapshot ArchiveSnapshot

Returns

Task

DeleteArchiveAsync(OctoObjectId)

Drops the storage table for the archive identified by . Idempotent. Called from the lifecycle service when an archive is deleted.

Task DeleteArchiveAsync(OctoObjectId archiveRtId)

Parameters

archiveRtId OctoObjectId

Returns

Task

ValidateComputedColumnsAsync(OctoObjectId, IReadOnlyList<CkArchiveColumnSpec>, CancellationToken)

Validates a prospective computed-column set (AB#4189 Phase 7) — syntax, reference resolution, acyclic dependencies, Path/Formula exclusivity, nullable, ResultType — without touching storage. The lifecycle service calls this before persisting an add (existing columns + the new one) or a remove (existing columns − the removed one, so a now-dangling reference is rejected). Throws a StreamDataException (stable GraphQL error code) on the first issue.

Task ValidateComputedColumnsAsync(OctoObjectId archiveRtId, IReadOnlyList<CkArchiveColumnSpec> prospectiveColumns, CancellationToken cancellationToken)

Parameters

archiveRtId OctoObjectId

prospectiveColumns IReadOnlyList<CkArchiveColumnSpec>

cancellationToken CancellationToken

Returns

Task

NormalizeComputedFormulaAsync(OctoObjectId, IReadOnlyList<CkArchiveColumnSpec>, String, CancellationToken)

Rewrites a computed-column formula from the archive's logical column vocabulary — the CK attribute paths the Studio lists and the query surface uses, e.g. Amount.Value — into the physical form the evaluation path binds, e.g. amountvalue (AB#4779).

The lifecycle service calls this before validating and persisting, so the stored formula is always physical and every downstream consumer keeps seeing exactly what it saw before. A name that is already physical, or that matches no column at all, is left as written — the latter so validation can reject it by the spelling the caller actually used.

It lives on the storage contract rather than in the lifecycle service because the logical→physical rule belongs to the storage layer, the same reason IStreamDataRepository.ValidateComputedColumnsAsync(OctoObjectId, IReadOnlyList<CkArchiveColumnSpec>, CancellationToken) does. No I/O.

Task<string> NormalizeComputedFormulaAsync(OctoObjectId archiveRtId, IReadOnlyList<CkArchiveColumnSpec> columns, string formula, CancellationToken cancellationToken)

Parameters

archiveRtId OctoObjectId

columns IReadOnlyList<CkArchiveColumnSpec>

formula String

cancellationToken CancellationToken

Returns

Task<String>

AddComputedColumnStorageAsync(ArchiveSnapshot, String, CancellationToken)

Adds the physical CrateDB column for the computed column named via ALTER TABLE … ADD COLUMN (AB#4189 Phase 7). Idempotent — tolerant of the column already existing (e.g. a re-add reusing an orphaned column). The column on supplies the declared result type the physical column is typed from.

Task AddComputedColumnStorageAsync(ArchiveSnapshot snapshot, string columnName, CancellationToken cancellationToken)

Parameters

snapshot ArchiveSnapshot

columnName String

cancellationToken CancellationToken

Returns

Task

AddPendingComputedColumnStorageAsync(ArchiveSnapshot, String, CancellationToken)

Adds the physical CrateDB column for the pending version of a computed column ({base}__v{ComputedVersion+1}) via ALTER TABLE … ADD COLUMN (AB#4189 Phase 7, formula change). Idempotent. Must run before the pending formula is marked so ingest's dual-write never targets a missing column.

Task AddPendingComputedColumnStorageAsync(ArchiveSnapshot snapshot, string columnName, CancellationToken cancellationToken)

Parameters

snapshot ArchiveSnapshot

columnName String

cancellationToken CancellationToken

Returns

Task

BackfillComputedColumnAsync(ArchiveSnapshot, String, CancellationToken)

Backfills the computed column named across the archive's existing rows (AB#4189 Phase 7, §8): pages through the rows, evaluates the column's formula per row, and writes the result into its physical cell. The physical column must already exist (see IStreamDataRepository.AddComputedColumnStorageAsync(ArchiveSnapshot, String, CancellationToken)). Readers keep seeing the previous state until the lifecycle flips the column to Active, because the column is hidden while non-active. Throws on a storage failure so the lifecycle can mark the column Failed.

Task BackfillComputedColumnAsync(ArchiveSnapshot snapshot, string columnName, CancellationToken cancellationToken)

Parameters

snapshot ArchiveSnapshot

columnName String

cancellationToken CancellationToken

Returns

Task

InsertAsync(OctoObjectId, StreamDataPoint)

Inserts a single data point into the archive. Throws ArchiveNotActivatedException if the archive's status is not Activated; throws RequiredAttributeMissingException on a missing required path.

Task InsertAsync(OctoObjectId archiveRtId, StreamDataPoint datapoint)

Parameters

archiveRtId OctoObjectId

datapoint StreamDataPoint

Returns

Task

InsertAsync(OctoObjectId, IEnumerable<StreamDataPoint>)

Inserts multiple data points into the archive. Pre-validates the entire batch before any SQL is sent; on first violation no row is written and the offending point's index is surfaced via the thrown exception.

Task InsertAsync(OctoObjectId archiveRtId, IEnumerable<StreamDataPoint> datapoints)

Parameters

archiveRtId OctoObjectId

datapoints IEnumerable<StreamDataPoint>

Returns

Task

InsertTimeRangeAsync(OctoObjectId, IEnumerable<TimeRangeStreamDataPoint>, CancellationToken)

Inserts externally pre-aggregated time-range data points into a TimeRangeArchive. Each point carries an explicit [from, to) window; the natural key (window_start, window_end, rtid, ckTypeId) handles re-deliveries via ON CONFLICT DO UPDATE, setting the row's was_updated flag to true on every upsert. Concept §3 / §5. Throws ArchiveNotActivatedException if the archive is not in Activated state, and ArgumentException if any point has To <= From.

Task InsertTimeRangeAsync(OctoObjectId archiveRtId, IEnumerable<TimeRangeStreamDataPoint> datapoints, CancellationToken cancellationToken)

Parameters

archiveRtId OctoObjectId

datapoints IEnumerable<TimeRangeStreamDataPoint>

cancellationToken CancellationToken

Returns

Task

ExecuteQueryAsync(OctoObjectId, StreamDataQueryOptions)

Executes a simple stream data query against the archive.

Task<StreamDataQueryResult> ExecuteQueryAsync(OctoObjectId archiveRtId, StreamDataQueryOptions options)

Parameters

archiveRtId OctoObjectId

options StreamDataQueryOptions

Returns

Task<StreamDataQueryResult>

ExecuteAggregationQueryAsync(OctoObjectId, StreamDataAggregationQueryOptions)

Executes an aggregation query (without grouping) against the archive.

Task<StreamDataQueryResult> ExecuteAggregationQueryAsync(OctoObjectId archiveRtId, StreamDataAggregationQueryOptions options)

Parameters

archiveRtId OctoObjectId

options StreamDataAggregationQueryOptions

Returns

Task<StreamDataQueryResult>

ExecuteGroupedAggregationQueryAsync(OctoObjectId, StreamDataGroupedAggregationQueryOptions)

Executes a grouped aggregation query against the archive.

Task<StreamDataQueryResult> ExecuteGroupedAggregationQueryAsync(OctoObjectId archiveRtId, StreamDataGroupedAggregationQueryOptions options)

Parameters

archiveRtId OctoObjectId

options StreamDataGroupedAggregationQueryOptions

Returns

Task<StreamDataQueryResult>

ExecuteDownsamplingQueryAsync(OctoObjectId, StreamDataDownsamplingQueryOptions)

Executes a downsampling query with time bins against the archive.

Task<StreamDataQueryResult> ExecuteDownsamplingQueryAsync(OctoObjectId archiveRtId, StreamDataDownsamplingQueryOptions options)

Parameters

archiveRtId OctoObjectId

options StreamDataDownsamplingQueryOptions

Returns

Task<StreamDataQueryResult>

ExportRowsAsync(OctoObjectId, TimeWindow, CancellationToken)

Streams the rows of the archive in a stable key order (keyset pagination on the natural key) so the caller can serialise NDJSON without buffering the table. When is non-null only rows whose timestamp (raw) or window_start (windowed: rollup / time-range) fall in [FromUtc, ToUtc) are emitted — the predicate rides on the already time-ordered keyset scan, so a windowed export is no more expensive than a full one (and cheaper). Each row is yielded as a dictionary of physical CrateDB column name → value (the standard columns plus the user columns). An archive without a backing table (e.g. Created) yields no rows rather than throwing. Archive data export/import concept (AB#4230) §4.1.

IAsyncEnumerable<IReadOnlyDictionary<string, object>> ExportRowsAsync(OctoObjectId archiveRtId, TimeWindow window, CancellationToken ct)

Parameters

archiveRtId OctoObjectId

window TimeWindow

ct CancellationToken

Returns

IAsyncEnumerable<IReadOnlyDictionary<String, Object>>

ImportRowsAsync(OctoObjectId, IAsyncEnumerable<IReadOnlyDictionary<String, Object>>, ArchiveImportMode, CancellationToken)

Bulk-inserts pre-parsed archive rows (the inverse of IStreamDataRepository.ExportRowsAsync(OctoObjectId, TimeWindow, CancellationToken)). Rows are streamed in batches into the existing batched insert path (the single-timestamp insert for raw archives, the (window_start, window_end) ON CONFLICT path for windowed archives). selects insert-only versus upsert semantics on the natural key. Each row's rtid is validated as 24-char hex; a violation surfaces a per-field error rather than a generic message. Archive data export/import concept (AB#4230) §4.1 / §7 / §10.

Task ImportRowsAsync(OctoObjectId archiveRtId, IAsyncEnumerable<IReadOnlyDictionary<string, object>> rows, ArchiveImportMode mode, CancellationToken ct)

Parameters

archiveRtId OctoObjectId

rows IAsyncEnumerable<IReadOnlyDictionary<String, Object>>

mode ArchiveImportMode

ct CancellationToken

Returns

Task

AggregateBucketAsync(ArchiveSnapshot, RollupArchiveSnapshot, DateTime, DateTime, CancellationToken)

Aggregates one bucket from into : reads source rows with timestamp ∈ [bucketStart, bucketEnd), groups by rtId, applies the CkRollupAggregationSpec aggregations, and upserts one row per entity into the rollup archive's table with timestamp = bucketEnd. Rollup-archives concept §5.

Task<int> AggregateBucketAsync(ArchiveSnapshot sourceArchive, RollupArchiveSnapshot rollup, DateTime bucketStart, DateTime bucketEnd, CancellationToken cancellationToken)

Parameters

sourceArchive ArchiveSnapshot

rollup RollupArchiveSnapshot

bucketStart DateTime

bucketEnd DateTime

cancellationToken CancellationToken

Returns

Task<Int32>

Remarks:

Idempotent on the natural key (timestamp, rtId): when the same bucket is re-aggregated (e.g. after a watermark rewind, or a crash before IRollupArchiveRuntimeStore.AdvanceWatermarkAsync(OctoObjectId, DateTime, Boolean) committed), the implementation must collapse duplicates via the data store's upsert primitive (CrateDB: ON CONFLICT (timestamp, rtId) DO UPDATE) so the orchestrator can always retry safely. Returns the number of upserted target rows.

ClearRecomputeGenerationsAsync(OctoObjectId, DateTime, CancellationToken)

Clears the per-window recompute generation pointers for a rollup archive at and after , so a subsequent forward re-aggregation (which writes generation 0) becomes visible again. Called when a rollup watermark is rewound over a range that was previously recomputed (AB#4184, Phase 6): the rewind re-aggregates forward at generation 0, but the active-generation pointer would otherwise keep readers on the stale recomputed generation. Implementations remove the generation-map entries whose range reaches past and the superseded (generation > 0) rows in that range. Idempotent — a no-op when there is no recompute state (no genmap / non-rollup).

Task ClearRecomputeGenerationsAsync(OctoObjectId rollupRtId, DateTime fromBucketEnd, CancellationToken cancellationToken)

Parameters

rollupRtId OctoObjectId

fromBucketEnd DateTime

cancellationToken CancellationToken

Returns

Task

GetArchiveMinTimestampAsync(OctoObjectId, CancellationToken)

Resolves the earliest stored timestamp in the archive's backing table — MIN(window_start) for windowed (rollup / time-range) archives, MIN(timestamp) for raw archives (AB#4269). Used by rollup backfill to recompute a rollup over its source archive's entire history without the operator supplying a start timestamp. Returns null when the archive has no backing table yet (e.g. Created) or the table is empty.

Task<Nullable<DateTime>> GetArchiveMinTimestampAsync(OctoObjectId archiveRtId, CancellationToken cancellationToken)

Parameters

archiveRtId OctoObjectId

cancellationToken CancellationToken

Returns

Task<Nullable<DateTime>>

GetArchiveStatsAsync(IReadOnlyList<OctoObjectId>, CancellationToken)

Returns per-archive storage stats (row count, on-disk size, health) for each entry. Bulk call so the studio's archives list can render stats columns without an N+1 round-trip per row. Archives whose backing table doesn't exist yet (not activated, or post-delete) appear in the result with ArchiveStorageStats.TableExists false and zero counters — the caller is not expected to filter the input list beforehand.

Task<IReadOnlyDictionary<OctoObjectId, ArchiveStorageStats>> GetArchiveStatsAsync(IReadOnlyList<OctoObjectId> archiveRtIds, CancellationToken cancellationToken)

Parameters

archiveRtIds IReadOnlyList<OctoObjectId>

cancellationToken CancellationToken

Returns

Task<IReadOnlyDictionary<OctoObjectId, ArchiveStorageStats>>

Remarks:

Implementations may issue a single underlying query against their introspection surface (e.g. CrateDB sys.shards + sys.health) and return one entry per requested rtId. Order of returned entries is implementation-defined; callers must look up by rtId.