Skip to content

feat: implement MVP insert mutation pipeline #31

Description

@dodok8

Objective

Implement the first end-to-end insert mutation pipeline for Gelite.

The issue should add support for parsing, resolving, planning, rendering, and executing a scoped MVP form of insert:

insert User {
  name := "Sheri",
  email := "sheri@example.com"
}

The first implementation should create one object row, generate an implicit id, write scalar and single-link values to SQLite, and return the generated object id through the runner-facing API.

Motivation or use case

Gelite currently supports schema application and select query execution, but test fixtures and user workflows still need raw SQL to create data. Adding insert is the next mutation milestone and will make the query language useful for creating object data through the same staged pipeline used by select.

This work should also establish the shared mutation assignment model that update can reuse later. insert and update both need field assignment parsing, writable-field validation, value type checking, link/scalar distinction, and SQLite value binding. Introducing those contracts during insert keeps the first mutation small while avoiding a throwaway design.

Expected outcome

Gelite supports top-level MVP insert statements with this shape:

insert <ObjectType> {
  <field> := <literal>,
  ...
}

Supported behavior:

  • The parser accepts a top-level insert statement.
  • The AST represents the insert target type and ordered assignment list.
  • The resolver validates the target object type and assignment fields.
  • Assignments may target declared scalar fields and declared single link fields.
  • Assignments may not target implicit id.
  • Required scalar fields and required single links must be provided unless a built-in default exists.
  • Optional scalar fields and optional single links may be omitted.
  • null is accepted only for optional scalar fields and optional single links.
  • Scalar assignment values are checked against the target scalar type.
  • Single-link assignment values use a temporary MVP object-id shorthand:
    • a string literal is treated as the target object's id
    • null is accepted for optional links
  • Multi-link assignment is rejected in the MVP.
  • The Semantic IR contains an InsertQuery with resolved target object type and resolved assignments.
  • SQLite planning lowers the insert into a backend-specific insert plan without exposing SQL table or column names in Semantic IR.
  • SQLite SQL generation renders an INSERT INTO ... statement with bind values.
  • The runner generates a UUID for the inserted object id.
  • The runner returns the generated object id for the inserted object.
  • CLI/REPL execution may display the inserted id only; full inserted-object result shaping is deferred.

Example accepted query:

insert Post {
  title := "Case File",
  author := "00000000-0000-0000-0000-000000000001"
}

Example rejected query:

insert User {
  id := "00000000-0000-0000-0000-000000000001",
  name := "Sheri"
}

Scope

Expected areas to change:

  • spec/query.md
    • tighten the MVP insert contract if needed
    • explicitly mark string-literal single-link assignment as a temporary object-id shorthand
  • spec/ir.md
    • define the concrete InsertQuery and shared assignment/value representation expected by implementation
  • spec/storage-sqlite.md
    • confirm runtime-generated UUID behavior and single-link column writes
  • engine/query-ast
    • add insert AST nodes and assignment/value nodes if they do not already exist
  • engine/query-parser
    • parse top-level insert
    • parse object-literal assignment lists
  • engine/query-resolver
    • resolve insert target type
    • resolve assignment fields
    • validate writable fields, required fields, cardinality, and value types
  • engine/query-ir
    • add InsertQuery
    • add shared mutation assignment/value types intended to be reused by UpdateQuery
  • engine/sqlite-query-plan
    • add SQLite insert plan structures and planning entry point
  • engine/sqlite-query-sqlgen
    • render SQLite insert statements and bind values
  • engine/sqlite-runner
    • execute insert statements
    • generate object ids
    • return inserted id
  • tools/gelite-commands
    • route insert execution through shared command orchestration if query execution is exposed there
  • tools/gelite-cli and/or tools/repl
    • expose insert execution where current query execution workflows require it
  • tests
    • parser tests for valid and invalid insert syntax
    • resolver tests for field/type/cardinality errors
    • SQLite planning/sqlgen tests for scalar and single-link inserts
    • runner or pipeline test proving an inserted row can be selected afterward

Related specs and plans

  • spec/query.md
    • already defines insert as one of the MVP top-level statements
    • already scopes MVP assignments to scalar fields and single relations
    • already defers nested inserts, multi relation mutation syntax, subqueries, and upsert
  • spec/ir.md
    • already reserves InsertQuery, UpdateQuery, and Assignment
    • should be tightened around mutation assignment values before or during implementation
  • spec/storage-sqlite.md
    • defines implicit id TEXT PRIMARY KEY
    • states that the runtime generates UUID values during insert
    • defines scalar columns and single-link <field>_id columns
  • plan/new-db-engine-plan.md
    • tracks the broader product scope where mutations are needed after the select path is established
  • plan/new-db-engine-design.md
    • defines the staged pipeline that this issue should preserve
  • plan/query-expression-model-plan.md
    • notes that mutation statements should reuse the expression model later
    • this issue intentionally starts with literal-only assignment RHS to keep mutation execution scoped
  • plan/cli-and-tooling-plan.md
    • relevant if insert execution is exposed through CLI or REPL workflows in this issue

Boundaries and non-goals

This issue does not implement:

  • create as a keyword or alias
  • update
  • delete
  • unless conflict
  • upsert behavior
  • with bindings
  • nested inserts
  • subquery assignment RHS
  • computed expression assignment RHS
  • function calls in assignment RHS
  • query parameters
  • bulk insert
  • for ... union
  • multi-link insertion
  • += or -=
  • select (insert ...) { ... }
  • full inserted-object result shaping
  • user-provided id values

The MVP single-link string-literal assignment is temporary. It is accepted to make the first insert execution path usable before object-valued subqueries exist. A later issue should decide whether to keep this shorthand or replace it with Gel-style object expression assignment.

Acceptance criteria

  • query-parser accepts a valid top-level insert statement with scalar literal assignments.
  • query-parser accepts a valid top-level insert statement with single-link string id assignment.
  • query-parser rejects malformed insert assignment syntax.
  • query-resolver resolves insert target object types against the schema catalog.
  • query-resolver rejects unknown target types.
  • query-resolver rejects unknown assignment fields.
  • query-resolver rejects assignment to implicit id.
  • query-resolver rejects assigning a scalar value to an incompatible scalar field.
  • query-resolver rejects assigning null to required fields.
  • query-resolver rejects missing required scalar fields.
  • query-resolver rejects missing required single links.
  • query-resolver rejects multi-link assignments.
  • query-resolver accepts optional scalar and optional single-link omission.
  • query-ir represents insert assignments with resolved field references, not raw field names.
  • SQLite planning does not leak SQLite table or column names into Semantic IR.
  • SQLite SQL generation renders an INSERT with deterministic column ordering.
  • SQLite SQL generation uses bind values for user-provided assignment values and generated id.
  • The runner generates a UUID for the inserted object id.
  • The runner returns the generated object id.
  • An end-to-end test can insert an object and then select it through the existing select pipeline.
  • cargo test --workspace passes.

Branch

issue-TBD-insert-mutation-mvp

Checks

  • I searched existing issues for the same request or task.
  • I checked the relevant spec/ or plan/ document when one exists.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions