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
Objective
Implement the first end-to-end
insertmutation pipeline for Gelite.The issue should add support for parsing, resolving, planning, rendering, and executing a scoped MVP form of
insert: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
selectquery execution, but test fixtures and user workflows still need raw SQL to create data. Addinginsertis the next mutation milestone and will make the query language useful for creating object data through the same staged pipeline used byselect.This work should also establish the shared mutation assignment model that
updatecan reuse later.insertandupdateboth need field assignment parsing, writable-field validation, value type checking, link/scalar distinction, and SQLite value binding. Introducing those contracts duringinsertkeeps the first mutation small while avoiding a throwaway design.Expected outcome
Gelite supports top-level MVP
insertstatements with this shape:Supported behavior:
insertstatement.linkfields.id.nullis accepted only for optional scalar fields and optional single links.nullis accepted for optional linksInsertQuerywith resolved target object type and resolved assignments.INSERT INTO ...statement with bind values.Example accepted query:
Example rejected query:
Scope
Expected areas to change:
spec/query.mdinsertcontract if neededspec/ir.mdInsertQueryand shared assignment/value representation expected by implementationspec/storage-sqlite.mdengine/query-astengine/query-parserinsertengine/query-resolverengine/query-irInsertQueryUpdateQueryengine/sqlite-query-planengine/sqlite-query-sqlgenengine/sqlite-runnertools/gelite-commandstools/gelite-cliand/ortools/replRelated specs and plans
spec/query.mdinsertas one of the MVP top-level statementsspec/ir.mdInsertQuery,UpdateQuery, andAssignmentspec/storage-sqlite.mdid TEXT PRIMARY KEY<field>_idcolumnsplan/new-db-engine-plan.mdplan/new-db-engine-design.mdplan/query-expression-model-plan.mdplan/cli-and-tooling-plan.mdBoundaries and non-goals
This issue does not implement:
createas a keyword or aliasupdatedeleteunless conflictwithbindingsfor ... union+=or-=select (insert ...) { ... }idvaluesThe 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-parseraccepts a valid top-levelinsertstatement with scalar literal assignments.query-parseraccepts a valid top-levelinsertstatement with single-link string id assignment.query-parserrejects malformed insert assignment syntax.query-resolverresolves insert target object types against the schema catalog.query-resolverrejects unknown target types.query-resolverrejects unknown assignment fields.query-resolverrejects assignment to implicitid.query-resolverrejects assigning a scalar value to an incompatible scalar field.query-resolverrejects assigningnullto required fields.query-resolverrejects missing required scalar fields.query-resolverrejects missing required single links.query-resolverrejects multi-link assignments.query-resolveraccepts optional scalar and optional single-link omission.query-irrepresents insert assignments with resolved field references, not raw field names.INSERTwith deterministic column ordering.cargo test --workspacepasses.Branch
issue-TBD-insert-mutation-mvp
Checks
spec/orplan/document when one exists.