@syncular/typegen 0.15.42 → 0.15.43

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syncular/typegen",
3
- "version": "0.15.42",
3
+ "version": "0.15.43",
4
4
  "description": "Syncular schema-to-TypeScript type generator and the `syncular` CLI",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Benjamin Kniffler",
@@ -56,9 +56,9 @@
56
56
  "!dist/**/*.test.d.ts"
57
57
  ],
58
58
  "dependencies": {
59
- "@syncular/core": "0.15.42"
59
+ "@syncular/core": "0.15.43"
60
60
  },
61
61
  "devDependencies": {
62
- "@syncular/server": "0.15.42"
62
+ "@syncular/server": "0.15.43"
63
63
  }
64
64
  }
package/src/generate.ts CHANGED
@@ -44,6 +44,7 @@ import {
44
44
  import {
45
45
  buildMigrationLock,
46
46
  LEGACY_MIGRATION_LOCK_FORMAT_VERSION,
47
+ lockedMigrationNames,
47
48
  MIGRATION_LOCK_FILENAME,
48
49
  readMigrationLock,
49
50
  serializeMigrationLock,
@@ -268,10 +269,13 @@ function buildSchemaVersions(
268
269
  return out;
269
270
  }
270
271
 
271
- /** Pure IR construction — the testable heart of the generator. */
272
+ /** Pure IR construction — the testable heart of the generator. Migrations
273
+ * named in `lockedNames` replay as immutable deployed history: rules that
274
+ * only appended migrations must satisfy are skipped for them. */
272
275
  export function buildIr(
273
276
  manifest: Manifest,
274
277
  migrations: readonly MigrationInput[],
278
+ lockedNames?: ReadonlySet<string>,
275
279
  ): IrDocument {
276
280
  if (migrations.length === 0) {
277
281
  throw new TypegenError(MANIFEST_FILENAME, 'no migrations found');
@@ -284,6 +288,7 @@ export function buildIr(
284
288
  migration.sql,
285
289
  `${migration.name}/up.sql`,
286
290
  droppedTables,
291
+ { lockedHistory: lockedNames?.has(migration.name) === true },
287
292
  );
288
293
  }
289
294
  validateFinalSchemaIdentifiers(parsedTables);
@@ -600,21 +605,35 @@ export function upgradeMigrationHistory(manifestDir: string): GeneratedOutput {
600
605
  }
601
606
  // Validate the immutable prefix before replacing its representation.
602
607
  updateMigrationLock(locked, migrations);
603
- buildIr(manifest, migrations);
608
+ // upgrade-lock converts the committed representation of history that is
609
+ // already locked. Extending the lock over appended migrations is its own
610
+ // reviewable act, so unlocked migrations stop the conversion here.
611
+ if (migrations.length > locked.migrations.length) {
612
+ const appended = migrations
613
+ .slice(locked.migrations.length)
614
+ .map((migration) => migration.name)
615
+ .join(', ');
616
+ throw new TypegenError(
617
+ MIGRATION_LOCK_FILENAME,
618
+ `migrations ${appended} are appended beyond the locked history — run generate to extend the lock over them, commit the extended lock, then rerun \`migrations upgrade-lock\``,
619
+ );
620
+ }
621
+ const lockedNames = lockedMigrationNames(locked);
622
+ buildIr(manifest, migrations, lockedNames);
604
623
  return {
605
624
  path: resolve(manifestDir, MIGRATION_LOCK_FILENAME),
606
- content: serializeMigrationLock(buildMigrationLock(migrations)),
625
+ content: serializeMigrationLock(
626
+ buildMigrationLock(migrations, undefined, lockedNames),
627
+ ),
607
628
  };
608
629
  }
609
630
 
610
631
  /** Fast CI check for migration history without emitting/query analysis. */
611
632
  export function checkMigrationHistory(manifestDir: string): string[] {
612
633
  const { manifest, migrations } = loadProjectInputs(manifestDir);
613
- const current = updateMigrationLock(
614
- readMigrationLock(manifestDir),
615
- migrations,
616
- );
617
- buildIr(manifest, migrations);
634
+ const locked = readMigrationLock(manifestDir);
635
+ const current = updateMigrationLock(locked, migrations);
636
+ buildIr(manifest, migrations, lockedMigrationNames(locked));
618
637
  const output = {
619
638
  path: resolve(manifestDir, MIGRATION_LOCK_FILENAME),
620
639
  content: serializeMigrationLock(current),
@@ -630,11 +649,9 @@ export function checkMigrationHistory(manifestDir: string): string[] {
630
649
  /** Read `syncular.json` + migrations under `manifestDir`; build outputs. */
631
650
  export function generate(manifestDir: string): GenerateResult {
632
651
  const { manifest, migrations } = loadProjectInputs(manifestDir);
633
- const migrationLock = updateMigrationLock(
634
- readMigrationLock(manifestDir),
635
- migrations,
636
- );
637
- const ir = buildIr(manifest, migrations);
652
+ const locked = readMigrationLock(manifestDir);
653
+ const migrationLock = updateMigrationLock(locked, migrations);
654
+ const ir = buildIr(manifest, migrations, lockedMigrationNames(locked));
638
655
 
639
656
  // §5/§12 naming: the emitter targets this run generates (keyword hazards
640
657
  // are only real on targets that exist), and the per-table collision check
package/src/lsp.ts CHANGED
@@ -7,6 +7,7 @@ import { formatSyql } from './fmt';
7
7
  import { buildIr, loadMigrations, loadQueries, makeQueryDb } from './generate';
8
8
  import type { IrDocument } from './ir';
9
9
  import { MANIFEST_FILENAME, parseManifest } from './manifest';
10
+ import { lockedMigrationNames, readMigrationLock } from './migration-lock';
10
11
  import type { QueryDb, QueryNamingOptions } from './query';
11
12
  import { SyqlFrontendError, type SyqlSourceSpan } from './syql-lexer';
12
13
  import type { SyqlLoweredQuery } from './syql-lowering';
@@ -260,9 +261,18 @@ export class SyqlLanguageServer {
260
261
  readFileSync(resolve(manifestDir, MANIFEST_FILENAME), 'utf8'),
261
262
  ),
262
263
  );
264
+ // Tolerate locked history exactly like generation does; a project with
265
+ // no readable lock builds strictly.
266
+ let lockedNames: ReadonlySet<string> | undefined;
267
+ try {
268
+ lockedNames = lockedMigrationNames(readMigrationLock(manifestDir));
269
+ } catch {
270
+ lockedNames = undefined;
271
+ }
263
272
  const ir = buildIr(
264
273
  manifest,
265
274
  loadMigrations(resolve(manifestDir, manifest.migrations)),
275
+ lockedNames,
266
276
  );
267
277
  const { db } = makeQueryDb(ir);
268
278
  const targets: QueryNamingOptions['targets'][number][] = ['ts'];
@@ -81,18 +81,29 @@ function snapshotColumn(column: IrColumn): MigrationLockColumn {
81
81
  function snapshotTables(
82
82
  tables: ReadonlyMap<string, ParsedTable>,
83
83
  ): MigrationLockTable[] {
84
- return [...tables.values()]
85
- .sort((a, b) => a.name.localeCompare(b.name))
86
- .map((table) => ({
87
- name: table.name,
88
- primaryKey: table.primaryKey,
89
- columns: table.columns.map(snapshotColumn),
90
- }));
84
+ return (
85
+ [...tables.values()]
86
+ // Code-point order keeps the serialization byte-identical across locales.
87
+ .sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0))
88
+ .map((table) => ({
89
+ name: table.name,
90
+ primaryKey: table.primaryKey,
91
+ columns: table.columns.map(snapshotColumn),
92
+ }))
93
+ );
91
94
  }
92
95
 
93
- /** Replay a complete migration sequence with ephemeral diagnostic snapshots. */
96
+ /** The names of every migration a committed lock has made immutable. */
97
+ export function lockedMigrationNames(lock: MigrationLock): ReadonlySet<string> {
98
+ return new Set(lock.migrations.map((migration) => migration.name));
99
+ }
100
+
101
+ /** Replay a complete migration sequence with ephemeral diagnostic snapshots.
102
+ * Migrations named in `lockedNames` replay as deployed history; rules that
103
+ * only appended migrations must satisfy are skipped for them. */
94
104
  function buildMigrationHistory(
95
105
  migrations: readonly MigrationInput[],
106
+ lockedNames?: ReadonlySet<string>,
96
107
  ): CurrentMigrationHistory {
97
108
  const tables = new Map<string, ParsedTable>();
98
109
  const droppedTables = new Set<string>();
@@ -103,6 +114,7 @@ function buildMigrationHistory(
103
114
  migration.sql,
104
115
  `${migration.name}/up.sql`,
105
116
  droppedTables,
117
+ { lockedHistory: lockedNames?.has(migration.name) === true },
106
118
  );
107
119
  entries.push({
108
120
  name: migration.name,
@@ -145,8 +157,12 @@ export function buildMigrationLock(
145
157
  formatVersion:
146
158
  | typeof LEGACY_MIGRATION_LOCK_FORMAT_VERSION
147
159
  | typeof MIGRATION_LOCK_FORMAT_VERSION = MIGRATION_LOCK_FORMAT_VERSION,
160
+ lockedNames?: ReadonlySet<string>,
148
161
  ): MigrationLock {
149
- return lockFromHistory(buildMigrationHistory(migrations), formatVersion);
162
+ return lockFromHistory(
163
+ buildMigrationHistory(migrations, lockedNames),
164
+ formatVersion,
165
+ );
150
166
  }
151
167
 
152
168
  /** Fixed-order, byte-deterministic serialization for clean code review. */
@@ -447,7 +463,10 @@ export function updateMigrationLock(
447
463
  locked: MigrationLock,
448
464
  migrations: readonly MigrationInput[],
449
465
  ): MigrationLock {
450
- const current = buildMigrationHistory(migrations);
466
+ const current = buildMigrationHistory(
467
+ migrations,
468
+ lockedMigrationNames(locked),
469
+ );
451
470
  validateMigrationHistory(locked, current);
452
471
  return lockFromHistory(current, locked.formatVersion);
453
472
  }
@@ -457,5 +476,8 @@ export function validateMigrationLock(
457
476
  locked: MigrationLock,
458
477
  migrations: readonly MigrationInput[],
459
478
  ): void {
460
- validateMigrationHistory(locked, buildMigrationHistory(migrations));
479
+ validateMigrationHistory(
480
+ locked,
481
+ buildMigrationHistory(migrations, lockedMigrationNames(locked)),
482
+ );
461
483
  }
package/src/query.ts CHANGED
@@ -767,6 +767,11 @@ function hasCommaJoinedSchemaTable(sql: string, ir: IrDocument): boolean {
767
767
  ]);
768
768
  let depth = 0;
769
769
  let cursor = 0;
770
+ /** The previous significant token: an uppercased word or a single
771
+ * punctuation character. Distinguishes a table-source group — a `(` after
772
+ * FROM, JOIN, `,` or another `(` — from a function call or parenthesized
773
+ * expression, whose `(` follows an identifier or an operator. */
774
+ let previous: string | undefined;
770
775
  const nextIdentifier = (start: number): string | undefined => {
771
776
  let index = start;
772
777
  while (
@@ -781,9 +786,19 @@ function hasCommaJoinedSchemaTable(sql: string, ir: IrDocument): boolean {
781
786
 
782
787
  while (cursor < cleaned.length) {
783
788
  const char = cleaned[cursor] as string;
789
+ if (/\s/.test(char)) {
790
+ cursor += 1;
791
+ continue;
792
+ }
784
793
  if (char === '(') {
794
+ const opensTableSource =
795
+ previous === 'FROM' ||
796
+ previous === 'JOIN' ||
797
+ previous === ',' ||
798
+ previous === '(';
785
799
  const next = nextIdentifier(cursor + 1);
786
800
  if (
801
+ opensTableSource &&
787
802
  activeFromDepths.has(depth) &&
788
803
  next !== undefined &&
789
804
  known.has(next.toLowerCase())
@@ -791,18 +806,21 @@ function hasCommaJoinedSchemaTable(sql: string, ir: IrDocument): boolean {
791
806
  activeFromDepths.add(depth + 1);
792
807
  }
793
808
  depth += 1;
809
+ previous = '(';
794
810
  cursor += 1;
795
811
  continue;
796
812
  }
797
813
  if (char === ')') {
798
814
  activeFromDepths.delete(depth);
799
815
  depth = Math.max(0, depth - 1);
816
+ previous = ')';
800
817
  cursor += 1;
801
818
  continue;
802
819
  }
803
820
  if (char === ',' && activeFromDepths.has(depth)) {
804
821
  const next = nextIdentifier(cursor + 1);
805
822
  if (next !== undefined && known.has(next.toLowerCase())) return true;
823
+ previous = ',';
806
824
  cursor += 1;
807
825
  continue;
808
826
  }
@@ -817,9 +835,11 @@ function hasCommaJoinedSchemaTable(sql: string, ir: IrDocument): boolean {
817
835
  const word = cleaned.slice(cursor, end).toUpperCase();
818
836
  if (word === 'FROM') activeFromDepths.add(depth);
819
837
  else if (clauseEnders.has(word)) activeFromDepths.delete(depth);
838
+ previous = word;
820
839
  cursor = end;
821
840
  continue;
822
841
  }
842
+ previous = char;
823
843
  cursor += 1;
824
844
  }
825
845
  return false;
package/src/sql.ts CHANGED
@@ -80,11 +80,32 @@ const DATA_MUTATION_GUIDANCE =
80
80
  const tableIdentifierSources = new WeakMap<ParsedTable, string>();
81
81
  const columnIdentifierSources = new WeakMap<IrColumn, string>();
82
82
  const indexIdentifierSources = new WeakMap<IrIndex, string>();
83
+ const ftsIndexIdentifierSources = new WeakMap<IrFtsIndex, string>();
84
+
85
+ /** Objects created while replaying the locked, immutable history prefix.
86
+ * Rules adopted while that prefix was already deployed (nullable-only ADD
87
+ * COLUMN, ASCII-portable identifiers) replay tolerantly for these objects;
88
+ * every migration beyond the locked prefix enforces them. */
89
+ const lockedHistoryObjects = new WeakSet<object>();
90
+
91
+ /** Options for replaying one migration's SQL. */
92
+ export interface ApplyMigrationSqlOptions {
93
+ /** True while this migration is part of the locked, immutable history
94
+ * prefix (`syncular.migrations.lock.json`). Deployed migrations are
95
+ * immutable, so checks that would require editing them are skipped for the
96
+ * locked prefix and enforced for appended migrations. */
97
+ readonly lockedHistory?: boolean;
98
+ }
99
+
100
+ /** ASCII identifier contract shared with named-query analysis: query
101
+ * dependency tracking and reactivity resolve identifiers with this shape. */
102
+ const PORTABLE_ASCII_IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
83
103
 
84
104
  function validateIdentifier(
85
105
  source: string,
86
106
  kind: string,
87
107
  identifier: string,
108
+ target: object,
88
109
  ): void {
89
110
  try {
90
111
  validatePortableRelationalIdentifier(kind, identifier);
@@ -94,25 +115,35 @@ function validateIdentifier(
94
115
  error instanceof Error ? error.message : 'invalid relational identifier',
95
116
  );
96
117
  }
118
+ if (lockedHistoryObjects.has(target)) return;
119
+ if (!PORTABLE_ASCII_IDENTIFIER_RE.test(identifier)) {
120
+ throw new TypegenError(
121
+ source,
122
+ `${kind} name ${JSON.stringify(identifier)} must be an ASCII identifier matching [A-Za-z_][A-Za-z0-9_]* — named-query analysis resolves ASCII identifiers, so a non-ASCII name silently loses dependency tracking and reactivity`,
123
+ );
124
+ }
97
125
  }
98
126
 
99
127
  /**
100
128
  * Validate the accumulated head schema after every migration has been
101
129
  * applied. This deliberately permits a locked historical migration to create
102
130
  * an invalid identifier when a later forward migration drops it; only final
103
- * generated objects must be portable.
131
+ * generated objects must be portable. Objects created by locked migrations
132
+ * are additionally exempt from the ASCII rule (deployed migrations are
133
+ * immutable, so the name can only be retired by a forward migration).
104
134
  */
105
135
  export function validateFinalSchemaIdentifiers(
106
136
  tables: ReadonlyMap<string, ParsedTable>,
107
137
  ): void {
108
138
  for (const table of tables.values()) {
109
139
  const tableSource = tableIdentifierSources.get(table) ?? 'migrations';
110
- validateIdentifier(tableSource, 'table', table.name);
140
+ validateIdentifier(tableSource, 'table', table.name, table);
111
141
  for (const column of table.columns) {
112
142
  validateIdentifier(
113
143
  columnIdentifierSources.get(column) ?? tableSource,
114
144
  `table ${table.name}: column`,
115
145
  column.name,
146
+ column,
116
147
  );
117
148
  }
118
149
  for (const index of table.indexes) {
@@ -120,6 +151,15 @@ export function validateFinalSchemaIdentifiers(
120
151
  indexIdentifierSources.get(index) ?? tableSource,
121
152
  `table ${table.name}: index`,
122
153
  index.name,
154
+ index,
155
+ );
156
+ }
157
+ for (const ftsIndex of table.ftsIndexes) {
158
+ validateIdentifier(
159
+ ftsIndexIdentifierSources.get(ftsIndex) ?? tableSource,
160
+ `table ${table.name}: FTS virtual table`,
161
+ ftsIndex.name,
162
+ ftsIndex,
123
163
  );
124
164
  }
125
165
  }
@@ -359,22 +399,23 @@ function parseCreate(
359
399
  tables: Map<string, ParsedTable>,
360
400
  droppedTables: ReadonlySet<string>,
361
401
  source: string,
402
+ options: ApplyMigrationSqlOptions,
362
403
  ): void {
363
404
  if (cursor.eatWord('VIRTUAL')) {
364
- parseCreateVirtualTable(cursor, tables);
405
+ parseCreateVirtualTable(cursor, tables, source, options);
365
406
  return;
366
407
  }
367
408
  if (cursor.eatWord('TABLE')) {
368
- parseCreateTable(cursor, tables, droppedTables, source);
409
+ parseCreateTable(cursor, tables, droppedTables, source, options);
369
410
  return;
370
411
  }
371
412
  if (cursor.eatWord('UNIQUE')) {
372
413
  cursor.expectWord('INDEX', 'after CREATE UNIQUE');
373
- parseCreateIndex(cursor, tables, true, source);
414
+ parseCreateIndex(cursor, tables, true, source, options);
374
415
  return;
375
416
  }
376
417
  if (cursor.eatWord('INDEX')) {
377
- parseCreateIndex(cursor, tables, false, source);
418
+ parseCreateIndex(cursor, tables, false, source, options);
378
419
  return;
379
420
  }
380
421
  const token = cursor.peek();
@@ -398,6 +439,8 @@ const ALLOWED_FTS_TOKENIZERS = new Set([
398
439
  function parseCreateVirtualTable(
399
440
  cursor: Cursor,
400
441
  tables: Map<string, ParsedTable>,
442
+ source: string,
443
+ options: ApplyMigrationSqlOptions,
401
444
  ): void {
402
445
  cursor.expectWord('TABLE', 'after CREATE VIRTUAL');
403
446
  if (cursor.eatWord('IF')) {
@@ -510,7 +553,10 @@ function parseCreateVirtualTable(
510
553
  );
511
554
  }
512
555
  }
513
- table.ftsIndexes.push({ name, columns, tokenize });
556
+ const ftsIndex = { name, columns, tokenize };
557
+ table.ftsIndexes.push(ftsIndex);
558
+ ftsIndexIdentifierSources.set(ftsIndex, source);
559
+ if (options.lockedHistory === true) lockedHistoryObjects.add(ftsIndex);
514
560
  }
515
561
 
516
562
  function parseCreateTable(
@@ -518,6 +564,7 @@ function parseCreateTable(
518
564
  tables: Map<string, ParsedTable>,
519
565
  droppedTables: ReadonlySet<string>,
520
566
  source: string,
567
+ options: ApplyMigrationSqlOptions,
521
568
  ): void {
522
569
  if (cursor.eatWord('IF')) {
523
570
  cursor.expectWord('NOT', 'after IF');
@@ -618,8 +665,10 @@ function parseCreateTable(
618
665
  };
619
666
  tables.set(name, table);
620
667
  tableIdentifierSources.set(table, source);
668
+ if (options.lockedHistory === true) lockedHistoryObjects.add(table);
621
669
  for (const column of finalColumns) {
622
670
  columnIdentifierSources.set(column, source);
671
+ if (options.lockedHistory === true) lockedHistoryObjects.add(column);
623
672
  }
624
673
  }
625
674
 
@@ -636,6 +685,7 @@ function parseCreateIndex(
636
685
  tables: Map<string, ParsedTable>,
637
686
  unique: boolean,
638
687
  source: string,
688
+ options: ApplyMigrationSqlOptions,
639
689
  ): void {
640
690
  // `INDEX` already matched by the dispatcher.
641
691
  if (cursor.eatWord('IF')) {
@@ -715,12 +765,14 @@ function parseCreateIndex(
715
765
  const index: IrIndex = { name, columns, unique };
716
766
  table.indexes.push(index);
717
767
  indexIdentifierSources.set(index, source);
768
+ if (options.lockedHistory === true) lockedHistoryObjects.add(index);
718
769
  }
719
770
 
720
771
  function parseAlterTable(
721
772
  cursor: Cursor,
722
773
  tables: Map<string, ParsedTable>,
723
774
  source: string,
775
+ options: ApplyMigrationSqlOptions,
724
776
  ): void {
725
777
  cursor.expectWord('TABLE', 'after ALTER');
726
778
  const name = cursor.identifier('a table name');
@@ -737,7 +789,9 @@ function parseAlterTable(
737
789
  cursor.eatWord('COLUMN');
738
790
  const def = parseColumnDef(cursor, false);
739
791
  cursor.expectEnd();
740
- if (!def.column.nullable) {
792
+ // A locked migration replays as deployed; the nullable rule applies to
793
+ // migrations beyond the locked prefix, where the SQL can still change.
794
+ if (!def.column.nullable && options.lockedHistory !== true) {
741
795
  cursor.fail(
742
796
  `ALTER TABLE ${name}: added column ${JSON.stringify(def.column.name)} must be nullable — SQL defaults do not backfill Syncular row payloads; add the column nullable, backfill it through versioned server-authoritative writes, and enforce required values in application validation`,
743
797
  );
@@ -749,6 +803,7 @@ function parseAlterTable(
749
803
  }
750
804
  table.columns.push(def.column);
751
805
  columnIdentifierSources.set(def.column, source);
806
+ if (options.lockedHistory === true) lockedHistoryObjects.add(def.column);
752
807
  }
753
808
 
754
809
  /** `DROP TABLE [IF EXISTS] name`; table-name reuse remains unsupported. */
@@ -792,6 +847,17 @@ function parseDropIndex(
792
847
  table.indexes.splice(index, 1);
793
848
  return;
794
849
  }
850
+ for (const table of tables.values()) {
851
+ if (table.ftsIndexes.some((candidate) => candidate.name === name)) {
852
+ // `DROP INDEX IF EXISTS <fts>` matches SQLite: an FTS5 virtual table is
853
+ // no regular index, so IF EXISTS resolves to a tolerant no-op (this also
854
+ // keeps a locked migration carrying the statement replayable).
855
+ if (ifExists) return;
856
+ cursor.fail(
857
+ `DROP INDEX ${name}: ${name} is an FTS5 virtual table (CREATE VIRTUAL TABLE … USING fts5); the migration subset removes an FTS projection together with its owning content table (DROP TABLE ${table.name})`,
858
+ );
859
+ }
860
+ }
795
861
  if (!ifExists) {
796
862
  cursor.fail(`DROP INDEX ${name}: index does not exist at this point`);
797
863
  }
@@ -825,15 +891,16 @@ export function applyMigrationSql(
825
891
  sql: string,
826
892
  source: string,
827
893
  droppedTables: Set<string> = new Set<string>(),
894
+ options: ApplyMigrationSqlOptions = {},
828
895
  ): void {
829
896
  for (const tokens of tokenizeStatements(sql, source)) {
830
897
  const cursor = new Cursor(tokens, source);
831
898
  const head = cursor.next();
832
899
  const word = head.kind === 'word' ? head.text.toUpperCase() : '';
833
900
  if (word === 'CREATE') {
834
- parseCreate(cursor, tables, droppedTables, source);
901
+ parseCreate(cursor, tables, droppedTables, source, options);
835
902
  } else if (word === 'ALTER') {
836
- parseAlterTable(cursor, tables, source);
903
+ parseAlterTable(cursor, tables, source, options);
837
904
  } else if (word === 'DROP') {
838
905
  parseDrop(cursor, tables, droppedTables);
839
906
  } else {