MoonFixture

    Reproducible relational test data construction for MoonBit.

    Download zip
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    2 hours ago
    Downloads
    2

    Dependencies

    #MoonFixture

    CI

    MoonBit 原生的可复现关联测试数据构造库。 用一个显式模型定义实体、主外键、唯一字段和派生关系,为数据库集成测试、接口回归与前端演示生成同一套可重放数据。

    Fixture 是测试运行前准备好的数据和环境;MoonFixture 聚焦其中的结构化数据。项目提供可复用库和原生 CLI,不是姓名词库,也不负责执行测试框架或求解任意业务约束。

    #已实现能力

    • 确定性 UInt32 随机流;按实体、字段、行及尝试次数隔离;完整模型、种子、UTC 参考时间和算法版本重放。
    • 常量、序列、整数区间、布尔概率、枚举、加权枚举、Unicode 字符串和相对日期。
    • 主键、唯一字段、外键、字段依赖、父表查值、整数加法/乘法及文本组合;稳定拓扑排序与循环诊断。
    • 有限唯一域无放回抽样;其他唯一约束使用明确的尝试预算;区分域耗尽与预算耗尽。
    • 命名场景覆盖;在副本上定向修改、删除或复制记录,并报告实际违反的约束。
    • 独立数据校验、业务期望断言、按主键比较、字段分布统计、关联查询及聚合结果构造。
    • JSON、NDJSON、CSV 和参数化 SQLite 批次;支持接收端停止并恢复的分批导出。
    • 输入大小/嵌套深度、实体数、字段数、总行数、单元格数、文本量和尝试次数限制。

    #工具链与验证环境

    本项目开发验证使用 2026-09-21 从 MoonBit 官方发布通道下载的工具链。以下是实际二进制版本,不以“最新稳定版”代替版本信息:

    组件版本
    moon0.1.20260920 (914d7da 2026-09-20)
    mooncv0.10.14+7d59c7ec9 (2026-09-18)
    moonrun0.1.20260920 (914d7da 2026-09-20)
    CLI 依赖moonbitlang/async 0.22.1moonbitlang/x 0.5.5
    本地验证Windows / MSVC;Node.js v26.5.1

    库支持 wasmwasm-gcjsnative;CLI 仅支持 native。核心库只导入 MoonBit core;上述第三方模块供 CLI 使用。CI 在 Linux/Windows 上安装官方发布通道工具链并打印完整版本,用于发现后续兼容性变化;它不等于锁定本次验证版本。

    #作为库使用

    moon add tlhuecdkoyg/MoonFixture@0.1.0

    在调用包的 moon.pkg 中加入:

    import {
    "tlhuecdkoyg/MoonFixture" @fixture,
    }

    以下完整测试可以放入调用包的测试文件:

    test "relational fixture" {
    let model : @fixture.Model = {
    name: "shop",
    entities: [
    {
    name: "users", count: 5,
    fields: [@fixture.Field::new("id", Sequence(1, 1), primary=true)],
    },
    {
    name: "orders", count: 20,
    fields: [
    @fixture.Field::new("id", Sequence(100, 1), primary=true),
    @fixture.Field::new("user_id", Reference("users", "id")),
    @fixture.Field::new("quantity", IntegerRange(1, 5)),
    @fixture.Field::new("unit_price", Constant(Integer(200))),
    @fixture.Field::new("total", Multiply("quantity", "unit_price")),
    ],
    },
    ],
    }
    let context = @fixture.Context::new(2026U)
    let plan = @fixture.compile(model, context~).unwrap()
    let data = plan.generate().unwrap()
    assert_true(@fixture.validate_dataset(model, data).is_valid())
    assert_eq(@fixture.replay(plan.replay_json()).unwrap(), data)
    }

    可复用 API 的完整签名由 moon info 生成,见 pkg.generated.mbti。模型文件格式及各生成器字段见 模型说明

    #命令行

    在仓库目录执行。moon run-- 后为程序参数:

    moon run cmd/main --target native -- --help moon run cmd/main --target native -- generate examples/shop.json --seed 2026 --output shop-data.json moon run cmd/main --target native -- validate shop-data.json --model examples/shop.json moon run cmd/main --target native -- manifest examples/shop.json --seed 2026 --output replay.json moon run cmd/main --target native -- replay replay.json --output replayed-data.json moon run cmd/main --target native -- generate examples/shop.json --format csv --table products moon run cmd/main --target native -- generate examples/shop.json --format sqlite --output sqlite-batches.json

    plan 只编译模型,不生成数据。- 可表示标准输入/输出。文件默认以新建方式写入;--force 允许覆盖已有输出,但仍拒绝覆盖输入和校验模型。退出码:0 成功,1 模型/数据失败,2 参数或 I/O 失败。CLI 默认每个输入文件最多 16 MiB;--max-input 可调整。

    SQLite 输出是包含 DDL、? 占位符语句和参数数组的 JSON 包。调用方应在事务外启用 PRAGMA foreign_keys = ON,然后在一个事务中建表并绑定参数插入;出现错误时回滚。库本身不包含 SQLite 驱动。

    #可实际运行的使用场景

    1. 数据库集成测试examples/shop.json 生成用户、商品、订单、明细。集成脚本使用 Python 标准库 SQLite 驱动实际入库,开启外键,执行联表金额汇总,与生成明细比较,并确认非法外键被数据库拒绝。
    2. 接口回归测试:相同订单数据装入一个真实本地 HTTP 示例服务。脚本通过 socket 请求列表、详情、新增订单及非法用户引用,校验响应。此服务是可运行的示范消费者,不宣称已有第三方业务系统接入。
    3. 前端演示与空状态测试:生成 JSON 后,直接打开 examples/browser/index.html 并选择文件,查看实体切换、分页和 Unicode 文本。把未被引用的子表 count 改成 0,即可生成空列表。页面通过 textContent 展示值,数据不上传到服务器。
    4. 第二业务领域复用examples/helpdesk.json 构造团队、坐席和工单,包含坐席归属查值、优先级、相对日期和可空备注;无需修改引擎。集成脚本独立校验工单团队与坐席团队一致。

    运行数据库和 HTTP 集成:

    moon build --target native --deny-warn python scripts/integration.py

    Python 仅作为独立验证消费者;所有模型解析、约束规划、随机构造及数据导出均由 MoonBit 实现。浏览器示例供手动验证,未将其计作自动浏览器测试。

    #测试与代码统计

    python scripts/verify.py python scripts/count_lines.py --minimum 4000

    验证脚本运行四后端检查与测试、格式检查、API 生成、生产代码统计、本机 CLI 构建和真实 SQLite/HTTP 集成。测试覆盖固定随机参考向量、64 组种子关联模型、唯一域耗尽、日期边界、派生溢出、循环依赖、重放、错误输入、批次恢复与副本隔离。

    统计脚本只计算根库、cli/cmd/ 下手写 .mbt 文件的有效非空代码行;排除注释、帮助文本块、测试、示例、依赖、生成接口和构建产物。统计值可由脚本重算,详细验证记录见 VALIDATION.md

    #可复现性及边界

    • 可复现输入包括模型、种子、算法版本、参考时间及资源限制。日期不读取系统时钟。模型指纹是非密码学摘要,仅辅助定位;完整 manifest 才是重放依据。
    • 添加无关字段不会改变已有独立随机流;修改父表规模、唯一约束或依赖可能改变关联结果。升级算法或生成语义可能改变结果,应随包版本固定重放环境。
    • 值域为 Null / Bool / Int32 / String。金额建议用最小货币单位整数;不提供浮点金额或任意精度数值。整数随机区间最多包含 2147483647 个值。
    • 日期采用公历 0001-01-019999-12-31,偏移单位为天。参考时间格式固定为 YYYY-MM-DDTHH:MM:SSZ,不支持时区偏移、分数秒和闰秒。
    • 只支持单字段主键和有向无环依赖;多对多可用中间表表达。没有任意约束求解器、循环关系生成器或完整 JSON Schema 支持。
    • 非空唯一整数、布尔、普通枚举、有限字符串、日期和引用域采用无放回抽样。普通枚举的重复值在唯一模式下去重;唯一布尔抽样也不再保持原始概率。加权枚举保持权重抽样,并受唯一重试预算约束。
    • null_per_mille 是每行抽样概率,不保证精确比例。唯一字段允许多个 null;常量/复制/查值也可产生 null。主键始终禁止 null。
    • 数据集整体驻留内存;主键索引、唯一集合和比较结果亦占内存。批次 API 只减少导出阶段的额外缓冲,未承诺流式生成或常量内存。
    • 数据集 JSON 的 seed 使用十进制字符串;导入后字段按名称排序,校验按名称匹配。CSV 中 null、缺失字段与空字符串均导出为空单元格,因此不可无损恢复类型。JSON 重复键沿用 core JSON 解析器的覆盖语义,请勿依赖重复键表达模型。
    • SQLite 适配不声明列类型亲和性,以区分字符串 "1" 与整数 1;拒绝同列混合布尔与整数,避免 SQLite 的类型折叠。对数据库驱动的测试在 Python SQLite 消费者上进行,并未声称已实现 MoonBit SQLite 驱动接入。

    #原创性与许可证

    MoonFixture 为原创 MoonBit 实现,采用 Apache-2.0。确定性随机算法、拓扑排序和无放回抽样属于通用算法;不是 Faker 或其他项目的源码移植。相邻项目及定位差异见 设计说明,依赖和复用说明见 THIRD_PARTY.md

    ConfigError

    pub suberror ConfigError {
    InvalidConfig(String, String)
    } derive(
    Debug
    )

    BatchProgress

    pub(all) struct BatchProgress {
    rows_accepted : Int
    batches_accepted : Int
    completed : Bool
    }

    Cell

    pub(all) struct Cell {
    name : String
    value : Value
    } derive(Eq,
    Debug
    )

    Cell::equal

    fn Cell::equal(Cell, Cell) -> Bool

    Cell::not_equal

    fn Cell::not_equal(x : Cell, y : Cell) -> Bool

    Cell::to_repr

    Comparison

    pub(all) struct Comparison {
    differences : Array[Difference]
    truncated : Bool
    }

    Comparison::equal

    fn Comparison::equal(self : Comparison) -> Bool

    Comparison::to_json

    fn Comparison::to_json(self : Comparison) -> Json

    Context

    pub(all) struct Context {
    seed : UInt
    reference_time : String
    limits : Limits
    } derive(Eq,
    Debug
    )

    Context::equal

    fn Context::equal(Context, Context) -> Bool

    Context::new

    fn Context::new(seed : UInt, reference_time? : String, limits? : Limits) -> Context

    Context::not_equal

    fn Context::not_equal(x : Context, y : Context) -> Bool

    Context::to_repr

    Dataset

    pub(all) struct Dataset {
    model : String
    seed : UInt
    algorithm : String
    reference_time : String
    tables : Array[Table]
    } derive(Eq,
    Debug
    )

    Dataset::equal

    fn Dataset::equal(Dataset, Dataset) -> Bool

    Dataset::mutate

    fn Dataset::mutate(self : Dataset, model : Model, operations : Array[Mutation]) -> Result[MutationResult, Issue]

    Mutations are ordered. Row indices refer to the state after preceding edits. The original remains unchanged even when a later operation fails.

    Dataset::not_equal

    fn Dataset::not_equal(x : Dataset, y : Dataset) -> Bool

    Dataset::profile_json

    fn Dataset::profile_json(self : Dataset) -> Json

    Dataset::snapshot

    fn Dataset::snapshot(self : Dataset) -> Dataset

    Dataset::table

    fn Dataset::table(self : Dataset, name : String) -> Table?

    Dataset::to_json_text

    fn Dataset::to_json_text(self : Dataset) -> String

    Dataset::to_repr

    Date

    pub(all) struct Date {
    year : Int
    month : Int
    day : Int
    } derive(Eq,
    Debug
    )

    Date::add_days

    fn Date::add_days(self : Date, delta : Int) -> Result[Date, Issue]

    Date::equal

    fn Date::equal(Date, Date) -> Bool

    Date::new

    fn Date::new(year : Int, month : Int, day : Int) -> Result[Date, Issue]

    Date::not_equal

    fn Date::not_equal(x : Date, y : Date) -> Bool

    Date::ordinal

    fn Date::ordinal(self : Date) -> Result[Int, Issue]

    Date::to_repr

    Date::to_string

    fn Date::to_string(self : Date) -> String

    Difference

    pub(all) struct Difference {
    kind : String
    table : String
    row_key : String
    field : String
    before : Value?
    after : Value?
    }

    Difference::to_json

    fn Difference::to_json(self : Difference) -> Json

    Entity

    pub(all) struct Entity {
    name : String
    count : Int
    fields : Array[Field]
    } derive(Eq,
    Debug
    )

    Entity::equal

    fn Entity::equal(Entity, Entity) -> Bool

    Entity::field

    fn Entity::field(self : Entity, name : String) -> Field?

    Entity::not_equal

    fn Entity::not_equal(x : Entity, y : Entity) -> Bool

    Entity::to_repr

    EntityPlan

    pub(all) struct EntityPlan {
    name : String
    rows : Int
    cells : Int64
    fields : Array[FieldPlan]
    }

    EntityPlan::to_json

    fn EntityPlan::to_json(self : EntityPlan) -> Json

    Expectation

    pub(all) enum Expectation {
    RowCount(String, Int, Int)
    NonNull(String, String)
    IntegerBounds(String, String, Int, Int)
    TextLength(String, String, Int, Int)
    LessEqual(String, String, String)
    SumEquals(String, String, Int64)
    RelatedCount(String, String, String, String, Int, Int)
    }

    Assertions over finished fixtures, independent of the generation model.

    Field

    pub(all) struct Field {
    name : String
    generator : Generator
    unique : Bool
    primary : Bool
    null_per_mille : Int
    } derive(Eq,
    Debug
    )

    Field::equal

    fn Field::equal(Field, Field) -> Bool

    Field::new

    fn Field::new(name : String, generator : Generator, unique? : Bool, primary? : Bool, null_per_mille? : Int) -> Field

    Field::not_equal

    fn Field::not_equal(x : Field, y : Field) -> Bool

    Field::to_json

    fn Field::to_json(self : Field) -> Json

    Field::to_repr

    FieldPlan

    pub(all) struct FieldPlan {
    name : String
    evaluation_index : Int
    unique : Bool
    primary : Bool
    finite_capacity : String?
    local_dependencies : Array[String]
    parent_entity : String?
    }

    FieldPlan::to_json

    fn FieldPlan::to_json(self : FieldPlan) -> Json

    FieldProfile

    pub(all) struct FieldProfile {
    name : String
    present : Int
    missing : Int
    nulls : Int
    booleans : Int
    true_values : Int
    integers : Int
    texts : Int
    distinct : Int
    min_integer : Int?
    max_integer : Int?
    sum_integer : Int64
    min_text_length : Int?
    max_text_length : Int?
    }

    FieldProfile::to_json

    fn FieldProfile::to_json(self : FieldProfile) -> Json

    Generator

    pub(all) enum Generator {
    Constant(Value)
    Sequence(Int, Int)
    IntegerRange(Int, Int)
    BooleanChance(Int)
    Choice(Array[Value])
    WeightedChoice(Array[(Value, Int)])
    Pattern(String, Int)
    DateOffset(Int, Int)
    Reference(String, String)
    Copy(String)
    Add(String, String)
    Multiply(String, String)
    Concat(Array[String], String)
    Lookup(String, String, String, String)
    } derive(Eq,
    Debug
    )

    Generator::entity_dependency

    fn Generator::entity_dependency(self : Generator) -> String?

    Generator::equal

    fn Generator::equal(Generator, Generator) -> Bool

    Generator::field_dependencies

    fn Generator::field_dependencies(self : Generator) -> Array[String]

    Generator::not_equal

    fn Generator::not_equal(x : Generator, y : Generator) -> Bool

    Generator::snapshot

    fn Generator::snapshot(self : Generator) -> Generator

    Deep-copy mutable arrays so compiled plans cannot be changed by their caller.

    Generator::to_json

    fn Generator::to_json(self : Generator) -> Json

    GroupSummary

    pub(all) struct GroupSummary {
    key : Value
    count : Int
    integer_count : Int
    null_count : Int
    sum : Int64
    min : Int?
    max : Int?
    }

    GroupSummary::to_json

    fn GroupSummary::to_json(self : GroupSummary) -> Json

    Issue

    pub(all) struct Issue {
    code : String
    path : String
    message : String
    } derive(Eq,
    Debug
    )

    Issue::equal

    fn Issue::equal(Issue, Issue) -> Bool

    Issue::not_equal

    fn Issue::not_equal(x : Issue, y : Issue) -> Bool

    Issue::to_json

    fn Issue::to_json(self : Issue) -> Json

    Issue::to_repr

    JoinMode

    pub(all) enum JoinMode {
    Inner
    Left
    }

    Limits

    pub(all) struct Limits {
    max_entities : Int
    max_fields : Int
    max_rows : Int
    max_cells : Int
    max_attempts : Int
    max_text_units : Int
    } derive(Eq,
    Debug
    )

    Limits::default

    fn Limits::default() -> Limits

    Limits::equal

    fn Limits::equal(Limits, Limits) -> Bool

    Limits::not_equal

    fn Limits::not_equal(x : Limits, y : Limits) -> Bool

    Limits::to_json

    fn Limits::to_json(self : Limits) -> Json

    Limits::to_repr

    Model

    pub(all) struct Model {
    name : String
    entities : Array[Entity]
    } derive(Eq,
    Debug
    )

    Model::entity

    fn Model::entity(self : Model, name : String) -> Entity?

    Model::equal

    fn Model::equal(Model, Model) -> Bool

    Model::fingerprint

    fn Model::fingerprint(self : Model) -> String

    Non-cryptographic identity for regression reports, not an integrity signature.

    Model::not_equal

    fn Model::not_equal(x : Model, y : Model) -> Bool

    Model::snapshot

    fn Model::snapshot(self : Model) -> Model

    Model::to_json

    fn Model::to_json(self : Model) -> Json

    Model::to_json_text

    fn Model::to_json_text(self : Model) -> String

    Model::to_repr

    Model::with_scenario

    fn Model::with_scenario(self : Model, scenario : Scenario) -> Result[Model, Array[Issue]]

    Apply explicit overrides to a copy. Dependencies are revalidated afterwards.

    Mutation

    pub(all) enum Mutation {
    SetCell(String, Int, String, Value)
    RemoveCell(String, Int, String)
    DeleteRow(String, Int)
    DuplicateRow(String, Int)
    } derive(Eq,
    Debug
    )

    Mutation::equal

    fn Mutation::equal(Mutation, Mutation) -> Bool

    Mutation::not_equal

    fn Mutation::not_equal(x : Mutation, y : Mutation) -> Bool

    Mutation::to_repr

    MutationResult

    pub(all) struct MutationResult {
    dataset : Dataset
    operations : Array[Mutation]
    report : ValidationReport
    }

    Override

    pub(all) enum Override {
    Count(String, Int)
    Generator(String, String, Generator)
    Nullable(String, String, Int)
    } derive(Eq,
    Debug
    )

    Override::equal

    fn Override::equal(Override, Override) -> Bool

    Override::not_equal

    fn Override::not_equal(x : Override, y : Override) -> Bool

    Override::to_repr

    Plan

    pub struct Plan {
    model : Model
    context : Context
    entity_order : Array[Int]
    field_orders : Array[Array[Int]]
    } derive(
    Debug
    )

    A plan owns a deep snapshot of its validated model.

    Plan::context

    fn Plan::context(self : Plan) -> Context

    Plan::entity_names

    fn Plan::entity_names(self : Plan) -> Array[String]

    Plan::generate

    fn Plan::generate(self : Plan) -> Result[Dataset, Issue]

    Construct a dataset. On failure no partial dataset is returned.

    Plan::model

    fn Plan::model(self : Plan) -> Model

    Plan::replay_json

    fn Plan::replay_json(self : Plan) -> String

    Full input manifest; replay also checks algorithm identity and resource limits.

    Plan::report

    fn Plan::report(self : Plan) -> PlanReport

    Estimates count stored values, not heap bytes; variable strings and indexes prevent translating cell counts into a portable exact memory budget.

    Plan::to_repr

    PlanReport

    pub(all) struct PlanReport {
    model : String
    fingerprint : String
    rows : Int64
    cells : Int64
    entities : Array[EntityPlan]
    notes : Array[String]
    }

    PlanReport::to_json

    fn PlanReport::to_json(self : PlanReport) -> Json

    Random

    pub struct Random {
    state : UInt
    } derive(
    Debug
    )

    Versioned xorshift32 stream; not suitable for secrets or cryptography.

    Random::below

    fn Random::below(self : Random, bound : Int) -> Int?

    Uniform bounded selection using rejection rather than biased modulo alone.

    Random::new

    fn Random::new(seed : UInt) -> Random

    Random::next

    fn Random::next(self : Random) -> UInt

    Random::to_repr

    Row

    pub(all) struct Row {
    cells : Array[Cell]
    } derive(Eq,
    Debug
    )

    Row::equal

    fn Row::equal(Row, Row) -> Bool

    Row::get

    fn Row::get(self : Row, name : String) -> Value?

    Row::not_equal

    fn Row::not_equal(x : Row, y : Row) -> Bool

    Row::to_json

    fn Row::to_json(self : Row) -> Json

    Row::to_json_text

    fn Row::to_json_text(self : Row) -> String

    Stable JSON output uses declaration order instead of map iteration order.

    Row::to_repr

    Scenario

    pub(all) struct Scenario {
    name : String
    overrides : Array[Override]
    }

    SqlBatch

    pub(all) struct SqlBatch {
    table : String
    sql : String
    parameters : Array[Array[Value]]
    }

    SqliteBundle

    pub(all) struct SqliteBundle {
    schema : Array[String]
    batches : Array[SqlBatch]
    }

    SqliteBundle::to_json

    fn SqliteBundle::to_json(self : SqliteBundle) -> Json

    SqliteBundle::to_json_text

    fn SqliteBundle::to_json_text(self : SqliteBundle) -> String

    Table

    pub(all) struct Table {
    name : String
    rows : Array[Row]
    } derive(Eq,
    Debug
    )

    Table::batches

    fn Table::batches(self : Table, size : Int) -> Result[Array[Array[Row]], Issue]

    Table::equal

    fn Table::equal(Table, Table) -> Bool

    Table::group_sum

    fn Table::group_sum(self : Table, key_field : String, amount_field : String) -> Result[Array[GroupSummary], Issue]

    Group order follows first occurrence, not map traversal. Null amounts are excluded from numeric aggregates; text/boolean amounts are errors.

    Table::join_parent

    fn Table::join_parent(self : Table, parent : Table, local_field : String, parent_key : String, columns : Array[String], prefix? : String, mode? : JoinMode) -> Result[Table, Issue]

    Materialize an assertion oracle using a unique parent key. A left join uses explicit Null values for the requested parent columns when no match exists.

    Table::not_equal

    fn Table::not_equal(x : Table, y : Table) -> Bool

    Table::page

    fn Table::page(self : Table, offset : Int, limit : Int) -> Result[Table, Issue]

    Return an independent row/field snapshot suitable for pagination assertions.

    Table::profile

    fn Table::profile(self : Table) -> TableProfile

    Distinct counts include null; missing cells are counted separately.

    Table::project

    fn Table::project(self : Table, columns : Array[String]) -> Result[Table, Issue]

    Table::to_csv

    fn Table::to_csv(self : Table, columns : Array[String]) -> String

    CSV is an interchange representation; null and empty text both become empty.

    Table::to_json_text

    fn Table::to_json_text(self : Table) -> String

    Table::to_ndjson

    fn Table::to_ndjson(self : Table) -> String

    Table::to_repr

    Table::visit_batches

    fn Table::visit_batches(self : Table, size : Int, consume : (Array[Row]) -> Bool, offset? : Int) -> Result[BatchProgress, Issue]

    Visit copied batches without constructing an array of all batches. Returning false declines the current batch and stops. Already accepted batches are not rolled back. This bounds export buffering, not the retained dataset itself.

    Table::visit_csv

    fn Table::visit_csv(self : Table, columns : Array[String], size : Int, consume : (String) -> Bool, offset? : Int) -> Result[BatchProgress, Issue]

    A CSV batch contains a header only at offset zero. Later chunks can be concatenated verbatim. Use the same projection and size when resuming.

    Table::visit_ndjson

    fn Table::visit_ndjson(self : Table, size : Int, consume : (String) -> Bool, offset? : Int) -> Result[BatchProgress, Issue]

    Encode one NDJSON chunk per callback, supporting backpressure and resumption by accepted row count. Callers are responsible for durable write semantics.

    Table::where_equal

    fn Table::where_equal(self : Table, field : String, value : Value) -> Table

    Equality is type-aware: integer 1 does not match text "1" or boolean true.

    TableProfile

    pub(all) struct TableProfile {
    name : String
    rows : Int
    fields : Array[FieldProfile]
    }

    TableProfile::to_json

    fn TableProfile::to_json(self : TableProfile) -> Json

    ValidationReport

    pub(all) struct ValidationReport {
    issues : Array[Issue]
    checked_rows : Int
    truncated : Bool
    }

    ValidationReport::is_valid

    fn ValidationReport::is_valid(self : ValidationReport) -> Bool

    ValidationReport::to_json

    fn ValidationReport::to_json(self : ValidationReport) -> Json

    Value

    pub(all) enum Value {
    Null
    Boolean(Bool)
    Integer(Int)
    Text(String)
    } derive(Eq,
    Debug
    )

    Supported scalar values. Integers are restricted to portable signed Int32.

    Value::display

    fn Value::display(self : Value) -> String

    Value::equal

    fn Value::equal(Value, Value) -> Bool

    Value::key

    fn Value::key(self : Value) -> String

    Type-prefixed key: text "1" differs from integer 1 and null from empty text.

    Value::not_equal

    fn Value::not_equal(x : Value, y : Value) -> Bool

    Value::to_json

    fn Value::to_json(self : Value) -> Json

    Value::to_repr

    algorithm_version

    fn algorithm_version() -> String

    check_expectations

    fn check_expectations(data : Dataset, expectations : Array[Expectation], max_issues? : Int) -> ValidationReport

    checked_rows counts row visits across assertions. Multiple rules may examine the same row. A failure cap truncates diagnostics, not assertion evaluation.

    compare_datasets

    fn compare_datasets(model : Model, before : Dataset, after : Dataset, max_differences? : Int) -> Result[Comparison, Issue]

    Compare fixture content by declared primary keys, otherwise by row position. Metadata is intentionally separate from content, allowing cross-seed analysis.

    compile

    fn compile(model : Model, context? : Context) -> Result[Plan, Array[Issue]]

    Validate names, cardinalities, references and DAGs before generating rows.

    generate

    fn generate(model : Model, context? : Context) -> Result[Dataset, Array[Issue]]

    parse_dataset

    fn parse_dataset(text : String, max_units? : Int, limits? : Limits) -> Result[Dataset, Issue]

    Parsing does not imply validity against a model; call validate_dataset next. Imported row fields are sorted; row/table array order is retained.

    parse_date

    fn parse_date(text : String) -> Result[Date, Issue]

    parse_model

    fn parse_model(text : String, max_units? : Int) -> Result[Model, Issue]

    replay

    fn replay(text : String, max_units? : Int) -> Result[Dataset, Array[Issue]]

    sqlite_bundle

    fn sqlite_bundle(model : Model, data : Dataset, batch_size? : Int) -> Result[SqliteBundle, Array[Issue]]

    Build driver-neutral SQLite statements. Bind parameters; never interpolate them. The caller enables foreign_keys before starting a transaction and rolls back all statements if any insertion fails. This function performs no database I/O.

    stream

    fn stream(seed : UInt, entity : String, field : String, row : Int, attempt? : Int) -> Random

    Stable stream identity is (seed, entity, field, row, attempt).

    validate_dataset

    fn validate_dataset(model : Model, data : Dataset, max_issues? : Int, check_counts? : Bool) -> ValidationReport

    Validate external or deliberately mutated data independently of generation. No random numbers are consumed; probabilities are not exact quotas.