Documentation
¶
Index ¶
- func CheckRequires(ctx context.Context, db *sql.DB, req *domain.Requires, ...) error
- type RequiresError
- type ResultWriter
- type RuleLoader
- type SchemaMapper
- type ValidateRecordUseCase
- func (uc *ValidateRecordUseCase) Execute(ctx context.Context, tableName, recordID string) ([]*domain.Result, error)
- func (uc *ValidateRecordUseCase) Neighborhoods(ctx context.Context, tableName, recordID string) ([]validator.NeighborRef, error)
- func (uc *ValidateRecordUseCase) NeighborhoodsFromRecord(ctx context.Context, tableName, recordID string, record map[string]interface{}) ([]validator.NeighborRef, error)
- func (uc *ValidateRecordUseCase) SetRelationResolver(r domain.ConditionResolver)
- type ValidateTableUseCase
- type ValidationReport
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func CheckRequires ¶
func CheckRequires( ctx context.Context, db *sql.DB, req *domain.Requires, availableRelations map[string]bool, ) error
CheckRequires verifies that the live database satisfies the bundle's Requires block. Returns nil when everything resolves (or when the bundle has no Requires). Returns a *RequiresError enumerating every unmet requirement otherwise.
availableRelations is the set of relation names known to the consumer's relation catalog (the union of all loaded bundles' Relations blocks by the time this check runs). Pass nil / empty map when the bundle doesn't declare relation requirements.
Type checks are loose: SQLite storage class comparison, so nullability / defaults / check constraints don't false-fail. Extra tables, columns, or relations in the live database or relation catalog are fine.
Types ¶
type RequiresError ¶
type RequiresError struct {
MissingTables []string
MissingColumns []string // "table.column" strings
TypeMismatches []string // "table.column: expected <type>, got <type>"
MissingRelations []string // relation names the bundle needs but the loaded catalog doesn't have
}
RequiresError enumerates every unmet requirement discovered by CheckRequires. Consumer applications surface these to the caller as a load-time failure so the bundle isn't applied against an incompatible schema.
func (*RequiresError) Error ¶
func (e *RequiresError) Error() string
Error implements the error interface. Concatenates the missing items into a readable multi-line message.
func (*RequiresError) HasIssues ¶
func (e *RequiresError) HasIssues() bool
HasIssues reports whether any requirement is unmet.
type ResultWriter ¶
type ResultWriter interface {
WriteResults(ctx context.Context, results []*domain.Result) error
WriteResult(ctx context.Context, result *domain.Result) error
}
ResultWriter writes validation results to a consumer-supplied sink (a database table, a JSON file, a stream, …).
type RuleLoader ¶
type RuleLoader interface {
LoadRules(ctx context.Context) ([]*domain.Rule, error)
LoadRuleByID(ctx context.Context, ruleID string) (*domain.Rule, error)
LoadRulesForTable(ctx context.Context, tableName string) ([]*domain.Rule, error)
}
RuleLoader loads validation rules from a consumer-supplied source (bundled JSON, a database table, an embedded byte slice, …).
type SchemaMapper ¶
type SchemaMapper interface {
// GetTableName resolves logical table name to physical table name
GetTableName(logicalName string) string
// GetFieldName resolves logical field name to physical field name
GetFieldName(tableName, logicalName string) string
// GetPrimaryKeyField returns the primary-key column for the given
// logical table.
GetPrimaryKeyField(tableName string) string
// LoadRecord loads a record by table name and ID
LoadRecord(ctx context.Context, db *sql.DB, tableName, id string) (map[string]interface{}, error)
// LoadRelatedRecords loads related records via foreign key
LoadRelatedRecords(ctx context.Context, db *sql.DB, tableName, foreignKey, id string) ([]map[string]interface{}, error)
// LoadAllRecords loads all records from a table
LoadAllRecords(ctx context.Context, db *sql.DB, tableName string) ([]map[string]interface{}, error)
}
SchemaMapper abstracts database schema differences between systems. Implementations are supplied by the consuming application.
type ValidateRecordUseCase ¶
type ValidateRecordUseCase struct {
// contains filtered or unexported fields
}
ValidateRecordUseCase validates a single record against all applicable rules.
func NewValidateRecordUseCase ¶
func NewValidateRecordUseCase(db *sql.DB, ruleLoader RuleLoader, schemaMapper SchemaMapper, validatorRegistry *validator.Registry) *ValidateRecordUseCase
NewValidateRecordUseCase creates a new validate record use case.
func (*ValidateRecordUseCase) Execute ¶
func (uc *ValidateRecordUseCase) Execute(ctx context.Context, tableName, recordID string) ([]*domain.Result, error)
Execute validates a single record and returns all validation results.
func (*ValidateRecordUseCase) Neighborhoods ¶
func (uc *ValidateRecordUseCase) Neighborhoods(ctx context.Context, tableName, recordID string) ([]validator.NeighborRef, error)
Neighborhoods returns the set of records whose validation results may have changed due to a mutation on (tableName, recordID). It walks the same rules Execute would run and, for each rule whose validator implements validator.NeighborhoodProvider, collects the neighboring records. Results are deduplicated (a record shows up once even if multiple rules point at it).
Consumers call this alongside Execute on the write path to propagate re-validation to related rows — aggregate rules like count uniqueness only see one side of the change when the record being validated is R; the "other side" needs to re-run to see that R now (or no longer) matches.
func (*ValidateRecordUseCase) NeighborhoodsFromRecord ¶
func (uc *ValidateRecordUseCase) NeighborhoodsFromRecord(ctx context.Context, tableName, recordID string, record map[string]interface{}) ([]validator.NeighborRef, error)
NeighborhoodsFromRecord is like Neighborhoods but uses the caller-supplied record snapshot rather than loading fresh. Lets write paths capture a record's pre-mutation state and, after the mutation, use that snapshot to find the "old-side" neighbors — records that used to match the record's aggregate predicates and now don't.
The record map must contain every field the rules reference. Missing keys are treated as nil (same semantic as an absent column). A nil record is passed straight through to the underlying providers, which typically means "no matches" for aggregate rules.
func (*ValidateRecordUseCase) SetRelationResolver ¶
func (uc *ValidateRecordUseCase) SetRelationResolver(r domain.ConditionResolver)
SetRelationResolver installs a resolver so rule conditions and validators that traverse named relations (from the bundle's Relations catalog) can evaluate. Call once at construction time; the resolver stays attached for the life of the use case.
type ValidateTableUseCase ¶
type ValidateTableUseCase struct {
// contains filtered or unexported fields
}
ValidateTableUseCase validates all records in a table.
func NewValidateTableUseCase ¶
func NewValidateTableUseCase(db *sql.DB, ruleLoader RuleLoader, schemaMapper SchemaMapper, validatorRegistry *validator.Registry) *ValidateTableUseCase
NewValidateTableUseCase creates a new validate table use case.
func (*ValidateTableUseCase) Execute ¶
func (uc *ValidateTableUseCase) Execute(ctx context.Context, tableName string) (*ValidationReport, error)
Execute validates all records in a table and returns a report.