DrivineDriftReportStore

open class DrivineDriftReportStore(persistenceManager: <Error class: unknown class>)

Drivine / Neo4j implementation of DriftReportStore: keeps every drift check as a (:MetamodelDriftReport) node.

The write MERGEs on the natural key (schemaName, versionHash, capturedAt, contextKey), so a retry updates the same node in place. That is race-free only under a uniqueness constraint on the same four properties; see MetamodelSchema, and see DriftReportRowMapper.GLOBAL_CONTEXT_KEY for why the fourth property is contextKey.

Every statement is parameterized; nothing caller-derived is interpolated into Cypher.

Scope is applied in the query, ahead of the limit

Each of the three reads has its own statement, with its scope in the WHERE clause and the LIMIT applied after it. Reading one limited page and filtering it in Kotlin would apply the limit before the scope, so a schema whose recent history is mostly context-scoped would report zero global drift while the store held plenty. Hence three statements, and no filter. The contract's test pins this.

Ordering: capture instant, with a per-schema counter breaking ties

The order is DriftReport.capturedAt descending, the instant the graph was looked at, which is what the contract promises and what a since window bounds. Write order can't stand in for it: a check of last week's snapshot saved today is still last week's observation.

The instant alone is not a total order. Two reports of one schema, say a global sweep and a per-context one, can share a capture instant, and a plain ORDER BY then leaves their relative order to the database. Under a LIMIT the page boundary lands arbitrarily, so the same read can return different rows each time and a caller walking the history can miss one. So each report also takes the next value off a per-schema (:MetamodelDriftReportCounter) node, only when its node is first created, and that sequence breaks ties. DrivineMetamodelVersionStore uses the same mechanism on its own counter node. Stamps and reports have very different volumes — a stamp per schema change, a report per scheduled check — so a shared counter would put every drift check in a run into a write conflict with the version stamp preceding it, and would leave gaps in the version store's sequence.

A re-save of an existing report leaves the counter and the sequence alone, so the write stays idempotent and a corrected observation keeps its original place.

Parameters

persistenceManager

Drivine's handle on the neo datasource.

Constructors

Link copied to clipboard
constructor(persistenceManager: <Error class: unknown class>)

Functions

Link copied to clipboard
open fun driftReports(schemaName: String, limit: Int, since: Instant?): List<<Error class: unknown class>>
Link copied to clipboard
open fun driftReportsInContext(schemaName: String, contextId: <Error class: unknown class>, limit: Int, since: Instant?): List<<Error class: unknown class>>
Link copied to clipboard
open fun globalDriftReports(schemaName: String, limit: Int, since: Instant?): List<<Error class: unknown class>>
Link copied to clipboard
open fun saveDriftReport(report: <Error class: unknown class>)