@syncular/typegen 0.15.8 → 0.15.10

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
@@ -236,12 +236,14 @@ and Rust clients create a contentful FTS table with a private stable source-ID
236
236
  column and deterministic maintenance triggers. FTS is local-only: it is not a
237
237
  wire/server table, cannot be subscribed or mutated, and maps back to its owner
238
238
  for named-query invalidation. Columns must precede options, be distinct
239
- non-encrypted strings, and number 1–32. `content` is required. Supported
240
- tokenizers are `unicode61` (default), its `remove_diacritics 0|1|2` variants,
241
- `porter unicode61`, and `trigram`. Other modules/options/tokenizers, encrypted
242
- columns, or schema-object name collisions fail generation. There is no
243
- automatic `LIKE` fallback when FTS5 is unavailable; local schema creation
244
- fails loudly.
239
+ declared strings, and number 1–32. Encrypted declared-string columns are
240
+ allowed because the projection is built only from the decrypted local mirror;
241
+ ciphertext remains the only wire and server representation. `content` is
242
+ required. Supported tokenizers are `unicode61` (default), its
243
+ `remove_diacritics 0|1|2` variants, `porter unicode61`, and `trigram`. Other
244
+ modules/options/tokenizers or schema-object name collisions fail generation.
245
+ There is no automatic `LIKE` fallback when FTS5 is unavailable; local schema
246
+ creation fails loudly.
245
247
 
246
248
  **Hard errors** (each names the construct and source file): any other
247
249
  statement (`CREATE TRIGGER/VIEW`, `DROP INDEX`, DML, `ALTER … RENAME`, …); unknown
@@ -252,7 +254,7 @@ or parameterized types (`VARCHAR(36)`); quoted identifiers
252
254
  or missing primary keys; `PRIMARY KEY` on `ADD COLUMN`; duplicate
253
255
  tables/columns; ASC/DESC, expression, or partial (`WHERE`) index columns; a
254
256
  duplicate or unknown-column index; unsupported virtual-table modules or FTS5
255
- options; an FTS projection without an owner or with invalid/encrypted columns;
257
+ options; an FTS projection without an owner or with invalid columns;
256
258
  trailing clauses (`STRICT`).
257
259
 
258
260
  **`DEFAULT` literals are accepted and ignored**: typegen extracts the
package/dist/generate.js CHANGED
@@ -50,14 +50,6 @@ function buildTable(manifestTable, parsed) {
50
50
  }
51
51
  }
52
52
  const columns = applyEncryption(parsed, scopes, manifestTable.encryptedColumns);
53
- for (const ftsIndex of parsed.ftsIndexes) {
54
- for (const columnName of ftsIndex.columns) {
55
- const column = columns.find((candidate) => candidate.name === columnName);
56
- if (column?.encrypted === true) {
57
- throw new TypegenError(MANIFEST_FILENAME, `table ${parsed.name}: FTS index ${JSON.stringify(ftsIndex.name)} cannot index encrypted column ${JSON.stringify(columnName)}`);
58
- }
59
- }
60
- }
61
53
  return {
62
54
  name: parsed.name,
63
55
  primaryKey: parsed.primaryKey,
package/dist/query.js CHANGED
@@ -575,6 +575,11 @@ function isSyncVersionSource(item, refs) {
575
575
  // Infer a param's type from `col <op> :name` or `col IN (:name, …)` where `col`
576
576
  // is a plain ref to an IR column. Equality/comparison/IN only — anything else
577
577
  // needs the `-- param` comment (kept deliberately simple and honest).
578
+ function applicationColumnType(column) {
579
+ return column.encrypted === true && column.declaredType !== undefined
580
+ ? column.declaredType
581
+ : column.type;
582
+ }
578
583
  function inferParamType(paramName, sql, refs, ir) {
579
584
  const cleaned = stripCommentsAndStrings(sql);
580
585
  const byName = new Map(ir.tables.map((t) => [t.name, t]));
@@ -582,13 +587,14 @@ function inferParamType(paramName, sql, refs, ir) {
582
587
  if (qualifier !== undefined) {
583
588
  const ref = refs.find((r) => r.alias === qualifier);
584
589
  const table = ref && byName.get(ref.table);
585
- return table?.columns.find((c) => c.name === column)?.type ?? null;
590
+ const resolved = table?.columns.find((c) => c.name === column);
591
+ return resolved === undefined ? null : applicationColumnType(resolved);
586
592
  }
587
593
  for (const ref of refs) {
588
594
  const table = byName.get(ref.table);
589
595
  const col = table?.columns.find((c) => c.name === column);
590
596
  if (col !== undefined)
591
- return col.type;
597
+ return applicationColumnType(col);
592
598
  }
593
599
  return null;
594
600
  };
@@ -656,14 +662,16 @@ export function inferParamTypeEvidence(paramName, sql, refs, ir) {
656
662
  if (qualifier !== undefined) {
657
663
  const ref = refs.find((candidate) => candidate.alias === qualifier);
658
664
  const table = ref === undefined ? undefined : byName.get(ref.table);
659
- const type = table?.columns.find((item) => item.name === column)?.type;
665
+ const item = table?.columns.find((candidate) => candidate.name === column);
666
+ const type = item === undefined ? undefined : applicationColumnType(item);
660
667
  if (type !== undefined)
661
668
  evidence.push(type);
662
669
  return;
663
670
  }
664
671
  const matches = refs.flatMap((ref) => {
665
672
  const table = byName.get(ref.table);
666
- const type = table?.columns.find((item) => item.name === column)?.type;
673
+ const item = table?.columns.find((candidate) => candidate.name === column);
674
+ const type = item === undefined ? undefined : applicationColumnType(item);
667
675
  return type === undefined ? [] : [type];
668
676
  });
669
677
  if (matches.length === 1)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syncular/typegen",
3
- "version": "0.15.8",
3
+ "version": "0.15.10",
4
4
  "description": "Syncular schema-to-TypeScript type generator and the `syncular` CLI",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Benjamin Kniffler",
@@ -48,7 +48,7 @@
48
48
  "!dist/**/*.test.d.ts"
49
49
  ],
50
50
  "devDependencies": {
51
- "@syncular/core": "0.15.8",
52
- "@syncular/server": "0.15.8"
51
+ "@syncular/core": "0.15.10",
52
+ "@syncular/server": "0.15.10"
53
53
  }
54
54
  }
package/src/generate.ts CHANGED
@@ -113,17 +113,6 @@ function buildTable(
113
113
  scopes,
114
114
  manifestTable.encryptedColumns,
115
115
  );
116
- for (const ftsIndex of parsed.ftsIndexes) {
117
- for (const columnName of ftsIndex.columns) {
118
- const column = columns.find((candidate) => candidate.name === columnName);
119
- if (column?.encrypted === true) {
120
- throw new TypegenError(
121
- MANIFEST_FILENAME,
122
- `table ${parsed.name}: FTS index ${JSON.stringify(ftsIndex.name)} cannot index encrypted column ${JSON.stringify(columnName)}`,
123
- );
124
- }
125
- }
126
- }
127
116
  return {
128
117
  name: parsed.name,
129
118
  primaryKey: parsed.primaryKey,
package/src/query.ts CHANGED
@@ -61,7 +61,7 @@
61
61
  * for the query shapes this tier supports.
62
62
  */
63
63
  import { TypegenError } from './errors';
64
- import type { IrColumnType, IrDocument, IrTable } from './ir';
64
+ import type { IrColumn, IrColumnType, IrDocument, IrTable } from './ir';
65
65
  import { lowerProjection, mainVerbAfterWith } from './lower';
66
66
  import { buildNamingMap, type NamingMode, type NamingTarget } from './naming';
67
67
 
@@ -868,6 +868,12 @@ function isSyncVersionSource(
868
868
  // is a plain ref to an IR column. Equality/comparison/IN only — anything else
869
869
  // needs the `-- param` comment (kept deliberately simple and honest).
870
870
 
871
+ function applicationColumnType(column: IrColumn): IrColumnType {
872
+ return column.encrypted === true && column.declaredType !== undefined
873
+ ? column.declaredType
874
+ : column.type;
875
+ }
876
+
871
877
  function inferParamType(
872
878
  paramName: string,
873
879
  sql: string,
@@ -883,12 +889,13 @@ function inferParamType(
883
889
  if (qualifier !== undefined) {
884
890
  const ref = refs.find((r) => r.alias === qualifier);
885
891
  const table = ref && byName.get(ref.table);
886
- return table?.columns.find((c) => c.name === column)?.type ?? null;
892
+ const resolved = table?.columns.find((c) => c.name === column);
893
+ return resolved === undefined ? null : applicationColumnType(resolved);
887
894
  }
888
895
  for (const ref of refs) {
889
896
  const table = byName.get(ref.table);
890
897
  const col = table?.columns.find((c) => c.name === column);
891
- if (col !== undefined) return col.type;
898
+ if (col !== undefined) return applicationColumnType(col);
892
899
  }
893
900
  return null;
894
901
  };
@@ -972,13 +979,19 @@ export function inferParamTypeEvidence(
972
979
  if (qualifier !== undefined) {
973
980
  const ref = refs.find((candidate) => candidate.alias === qualifier);
974
981
  const table = ref === undefined ? undefined : byName.get(ref.table);
975
- const type = table?.columns.find((item) => item.name === column)?.type;
982
+ const item = table?.columns.find(
983
+ (candidate) => candidate.name === column,
984
+ );
985
+ const type = item === undefined ? undefined : applicationColumnType(item);
976
986
  if (type !== undefined) evidence.push(type);
977
987
  return;
978
988
  }
979
989
  const matches = refs.flatMap((ref) => {
980
990
  const table = byName.get(ref.table);
981
- const type = table?.columns.find((item) => item.name === column)?.type;
991
+ const item = table?.columns.find(
992
+ (candidate) => candidate.name === column,
993
+ );
994
+ const type = item === undefined ? undefined : applicationColumnType(item);
982
995
  return type === undefined ? [] : [type];
983
996
  });
984
997
  if (matches.length === 1) evidence.push(matches[0] as IrColumnType);