@syncular/typegen 0.15.12 → 0.15.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -77,6 +77,7 @@ schema guide and suggests `syncular init`.
77
77
  | `output.swift` | no | Opt-in Swift emitter (see §5). A path string, or `{ "path", "enumName", "queriesPath" }` (default `enumName` `SyncularSchema`; `queriesPath` opts into §6 Swift named queries). |
78
78
  | `output.kotlin` | no | Opt-in Kotlin emitter (see §5). A path string, or `{ "path", "package", "objectName", "queriesPath" }` (defaults `syncular.generated` / `SyncularSchema`). |
79
79
  | `output.dart` | no | Opt-in Dart emitter (see §5). A path string, or `{ "path", "queriesPath" }`. |
80
+ | `output.rust` | no | Opt-in Rust named-query emitter (see §6). An object `{ "queriesPath", "clientCrate"? }`; `clientCrate` defaults to `syncular_client`. Rust consumes neutral schema IR rather than a generated schema source file. |
80
81
  | `schemaVersions` | yes, non-empty | The §1.5 version history. See below. |
81
82
  | `tables` | yes, non-empty | Synced tables. **Array order is the handler-declared bootstrap order (§4.7)** and flows unchanged into the IR and `schema.tables`. |
82
83
  | `tables[].name` | yes | Must be created by a migration. |
@@ -410,14 +411,15 @@ present-null, and present-value remain distinct. A group is one optional host
410
411
  object whose members are all required. A `bool = false` flag activates on
411
412
  true. Sort is a generated enum/union of complete checked profiles; limit is validated as a
412
413
  positive bounded integer before execution. `integer` inputs are exact signed
413
- 64-bit values in the SYQL API (`bigint` in TypeScript, `Int64`/`Long`/`int` on
414
- native targets).
414
+ 64-bit values in the SYQL API (`bigint` in TypeScript,
415
+ `Int64`/`Long`/`int` on Swift/Kotlin/Dart, and `i64` on Rust).
415
416
 
416
417
  **File & naming convention.** Named queries live in a `queries/` directory
417
418
  next to `migrations/` (override with the top-level `"queries"` manifest key).
418
419
  The directory is **walked recursively** — subfolders are pure organization.
419
420
  Each language's queries file is a **separate output** (`output.queries` for TS,
420
- and `queriesPath` on `output.swift`/`output.kotlin`/`output.dart`), so
421
+ and `queriesPath` on `output.swift`/`output.kotlin`/`output.dart` plus
422
+ `output.rust.queriesPath`), so
421
423
  schema-only consumers never churn when a query changes. A queries output is
422
424
  opt-in per language; when none is requested the `queries/` dir is not even
423
425
  read.
@@ -577,7 +579,7 @@ required, non-null, exactly typed binds are allowed. Result identity is inferred
577
579
  from schema keys and the projection. Without constructive proof the compiler
578
580
  falls back to table-wide dependency, no coverage, and/or unkeyed reconciliation.
579
581
 
580
- **Emitted shape, per language** (one query, five outputs — abbreviated):
582
+ **Emitted shape, per language** (abbreviated):
581
583
 
582
584
  | | Output |
583
585
  |---|---|
@@ -585,13 +587,45 @@ falls back to table-wide dependency, no coverage, and/or unkeyed reconciliation.
585
587
  | Swift | `struct ListTodosRow` + `init?(row:)` and `<Enum>Queries.listTodos(client:listId:) throws -> [ListTodosRow]` + `listTodosTables` |
586
588
  | Kotlin | `data class ListTodosRow` + `fromRow` and `<Object>Queries.listTodos(client, listId): List<ListTodosRow>` + `listTodosTables` |
587
589
  | Dart | `class ListTodosRow` + `fromRow` and `syncularListTodosQuery(client, listId): List<ListTodosRow>` + `syncularListTodosQueryTables` |
590
+ | Rust | `list_todos::{Row, Params, DESCRIPTOR, select, run, snapshot}` with strict decoding, `i64` fidelity, reactive dependencies, `WindowCoverage`, and proven `row_key` |
588
591
 
589
592
  Each projection row is its **own** generated type per query (the drift-kill:
590
- the row shape is exactly what the SELECT returns). Native rows decode through
591
- the same `fromRow` mapping rules (0/1 booleans, `{"$bytes":"<hex>"}` bytes) as
592
- the schema structs. `--check` gates every queries file byte-exactly, like the
593
+ the row shape is exactly what the SELECT returns). Swift/Kotlin/Dart rows use
594
+ their wrapper `fromRow` mapping. Rust returns a query/column-specific error for
595
+ missing or malformed values and accepts the client's lossless `$bigint` and
596
+ `$bytes` envelopes. `--check` gates every queries file byte-exactly, like the
593
597
  schema files; each carries the DO-NOT-EDIT header + IR hash.
594
598
 
599
+ Rust is object-only in the manifest:
600
+
601
+ ```json
602
+ {
603
+ "output": {
604
+ "rust": {
605
+ "queriesPath": "./src/syncular_queries.rs",
606
+ "clientCrate": "syncular_client"
607
+ }
608
+ }
609
+ }
610
+ ```
611
+
612
+ Each query is a snake-case module. Required inputs go through `Params::new`;
613
+ optional nullable inputs use `SyqlPresence<Option<T>>`; sort profiles are
614
+ closed enums; and `select(&params)` exposes the exact checked SQL and binds for
615
+ diagnostics. `run` executes a typed local read. `snapshot` returns typed rows,
616
+ the local revision, and coverage from one SQLite read snapshot. The generated
617
+ `DESCRIPTOR` contains the QueryIR hash identity, tables, dependencies,
618
+ coverage, plan selector, and optional proven row-key function. It deliberately
619
+ does not prescribe a Rust UI observer.
620
+
621
+ TypeScript named queries also emit one `mapRow` decoder per projection. The
622
+ direct async runner and the React descriptor share that decoder, so a boolean
623
+ field is always a JavaScript boolean on the first read and every reactive
624
+ re-read (`0` → false, finite non-zero → true, an existing boolean is
625
+ preserved, and nullable booleans preserve `null`). A value that does not match
626
+ the analyzed result type throws `QueryResultDecodeError`; raw `client.query()`
627
+ and `useRawSql()` remain storage-shaped unless the caller supplies a mapper.
628
+
595
629
  **React helper.** `@syncular/react` exports `useQuery(query, params?)`,
596
630
  which takes the TS `NamedQuery` descriptor and observes the client-scoped
597
631
  revisioned store:
@@ -0,0 +1,2 @@
1
+ import type { AnalyzedQuery } from './query.js';
2
+ export declare function emitQueriesRustModule(queries: readonly AnalyzedQuery[], hash: string, irVersion: number, clientCrate?: string): string;