From 906c87e26d58df2ac8d44ce4d7bad8f1860976da Mon Sep 17 00:00:00 2001 From: Andrii Sherman Date: Wed, 6 Nov 2024 21:20:13 +0200 Subject: [PATCH] Beta (#3503) * Fix breakpoints option default value * fix: added commonly used columns to supabase auth.users table schema * imports checker with OHM grammar * imports checker with OHM grammar + fix of imports issues * Formatting fix * [MySQL] Add unsigned floating point types + Fix unsigned integer type bugs in Kit (#3284) * Fix bugs with MySQL introspection tests * Update float data type in MySQL * Better support for float types in MySQL * Handle existing unsigned numerical types in MySQL * Add unsigned to floating point types in MySQL * Handle unsigned floating point types in MySQL * Update decimal data type --------- Co-authored-by: Andrii Sherman * Batch of bugfixes for ORM (#3181) * (MySQL) Fix placeholder type error in offset and limit * Add prepared statement tests * Add PG test * Fix blob parsing in bun sqlite driver * Lint and format * Fix file * Fix tests * Use const instead of let in tests * Format --------- Co-authored-by: Andrii Sherman * main to beta (#3404) * Update Github issue templates (#3157) * Update GH issue templates * Update issue templates --------- Co-authored-by: Andrii Sherman * Fix checkboxes --------- Co-authored-by: L-Mario564 * feat: add tablesFilter to pushSchema api (#3141) * feat: add tablesFilter to pushSchema api * Format with dprint --------- Co-authored-by: Andrii Sherman * Batch of bugfixes for Kit (#2959) * Escape single quote in enum value * Escape single quotes in string default values * Handle instrospection of strings with single quotes * Add tests * Add tests * Uncomment tests * Fix SQL statement order in MySQL * Add MySQL test * Fix alter composite PK statement missing quotes in PG * Add tests * Handle SQL expressions in timestamp, date and time in PG * Use `.run` instead of `.query` in SQLite queries that don't return anything * Fix parsing of enum array types in PG * Generate more PG index operators * Fix primary key recreate on table rename * Format * Format * Update test * Format * Fix tests * Fix terminal output mistake * Remove duplicate import --------- Co-authored-by: Andrii Sherman * Bump versions --------- Co-authored-by: Steffen <3752127+klotztech@users.noreply.github.com> Co-authored-by: Nicholas Ly Co-authored-by: Alex Blokh Co-authored-by: Sukairo-02 Co-authored-by: L-Mario564 Co-authored-by: Dan Ribbens --- changelogs/drizzle-kit/0.28.0.md | 28 + changelogs/drizzle-orm/0.36.1.md | 6 + drizzle-kit/.gitignore | 1 + drizzle-kit/imports-checker/analyze.ts | 78 ++ drizzle-kit/imports-checker/checker.ts | 296 +++++++ .../imports-checker/grammar/grammar.ohm | 121 +++ .../grammar/grammar.ohm-bundle.d.ts | 164 ++++ .../grammar/grammar.ohm-bundle.js | 753 ++++++++++++++++++ drizzle-kit/imports-checker/index.ts | 48 ++ drizzle-kit/package.json | 7 +- drizzle-kit/src/@types/utils.ts | 1 + drizzle-kit/src/api.ts | 9 +- drizzle-kit/src/cli/commands/push.ts | 8 +- drizzle-kit/src/cli/commands/utils.ts | 14 +- drizzle-kit/src/cli/schema.ts | 3 +- drizzle-kit/src/cli/validations/outputs.ts | 2 +- .../extensions/getTablesFilterByExtensions.ts | 16 + drizzle-kit/src/introspect-mysql.ts | 84 +- drizzle-kit/src/introspect-pg.ts | 42 +- drizzle-kit/src/introspect-sqlite.ts | 4 +- drizzle-kit/src/jsonStatements.ts | 31 +- drizzle-kit/src/serializer/mysqlSerializer.ts | 28 +- drizzle-kit/src/serializer/pgSchema.ts | 6 +- drizzle-kit/src/serializer/pgSerializer.ts | 16 +- .../src/serializer/sqliteSerializer.ts | 4 +- drizzle-kit/src/snapshotsDiffer.ts | 18 +- drizzle-kit/src/sqlgenerator.ts | 139 ++-- drizzle-kit/src/utils.ts | 10 + drizzle-kit/tests/bin.test.ts | 58 ++ drizzle-kit/tests/indexes/pg.test.ts | 4 +- drizzle-kit/tests/introspect/mysql.test.ts | 113 ++- drizzle-kit/tests/introspect/pg.test.ts | 27 + drizzle-kit/tests/introspect/sqlite.test.ts | 19 + drizzle-kit/tests/mysql.test.ts | 102 +++ drizzle-kit/tests/pg-columns.test.ts | 28 +- drizzle-kit/tests/pg-enums.test.ts | 73 +- drizzle-kit/tests/pg-tables.test.ts | 100 +++ drizzle-kit/tests/push/common.ts | 10 +- drizzle-kit/tests/push/mysql.test.ts | 91 ++- drizzle-kit/tests/push/pg.test.ts | 159 ++++ drizzle-kit/tests/push/sqlite.test.ts | 77 ++ drizzle-kit/tests/sqlite-columns.test.ts | 22 + drizzle-kit/tests/sqlite-tables.test.ts | 44 + drizzle-orm/package.json | 4 +- drizzle-orm/src/mysql-core/columns/decimal.ts | 20 +- drizzle-orm/src/mysql-core/columns/double.ts | 15 +- drizzle-orm/src/mysql-core/columns/float.ts | 45 +- .../src/mysql-core/query-builders/select.ts | 6 +- drizzle-orm/src/sqlite-core/columns/blob.ts | 8 +- drizzle-orm/src/supabase/rls.ts | 9 +- drizzle-orm/type-tests/mysql/tables.ts | 6 + integration-tests/tests/bun/sqlite.test.ts | 56 +- integration-tests/tests/mysql/mysql-common.ts | 67 +- integration-tests/tests/pg/pg-common.ts | 47 ++ .../tests/sqlite/sqlite-common.ts | 62 ++ pnpm-lock.yaml | 199 ++--- 56 files changed, 2993 insertions(+), 415 deletions(-) create mode 100644 changelogs/drizzle-kit/0.28.0.md create mode 100644 changelogs/drizzle-orm/0.36.1.md create mode 100644 drizzle-kit/imports-checker/analyze.ts create mode 100644 drizzle-kit/imports-checker/checker.ts create mode 100644 drizzle-kit/imports-checker/grammar/grammar.ohm create mode 100644 drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts create mode 100644 drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js create mode 100644 drizzle-kit/imports-checker/index.ts create mode 100644 drizzle-kit/src/extensions/getTablesFilterByExtensions.ts create mode 100644 drizzle-kit/tests/bin.test.ts diff --git a/changelogs/drizzle-kit/0.28.0.md b/changelogs/drizzle-kit/0.28.0.md new file mode 100644 index 000000000..6881c677e --- /dev/null +++ b/changelogs/drizzle-kit/0.28.0.md @@ -0,0 +1,28 @@ +# Improvements + +- Added an OHM static imports checker to identify unexpected imports within a chain of imports in the drizzle-kit repo. For example, it checks if drizzle-orm is imported before drizzle-kit and verifies if the drizzle-orm import is available in your project. +- [Adding more columns to Supabase auth.users table schema](https://github.com/drizzle-team/drizzle-orm/issues/3327) - thanks @nicholasdly + +# Bug Fixes + +- [[BUG]: [drizzle-kit]: Fix breakpoints option cannot be disabled](https://github.com/drizzle-team/drizzle-orm/issues/2828) - thanks @klotztech +- [[BUG]: drizzle-kit introspect: SMALLINT import missing and incorrect DECIMAL UNSIGNED handling](https://github.com/drizzle-team/drizzle-orm/issues/2950) - thanks @L-Mario564 +- [Unsigned tinyints preventing migrations](https://github.com/drizzle-team/drizzle-orm/issues/1571) - thanks @L-Mario564 +- [[BUG]: Can't parse float(8,2) from database (precision and scale and/or unsigned breaks float types)](https://github.com/drizzle-team/drizzle-orm/issues/3285) - thanks @L-Mario564 +- [[BUG]: PgEnum generated migration doesn't escape single quotes](https://github.com/drizzle-team/drizzle-orm/issues/1272) - thanks @L-Mario564 +- [[BUG]: single quote not escaped correctly in migration file](https://github.com/drizzle-team/drizzle-orm/issues/2184) - thanks @L-Mario564 +- [[BUG]: Migrations does not escape single quotes](https://github.com/drizzle-team/drizzle-orm/issues/1765) - thanks @L-Mario564 +- [[BUG]: Issue with quoted default string values](https://github.com/drizzle-team/drizzle-orm/issues/2122) - thanks @L-Mario564 +- [[BUG]: SQl commands in wrong roder](https://github.com/drizzle-team/drizzle-orm/issues/2390) - thanks @L-Mario564 +- [[BUG]: Time with precision in drizzle-orm/pg-core adds double-quotes around type](https://github.com/drizzle-team/drizzle-orm/issues/1804) - thanks @L-Mario564 +- [[BUG]: Postgres push fails due to lack of quotes](https://github.com/drizzle-team/drizzle-orm/issues/2396) - thanks @L-Mario564 +- [[BUG]: TypeError: Cannot read properties of undefined (reading 'compositePrimaryKeys')](https://github.com/drizzle-team/drizzle-orm/issues/2344) - thanks @L-Mario564 +- [[BUG]: drizzle-kit introspect generates CURRENT_TIMESTAMP without sql operator on date column](https://github.com/drizzle-team/drizzle-orm/issues/2899) - thanks @L-Mario564 +- [[BUG]: Drizzle-kit introspect doesn't pull correct defautl statement](https://github.com/drizzle-team/drizzle-orm/issues/2905) - thanks @L-Mario564 +- [[BUG]: Problem on MacBook - This statement does not return data. Use run() instead](https://github.com/drizzle-team/drizzle-orm/issues/2623) - thanks @L-Mario564 +- [[BUG]: Enum column names that are used as arrays are not quoted](https://github.com/drizzle-team/drizzle-orm/issues/2598) - thanks @L-Mario564 +- [[BUG]: drizzle-kit generate ignores index operators](https://github.com/drizzle-team/drizzle-orm/issues/2935) - thanks @L-Mario564 +- [dialect param config error message is wrong](https://github.com/drizzle-team/drizzle-orm/issues/3427) - thanks @L-Mario564 +- [[BUG]: Error setting default enum field values](https://github.com/drizzle-team/drizzle-orm/issues/2299) - thanks @L-Mario564 +- [[BUG]: drizzle-kit does not respect the order of columns configured in primaryKey()](https://github.com/drizzle-team/drizzle-orm/issues/2326) - thanks @L-Mario564 +- [[BUG]: Cannot drop Unique Constraint MySQL](https://github.com/drizzle-team/drizzle-orm/issues/998) - thanks @L-Mario564 diff --git a/changelogs/drizzle-orm/0.36.1.md b/changelogs/drizzle-orm/0.36.1.md new file mode 100644 index 000000000..1c0e96756 --- /dev/null +++ b/changelogs/drizzle-orm/0.36.1.md @@ -0,0 +1,6 @@ +# Bug Fixes + +- [[BUG]: Using sql.placeholder with limit and/or offset for a prepared statement produces TS error](https://github.com/drizzle-team/drizzle-orm/issues/2146) - thanks @L-Mario564 +- [[BUG] If a query I am trying to modify with a dynamic query (....$dynamic()) contains any placeholders, I'm getting an error that says No value for placeholder.... provided](https://github.com/drizzle-team/drizzle-orm/issues/2272) - thanks @L-Mario564 +- [[BUG]: Error thrown when trying to insert an array of new rows using generatedAlwaysAsIdentity() for the id column](https://github.com/drizzle-team/drizzle-orm/issues/2849) - thanks @L-Mario564 +- [[BUG]: Unable to Use BigInt Types with Bun and Drizzle](https://github.com/drizzle-team/drizzle-orm/issues/2603) - thanks @L-Mario564 \ No newline at end of file diff --git a/drizzle-kit/.gitignore b/drizzle-kit/.gitignore index 6269daaf5..4916f095a 100644 --- a/drizzle-kit/.gitignore +++ b/drizzle-kit/.gitignore @@ -2,6 +2,7 @@ **/.DS_Store !src +!imports-checker !tests !vitest.config.ts !README.md diff --git a/drizzle-kit/imports-checker/analyze.ts b/drizzle-kit/imports-checker/analyze.ts new file mode 100644 index 000000000..b31686e16 --- /dev/null +++ b/drizzle-kit/imports-checker/analyze.ts @@ -0,0 +1,78 @@ +import { readFileSync } from 'fs'; +import type { Node } from 'ohm-js'; +import JSImports from './grammar/grammar.ohm-bundle'; + +export type CollectionItem = { + type: 'data' | 'types'; + source: string; +}; + +function recursiveRun(...args: Node[]): boolean { + for (const arg of args) { + if ( + arg.ctorName === 'Rest' + || arg.ctorName === 'comment' + || arg.ctorName === 'stringLiteral' + ) { + continue; + } + + if ( + arg.ctorName === 'ImportExpr_From' + || arg.ctorName === 'ImportExpr_NoFrom' + ) { + arg['analyze'](); + + continue; + } + + if (arg.isTerminal()) continue; + + for (const c of arg.children) { + if (!recursiveRun(c)) return false; + } + } + + return true; +} +function init(collection: CollectionItem[]) { + const semantics = JSImports.createSemantics(); + + semantics.addOperation('analyze', { + JSImports(arg0, arg1) { + recursiveRun(arg0, arg1); + }, + + ImportExpr_From(kImport, importInner, kFrom, importSource) { + const ruleName = importInner.children[0]!.ctorName; + const importType = ruleName === 'ImportInner_Type' || ruleName === 'ImportInner_Types' + ? 'types' + : 'data'; + + collection.push({ + source: importSource.children[1]!.sourceString!, + type: importType, + }); + }, + + ImportExpr_NoFrom(kImport, importSource) { + collection.push({ + source: importSource.children[1]!.sourceString!, + type: 'data', + }); + }, + }); + + return semantics; +} + +export function analyze(path: string) { + const file = readFileSync(path).toString(); + const match = JSImports.match(file, 'JSImports'); + + if (match.failed()) throw new Error(`Failed to parse file: ${path}`); + const collection: CollectionItem[] = []; + + init(collection)(match)['analyze'](); + return collection; +} diff --git a/drizzle-kit/imports-checker/checker.ts b/drizzle-kit/imports-checker/checker.ts new file mode 100644 index 000000000..d8fc4b219 --- /dev/null +++ b/drizzle-kit/imports-checker/checker.ts @@ -0,0 +1,296 @@ +import fs from 'fs'; +import m from 'micromatch'; +import { dirname, join as joinPath, relative, resolve as resolvePath } from 'path'; +import { analyze } from './analyze'; + +type External = { + file: string; + import: string; + type: 'data' | 'types'; +}; + +export type Issue = { + file: string; + imports: IssueImport[]; + accessChains: ChainLink[][]; +}; + +export type IssueImport = { + name: string; + type: 'data' | 'types'; +}; + +export type ChainLink = { + file: string; + import: string; +}; + +type ListMode = 'whitelist' | 'blacklist'; + +class ImportAnalyzer { + private localImportRegex = /^(\.?\.?\/|\.\.?$)/; + private importedFileFormatRegex = /^.*\.(ts|tsx|mts|cts|js|jsx|mjs|cjs|json)$/i; + + private visited: Set = new Set(); + + private externals: External[] = []; + private accessChains: Record = {}; + + constructor( + private basePath: string, + private entry: string, + private listMode: ListMode, + private readonly wantedList: string[], + private localPaths: string[], + private logger?: boolean, + private ignoreTypes?: boolean, + ) {} + + private isDirectory = (path: string) => { + try { + return fs.lstatSync(path).isDirectory(); + } catch (e) { + return false; + } + }; + + private isFile = (path: string) => { + try { + return fs.lstatSync(path).isFile(); + } catch (e) { + return false; + } + }; + + private localizePath = (path: string) => relative(resolvePath(this.basePath), resolvePath(path)); + + private isCustomLocal = (importTarget: string) => + !!this.localPaths.find( + (l) => + importTarget === l + || importTarget.startsWith(l.endsWith('/') ? l : `${l}/`), + ); + private isLocal = (importTarget: string) => + this.localImportRegex.test(importTarget) + || this.isCustomLocal(importTarget); + private isTsFormat = (path: string) => this.importedFileFormatRegex.test(path); + + private resolveCustomLocalPath = ( + absoluteBase: string, + base: string, + target: string, + ): string => { + return joinPath(absoluteBase, target); + }; + + private resolveTargetFile = (path: string): string => { + if (this.isFile(path)) return path; + + const formats = [ + '.ts', + '.mts', + '.cts', + '.tsx', + '.js', + '.mjs', + '.cjs', + '.jsx', + ]; + + for (const format of formats) { + const indexPath = joinPath(path, `/index${format}`); + if (this.isFile(indexPath)) return indexPath; + + const formatFilePath = `${path}${format}`; + if (this.isFile(formatFilePath)) return formatFilePath; + } + + return path; + }; + + private resolveTargetPath = ( + absoluteBase: string, + base: string, + target: string, + ): string => { + if (this.isCustomLocal(target)) { + return this.resolveTargetFile( + this.resolveCustomLocalPath(absoluteBase, base, target), + ); + } + + const dir = this.isDirectory(base) ? base : dirname(base); + const joined = joinPath(dir, target); + + return this.resolveTargetFile(joined); + }; + + private _analyzeImports = ( + target: string = this.entry, + basePath: string = this.basePath, + accessChain: ChainLink[] = [], + ) => { + if (this.visited.has(target)) return; + + const locals: string[] = []; + + try { + if (this.logger) console.log(`${this.localizePath(target)}`); + + const imports = analyze(target); + + for (const { source: i, type } of imports) { + if (this.ignoreTypes && type === 'types') continue; + + if (this.isLocal(i)) { + locals.push(i); + + continue; + } + + this.externals.push({ + file: this.localizePath(target), + import: i, + type: type, + }); + } + } catch (e) { + throw e; + } finally { + this.visited.add(target); + } + + for (const local of locals) { + const transformedTarget = this.resolveTargetPath(basePath, target, local); + + const localChain = [ + ...accessChain, + { + file: this.localizePath(target), + import: local, + }, + ]; + + const localized = this.localizePath(transformedTarget); + + if (this.accessChains[localized]) { + this.accessChains[localized].push(localChain); + } else this.accessChains[localized] = [localChain]; + + if (this.isTsFormat(transformedTarget)) { + this._analyzeImports(transformedTarget, basePath, localChain); + } else { + throw new Error(`unrecognized: ${localized}`); + } + } + }; + + public analyzeImports = () => { + const entryLocalized = this.localizePath(this.entry); + if (!this.accessChains[entryLocalized]) { + this.accessChains[entryLocalized] = [[]]; + } + + this._analyzeImports(); + + const rawIssues = this.listMode === 'whitelist' + ? this.externals.filter((e) => !m([e.import], this.wantedList).length) + : this.externals.filter((e) => m([e.import], this.wantedList).length); + + const issueMap: Record = {}; + for (const { file, import: i, type } of rawIssues) { + if (issueMap[file]) { + issueMap[file].imports.push({ + name: i, + type, + }); + + continue; + } + + issueMap[file] = { + file, + imports: [ + { + name: i, + type, + }, + ], + accessChains: this.accessChains[file]!, + }; + } + + return { + issues: Object.entries(issueMap).map(([file, data]) => { + for (const chain of data.accessChains) { + chain.push({ + file, + import: '', + }); + } + + return data; + }), + accessChains: this.accessChains, + }; + }; +} + +export type CustomLocalPathResolver = ( + basePath: string, + path: string, + target: string, +) => string; + +export type AnalyzeImportsConfig = + & { + basePath: string; + entry: string; + logger?: boolean; + ignoreTypes?: boolean; + localPaths?: string[]; + } + & ( + | { + blackList: string[]; + } + | { + whiteList: string[]; + } + ); + +type AnyAnalyzeImportsConfig = { + basePath: string; + entry: string; + blackList?: string[]; + whiteList?: string[]; + logger?: boolean; + ignoreTypes?: boolean; + localPaths?: string[]; +}; + +export function analyzeImports(cfg: AnalyzeImportsConfig) { + const { + basePath, + blackList, + whiteList, + entry, + localPaths: localImports, + ignoreTypes, + logger, + } = cfg as AnyAnalyzeImportsConfig; + const mode = whiteList ? 'whitelist' : 'blacklist'; + const wantedList = blackList ?? whiteList!; + + const analyzer = new ImportAnalyzer( + joinPath(basePath), + joinPath(entry), + mode, + wantedList, + localImports ?? [], + logger, + ignoreTypes, + ); + + return analyzer.analyzeImports(); +} diff --git a/drizzle-kit/imports-checker/grammar/grammar.ohm b/drizzle-kit/imports-checker/grammar/grammar.ohm new file mode 100644 index 000000000..de1459942 --- /dev/null +++ b/drizzle-kit/imports-checker/grammar/grammar.ohm @@ -0,0 +1,121 @@ +JSImports { + JSImports = (Expr ";"?)* + + Expr = + | comment + | stringLiteral + | ImportExpr + | Rest + + ImportExpr = + | "import" ImportInner "from" importSource -- From + | "import" importSource -- NoFrom + + Rest = (~(ImportExpr | comment | stringLiteral) any)+ + + ImportInner = + | ("type" "{" NonemptyListOf ","? "}") -- Type + | ("{" NonemptyListOf ","? "}") -- Types + | ("{" NonemptyListOf ","? "}") -- Extended + | (identifier ("," "type"? "{" NonemptyListOf ","? "}")?) -- Mixed + | ("*" ("as" identifier)?) -- All + | (identifier ("as" identifier)?) -- Default + + + ImportExtendedSelection = TypeImport | Import + ImportExtendedSelectionTypes = TypeImport + ImportExtendedSelectionTypeless = Import + + Import = identifier ("as" identifier)? + TypeImport = "type" Import ("as" identifier)? + + identifier = letter alnum* + quote = "\"" | "'" | "`" + notQuote = ~quote any + importSource = + | "\"" notQuote+ "\"" + | "'" notQuote+ "'" + | "`" notQuote+ "`" + + lineTerminator = "\n" | "\r" | "\u2028" | "\u2029" + lineTerminatorSequence = "\n" | "\r" ~"\n" | "\u2028" | "\u2029" | "\r\n" + + comment = multiLineComment | singleLineComment + + multiLineComment = "/*" (~"*/" any)* "*/" + singleLineComment = "//" (~lineTerminator any)* + + stringLiteral = + | "\"" doubleStringCharacter* "\"" + | "'" singleStringCharacter* "'" + | "`" templateStringCharacter* "`" + doubleStringCharacter = + | ~("\"" | "\\" | lineTerminator) any -- NonEscaped + | "\\" escapeSequence -- Escaped + | lineContinuation -- LineContinuation + singleStringCharacter = + | ~("'" | "\\" | lineTerminator) any -- NonEscaped + | "\\" escapeSequence -- Escaped + | lineContinuation -- LineContinuation + templateStringCharacter = + | ~ ("`" | "\\") any -- NonEscaped + | "\\" escapeSequence -- Escaped + lineContinuation = "\\" lineTerminatorSequence + escapeSequence = unicodeEscapeSequence | hexEscapeSequence | octalEscapeSequence | characterEscapeSequence + characterEscapeSequence = singleEscapeCharacter | nonEscapeCharacter + singleEscapeCharacter = "'" | "\"" | "\\" | "b" | "f" | "n" | "r" | "t" | "v" + nonEscapeCharacter = ~(escapeCharacter | lineTerminator) any + escapeCharacter = singleEscapeCharacter | decimalDigit | "x" | "u" + octalEscapeSequence = + | zeroToThree octalDigit octalDigit -- Whole + | fourToSeven octalDigit -- EightTimesfourToSeven + | zeroToThree octalDigit ~decimalDigit -- EightTimesZeroToThree + | octalDigit ~decimalDigit -- Octal + hexEscapeSequence = "x" hexDigit hexDigit + unicodeEscapeSequence = "u" hexDigit hexDigit hexDigit hexDigit + + zeroToThree = "0".."3" + fourToSeven = "4".."7" + decimalDigit = "0".."9" + nonZeroDigit = "1".."9" + octalDigit = "0".."7" + + regularExpressionLiteral = "/" regularExpressionBody "/" regularExpressionFlags + regularExpressionBody = regularExpressionFirstChar regularExpressionChar* + regularExpressionFirstChar = + | ~("*" | "\\" | "/" | "[") regularExpressionNonTerminator + | regularExpressionBackslashSequence + | regularExpressionClass + regularExpressionChar = ~("\\" | "/" | "[") regularExpressionNonTerminator + | regularExpressionBackslashSequence + | regularExpressionClass + regularExpressionBackslashSequence = "\\" regularExpressionNonTerminator + regularExpressionNonTerminator = ~(lineTerminator) any + regularExpressionClass = "[" regularExpressionClassChar* "]" + regularExpressionClassChar = + | ~("]" | "\\") regularExpressionNonTerminator + | regularExpressionBackslashSequence + regularExpressionFlags = identifierPart* + + multiLineCommentNoNL = "/*" (~("*/" | lineTerminator) any)* "*/" + + identifierStart = + | letter | "$" | "_" + | "\\" unicodeEscapeSequence -- escaped + identifierPart = + | identifierStart | unicodeCombiningMark + | unicodeDigit | unicodeConnectorPunctuation + | "\u200C" | "\u200D" + letter += unicodeCategoryNl + unicodeCategoryNl + = "\u2160".."\u2182" | "\u3007" | "\u3021".."\u3029" + unicodeDigit (a digit) + = "\u0030".."\u0039" | "\u0660".."\u0669" | "\u06F0".."\u06F9" | "\u0966".."\u096F" | "\u09E6".."\u09EF" | "\u0A66".."\u0A6F" | "\u0AE6".."\u0AEF" | "\u0B66".."\u0B6F" | "\u0BE7".."\u0BEF" | "\u0C66".."\u0C6F" | "\u0CE6".."\u0CEF" | "\u0D66".."\u0D6F" | "\u0E50".."\u0E59" | "\u0ED0".."\u0ED9" | "\u0F20".."\u0F29" | "\uFF10".."\uFF19" + + unicodeCombiningMark (a Unicode combining mark) + = "\u0300".."\u0345" | "\u0360".."\u0361" | "\u0483".."\u0486" | "\u0591".."\u05A1" | "\u05A3".."\u05B9" | "\u05BB".."\u05BD" | "\u05BF".."\u05BF" | "\u05C1".."\u05C2" | "\u05C4".."\u05C4" | "\u064B".."\u0652" | "\u0670".."\u0670" | "\u06D6".."\u06DC" | "\u06DF".."\u06E4" | "\u06E7".."\u06E8" | "\u06EA".."\u06ED" | "\u0901".."\u0902" | "\u093C".."\u093C" | "\u0941".."\u0948" | "\u094D".."\u094D" | "\u0951".."\u0954" | "\u0962".."\u0963" | "\u0981".."\u0981" | "\u09BC".."\u09BC" | "\u09C1".."\u09C4" | "\u09CD".."\u09CD" | "\u09E2".."\u09E3" | "\u0A02".."\u0A02" | "\u0A3C".."\u0A3C" | "\u0A41".."\u0A42" | "\u0A47".."\u0A48" | "\u0A4B".."\u0A4D" | "\u0A70".."\u0A71" | "\u0A81".."\u0A82" | "\u0ABC".."\u0ABC" | "\u0AC1".."\u0AC5" | "\u0AC7".."\u0AC8" | "\u0ACD".."\u0ACD" | "\u0B01".."\u0B01" | "\u0B3C".."\u0B3C" | "\u0B3F".."\u0B3F" | "\u0B41".."\u0B43" | "\u0B4D".."\u0B4D" | "\u0B56".."\u0B56" | "\u0B82".."\u0B82" | "\u0BC0".."\u0BC0" | "\u0BCD".."\u0BCD" | "\u0C3E".."\u0C40" | "\u0C46".."\u0C48" | "\u0C4A".."\u0C4D" | "\u0C55".."\u0C56" | "\u0CBF".."\u0CBF" | "\u0CC6".."\u0CC6" | "\u0CCC".."\u0CCD" | "\u0D41".."\u0D43" | "\u0D4D".."\u0D4D" | "\u0E31".."\u0E31" | "\u0E34".."\u0E3A" | "\u0E47".."\u0E4E" | "\u0EB1".."\u0EB1" | "\u0EB4".."\u0EB9" | "\u0EBB".."\u0EBC" | "\u0EC8".."\u0ECD" | "\u0F18".."\u0F19" | "\u0F35".."\u0F35" | "\u0F37".."\u0F37" | "\u0F39".."\u0F39" | "\u0F71".."\u0F7E" | "\u0F80".."\u0F84" | "\u0F86".."\u0F87" | "\u0F90".."\u0F95" | "\u0F97".."\u0F97" | "\u0F99".."\u0FAD" | "\u0FB1".."\u0FB7" | "\u0FB9".."\u0FB9" | "\u20D0".."\u20DC" | "\u20E1".."\u20E1" | "\u302A".."\u302F" | "\u3099".."\u309A" | "\uFB1E".."\uFB1E" | "\uFE20".."\uFE23" + + unicodeConnectorPunctuation = "\u005F" | "\u203F".."\u2040" | "\u30FB" | "\uFE33".."\uFE34" | "\uFE4D".."\uFE4F" | "\uFF3F" | "\uFF65" + unicodeSpaceSeparator = "\u2000".."\u200B" | "\u3000" + +} \ No newline at end of file diff --git a/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts new file mode 100644 index 000000000..64b5dfb78 --- /dev/null +++ b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.d.ts @@ -0,0 +1,164 @@ +// AUTOGENERATED FILE +// This file was generated from grammar.ohm by `ohm generateBundles`. + +import { BaseActionDict, Grammar, IterationNode, Node, NonterminalNode, Semantics, TerminalNode } from 'ohm-js'; + +export interface JSImportsActionDict extends BaseActionDict { + JSImports?: (this: NonterminalNode, arg0: IterationNode, arg1: IterationNode) => T; + Expr?: (this: NonterminalNode, arg0: NonterminalNode) => T; + ImportExpr_From?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: NonterminalNode, + arg2: TerminalNode, + arg3: NonterminalNode, + ) => T; + ImportExpr_NoFrom?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + ImportExpr?: (this: NonterminalNode, arg0: NonterminalNode) => T; + Rest?: (this: NonterminalNode, arg0: IterationNode) => T; + ImportInner_Type?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: TerminalNode, + arg2: NonterminalNode, + arg3: IterationNode, + arg4: TerminalNode, + ) => T; + ImportInner_Types?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: NonterminalNode, + arg2: IterationNode, + arg3: TerminalNode, + ) => T; + ImportInner_Extended?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: NonterminalNode, + arg2: IterationNode, + arg3: TerminalNode, + ) => T; + ImportInner_Mixed?: ( + this: NonterminalNode, + arg0: NonterminalNode, + arg1: IterationNode, + arg2: IterationNode, + arg3: IterationNode, + arg4: IterationNode, + arg5: IterationNode, + arg6: IterationNode, + ) => T; + ImportInner_All?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: IterationNode) => T; + ImportInner_Default?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode, arg2: IterationNode) => T; + ImportInner?: (this: NonterminalNode, arg0: NonterminalNode) => T; + ImportExtendedSelection?: (this: NonterminalNode, arg0: NonterminalNode) => T; + ImportExtendedSelectionTypes?: (this: NonterminalNode, arg0: NonterminalNode) => T; + ImportExtendedSelectionTypeless?: (this: NonterminalNode, arg0: NonterminalNode) => T; + Import?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode, arg2: IterationNode) => T; + TypeImport?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: NonterminalNode, + arg2: IterationNode, + arg3: IterationNode, + ) => T; + identifier?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode) => T; + quote?: (this: NonterminalNode, arg0: TerminalNode) => T; + notQuote?: (this: NonterminalNode, arg0: NonterminalNode) => T; + importSource?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + lineTerminator?: (this: NonterminalNode, arg0: TerminalNode) => T; + lineTerminatorSequence?: (this: NonterminalNode, arg0: TerminalNode) => T; + comment?: (this: NonterminalNode, arg0: NonterminalNode) => T; + multiLineComment?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + singleLineComment?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode) => T; + stringLiteral?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + doubleStringCharacter_NonEscaped?: (this: NonterminalNode, arg0: NonterminalNode) => T; + doubleStringCharacter_Escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + doubleStringCharacter_LineContinuation?: (this: NonterminalNode, arg0: NonterminalNode) => T; + doubleStringCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + singleStringCharacter_NonEscaped?: (this: NonterminalNode, arg0: NonterminalNode) => T; + singleStringCharacter_Escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + singleStringCharacter_LineContinuation?: (this: NonterminalNode, arg0: NonterminalNode) => T; + singleStringCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + templateStringCharacter_NonEscaped?: (this: NonterminalNode, arg0: NonterminalNode) => T; + templateStringCharacter_Escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + templateStringCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + lineContinuation?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + escapeSequence?: (this: NonterminalNode, arg0: NonterminalNode) => T; + characterEscapeSequence?: (this: NonterminalNode, arg0: NonterminalNode) => T; + singleEscapeCharacter?: (this: NonterminalNode, arg0: TerminalNode) => T; + nonEscapeCharacter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + escapeCharacter?: (this: NonterminalNode, arg0: NonterminalNode | TerminalNode) => T; + octalEscapeSequence_Whole?: ( + this: NonterminalNode, + arg0: NonterminalNode, + arg1: NonterminalNode, + arg2: NonterminalNode, + ) => T; + octalEscapeSequence_EightTimesfourToSeven?: ( + this: NonterminalNode, + arg0: NonterminalNode, + arg1: NonterminalNode, + ) => T; + octalEscapeSequence_EightTimesZeroToThree?: ( + this: NonterminalNode, + arg0: NonterminalNode, + arg1: NonterminalNode, + ) => T; + octalEscapeSequence_Octal?: (this: NonterminalNode, arg0: NonterminalNode) => T; + octalEscapeSequence?: (this: NonterminalNode, arg0: NonterminalNode) => T; + hexEscapeSequence?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode, arg2: NonterminalNode) => T; + unicodeEscapeSequence?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: NonterminalNode, + arg2: NonterminalNode, + arg3: NonterminalNode, + arg4: NonterminalNode, + ) => T; + zeroToThree?: (this: NonterminalNode, arg0: TerminalNode) => T; + fourToSeven?: (this: NonterminalNode, arg0: TerminalNode) => T; + decimalDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; + nonZeroDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; + octalDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; + regularExpressionLiteral?: ( + this: NonterminalNode, + arg0: TerminalNode, + arg1: NonterminalNode, + arg2: TerminalNode, + arg3: NonterminalNode, + ) => T; + regularExpressionBody?: (this: NonterminalNode, arg0: NonterminalNode, arg1: IterationNode) => T; + regularExpressionFirstChar?: (this: NonterminalNode, arg0: NonterminalNode) => T; + regularExpressionChar?: (this: NonterminalNode, arg0: NonterminalNode) => T; + regularExpressionBackslashSequence?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + regularExpressionNonTerminator?: (this: NonterminalNode, arg0: NonterminalNode) => T; + regularExpressionClass?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + regularExpressionClassChar?: (this: NonterminalNode, arg0: NonterminalNode) => T; + regularExpressionFlags?: (this: NonterminalNode, arg0: IterationNode) => T; + multiLineCommentNoNL?: (this: NonterminalNode, arg0: TerminalNode, arg1: IterationNode, arg2: TerminalNode) => T; + identifierStart_escaped?: (this: NonterminalNode, arg0: TerminalNode, arg1: NonterminalNode) => T; + identifierStart?: (this: NonterminalNode, arg0: NonterminalNode | TerminalNode) => T; + identifierPart?: (this: NonterminalNode, arg0: NonterminalNode | TerminalNode) => T; + letter?: (this: NonterminalNode, arg0: NonterminalNode) => T; + unicodeCategoryNl?: (this: NonterminalNode, arg0: TerminalNode) => T; + unicodeDigit?: (this: NonterminalNode, arg0: TerminalNode) => T; + unicodeCombiningMark?: (this: NonterminalNode, arg0: TerminalNode) => T; + unicodeConnectorPunctuation?: (this: NonterminalNode, arg0: TerminalNode) => T; + unicodeSpaceSeparator?: (this: NonterminalNode, arg0: TerminalNode) => T; +} + +export interface JSImportsSemantics extends Semantics { + addOperation(name: string, actionDict: JSImportsActionDict): this; + extendOperation(name: string, actionDict: JSImportsActionDict): this; + addAttribute(name: string, actionDict: JSImportsActionDict): this; + extendAttribute(name: string, actionDict: JSImportsActionDict): this; +} + +export interface JSImportsGrammar extends Grammar { + createSemantics(): JSImportsSemantics; + extendSemantics(superSemantics: JSImportsSemantics): JSImportsSemantics; +} + +declare const grammar: JSImportsGrammar; +export default grammar; diff --git a/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js new file mode 100644 index 000000000..9a889d66f --- /dev/null +++ b/drizzle-kit/imports-checker/grammar/grammar.ohm-bundle.js @@ -0,0 +1,753 @@ +import { makeRecipe } from 'ohm-js'; +const result = makeRecipe([ + 'grammar', + { + source: + 'JSImports {\n JSImports = (Expr ";"?)*\n\n Expr = \n | comment\n | stringLiteral\n | ImportExpr\n | Rest\n\n ImportExpr =\n | "import" ImportInner "from" importSource -- From\n | "import" importSource -- NoFrom\n\n Rest = (~(ImportExpr | comment | stringLiteral) any)+\n\n ImportInner = \n | ("type" "{" NonemptyListOf ","? "}") -- Type\n | ("{" NonemptyListOf ","? "}") -- Types\n | ("{" NonemptyListOf ","? "}") -- Extended\n | (identifier ("," "type"? "{" NonemptyListOf ","? "}")?) -- Mixed\n | ("*" ("as" identifier)?) -- All\n | (identifier ("as" identifier)?) -- Default\n \n\n ImportExtendedSelection = TypeImport | Import\n ImportExtendedSelectionTypes = TypeImport\n ImportExtendedSelectionTypeless = Import\n\n Import = identifier ("as" identifier)?\n TypeImport = "type" Import ("as" identifier)?\n\n identifier = letter alnum*\n quote = "\\"" | "\'" | "`"\n notQuote = ~quote any\n importSource =\n | "\\"" notQuote+ "\\""\n | "\'" notQuote+ "\'"\n | "`" notQuote+ "`"\n\n lineTerminator = "\\n" | "\\r" | "\\u2028" | "\\u2029"\n lineTerminatorSequence = "\\n" | "\\r" ~"\\n" | "\\u2028" | "\\u2029" | "\\r\\n"\n \n comment = multiLineComment | singleLineComment\n\n multiLineComment = "/*" (~"*/" any)* "*/"\n singleLineComment = "//" (~lineTerminator any)*\n\n stringLiteral =\n | "\\"" doubleStringCharacter* "\\""\n | "\'" singleStringCharacter* "\'"\n | "`" templateStringCharacter* "`"\n doubleStringCharacter =\n | ~("\\"" | "\\\\" | lineTerminator) any -- NonEscaped\n | "\\\\" escapeSequence -- Escaped\n | lineContinuation -- LineContinuation\n singleStringCharacter =\n | ~("\'" | "\\\\" | lineTerminator) any -- NonEscaped\n | "\\\\" escapeSequence -- Escaped\n | lineContinuation -- LineContinuation\n templateStringCharacter = \n | ~ ("`" | "\\\\") any -- NonEscaped\n | "\\\\" escapeSequence -- Escaped\n lineContinuation = "\\\\" lineTerminatorSequence\n escapeSequence = unicodeEscapeSequence | hexEscapeSequence | octalEscapeSequence | characterEscapeSequence\n characterEscapeSequence = singleEscapeCharacter | nonEscapeCharacter\n singleEscapeCharacter = "\'" | "\\"" | "\\\\" | "b" | "f" | "n" | "r" | "t" | "v"\n nonEscapeCharacter = ~(escapeCharacter | lineTerminator) any\n escapeCharacter = singleEscapeCharacter | decimalDigit | "x" | "u"\n octalEscapeSequence =\n | zeroToThree octalDigit octalDigit -- Whole\n | fourToSeven octalDigit -- EightTimesfourToSeven\n | zeroToThree octalDigit ~decimalDigit -- EightTimesZeroToThree\n | octalDigit ~decimalDigit -- Octal\n hexEscapeSequence = "x" hexDigit hexDigit\n unicodeEscapeSequence = "u" hexDigit hexDigit hexDigit hexDigit\n\n zeroToThree = "0".."3"\n fourToSeven = "4".."7"\n decimalDigit = "0".."9"\n nonZeroDigit = "1".."9"\n octalDigit = "0".."7"\n\n regularExpressionLiteral = "/" regularExpressionBody "/" regularExpressionFlags\n regularExpressionBody = regularExpressionFirstChar regularExpressionChar*\n regularExpressionFirstChar =\n | ~("*" | "\\\\" | "/" | "[") regularExpressionNonTerminator\n | regularExpressionBackslashSequence\n | regularExpressionClass\n regularExpressionChar = ~("\\\\" | "/" | "[") regularExpressionNonTerminator\n | regularExpressionBackslashSequence\n | regularExpressionClass\n regularExpressionBackslashSequence = "\\\\" regularExpressionNonTerminator\n regularExpressionNonTerminator = ~(lineTerminator) any\n regularExpressionClass = "[" regularExpressionClassChar* "]"\n regularExpressionClassChar =\n | ~("]" | "\\\\") regularExpressionNonTerminator\n | regularExpressionBackslashSequence\n regularExpressionFlags = identifierPart*\n\n multiLineCommentNoNL = "/*" (~("*/" | lineTerminator) any)* "*/"\n\n identifierStart =\n | letter | "$" | "_"\n | "\\\\" unicodeEscapeSequence -- escaped\n identifierPart =\n | identifierStart | unicodeCombiningMark\n | unicodeDigit | unicodeConnectorPunctuation\n | "\\u200C" | "\\u200D"\n letter += unicodeCategoryNl\n unicodeCategoryNl\n = "\\u2160".."\\u2182" | "\\u3007" | "\\u3021".."\\u3029"\n unicodeDigit (a digit)\n = "\\u0030".."\\u0039" | "\\u0660".."\\u0669" | "\\u06F0".."\\u06F9" | "\\u0966".."\\u096F" | "\\u09E6".."\\u09EF" | "\\u0A66".."\\u0A6F" | "\\u0AE6".."\\u0AEF" | "\\u0B66".."\\u0B6F" | "\\u0BE7".."\\u0BEF" | "\\u0C66".."\\u0C6F" | "\\u0CE6".."\\u0CEF" | "\\u0D66".."\\u0D6F" | "\\u0E50".."\\u0E59" | "\\u0ED0".."\\u0ED9" | "\\u0F20".."\\u0F29" | "\\uFF10".."\\uFF19"\n\n unicodeCombiningMark (a Unicode combining mark)\n = "\\u0300".."\\u0345" | "\\u0360".."\\u0361" | "\\u0483".."\\u0486" | "\\u0591".."\\u05A1" | "\\u05A3".."\\u05B9" | "\\u05BB".."\\u05BD" | "\\u05BF".."\\u05BF" | "\\u05C1".."\\u05C2" | "\\u05C4".."\\u05C4" | "\\u064B".."\\u0652" | "\\u0670".."\\u0670" | "\\u06D6".."\\u06DC" | "\\u06DF".."\\u06E4" | "\\u06E7".."\\u06E8" | "\\u06EA".."\\u06ED" | "\\u0901".."\\u0902" | "\\u093C".."\\u093C" | "\\u0941".."\\u0948" | "\\u094D".."\\u094D" | "\\u0951".."\\u0954" | "\\u0962".."\\u0963" | "\\u0981".."\\u0981" | "\\u09BC".."\\u09BC" | "\\u09C1".."\\u09C4" | "\\u09CD".."\\u09CD" | "\\u09E2".."\\u09E3" | "\\u0A02".."\\u0A02" | "\\u0A3C".."\\u0A3C" | "\\u0A41".."\\u0A42" | "\\u0A47".."\\u0A48" | "\\u0A4B".."\\u0A4D" | "\\u0A70".."\\u0A71" | "\\u0A81".."\\u0A82" | "\\u0ABC".."\\u0ABC" | "\\u0AC1".."\\u0AC5" | "\\u0AC7".."\\u0AC8" | "\\u0ACD".."\\u0ACD" | "\\u0B01".."\\u0B01" | "\\u0B3C".."\\u0B3C" | "\\u0B3F".."\\u0B3F" | "\\u0B41".."\\u0B43" | "\\u0B4D".."\\u0B4D" | "\\u0B56".."\\u0B56" | "\\u0B82".."\\u0B82" | "\\u0BC0".."\\u0BC0" | "\\u0BCD".."\\u0BCD" | "\\u0C3E".."\\u0C40" | "\\u0C46".."\\u0C48" | "\\u0C4A".."\\u0C4D" | "\\u0C55".."\\u0C56" | "\\u0CBF".."\\u0CBF" | "\\u0CC6".."\\u0CC6" | "\\u0CCC".."\\u0CCD" | "\\u0D41".."\\u0D43" | "\\u0D4D".."\\u0D4D" | "\\u0E31".."\\u0E31" | "\\u0E34".."\\u0E3A" | "\\u0E47".."\\u0E4E" | "\\u0EB1".."\\u0EB1" | "\\u0EB4".."\\u0EB9" | "\\u0EBB".."\\u0EBC" | "\\u0EC8".."\\u0ECD" | "\\u0F18".."\\u0F19" | "\\u0F35".."\\u0F35" | "\\u0F37".."\\u0F37" | "\\u0F39".."\\u0F39" | "\\u0F71".."\\u0F7E" | "\\u0F80".."\\u0F84" | "\\u0F86".."\\u0F87" | "\\u0F90".."\\u0F95" | "\\u0F97".."\\u0F97" | "\\u0F99".."\\u0FAD" | "\\u0FB1".."\\u0FB7" | "\\u0FB9".."\\u0FB9" | "\\u20D0".."\\u20DC" | "\\u20E1".."\\u20E1" | "\\u302A".."\\u302F" | "\\u3099".."\\u309A" | "\\uFB1E".."\\uFB1E" | "\\uFE20".."\\uFE23"\n\n unicodeConnectorPunctuation = "\\u005F" | "\\u203F".."\\u2040" | "\\u30FB" | "\\uFE33".."\\uFE34" | "\\uFE4D".."\\uFE4F" | "\\uFF3F" | "\\uFF65"\n unicodeSpaceSeparator = "\\u2000".."\\u200B" | "\\u3000"\n\n}', + }, + 'JSImports', + null, + 'JSImports', + { + JSImports: ['define', { sourceInterval: [16, 40] }, null, [], ['star', { sourceInterval: [28, 40] }, [ + 'seq', + { sourceInterval: [29, 38] }, + ['app', { sourceInterval: [29, 33] }, 'Expr', []], + ['opt', { sourceInterval: [34, 38] }, ['terminal', { sourceInterval: [34, 37] }, ';']], + ]]], + Expr: ['define', { sourceInterval: [46, 115] }, null, [], [ + 'alt', + { sourceInterval: [58, 115] }, + ['app', { sourceInterval: [60, 67] }, 'comment', []], + ['app', { sourceInterval: [74, 87] }, 'stringLiteral', []], + ['app', { sourceInterval: [94, 104] }, 'ImportExpr', []], + ['app', { sourceInterval: [111, 115] }, 'Rest', []], + ]], + ImportExpr_From: ['define', { sourceInterval: [140, 188] }, null, [], [ + 'seq', + { sourceInterval: [140, 180] }, + ['terminal', { sourceInterval: [140, 148] }, 'import'], + ['app', { sourceInterval: [149, 160] }, 'ImportInner', []], + ['terminal', { sourceInterval: [161, 167] }, 'from'], + ['app', { sourceInterval: [168, 180] }, 'importSource', []], + ]], + ImportExpr_NoFrom: ['define', { sourceInterval: [195, 226] }, null, [], ['seq', { sourceInterval: [195, 216] }, [ + 'terminal', + { sourceInterval: [195, 203] }, + 'import', + ], ['app', { sourceInterval: [204, 216] }, 'importSource', []]]], + ImportExpr: ['define', { sourceInterval: [121, 226] }, null, [], ['alt', { sourceInterval: [138, 226] }, [ + 'app', + { sourceInterval: [140, 180] }, + 'ImportExpr_From', + [], + ], ['app', { sourceInterval: [195, 216] }, 'ImportExpr_NoFrom', []]]], + Rest: ['define', { sourceInterval: [232, 285] }, null, [], ['plus', { sourceInterval: [239, 285] }, ['seq', { + sourceInterval: [240, 283], + }, ['not', { sourceInterval: [240, 279] }, [ + 'alt', + { sourceInterval: [242, 278] }, + ['app', { sourceInterval: [242, 252] }, 'ImportExpr', []], + ['app', { sourceInterval: [255, 262] }, 'comment', []], + ['app', { sourceInterval: [265, 278] }, 'stringLiteral', []], + ]], ['app', { sourceInterval: [280, 283] }, 'any', []]]]], + ImportInner_Type: ['define', { sourceInterval: [312, 405] }, null, [], [ + 'seq', + { sourceInterval: [312, 386] }, + ['terminal', { sourceInterval: [313, 319] }, 'type'], + ['terminal', { sourceInterval: [320, 323] }, '{'], + ['app', { sourceInterval: [324, 376] }, 'NonemptyListOf', [[ + 'app', + { sourceInterval: [339, 370] }, + 'ImportExtendedSelectionTypeless', + [], + ], ['terminal', { sourceInterval: [372, 375] }, ',']]], + ['opt', { sourceInterval: [377, 381] }, ['terminal', { sourceInterval: [377, 380] }, ',']], + ['terminal', { sourceInterval: [382, 385] }, '}'], + ]], + ImportInner_Types: ['define', { sourceInterval: [412, 506] }, null, [], ['seq', { sourceInterval: [412, 476] }, [ + 'terminal', + { sourceInterval: [413, 416] }, + '{', + ], ['app', { sourceInterval: [417, 466] }, 'NonemptyListOf', [[ + 'app', + { sourceInterval: [432, 460] }, + 'ImportExtendedSelectionTypes', + [], + ], ['terminal', { sourceInterval: [462, 465] }, ',']]], ['opt', { sourceInterval: [467, 471] }, ['terminal', { + sourceInterval: [467, 470], + }, ',']], ['terminal', { sourceInterval: [472, 475] }, '}']]], + ImportInner_Extended: ['define', { sourceInterval: [513, 610] }, null, [], ['seq', { sourceInterval: [513, 572] }, [ + 'terminal', + { sourceInterval: [514, 517] }, + '{', + ], ['app', { sourceInterval: [518, 562] }, 'NonemptyListOf', [[ + 'app', + { sourceInterval: [533, 556] }, + 'ImportExtendedSelection', + [], + ], ['terminal', { sourceInterval: [558, 561] }, ',']]], ['opt', { sourceInterval: [563, 567] }, ['terminal', { + sourceInterval: [563, 566], + }, ',']], ['terminal', { sourceInterval: [568, 571] }, '}']]], + ImportInner_Mixed: ['define', { sourceInterval: [617, 711] }, null, [], ['seq', { sourceInterval: [617, 702] }, [ + 'app', + { sourceInterval: [618, 628] }, + 'identifier', + [], + ], ['opt', { sourceInterval: [629, 701] }, [ + 'seq', + { sourceInterval: [630, 699] }, + ['terminal', { sourceInterval: [630, 633] }, ','], + ['opt', { sourceInterval: [634, 641] }, ['terminal', { sourceInterval: [634, 640] }, 'type']], + ['terminal', { sourceInterval: [642, 645] }, '{'], + ['app', { sourceInterval: [646, 690] }, 'NonemptyListOf', [[ + 'app', + { sourceInterval: [661, 684] }, + 'ImportExtendedSelection', + [], + ], ['terminal', { sourceInterval: [686, 689] }, ',']]], + ['opt', { sourceInterval: [691, 695] }, ['terminal', { sourceInterval: [691, 694] }, ',']], + ['terminal', { sourceInterval: [696, 699] }, '}'], + ]]]], + ImportInner_All: ['define', { sourceInterval: [718, 810] }, null, [], ['seq', { sourceInterval: [718, 742] }, [ + 'terminal', + { sourceInterval: [719, 722] }, + '*', + ], ['opt', { sourceInterval: [723, 741] }, ['seq', { sourceInterval: [724, 739] }, ['terminal', { + sourceInterval: [724, 728], + }, 'as'], ['app', { sourceInterval: [729, 739] }, 'identifier', []]]]]], + ImportInner_Default: ['define', { sourceInterval: [817, 913] }, null, [], ['seq', { sourceInterval: [817, 848] }, [ + 'app', + { sourceInterval: [818, 828] }, + 'identifier', + [], + ], ['opt', { sourceInterval: [829, 847] }, ['seq', { sourceInterval: [830, 845] }, ['terminal', { + sourceInterval: [830, 834], + }, 'as'], ['app', { sourceInterval: [835, 845] }, 'identifier', []]]]]], + ImportInner: ['define', { sourceInterval: [291, 913] }, null, [], [ + 'alt', + { sourceInterval: [310, 913] }, + ['app', { sourceInterval: [312, 386] }, 'ImportInner_Type', []], + ['app', { sourceInterval: [412, 476] }, 'ImportInner_Types', []], + ['app', { sourceInterval: [513, 572] }, 'ImportInner_Extended', []], + ['app', { sourceInterval: [617, 702] }, 'ImportInner_Mixed', []], + ['app', { sourceInterval: [718, 742] }, 'ImportInner_All', []], + ['app', { sourceInterval: [817, 848] }, 'ImportInner_Default', []], + ]], + ImportExtendedSelection: ['define', { sourceInterval: [924, 969] }, null, [], [ + 'alt', + { sourceInterval: [950, 969] }, + ['app', { sourceInterval: [950, 960] }, 'TypeImport', []], + ['app', { sourceInterval: [963, 969] }, 'Import', []], + ]], + ImportExtendedSelectionTypes: ['define', { sourceInterval: [974, 1015] }, null, [], [ + 'app', + { sourceInterval: [1005, 1015] }, + 'TypeImport', + [], + ]], + ImportExtendedSelectionTypeless: ['define', { sourceInterval: [1020, 1060] }, null, [], [ + 'app', + { sourceInterval: [1054, 1060] }, + 'Import', + [], + ]], + Import: ['define', { sourceInterval: [1066, 1104] }, null, [], ['seq', { sourceInterval: [1075, 1104] }, [ + 'app', + { sourceInterval: [1075, 1085] }, + 'identifier', + [], + ], ['opt', { sourceInterval: [1086, 1104] }, ['seq', { sourceInterval: [1087, 1102] }, ['terminal', { + sourceInterval: [1087, 1091], + }, 'as'], ['app', { sourceInterval: [1092, 1102] }, 'identifier', []]]]]], + TypeImport: ['define', { sourceInterval: [1109, 1154] }, null, [], [ + 'seq', + { sourceInterval: [1122, 1154] }, + ['terminal', { sourceInterval: [1122, 1128] }, 'type'], + ['app', { sourceInterval: [1129, 1135] }, 'Import', []], + ['opt', { sourceInterval: [1136, 1154] }, ['seq', { sourceInterval: [1137, 1152] }, ['terminal', { + sourceInterval: [1137, 1141], + }, 'as'], ['app', { sourceInterval: [1142, 1152] }, 'identifier', []]]], + ]], + identifier: ['define', { sourceInterval: [1160, 1186] }, null, [], ['seq', { sourceInterval: [1173, 1186] }, [ + 'app', + { sourceInterval: [1173, 1179] }, + 'letter', + [], + ], ['star', { sourceInterval: [1180, 1186] }, ['app', { sourceInterval: [1180, 1185] }, 'alnum', []]]]], + quote: ['define', { sourceInterval: [1191, 1215] }, null, [], [ + 'alt', + { sourceInterval: [1199, 1215] }, + ['terminal', { sourceInterval: [1199, 1203] }, '"'], + ['terminal', { sourceInterval: [1206, 1209] }, "'"], + ['terminal', { sourceInterval: [1212, 1215] }, '`'], + ]], + notQuote: ['define', { sourceInterval: [1220, 1241] }, null, [], ['seq', { sourceInterval: [1231, 1241] }, ['not', { + sourceInterval: [1231, 1237], + }, ['app', { sourceInterval: [1232, 1237] }, 'quote', []]], ['app', { sourceInterval: [1238, 1241] }, 'any', []]]], + importSource: ['define', { sourceInterval: [1246, 1334] }, null, [], [ + 'alt', + { sourceInterval: [1265, 1334] }, + ['seq', { sourceInterval: [1267, 1286] }, ['terminal', { sourceInterval: [1267, 1271] }, '"'], ['plus', { + sourceInterval: [1272, 1281], + }, ['app', { sourceInterval: [1272, 1280] }, 'notQuote', []]], [ + 'terminal', + { sourceInterval: [1282, 1286] }, + '"', + ]], + ['seq', { sourceInterval: [1293, 1310] }, ['terminal', { sourceInterval: [1293, 1296] }, "'"], ['plus', { + sourceInterval: [1297, 1306], + }, ['app', { sourceInterval: [1297, 1305] }, 'notQuote', []]], [ + 'terminal', + { sourceInterval: [1307, 1310] }, + "'", + ]], + ['seq', { sourceInterval: [1317, 1334] }, ['terminal', { sourceInterval: [1317, 1320] }, '`'], ['plus', { + sourceInterval: [1321, 1330], + }, ['app', { sourceInterval: [1321, 1329] }, 'notQuote', []]], [ + 'terminal', + { sourceInterval: [1331, 1334] }, + '`', + ]], + ]], + lineTerminator: ['define', { sourceInterval: [1340, 1390] }, null, [], [ + 'alt', + { sourceInterval: [1357, 1390] }, + ['terminal', { sourceInterval: [1357, 1361] }, '\n'], + ['terminal', { sourceInterval: [1364, 1368] }, '\r'], + ['terminal', { sourceInterval: [1371, 1379] }, '\u2028'], + ['terminal', { sourceInterval: [1382, 1390] }, '\u2029'], + ]], + lineTerminatorSequence: ['define', { sourceInterval: [1395, 1468] }, null, [], [ + 'alt', + { sourceInterval: [1420, 1468] }, + ['terminal', { sourceInterval: [1420, 1424] }, '\n'], + ['seq', { sourceInterval: [1427, 1437] }, ['terminal', { sourceInterval: [1427, 1431] }, '\r'], ['not', { + sourceInterval: [1432, 1437], + }, ['terminal', { sourceInterval: [1433, 1437] }, '\n']]], + ['terminal', { sourceInterval: [1440, 1448] }, '\u2028'], + ['terminal', { sourceInterval: [1451, 1459] }, '\u2029'], + ['terminal', { sourceInterval: [1462, 1468] }, '\r\n'], + ]], + comment: ['define', { sourceInterval: [1478, 1524] }, null, [], ['alt', { sourceInterval: [1488, 1524] }, [ + 'app', + { sourceInterval: [1488, 1504] }, + 'multiLineComment', + [], + ], ['app', { sourceInterval: [1507, 1524] }, 'singleLineComment', []]]], + multiLineComment: ['define', { sourceInterval: [1530, 1571] }, null, [], ['seq', { sourceInterval: [1549, 1571] }, [ + 'terminal', + { sourceInterval: [1549, 1553] }, + '/*', + ], ['star', { sourceInterval: [1554, 1566] }, ['seq', { sourceInterval: [1555, 1564] }, ['not', { + sourceInterval: [1555, 1560], + }, ['terminal', { sourceInterval: [1556, 1560] }, '*/']], ['app', { sourceInterval: [1561, 1564] }, 'any', []]]], [ + 'terminal', + { sourceInterval: [1567, 1571] }, + '*/', + ]]], + singleLineComment: ['define', { sourceInterval: [1576, 1623] }, null, [], [ + 'seq', + { sourceInterval: [1596, 1623] }, + ['terminal', { sourceInterval: [1596, 1600] }, '//'], + ['star', { sourceInterval: [1601, 1623] }, ['seq', { sourceInterval: [1602, 1621] }, ['not', { + sourceInterval: [1602, 1617], + }, ['app', { sourceInterval: [1603, 1617] }, 'lineTerminator', []]], [ + 'app', + { sourceInterval: [1618, 1621] }, + 'any', + [], + ]]], + ]], + stringLiteral: ['define', { sourceInterval: [1629, 1759] }, null, [], ['alt', { sourceInterval: [1649, 1759] }, [ + 'seq', + { sourceInterval: [1651, 1683] }, + ['terminal', { sourceInterval: [1651, 1655] }, '"'], + ['star', { sourceInterval: [1656, 1678] }, [ + 'app', + { sourceInterval: [1656, 1677] }, + 'doubleStringCharacter', + [], + ]], + ['terminal', { sourceInterval: [1679, 1683] }, '"'], + ], ['seq', { sourceInterval: [1690, 1720] }, ['terminal', { sourceInterval: [1690, 1693] }, "'"], ['star', { + sourceInterval: [1694, 1716], + }, ['app', { sourceInterval: [1694, 1715] }, 'singleStringCharacter', []]], ['terminal', { + sourceInterval: [1717, 1720], + }, "'"]], ['seq', { sourceInterval: [1727, 1759] }, ['terminal', { sourceInterval: [1727, 1730] }, '`'], ['star', { + sourceInterval: [1731, 1755], + }, ['app', { sourceInterval: [1731, 1754] }, 'templateStringCharacter', []]], ['terminal', { + sourceInterval: [1756, 1759], + }, '`']]]], + doubleStringCharacter_NonEscaped: ['define', { sourceInterval: [1794, 1845] }, null, [], ['seq', { + sourceInterval: [1794, 1829], + }, ['not', { sourceInterval: [1794, 1825] }, [ + 'alt', + { sourceInterval: [1796, 1824] }, + ['terminal', { sourceInterval: [1796, 1800] }, '"'], + ['terminal', { sourceInterval: [1803, 1807] }, '\\'], + ['app', { sourceInterval: [1810, 1824] }, 'lineTerminator', []], + ]], ['app', { sourceInterval: [1826, 1829] }, 'any', []]]], + doubleStringCharacter_Escaped: ['define', { sourceInterval: [1852, 1900] }, null, [], [ + 'seq', + { sourceInterval: [1852, 1871] }, + ['terminal', { sourceInterval: [1852, 1856] }, '\\'], + ['app', { sourceInterval: [1857, 1871] }, 'escapeSequence', []], + ]], + doubleStringCharacter_LineContinuation: ['define', { sourceInterval: [1907, 1964] }, null, [], [ + 'app', + { sourceInterval: [1907, 1923] }, + 'lineContinuation', + [], + ]], + doubleStringCharacter: ['define', { sourceInterval: [1764, 1964] }, null, [], [ + 'alt', + { sourceInterval: [1792, 1964] }, + ['app', { sourceInterval: [1794, 1829] }, 'doubleStringCharacter_NonEscaped', []], + ['app', { sourceInterval: [1852, 1871] }, 'doubleStringCharacter_Escaped', []], + ['app', { sourceInterval: [1907, 1923] }, 'doubleStringCharacter_LineContinuation', []], + ]], + singleStringCharacter_NonEscaped: ['define', { sourceInterval: [1999, 2050] }, null, [], ['seq', { + sourceInterval: [1999, 2033], + }, ['not', { sourceInterval: [1999, 2029] }, [ + 'alt', + { sourceInterval: [2001, 2028] }, + ['terminal', { sourceInterval: [2001, 2004] }, "'"], + ['terminal', { sourceInterval: [2007, 2011] }, '\\'], + ['app', { sourceInterval: [2014, 2028] }, 'lineTerminator', []], + ]], ['app', { sourceInterval: [2030, 2033] }, 'any', []]]], + singleStringCharacter_Escaped: ['define', { sourceInterval: [2057, 2105] }, null, [], [ + 'seq', + { sourceInterval: [2057, 2076] }, + ['terminal', { sourceInterval: [2057, 2061] }, '\\'], + ['app', { sourceInterval: [2062, 2076] }, 'escapeSequence', []], + ]], + singleStringCharacter_LineContinuation: ['define', { sourceInterval: [2112, 2169] }, null, [], [ + 'app', + { sourceInterval: [2112, 2128] }, + 'lineContinuation', + [], + ]], + singleStringCharacter: ['define', { sourceInterval: [1969, 2169] }, null, [], [ + 'alt', + { sourceInterval: [1997, 2169] }, + ['app', { sourceInterval: [1999, 2033] }, 'singleStringCharacter_NonEscaped', []], + ['app', { sourceInterval: [2057, 2076] }, 'singleStringCharacter_Escaped', []], + ['app', { sourceInterval: [2112, 2128] }, 'singleStringCharacter_LineContinuation', []], + ]], + templateStringCharacter_NonEscaped: ['define', { sourceInterval: [2207, 2258] }, null, [], ['seq', { + sourceInterval: [2207, 2225], + }, ['not', { sourceInterval: [2207, 2221] }, ['alt', { sourceInterval: [2210, 2220] }, ['terminal', { + sourceInterval: [2210, 2213], + }, '`'], ['terminal', { sourceInterval: [2216, 2220] }, '\\']]], [ + 'app', + { sourceInterval: [2222, 2225] }, + 'any', + [], + ]]], + templateStringCharacter_Escaped: ['define', { sourceInterval: [2265, 2318] }, null, [], [ + 'seq', + { sourceInterval: [2265, 2284] }, + ['terminal', { sourceInterval: [2265, 2269] }, '\\'], + ['app', { sourceInterval: [2270, 2284] }, 'escapeSequence', []], + ]], + templateStringCharacter: ['define', { sourceInterval: [2174, 2318] }, null, [], [ + 'alt', + { sourceInterval: [2205, 2318] }, + ['app', { sourceInterval: [2207, 2225] }, 'templateStringCharacter_NonEscaped', []], + ['app', { sourceInterval: [2265, 2284] }, 'templateStringCharacter_Escaped', []], + ]], + lineContinuation: ['define', { sourceInterval: [2323, 2369] }, null, [], ['seq', { sourceInterval: [2342, 2369] }, [ + 'terminal', + { sourceInterval: [2342, 2346] }, + '\\', + ], ['app', { sourceInterval: [2347, 2369] }, 'lineTerminatorSequence', []]]], + escapeSequence: ['define', { sourceInterval: [2374, 2480] }, null, [], [ + 'alt', + { sourceInterval: [2391, 2480] }, + ['app', { sourceInterval: [2391, 2412] }, 'unicodeEscapeSequence', []], + ['app', { sourceInterval: [2415, 2432] }, 'hexEscapeSequence', []], + ['app', { sourceInterval: [2435, 2454] }, 'octalEscapeSequence', []], + ['app', { sourceInterval: [2457, 2480] }, 'characterEscapeSequence', []], + ]], + characterEscapeSequence: ['define', { sourceInterval: [2485, 2553] }, null, [], [ + 'alt', + { sourceInterval: [2511, 2553] }, + ['app', { sourceInterval: [2511, 2532] }, 'singleEscapeCharacter', []], + ['app', { sourceInterval: [2535, 2553] }, 'nonEscapeCharacter', []], + ]], + singleEscapeCharacter: ['define', { sourceInterval: [2558, 2635] }, null, [], [ + 'alt', + { sourceInterval: [2582, 2635] }, + ['terminal', { sourceInterval: [2582, 2585] }, "'"], + ['terminal', { sourceInterval: [2588, 2592] }, '"'], + ['terminal', { sourceInterval: [2595, 2599] }, '\\'], + ['terminal', { sourceInterval: [2602, 2605] }, 'b'], + ['terminal', { sourceInterval: [2608, 2611] }, 'f'], + ['terminal', { sourceInterval: [2614, 2617] }, 'n'], + ['terminal', { sourceInterval: [2620, 2623] }, 'r'], + ['terminal', { sourceInterval: [2626, 2629] }, 't'], + ['terminal', { sourceInterval: [2632, 2635] }, 'v'], + ]], + nonEscapeCharacter: ['define', { sourceInterval: [2640, 2700] }, null, [], [ + 'seq', + { sourceInterval: [2661, 2700] }, + ['not', { sourceInterval: [2661, 2696] }, ['alt', { sourceInterval: [2663, 2695] }, [ + 'app', + { sourceInterval: [2663, 2678] }, + 'escapeCharacter', + [], + ], ['app', { sourceInterval: [2681, 2695] }, 'lineTerminator', []]]], + ['app', { sourceInterval: [2697, 2700] }, 'any', []], + ]], + escapeCharacter: ['define', { sourceInterval: [2705, 2771] }, null, [], [ + 'alt', + { sourceInterval: [2723, 2771] }, + ['app', { sourceInterval: [2723, 2744] }, 'singleEscapeCharacter', []], + ['app', { sourceInterval: [2747, 2759] }, 'decimalDigit', []], + ['terminal', { sourceInterval: [2762, 2765] }, 'x'], + ['terminal', { sourceInterval: [2768, 2771] }, 'u'], + ]], + octalEscapeSequence_Whole: ['define', { sourceInterval: [2804, 2850] }, null, [], [ + 'seq', + { sourceInterval: [2804, 2837] }, + ['app', { sourceInterval: [2804, 2815] }, 'zeroToThree', []], + ['app', { sourceInterval: [2816, 2826] }, 'octalDigit', []], + ['app', { sourceInterval: [2827, 2837] }, 'octalDigit', []], + ]], + octalEscapeSequence_EightTimesfourToSeven: ['define', { sourceInterval: [2857, 2919] }, null, [], [ + 'seq', + { sourceInterval: [2857, 2879] }, + ['app', { sourceInterval: [2857, 2868] }, 'fourToSeven', []], + ['app', { sourceInterval: [2869, 2879] }, 'octalDigit', []], + ]], + octalEscapeSequence_EightTimesZeroToThree: ['define', { sourceInterval: [2926, 2988] }, null, [], [ + 'seq', + { sourceInterval: [2926, 2962] }, + ['app', { sourceInterval: [2926, 2937] }, 'zeroToThree', []], + ['app', { sourceInterval: [2938, 2948] }, 'octalDigit', []], + ['not', { sourceInterval: [2949, 2962] }, ['app', { sourceInterval: [2950, 2962] }, 'decimalDigit', []]], + ]], + octalEscapeSequence_Octal: ['define', { sourceInterval: [2995, 3041] }, null, [], [ + 'seq', + { sourceInterval: [2995, 3019] }, + ['app', { sourceInterval: [2995, 3005] }, 'octalDigit', []], + ['not', { sourceInterval: [3006, 3019] }, ['app', { sourceInterval: [3007, 3019] }, 'decimalDigit', []]], + ]], + octalEscapeSequence: ['define', { sourceInterval: [2776, 3041] }, null, [], [ + 'alt', + { sourceInterval: [2802, 3041] }, + ['app', { sourceInterval: [2804, 2837] }, 'octalEscapeSequence_Whole', []], + ['app', { sourceInterval: [2857, 2879] }, 'octalEscapeSequence_EightTimesfourToSeven', []], + ['app', { sourceInterval: [2926, 2962] }, 'octalEscapeSequence_EightTimesZeroToThree', []], + ['app', { sourceInterval: [2995, 3019] }, 'octalEscapeSequence_Octal', []], + ]], + hexEscapeSequence: ['define', { sourceInterval: [3046, 3087] }, null, [], [ + 'seq', + { sourceInterval: [3066, 3087] }, + ['terminal', { sourceInterval: [3066, 3069] }, 'x'], + ['app', { sourceInterval: [3070, 3078] }, 'hexDigit', []], + ['app', { sourceInterval: [3079, 3087] }, 'hexDigit', []], + ]], + unicodeEscapeSequence: ['define', { sourceInterval: [3092, 3155] }, null, [], [ + 'seq', + { sourceInterval: [3116, 3155] }, + ['terminal', { sourceInterval: [3116, 3119] }, 'u'], + ['app', { sourceInterval: [3120, 3128] }, 'hexDigit', []], + ['app', { sourceInterval: [3129, 3137] }, 'hexDigit', []], + ['app', { sourceInterval: [3138, 3146] }, 'hexDigit', []], + ['app', { sourceInterval: [3147, 3155] }, 'hexDigit', []], + ]], + zeroToThree: ['define', { sourceInterval: [3161, 3183] }, null, [], [ + 'range', + { sourceInterval: [3175, 3183] }, + '0', + '3', + ]], + fourToSeven: ['define', { sourceInterval: [3188, 3210] }, null, [], [ + 'range', + { sourceInterval: [3202, 3210] }, + '4', + '7', + ]], + decimalDigit: ['define', { sourceInterval: [3215, 3238] }, null, [], [ + 'range', + { sourceInterval: [3230, 3238] }, + '0', + '9', + ]], + nonZeroDigit: ['define', { sourceInterval: [3243, 3266] }, null, [], [ + 'range', + { sourceInterval: [3258, 3266] }, + '1', + '9', + ]], + octalDigit: ['define', { sourceInterval: [3271, 3292] }, null, [], [ + 'range', + { sourceInterval: [3284, 3292] }, + '0', + '7', + ]], + regularExpressionLiteral: ['define', { sourceInterval: [3298, 3377] }, null, [], [ + 'seq', + { sourceInterval: [3325, 3377] }, + ['terminal', { sourceInterval: [3325, 3328] }, '/'], + ['app', { sourceInterval: [3329, 3350] }, 'regularExpressionBody', []], + ['terminal', { sourceInterval: [3351, 3354] }, '/'], + ['app', { sourceInterval: [3355, 3377] }, 'regularExpressionFlags', []], + ]], + regularExpressionBody: ['define', { sourceInterval: [3382, 3455] }, null, [], [ + 'seq', + { sourceInterval: [3406, 3455] }, + ['app', { sourceInterval: [3406, 3432] }, 'regularExpressionFirstChar', []], + ['star', { sourceInterval: [3433, 3455] }, [ + 'app', + { sourceInterval: [3433, 3454] }, + 'regularExpressionChar', + [], + ]], + ]], + regularExpressionFirstChar: ['define', { sourceInterval: [3460, 3621] }, null, [], ['alt', { + sourceInterval: [3493, 3621], + }, ['seq', { sourceInterval: [3495, 3551] }, ['not', { sourceInterval: [3495, 3520] }, [ + 'alt', + { sourceInterval: [3497, 3519] }, + ['terminal', { sourceInterval: [3497, 3500] }, '*'], + ['terminal', { sourceInterval: [3503, 3507] }, '\\'], + ['terminal', { sourceInterval: [3510, 3513] }, '/'], + ['terminal', { sourceInterval: [3516, 3519] }, '['], + ]], ['app', { sourceInterval: [3521, 3551] }, 'regularExpressionNonTerminator', []]], [ + 'app', + { sourceInterval: [3558, 3592] }, + 'regularExpressionBackslashSequence', + [], + ], ['app', { sourceInterval: [3599, 3621] }, 'regularExpressionClass', []]]], + regularExpressionChar: ['define', { sourceInterval: [3626, 3770] }, null, [], ['alt', { + sourceInterval: [3650, 3770], + }, ['seq', { sourceInterval: [3650, 3700] }, ['not', { sourceInterval: [3650, 3669] }, [ + 'alt', + { sourceInterval: [3652, 3668] }, + ['terminal', { sourceInterval: [3652, 3656] }, '\\'], + ['terminal', { sourceInterval: [3659, 3662] }, '/'], + ['terminal', { sourceInterval: [3665, 3668] }, '['], + ]], ['app', { sourceInterval: [3670, 3700] }, 'regularExpressionNonTerminator', []]], [ + 'app', + { sourceInterval: [3707, 3741] }, + 'regularExpressionBackslashSequence', + [], + ], ['app', { sourceInterval: [3748, 3770] }, 'regularExpressionClass', []]]], + regularExpressionBackslashSequence: ['define', { sourceInterval: [3775, 3847] }, null, [], [ + 'seq', + { sourceInterval: [3812, 3847] }, + ['terminal', { sourceInterval: [3812, 3816] }, '\\'], + ['app', { sourceInterval: [3817, 3847] }, 'regularExpressionNonTerminator', []], + ]], + regularExpressionNonTerminator: ['define', { sourceInterval: [3852, 3906] }, null, [], [ + 'seq', + { sourceInterval: [3885, 3906] }, + ['not', { sourceInterval: [3885, 3902] }, ['app', { sourceInterval: [3887, 3901] }, 'lineTerminator', []]], + ['app', { sourceInterval: [3903, 3906] }, 'any', []], + ]], + regularExpressionClass: ['define', { sourceInterval: [3911, 3971] }, null, [], [ + 'seq', + { sourceInterval: [3936, 3971] }, + ['terminal', { sourceInterval: [3936, 3939] }, '['], + ['star', { sourceInterval: [3940, 3967] }, [ + 'app', + { sourceInterval: [3940, 3966] }, + 'regularExpressionClassChar', + [], + ]], + ['terminal', { sourceInterval: [3968, 3971] }, ']'], + ]], + regularExpressionClassChar: ['define', { sourceInterval: [3976, 4096] }, null, [], ['alt', { + sourceInterval: [4009, 4096], + }, ['seq', { sourceInterval: [4011, 4055] }, ['not', { sourceInterval: [4011, 4024] }, [ + 'alt', + { sourceInterval: [4013, 4023] }, + ['terminal', { sourceInterval: [4013, 4016] }, ']'], + ['terminal', { sourceInterval: [4019, 4023] }, '\\'], + ]], ['app', { sourceInterval: [4025, 4055] }, 'regularExpressionNonTerminator', []]], [ + 'app', + { sourceInterval: [4062, 4096] }, + 'regularExpressionBackslashSequence', + [], + ]]], + regularExpressionFlags: ['define', { sourceInterval: [4101, 4141] }, null, [], ['star', { + sourceInterval: [4126, 4141], + }, ['app', { sourceInterval: [4126, 4140] }, 'identifierPart', []]]], + multiLineCommentNoNL: ['define', { sourceInterval: [4147, 4211] }, null, [], [ + 'seq', + { sourceInterval: [4170, 4211] }, + ['terminal', { sourceInterval: [4170, 4174] }, '/*'], + ['star', { sourceInterval: [4175, 4206] }, ['seq', { sourceInterval: [4176, 4204] }, ['not', { + sourceInterval: [4176, 4200], + }, ['alt', { sourceInterval: [4178, 4199] }, ['terminal', { sourceInterval: [4178, 4182] }, '*/'], [ + 'app', + { sourceInterval: [4185, 4199] }, + 'lineTerminator', + [], + ]]], ['app', { sourceInterval: [4201, 4204] }, 'any', []]]], + ['terminal', { sourceInterval: [4207, 4211] }, '*/'], + ]], + identifierStart_escaped: ['define', { sourceInterval: [4266, 4303] }, null, [], [ + 'seq', + { sourceInterval: [4266, 4292] }, + ['terminal', { sourceInterval: [4266, 4270] }, '\\'], + ['app', { sourceInterval: [4271, 4292] }, 'unicodeEscapeSequence', []], + ]], + identifierStart: ['define', { sourceInterval: [4217, 4303] }, null, [], [ + 'alt', + { sourceInterval: [4239, 4303] }, + ['app', { sourceInterval: [4241, 4247] }, 'letter', []], + ['terminal', { sourceInterval: [4250, 4253] }, '$'], + ['terminal', { sourceInterval: [4256, 4259] }, '_'], + ['app', { sourceInterval: [4266, 4292] }, 'identifierStart_escaped', []], + ]], + identifierPart: ['define', { sourceInterval: [4308, 4444] }, null, [], [ + 'alt', + { sourceInterval: [4329, 4444] }, + ['app', { sourceInterval: [4331, 4346] }, 'identifierStart', []], + ['app', { sourceInterval: [4349, 4369] }, 'unicodeCombiningMark', []], + ['app', { sourceInterval: [4376, 4388] }, 'unicodeDigit', []], + ['app', { sourceInterval: [4391, 4418] }, 'unicodeConnectorPunctuation', []], + ['terminal', { sourceInterval: [4425, 4433] }, '‌'], + ['terminal', { sourceInterval: [4436, 4444] }, '‍'], + ]], + letter: ['extend', { sourceInterval: [4449, 4476] }, null, [], [ + 'app', + { sourceInterval: [4459, 4476] }, + 'unicodeCategoryNl', + [], + ]], + unicodeCategoryNl: ['define', { sourceInterval: [4481, 4555] }, null, [], [ + 'alt', + { sourceInterval: [4505, 4555] }, + ['range', { sourceInterval: [4505, 4523] }, 'Ⅰ', 'ↂ'], + ['terminal', { sourceInterval: [4526, 4534] }, '〇'], + ['range', { sourceInterval: [4537, 4555] }, '〡', '〩'], + ]], + unicodeDigit: ['define', { sourceInterval: [4560, 4922] }, 'a digit', [], [ + 'alt', + { sourceInterval: [4589, 4922] }, + ['range', { sourceInterval: [4589, 4607] }, '0', '9'], + ['range', { sourceInterval: [4610, 4628] }, '٠', '٩'], + ['range', { sourceInterval: [4631, 4649] }, '۰', '۹'], + ['range', { sourceInterval: [4652, 4670] }, '०', '९'], + ['range', { sourceInterval: [4673, 4691] }, '০', '৯'], + ['range', { sourceInterval: [4694, 4712] }, '੦', '੯'], + ['range', { sourceInterval: [4715, 4733] }, '૦', '૯'], + ['range', { sourceInterval: [4736, 4754] }, '୦', '୯'], + ['range', { sourceInterval: [4757, 4775] }, '௧', '௯'], + ['range', { sourceInterval: [4778, 4796] }, '౦', '౯'], + ['range', { sourceInterval: [4799, 4817] }, '೦', '೯'], + ['range', { sourceInterval: [4820, 4838] }, '൦', '൯'], + ['range', { sourceInterval: [4841, 4859] }, '๐', '๙'], + ['range', { sourceInterval: [4862, 4880] }, '໐', '໙'], + ['range', { sourceInterval: [4883, 4901] }, '༠', '༩'], + ['range', { sourceInterval: [4904, 4922] }, '0', '9'], + ]], + unicodeCombiningMark: ['define', { sourceInterval: [4928, 6659] }, 'a Unicode combining mark', [], [ + 'alt', + { sourceInterval: [4982, 6659] }, + ['range', { sourceInterval: [4982, 5000] }, '̀', 'ͅ'], + ['range', { sourceInterval: [5003, 5021] }, '͠', '͡'], + ['range', { sourceInterval: [5024, 5042] }, '҃', '҆'], + ['range', { sourceInterval: [5045, 5063] }, '֑', '֡'], + ['range', { sourceInterval: [5066, 5084] }, '֣', 'ֹ'], + ['range', { sourceInterval: [5087, 5105] }, 'ֻ', 'ֽ'], + ['range', { sourceInterval: [5108, 5126] }, 'ֿ', 'ֿ'], + ['range', { sourceInterval: [5129, 5147] }, 'ׁ', 'ׂ'], + ['range', { sourceInterval: [5150, 5168] }, 'ׄ', 'ׄ'], + ['range', { sourceInterval: [5171, 5189] }, 'ً', 'ْ'], + ['range', { sourceInterval: [5192, 5210] }, 'ٰ', 'ٰ'], + ['range', { sourceInterval: [5213, 5231] }, 'ۖ', 'ۜ'], + ['range', { sourceInterval: [5234, 5252] }, '۟', 'ۤ'], + ['range', { sourceInterval: [5255, 5273] }, 'ۧ', 'ۨ'], + ['range', { sourceInterval: [5276, 5294] }, '۪', 'ۭ'], + ['range', { sourceInterval: [5297, 5315] }, 'ँ', 'ं'], + ['range', { sourceInterval: [5318, 5336] }, '़', '़'], + ['range', { sourceInterval: [5339, 5357] }, 'ु', 'ै'], + ['range', { sourceInterval: [5360, 5378] }, '्', '्'], + ['range', { sourceInterval: [5381, 5399] }, '॑', '॔'], + ['range', { sourceInterval: [5402, 5420] }, 'ॢ', 'ॣ'], + ['range', { sourceInterval: [5423, 5441] }, 'ঁ', 'ঁ'], + ['range', { sourceInterval: [5444, 5462] }, '়', '়'], + ['range', { sourceInterval: [5465, 5483] }, 'ু', 'ৄ'], + ['range', { sourceInterval: [5486, 5504] }, '্', '্'], + ['range', { sourceInterval: [5507, 5525] }, 'ৢ', 'ৣ'], + ['range', { sourceInterval: [5528, 5546] }, 'ਂ', 'ਂ'], + ['range', { sourceInterval: [5549, 5567] }, '਼', '਼'], + ['range', { sourceInterval: [5570, 5588] }, 'ੁ', 'ੂ'], + ['range', { sourceInterval: [5591, 5609] }, 'ੇ', 'ੈ'], + ['range', { sourceInterval: [5612, 5630] }, 'ੋ', '੍'], + ['range', { sourceInterval: [5633, 5651] }, 'ੰ', 'ੱ'], + ['range', { sourceInterval: [5654, 5672] }, 'ઁ', 'ં'], + ['range', { sourceInterval: [5675, 5693] }, '઼', '઼'], + ['range', { sourceInterval: [5696, 5714] }, 'ુ', 'ૅ'], + ['range', { sourceInterval: [5717, 5735] }, 'ે', 'ૈ'], + ['range', { sourceInterval: [5738, 5756] }, '્', '્'], + ['range', { sourceInterval: [5759, 5777] }, 'ଁ', 'ଁ'], + ['range', { sourceInterval: [5780, 5798] }, '଼', '଼'], + ['range', { sourceInterval: [5801, 5819] }, 'ି', 'ି'], + ['range', { sourceInterval: [5822, 5840] }, 'ୁ', 'ୃ'], + ['range', { sourceInterval: [5843, 5861] }, '୍', '୍'], + ['range', { sourceInterval: [5864, 5882] }, 'ୖ', 'ୖ'], + ['range', { sourceInterval: [5885, 5903] }, 'ஂ', 'ஂ'], + ['range', { sourceInterval: [5906, 5924] }, 'ீ', 'ீ'], + ['range', { sourceInterval: [5927, 5945] }, '்', '்'], + ['range', { sourceInterval: [5948, 5966] }, 'ా', 'ీ'], + ['range', { sourceInterval: [5969, 5987] }, 'ె', 'ై'], + ['range', { sourceInterval: [5990, 6008] }, 'ొ', '్'], + ['range', { sourceInterval: [6011, 6029] }, 'ౕ', 'ౖ'], + ['range', { sourceInterval: [6032, 6050] }, 'ಿ', 'ಿ'], + ['range', { sourceInterval: [6053, 6071] }, 'ೆ', 'ೆ'], + ['range', { sourceInterval: [6074, 6092] }, 'ೌ', '್'], + ['range', { sourceInterval: [6095, 6113] }, 'ു', 'ൃ'], + ['range', { sourceInterval: [6116, 6134] }, '്', '്'], + ['range', { sourceInterval: [6137, 6155] }, 'ั', 'ั'], + ['range', { sourceInterval: [6158, 6176] }, 'ิ', 'ฺ'], + ['range', { sourceInterval: [6179, 6197] }, '็', '๎'], + ['range', { sourceInterval: [6200, 6218] }, 'ັ', 'ັ'], + ['range', { sourceInterval: [6221, 6239] }, 'ິ', 'ູ'], + ['range', { sourceInterval: [6242, 6260] }, 'ົ', 'ຼ'], + ['range', { sourceInterval: [6263, 6281] }, '່', 'ໍ'], + ['range', { sourceInterval: [6284, 6302] }, '༘', '༙'], + ['range', { sourceInterval: [6305, 6323] }, '༵', '༵'], + ['range', { sourceInterval: [6326, 6344] }, '༷', '༷'], + ['range', { sourceInterval: [6347, 6365] }, '༹', '༹'], + ['range', { sourceInterval: [6368, 6386] }, 'ཱ', 'ཾ'], + ['range', { sourceInterval: [6389, 6407] }, 'ྀ', '྄'], + ['range', { sourceInterval: [6410, 6428] }, '྆', '྇'], + ['range', { sourceInterval: [6431, 6449] }, 'ྐ', 'ྕ'], + ['range', { sourceInterval: [6452, 6470] }, 'ྗ', 'ྗ'], + ['range', { sourceInterval: [6473, 6491] }, 'ྙ', 'ྭ'], + ['range', { sourceInterval: [6494, 6512] }, 'ྱ', 'ྷ'], + ['range', { sourceInterval: [6515, 6533] }, 'ྐྵ', 'ྐྵ'], + ['range', { sourceInterval: [6536, 6554] }, '⃐', '⃜'], + ['range', { sourceInterval: [6557, 6575] }, '⃡', '⃡'], + ['range', { sourceInterval: [6578, 6596] }, '〪', '〯'], + ['range', { sourceInterval: [6599, 6617] }, '゙', '゚'], + ['range', { sourceInterval: [6620, 6638] }, 'ﬞ', 'ﬞ'], + ['range', { sourceInterval: [6641, 6659] }, '︠', '︣'], + ]], + unicodeConnectorPunctuation: ['define', { sourceInterval: [6665, 6799] }, null, [], [ + 'alt', + { sourceInterval: [6695, 6799] }, + ['terminal', { sourceInterval: [6695, 6703] }, '_'], + ['range', { sourceInterval: [6706, 6724] }, '‿', '⁀'], + ['terminal', { sourceInterval: [6727, 6735] }, '・'], + ['range', { sourceInterval: [6738, 6756] }, '︳', '︴'], + ['range', { sourceInterval: [6759, 6777] }, '﹍', '﹏'], + ['terminal', { sourceInterval: [6780, 6788] }, '_'], + ['terminal', { sourceInterval: [6791, 6799] }, '・'], + ]], + unicodeSpaceSeparator: ['define', { sourceInterval: [6804, 6857] }, null, [], [ + 'alt', + { sourceInterval: [6828, 6857] }, + ['range', { sourceInterval: [6828, 6846] }, ' ', '​'], + ['terminal', { sourceInterval: [6849, 6857] }, ' '], + ]], + }, +]); +export default result; diff --git a/drizzle-kit/imports-checker/index.ts b/drizzle-kit/imports-checker/index.ts new file mode 100644 index 000000000..7a4e90838 --- /dev/null +++ b/drizzle-kit/imports-checker/index.ts @@ -0,0 +1,48 @@ +import chalk from 'chalk'; +import { analyzeImports, ChainLink } from './checker'; + +const issues = analyzeImports({ + basePath: './drizzle-kit', + localPaths: ['src'], + whiteList: [ + '@drizzle-team/brocli', + 'json-diff', + 'path', + 'fs', + 'fs/*', + 'url', + 'zod', + 'node:*', + 'hono', + 'glob', + 'hono/*', + 'hono/**/*', + '@hono/*', + 'crypto', + 'hanji', + ], + entry: './drizzle-kit/src/cli/index.ts', + logger: true, + ignoreTypes: true, +}).issues; + +const chainToString = (chains: ChainLink[]) => { + if (chains.length === 0) throw new Error(); + + let out = chains[0]!.file + '\n'; + let indentation = 0; + for (let chain of chains) { + out += ' '.repeat(indentation) + + '└' + + chain.import + + ` ${chalk.gray(chain.file)}\n`; + indentation += 1; + } + return out; +}; + +console.log(); +for (const issue of issues) { + console.log(chalk.red(issue.imports.map((it) => it.name).join('\n'))); + console.log(issue.accessChains.map((it) => chainToString(it)).join('\n')); +} diff --git a/drizzle-kit/package.json b/drizzle-kit/package.json index 26163fed2..e45f7dbc5 100644 --- a/drizzle-kit/package.json +++ b/drizzle-kit/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-kit", - "version": "0.27.2", + "version": "0.28.0", "homepage": "https://orm.drizzle.team", "keywords": [ "drizzle", @@ -62,6 +62,7 @@ "@types/dockerode": "^3.3.28", "@types/glob": "^8.1.0", "@types/json-diff": "^1.0.3", + "@types/micromatch": "^4.0.9", "@types/minimatch": "^5.1.2", "@types/node": "^18.11.15", "@types/pg": "^8.10.7", @@ -92,9 +93,11 @@ "hanji": "^0.0.5", "hono": "^4.1.5", "json-diff": "1.0.6", + "micromatch": "^4.0.8", "minimatch": "^7.4.3", "mysql2": "3.3.3", "node-fetch": "^3.3.2", + "ohm-js": "^17.1.0", "pg": "^8.11.5", "pluralize": "^8.0.0", "postgres": "^3.4.4", @@ -138,4 +141,4 @@ "default": "./api.mjs" } } -} +} \ No newline at end of file diff --git a/drizzle-kit/src/@types/utils.ts b/drizzle-kit/src/@types/utils.ts index 04e7e125f..e71d45b89 100644 --- a/drizzle-kit/src/@types/utils.ts +++ b/drizzle-kit/src/@types/utils.ts @@ -13,6 +13,7 @@ declare global { random(): T; } } + import camelcase from 'camelcase'; String.prototype.trimChar = function(char: string) { diff --git a/drizzle-kit/src/api.ts b/drizzle-kit/src/api.ts index 83b7139ad..b18ed95f4 100644 --- a/drizzle-kit/src/api.ts +++ b/drizzle-kit/src/api.ts @@ -21,7 +21,9 @@ import { updateUpToV6 as upPgV6, updateUpToV7 as upPgV7 } from './cli/commands/p import { sqlitePushIntrospect } from './cli/commands/sqliteIntrospect'; import { logSuggestionsAndReturn } from './cli/commands/sqlitePushUtils'; import type { CasingType } from './cli/validations/common'; +import { getTablesFilterByExtensions } from './extensions/getTablesFilterByExtensions'; import { originUUID } from './global'; +import type { Config } from './index'; import { fillPgSnapshot } from './migrationPreparator'; import { MySqlSchema as MySQLSchemaKit, mysqlSchema, squashMysqlScheme } from './serializer/mysqlSchema'; import { generateMySqlSnapshot } from './serializer/mysqlSerializer'; @@ -100,9 +102,14 @@ export const pushSchema = async ( imports: Record, drizzleInstance: PgDatabase, schemaFilters?: string[], + tablesFilter?: string[], + extensionsFilters?: Config['extensionsFilters'], ) => { const { applyPgSnapshotsDiff } = await import('./snapshotsDiffer'); const { sql } = await import('drizzle-orm'); + const filters = (tablesFilter ?? []).concat( + getTablesFilterByExtensions({ extensionsFilters, dialect: 'postgresql' }), + ); const db: DB = { query: async (query: string, params?: any[]) => { @@ -114,7 +121,7 @@ export const pushSchema = async ( const cur = generateDrizzleJson(imports); const { schema: prev } = await pgPushIntrospect( db, - [], + filters, schemaFilters ?? ['public'], undefined, ); diff --git a/drizzle-kit/src/cli/commands/push.ts b/drizzle-kit/src/cli/commands/push.ts index 54dbb4ba0..4a41a46d4 100644 --- a/drizzle-kit/src/cli/commands/push.ts +++ b/drizzle-kit/src/cli/commands/push.ts @@ -383,15 +383,15 @@ export const sqlitePush = async ( render(`\n[${chalk.blue('i')}] No changes detected`); } else { if (!('driver' in credentials)) { - await db.query('begin'); + await db.run('begin'); try { for (const dStmnt of statementsToExecute) { - await db.query(dStmnt); + await db.run(dStmnt); } - await db.query('commit'); + await db.run('commit'); } catch (e) { console.error(e); - await db.query('rollback'); + await db.run('rollback'); process.exit(1); } } diff --git a/drizzle-kit/src/cli/commands/utils.ts b/drizzle-kit/src/cli/commands/utils.ts index 203e38cca..7386b74d5 100644 --- a/drizzle-kit/src/cli/commands/utils.ts +++ b/drizzle-kit/src/cli/commands/utils.ts @@ -3,6 +3,7 @@ import { existsSync } from 'fs'; import { render } from 'hanji'; import { join, resolve } from 'path'; import { object, string } from 'zod'; +import { getTablesFilterByExtensions } from '../../extensions/getTablesFilterByExtensions'; import { assertUnreachable } from '../../global'; import { type Dialect, dialect } from '../../schemaValidator'; import { prepareFilenames } from '../../serializer'; @@ -169,7 +170,7 @@ export const prepareGenerateConfig = async ( name: options.name, custom: options.custom || false, prefix, - breakpoints: breakpoints || true, + breakpoints: breakpoints ?? true, schema: schema, out: out || 'drizzle', bundle: driver === 'expo', @@ -273,16 +274,7 @@ export const preparePushConfig = async ( : schemasFilterConfig : []; - if (config.extensionsFilters) { - if ( - config.extensionsFilters.includes('postgis') - && config.dialect === 'postgresql' - ) { - tablesFilter.push( - ...['!geography_columns', '!geometry_columns', '!spatial_ref_sys'], - ); - } - } + tablesFilter.push(...getTablesFilterByExtensions(config)); if (config.dialect === 'postgresql') { const parsed = postgresCredentials.safeParse(config); diff --git a/drizzle-kit/src/cli/schema.ts b/drizzle-kit/src/cli/schema.ts index 64ceb5841..b03acde95 100644 --- a/drizzle-kit/src/cli/schema.ts +++ b/drizzle-kit/src/cli/schema.ts @@ -24,7 +24,7 @@ import { mkdirSync } from 'fs'; import { renderWithTask } from 'hanji'; import { dialects } from 'src/schemaValidator'; import { assertUnreachable } from '../global'; -import { drizzleForLibSQL, type Setup } from '../serializer/studio'; +import type { Setup } from '../serializer/studio'; import { certs } from '../utils/certs'; import { grey, MigrateProgress } from './views'; @@ -591,6 +591,7 @@ export const studio = command({ drizzleForMySQL, prepareSQLiteSchema, drizzleForSQLite, + drizzleForLibSQL, } = await import('../serializer/studio'); let setup: Setup; diff --git a/drizzle-kit/src/cli/validations/outputs.ts b/drizzle-kit/src/cli/validations/outputs.ts index 6b92829d5..3ef499651 100644 --- a/drizzle-kit/src/cli/validations/outputs.ts +++ b/drizzle-kit/src/cli/validations/outputs.ts @@ -26,7 +26,7 @@ export const outputs = { ), noDialect: () => withStyle.error( - `Please specify 'dialect' param in config, either of 'pg', 'mysql' or 'sqlite'`, + `Please specify 'dialect' param in config, either of 'postgresql', 'mysql', 'sqlite' or 'turso'`, ), }, common: { diff --git a/drizzle-kit/src/extensions/getTablesFilterByExtensions.ts b/drizzle-kit/src/extensions/getTablesFilterByExtensions.ts new file mode 100644 index 000000000..80321fc6a --- /dev/null +++ b/drizzle-kit/src/extensions/getTablesFilterByExtensions.ts @@ -0,0 +1,16 @@ +import type { Config } from '../index'; + +export const getTablesFilterByExtensions = ({ + extensionsFilters, + dialect, +}: Pick): string[] => { + if (extensionsFilters) { + if ( + extensionsFilters.includes('postgis') + && dialect === 'postgresql' + ) { + return ['!geography_columns', '!geometry_columns', '!spatial_ref_sys']; + } + } + return []; +}; diff --git a/drizzle-kit/src/introspect-mysql.ts b/drizzle-kit/src/introspect-mysql.ts index ea287713f..ebf30f70d 100644 --- a/drizzle-kit/src/introspect-mysql.ts +++ b/drizzle-kit/src/introspect-mysql.ts @@ -14,6 +14,7 @@ import { UniqueConstraint, } from './serializer/mysqlSchema'; import { indexName } from './serializer/mysqlSerializer'; +import { unescapeSingleQuotes } from './utils'; // time precision to fsp // {mode: "string"} for timestamp by default @@ -179,6 +180,12 @@ export const schemaToTypeScript = ( patched = patched.startsWith('varbinary(') ? 'varbinary' : patched; patched = patched.startsWith('int(') ? 'int' : patched; patched = patched.startsWith('double(') ? 'double' : patched; + patched = patched.startsWith('float(') ? 'float' : patched; + patched = patched.startsWith('int unsigned') ? 'int' : patched; + patched = patched.startsWith('tinyint unsigned') ? 'tinyint' : patched; + patched = patched.startsWith('smallint unsigned') ? 'smallint' : patched; + patched = patched.startsWith('mediumint unsigned') ? 'mediumint' : patched; + patched = patched.startsWith('bigint unsigned') ? 'bigint' : patched; return patched; }) .filter((type) => { @@ -207,6 +214,12 @@ export const schemaToTypeScript = ( patched = patched.startsWith('varbinary(') ? 'varbinary' : patched; patched = patched.startsWith('int(') ? 'int' : patched; patched = patched.startsWith('double(') ? 'double' : patched; + patched = patched.startsWith('float(') ? 'float' : patched; + patched = patched.startsWith('int unsigned') ? 'int' : patched; + patched = patched.startsWith('tinyint unsigned') ? 'tinyint' : patched; + patched = patched.startsWith('smallint unsigned') ? 'smallint' : patched; + patched = patched.startsWith('mediumint unsigned') ? 'mediumint' : patched; + patched = patched.startsWith('bigint unsigned') ? 'bigint' : patched; return patched; }) .filter((type) => { @@ -397,8 +410,9 @@ const column = ( if (lowered.startsWith('int')) { const isUnsigned = lowered.startsWith('int unsigned'); - let out = `${casing(name)}: int(${dbColumnName({ name, casing: rawCasing, withMode: isUnsigned })}${ - isUnsigned ? '{ unsigned: true }' : '' + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); + let out = `${casing(name)}: int(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' })`; out += autoincrement ? `.autoincrement()` : ''; out += typeof defaultValue !== 'undefined' @@ -409,9 +423,10 @@ const column = ( if (lowered.startsWith('tinyint')) { const isUnsigned = lowered.startsWith('tinyint unsigned'); + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); // let out = `${name.camelCase()}: tinyint("${name}")`; - let out: string = `${casing(name)}: tinyint(${dbColumnName({ name, casing: rawCasing, withMode: isUnsigned })}${ - isUnsigned ? ', { unsigned: true }' : '' + let out: string = `${casing(name)}: tinyint(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' })`; out += autoincrement ? `.autoincrement()` : ''; out += typeof defaultValue !== 'undefined' @@ -422,8 +437,9 @@ const column = ( if (lowered.startsWith('smallint')) { const isUnsigned = lowered.startsWith('smallint unsigned'); - let out = `${casing(name)}: smallint(${dbColumnName({ name, casing: rawCasing, withMode: isUnsigned })}${ - isUnsigned ? ', { unsigned: true }' : '' + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); + let out = `${casing(name)}: smallint(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' })`; out += autoincrement ? `.autoincrement()` : ''; out += defaultValue @@ -434,8 +450,9 @@ const column = ( if (lowered.startsWith('mediumint')) { const isUnsigned = lowered.startsWith('mediumint unsigned'); - let out = `${casing(name)}: mediumint(${dbColumnName({ name, casing: rawCasing, withMode: isUnsigned })}${ - isUnsigned ? ', { unsigned: true }' : '' + const columnName = dbColumnName({ name, casing: rawCasing, withMode: isUnsigned }); + let out = `${casing(name)}: mediumint(${columnName}${ + isUnsigned ? `${columnName.length > 0 ? ', ' : ''}{ unsigned: true }` : '' })`; out += autoincrement ? `.autoincrement()` : ''; out += defaultValue @@ -466,16 +483,20 @@ const column = ( if (lowered.startsWith('double')) { let params: - | { precision: string | undefined; scale: string | undefined } + | { precision?: string; scale?: string; unsigned?: boolean } | undefined; - if (lowered.length > 6) { + if (lowered.length > (lowered.includes('unsigned') ? 15 : 6)) { const [precision, scale] = lowered - .slice(7, lowered.length - 1) + .slice(7, lowered.length - (1 + (lowered.includes('unsigned') ? 9 : 0))) .split(','); params = { precision, scale }; } + if (lowered.includes('unsigned')) { + params = { ...(params ?? {}), unsigned: true }; + } + const timeConfigParams = params ? timeConfig(params) : undefined; let out = params @@ -491,8 +512,23 @@ const column = ( return out; } - if (lowered === 'float') { - let out = `${casing(name)}: float(${dbColumnName({ name, casing: rawCasing })})`; + if (lowered.startsWith('float')) { + let params: + | { precision?: string; scale?: string; unsigned?: boolean } + | undefined; + + if (lowered.length > (lowered.includes('unsigned') ? 14 : 5)) { + const [precision, scale] = lowered + .slice(6, lowered.length - (1 + (lowered.includes('unsigned') ? 9 : 0))) + .split(','); + params = { precision, scale }; + } + + if (lowered.includes('unsigned')) { + params = { ...(params ?? {}), unsigned: true }; + } + + let out = `${casing(name)}: float(${dbColumnName({ name, casing: rawCasing })}${params ? timeConfig(params) : ''})`; out += defaultValue ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; @@ -644,8 +680,9 @@ const column = ( ) } })`; + const mappedDefaultValue = mapColumnDefault(defaultValue, isExpression); out += defaultValue - ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + ? `.default(${isExpression ? mappedDefaultValue : unescapeSingleQuotes(mappedDefaultValue, true)})` : ''; return out; } @@ -700,16 +737,20 @@ const column = ( if (lowered.startsWith('decimal')) { let params: - | { precision: string | undefined; scale: string | undefined } + | { precision?: string; scale?: string; unsigned?: boolean } | undefined; - if (lowered.length > 7) { + if (lowered.length > (lowered.includes('unsigned') ? 16 : 7)) { const [precision, scale] = lowered - .slice(8, lowered.length - 1) + .slice(8, lowered.length - (1 + (lowered.includes('unsigned') ? 9 : 0))) .split(','); params = { precision, scale }; } + if (lowered.includes('unsigned')) { + params = { ...(params ?? {}), unsigned: true }; + } + const timeConfigParams = params ? timeConfig(params) : undefined; let out = params @@ -748,10 +789,15 @@ const column = ( } if (lowered.startsWith('enum')) { - const values = lowered.substring('enum'.length + 1, lowered.length - 1); + const values = lowered + .substring('enum'.length + 1, lowered.length - 1) + .split(',') + .map((v) => unescapeSingleQuotes(v, true)) + .join(','); let out = `${casing(name)}: mysqlEnum(${dbColumnName({ name, casing: rawCasing, withMode: true })}[${values}])`; + const mappedDefaultValue = mapColumnDefault(defaultValue, isExpression); out += defaultValue - ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + ? `.default(${isExpression ? mappedDefaultValue : unescapeSingleQuotes(mappedDefaultValue, true)})` : ''; return out; } diff --git a/drizzle-kit/src/introspect-pg.ts b/drizzle-kit/src/introspect-pg.ts index ed26e8117..9c9383ebe 100644 --- a/drizzle-kit/src/introspect-pg.ts +++ b/drizzle-kit/src/introspect-pg.ts @@ -11,7 +11,6 @@ import { import './@types/utils'; import { toCamelCase } from 'drizzle-orm/casing'; import { Casing } from './cli/validations/common'; -import { vectorOps } from './extensions/vector'; import { assertUnreachable } from './global'; import { CheckConstraint, @@ -25,6 +24,7 @@ import { UniqueConstraint, } from './serializer/pgSchema'; import { indexName } from './serializer/pgSerializer'; +import { unescapeSingleQuotes } from './utils'; const pgImportsList = new Set([ 'pgTable', @@ -436,7 +436,7 @@ export const schemaToTypeScript = (schema: PgSchemaInternal, casing: Casing) => const func = enumSchema ? `${enumSchema}.enum` : 'pgEnum'; const values = Object.values(it.values) - .map((it) => `'${it}'`) + .map((it) => `'${unescapeSingleQuotes(it, false)}'`) .join(', '); return `export const ${withCasing(paramName, casing)} = ${func}("${it.name}", [${values}])\n`; }) @@ -690,7 +690,9 @@ const mapDefault = ( } if (enumTypes.has(`${typeSchema}.${type.replace('[]', '')}`)) { - return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + return typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})` + : ''; } if (lowered.startsWith('integer')) { @@ -737,18 +739,20 @@ const mapDefault = ( if (lowered.startsWith('timestamp')) { return defaultValue === 'now()' ? '.defaultNow()' - : defaultValue === 'CURRENT_TIMESTAMP' - ? '.default(sql`CURRENT_TIMESTAMP`)' - : defaultValue + : /^'\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(\.\d+)?([+-]\d{2}(:\d{2})?)?'$/.test(defaultValue) // Matches 'YYYY-MM-DD HH:MI:SS', 'YYYY-MM-DD HH:MI:SS.FFFFFF', 'YYYY-MM-DD HH:MI:SS+TZ', 'YYYY-MM-DD HH:MI:SS.FFFFFF+TZ' and 'YYYY-MM-DD HH:MI:SS+HH:MI' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : defaultValue + ? `.default(sql\`${defaultValue}\`)` : ''; } if (lowered.startsWith('time')) { return defaultValue === 'now()' ? '.defaultNow()' - : defaultValue + : /^'\d{2}:\d{2}(:\d{2})?(\.\d+)?'$/.test(defaultValue) // Matches 'HH:MI', 'HH:MI:SS' and 'HH:MI:SS.FFFFFF' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` + : defaultValue + ? `.default(sql\`${defaultValue}\`)` : ''; } @@ -759,15 +763,17 @@ const mapDefault = ( if (lowered === 'date') { return defaultValue === 'now()' ? '.defaultNow()' - : defaultValue === 'CURRENT_DATE' - ? `.default(sql\`${defaultValue}\`)` - : defaultValue + : /^'\d{4}-\d{2}-\d{2}'$/.test(defaultValue) // Matches 'YYYY-MM-DD' ? `.default(${defaultValue})` + : defaultValue + ? `.default(sql\`${defaultValue}\`)` : ''; } if (lowered.startsWith('text')) { - return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + return typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})` + : ''; } if (lowered.startsWith('jsonb')) { @@ -801,7 +807,9 @@ const mapDefault = ( } if (lowered.startsWith('varchar')) { - return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + return typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})` + : ''; } if (lowered.startsWith('point')) { @@ -821,7 +829,9 @@ const mapDefault = ( } if (lowered.startsWith('char')) { - return typeof defaultValue !== 'undefined' ? `.default(${mapColumnDefault(defaultValue, isExpression)})` : ''; + return typeof defaultValue !== 'undefined' + ? `.default(${mapColumnDefault(unescapeSingleQuotes(defaultValue, true), isExpression)})` + : ''; } return ''; @@ -1219,7 +1229,11 @@ const createTableIndexes = (tableName: string, idxs: Index[], casing: Casing): s } else { return `table.${withCasing(it.expression, casing)}${it.asc ? '.asc()' : '.desc()'}${ it.nulls === 'first' ? '.nullsFirst()' : '.nullsLast()' - }${it.opclass && vectorOps.includes(it.opclass) ? `.op("${it.opclass}")` : ''}`; + }${ + it.opclass + ? `.op("${it.opclass}")` + : '' + }`; } }) .join(', ') diff --git a/drizzle-kit/src/introspect-sqlite.ts b/drizzle-kit/src/introspect-sqlite.ts index e21f2a5c4..464a32aa3 100644 --- a/drizzle-kit/src/introspect-sqlite.ts +++ b/drizzle-kit/src/introspect-sqlite.ts @@ -272,10 +272,8 @@ const mapColumnDefault = (defaultValue: any) => { if ( typeof defaultValue === 'string' - && defaultValue.startsWith("'") - && defaultValue.endsWith("'") ) { - return defaultValue.substring(1, defaultValue.length - 1); + return defaultValue.substring(1, defaultValue.length - 1).replaceAll('"', '\\"').replaceAll("''", "'"); } return defaultValue; diff --git a/drizzle-kit/src/jsonStatements.ts b/drizzle-kit/src/jsonStatements.ts index 9359b1a8d..18b28fac4 100644 --- a/drizzle-kit/src/jsonStatements.ts +++ b/drizzle-kit/src/jsonStatements.ts @@ -2704,19 +2704,14 @@ export const prepareAddCompositePrimaryKeyPg = ( tableName: string, schema: string, pks: Record, - // TODO: remove? - json2: PgSchema, ): JsonCreateCompositePK[] => { return Object.values(pks).map((it) => { - const unsquashed = PgSquasher.unsquashPK(it); return { type: 'create_composite_pk', tableName, data: it, schema, - constraintName: json2.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - unsquashed.name - ].name, + constraintName: PgSquasher.unsquashPK(it).name, } as JsonCreateCompositePK; }); }; @@ -2725,8 +2720,6 @@ export const prepareDeleteCompositePrimaryKeyPg = ( tableName: string, schema: string, pks: Record, - // TODO: remove? - json1: PgSchema, ): JsonDeleteCompositePK[] => { return Object.values(pks).map((it) => { return { @@ -2734,9 +2727,7 @@ export const prepareDeleteCompositePrimaryKeyPg = ( tableName, data: it, schema, - constraintName: json1.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - PgSquasher.unsquashPK(it).name - ].name, + constraintName: PgSquasher.unsquashPK(it).name, } as JsonDeleteCompositePK; }); }; @@ -2745,9 +2736,6 @@ export const prepareAlterCompositePrimaryKeyPg = ( tableName: string, schema: string, pks: Record, - // TODO: remove? - json1: PgSchema, - json2: PgSchema, ): JsonAlterCompositePK[] => { return Object.values(pks).map((it) => { return { @@ -2756,12 +2744,8 @@ export const prepareAlterCompositePrimaryKeyPg = ( old: it.__old, new: it.__new, schema, - oldConstraintName: json1.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - PgSquasher.unsquashPK(it.__old).name - ].name, - newConstraintName: json2.tables[`${schema || 'public'}.${tableName}`].compositePrimaryKeys[ - PgSquasher.unsquashPK(it.__new).name - ].name, + oldConstraintName: PgSquasher.unsquashPK(it.__old).name, + newConstraintName: PgSquasher.unsquashPK(it.__new).name, } as JsonAlterCompositePK; }); }; @@ -2874,7 +2858,7 @@ export const prepareAddCompositePrimaryKeyMySql = ( type: 'create_composite_pk', tableName, data: it, - constraintName: json2.tables[tableName].compositePrimaryKeys[unsquashed.name].name, + constraintName: unsquashed.name, } as JsonCreateCompositePK); } return res; @@ -2887,13 +2871,12 @@ export const prepareDeleteCompositePrimaryKeyMySql = ( json1: MySqlSchema, ): JsonDeleteCompositePK[] => { return Object.values(pks).map((it) => { + const unsquashed = MySqlSquasher.unsquashPK(it); return { type: 'delete_composite_pk', tableName, data: it, - constraintName: json1.tables[tableName].compositePrimaryKeys[ - MySqlSquasher.unsquashPK(it).name - ].name, + constraintName: unsquashed.name, } as JsonDeleteCompositePK; }); }; diff --git a/drizzle-kit/src/serializer/mysqlSerializer.ts b/drizzle-kit/src/serializer/mysqlSerializer.ts index f7fa7f3f0..aaa1acb82 100644 --- a/drizzle-kit/src/serializer/mysqlSerializer.ts +++ b/drizzle-kit/src/serializer/mysqlSerializer.ts @@ -26,13 +26,20 @@ import { UniqueConstraint, View, } from '../serializer/mysqlSchema'; -import type { DB } from '../utils'; +import { type DB, escapeSingleQuotes } from '../utils'; import { getColumnCasing, sqlToStr } from './utils'; export const indexName = (tableName: string, columns: string[]) => { return `${tableName}_${columns.join('_')}_index`; }; +const handleEnumType = (type: string) => { + let str = type.split('(')[1]; + str = str.substring(0, str.length - 1); + const values = str.split(',').map((v) => `'${escapeSingleQuotes(v.substring(1, v.length - 1))}'`); + return `enum(${values.join(',')})`; +}; + export const generateMySqlSnapshot = ( tables: AnyMySqlTable[], views: MySqlView[], @@ -68,7 +75,8 @@ export const generateMySqlSnapshot = ( columns.forEach((column) => { const name = getColumnCasing(column, casing); const notNull: boolean = column.notNull; - const sqlTypeLowered = column.getSQLType().toLowerCase(); + const sqlType = column.getSQLType(); + const sqlTypeLowered = sqlType.toLowerCase(); const autoIncrement = typeof (column as any).autoIncrement === 'undefined' ? false : (column as any).autoIncrement; @@ -77,7 +85,7 @@ export const generateMySqlSnapshot = ( const columnToSet: Column = { name, - type: column.getSQLType(), + type: sqlType.startsWith('enum') ? handleEnumType(sqlType) : sqlType, primaryKey: false, // If field is autoincrement it's notNull by default // notNull: autoIncrement ? true : notNull, @@ -141,7 +149,7 @@ export const generateMySqlSnapshot = ( columnToSet.default = sqlToStr(column.default, casing); } else { if (typeof column.default === 'string') { - columnToSet.default = `'${column.default}'`; + columnToSet.default = `'${escapeSingleQuotes(column.default)}'`; } else { if (sqlTypeLowered === 'json') { columnToSet.default = `'${JSON.stringify(column.default)}'`; @@ -544,9 +552,9 @@ function clearDefaults(defaultValue: any, collate: string) { .substring(collate.length, defaultValue.length) .replace(/\\/g, ''); if (resultDefault.startsWith("'") && resultDefault.endsWith("'")) { - return `('${resultDefault.substring(1, resultDefault.length - 1)}')`; + return `('${escapeSingleQuotes(resultDefault.substring(1, resultDefault.length - 1))}')`; } else { - return `'${resultDefault}'`; + return `'${escapeSingleQuotes(resultDefault.substring(1, resultDefault.length - 1))}'`; } } else { return `(${resultDefault})`; @@ -651,8 +659,8 @@ export const fromDatabase = async ( } } - if (columnType.startsWith('tinyint')) { - changedType = 'tinyint'; + if (columnType.includes('decimal(10,0)')) { + changedType = columnType.replace('decimal(10,0)', 'decimal'); } let onUpdate: boolean | undefined = undefined; @@ -665,14 +673,14 @@ export const fromDatabase = async ( } const newColumn: Column = { - default: columnDefault === null + default: columnDefault === null || columnDefault === undefined ? undefined : /^-?[\d.]+(?:e-?\d+)?$/.test(columnDefault) && !['decimal', 'char', 'varchar'].some((type) => columnType.startsWith(type)) ? Number(columnDefault) : isDefaultAnExpression ? clearDefaults(columnDefault, collation) - : `'${columnDefault}'`, + : `'${escapeSingleQuotes(columnDefault)}'`, autoincrement: isAutoincrement, name: columnName, type: changedType, diff --git a/drizzle-kit/src/serializer/pgSchema.ts b/drizzle-kit/src/serializer/pgSchema.ts index f5810bbc8..d7604d645 100644 --- a/drizzle-kit/src/serializer/pgSchema.ts +++ b/drizzle-kit/src/serializer/pgSchema.ts @@ -1,4 +1,3 @@ -import { vectorOps } from 'src/extensions/vector'; import { mapValues, originUUID, snapshotVersion } from '../global'; import { any, array, boolean, enum as enumType, literal, number, object, record, string, TypeOf, union } from 'zod'; @@ -555,10 +554,7 @@ export const PgSquasher = { return `${idx.name};${ idx.columns .map( - (c) => - `${c.expression}--${c.isExpression}--${c.asc}--${c.nulls}--${ - c.opclass && vectorOps.includes(c.opclass) ? c.opclass : '' - }`, + (c) => `${c.expression}--${c.isExpression}--${c.asc}--${c.nulls}--${c.opclass ? c.opclass : ''}`, ) .join(',,') };${idx.isUnique};${idx.concurrently};${idx.method};${idx.where};${JSON.stringify(idx.with)}`; diff --git a/drizzle-kit/src/serializer/pgSerializer.ts b/drizzle-kit/src/serializer/pgSerializer.ts index 66b8db85f..b0faa5ea8 100644 --- a/drizzle-kit/src/serializer/pgSerializer.ts +++ b/drizzle-kit/src/serializer/pgSerializer.ts @@ -39,7 +39,7 @@ import type { UniqueConstraint, View, } from '../serializer/pgSchema'; -import { type DB, isPgArrayType } from '../utils'; +import { type DB, escapeSingleQuotes, isPgArrayType } from '../utils'; import { getColumnCasing, sqlToStr } from './utils'; export const indexName = (tableName: string, columns: string[]) => { @@ -241,7 +241,7 @@ export const generatePgSnapshot = ( columnToSet.default = sqlToStr(column.default, casing); } else { if (typeof column.default === 'string') { - columnToSet.default = `'${column.default}'`; + columnToSet.default = `'${escapeSingleQuotes(column.default)}'`; } else { if (sqlTypeLowered === 'jsonb' || sqlTypeLowered === 'json') { columnToSet.default = `'${JSON.stringify(column.default)}'::${sqlTypeLowered}`; @@ -1937,11 +1937,13 @@ const defaultForColumn = (column: any, internals: PgKitInternals, tableName: str const columnName = column.column_name; const isArray = internals?.tables[tableName]?.columns[columnName]?.isArray ?? false; - if (column.column_default === null) { - return undefined; - } - - if (column.data_type === 'serial' || column.data_type === 'smallserial' || column.data_type === 'bigserial') { + if ( + column.column_default === null + || column.column_default === undefined + || column.data_type === 'serial' + || column.data_type === 'smallserial' + || column.data_type === 'bigserial' + ) { return undefined; } diff --git a/drizzle-kit/src/serializer/sqliteSerializer.ts b/drizzle-kit/src/serializer/sqliteSerializer.ts index 1ba24b69c..107a1b292 100644 --- a/drizzle-kit/src/serializer/sqliteSerializer.ts +++ b/drizzle-kit/src/serializer/sqliteSerializer.ts @@ -25,7 +25,7 @@ import type { UniqueConstraint, View, } from '../serializer/sqliteSchema'; -import type { SQLiteDB } from '../utils'; +import { escapeSingleQuotes, type SQLiteDB } from '../utils'; import { getColumnCasing, sqlToStr } from './utils'; export const generateSqliteSnapshot = ( @@ -90,7 +90,7 @@ export const generateSqliteSnapshot = ( columnToSet.default = sqlToStr(column.default, casing); } else { columnToSet.default = typeof column.default === 'string' - ? `'${column.default}'` + ? `'${escapeSingleQuotes(column.default)}'` : typeof column.default === 'object' || Array.isArray(column.default) ? `'${JSON.stringify(column.default)}'` diff --git a/drizzle-kit/src/snapshotsDiffer.ts b/drizzle-kit/src/snapshotsDiffer.ts index dda13b967..060f12bbd 100644 --- a/drizzle-kit/src/snapshotsDiffer.ts +++ b/drizzle-kit/src/snapshotsDiffer.ts @@ -131,7 +131,6 @@ import { PgSchemaSquashed, PgSquasher, Policy, - policy, policySquashed, Role, roleSchema, @@ -1243,22 +1242,22 @@ export const applyPgSnapshotsDiff = async ( // This part is needed to make sure that same columns in a table are not triggered for change // there is a case where orm and kit are responsible for pk name generation and one of them is not sorting name // We double-check that pk with same set of columns are both in added and deleted diffs - let addedColumns: string[] = []; + let addedColumns: { name: string; columns: string[] } | undefined; for (const addedPkName of Object.keys(it.addedCompositePKs)) { const addedPkColumns = it.addedCompositePKs[addedPkName]; - addedColumns = SQLiteSquasher.unsquashPK(addedPkColumns); + addedColumns = PgSquasher.unsquashPK(addedPkColumns); } - let deletedColumns: string[] = []; + let deletedColumns: { name: string; columns: string[] } | undefined; for (const deletedPkName of Object.keys(it.deletedCompositePKs)) { const deletedPkColumns = it.deletedCompositePKs[deletedPkName]; - deletedColumns = SQLiteSquasher.unsquashPK(deletedPkColumns); + deletedColumns = PgSquasher.unsquashPK(deletedPkColumns); } // Don't need to sort, but need to add tests for it // addedColumns.sort(); // deletedColumns.sort(); - const doPerformDeleteAndCreate = JSON.stringify(addedColumns) !== JSON.stringify(deletedColumns); + const doPerformDeleteAndCreate = JSON.stringify(addedColumns ?? {}) !== JSON.stringify(deletedColumns ?? {}); let addedCompositePKs: JsonCreateCompositePK[] = []; let deletedCompositePKs: JsonDeleteCompositePK[] = []; @@ -1268,21 +1267,17 @@ export const applyPgSnapshotsDiff = async ( it.name, it.schema, it.addedCompositePKs, - curFull as PgSchema, ); deletedCompositePKs = prepareDeleteCompositePrimaryKeyPg( it.name, it.schema, it.deletedCompositePKs, - prevFull as PgSchema, ); } alteredCompositePKs = prepareAlterCompositePrimaryKeyPg( it.name, it.schema, it.alteredCompositePKs, - prevFull as PgSchema, - curFull as PgSchema, ); // add logic for unique constraints @@ -2634,12 +2629,11 @@ export const applyMysqlSnapshotsDiff = async ( jsonStatements.push(...jsonDeletedCompositePKs); jsonStatements.push(...jsonTableAlternations); jsonStatements.push(...jsonAddedCompositePKs); + jsonStatements.push(...jsonAddColumnsStatemets); jsonStatements.push(...jsonAddedUniqueConstraints); jsonStatements.push(...jsonDeletedUniqueConstraints); - jsonStatements.push(...jsonAddColumnsStatemets); - jsonStatements.push(...jsonCreateReferencesForCreatedTables); jsonStatements.push(...jsonCreateIndexesForCreatedTables); jsonStatements.push(...jsonCreatedCheckConstraints); diff --git a/drizzle-kit/src/sqlgenerator.ts b/drizzle-kit/src/sqlgenerator.ts index bb3335941..3c88a86ce 100644 --- a/drizzle-kit/src/sqlgenerator.ts +++ b/drizzle-kit/src/sqlgenerator.ts @@ -86,75 +86,59 @@ import { Dialect } from './schemaValidator'; import { MySqlSquasher } from './serializer/mysqlSchema'; import { PgSquasher, policy } from './serializer/pgSchema'; import { SQLiteSchemaSquashed, SQLiteSquasher } from './serializer/sqliteSchema'; - -export const pgNativeTypes = new Set([ - 'uuid', - 'smallint', - 'integer', - 'bigint', - 'boolean', - 'text', - 'varchar', - 'serial', - 'bigserial', - 'decimal', - 'numeric', - 'real', - 'json', - 'jsonb', - 'time', - 'time with time zone', - 'time without time zone', - 'time', - 'timestamp', - 'timestamp with time zone', - 'timestamp without time zone', - 'date', - 'interval', - 'bigint', - 'bigserial', - 'double precision', - 'interval year', - 'interval month', - 'interval day', - 'interval hour', - 'interval minute', - 'interval second', - 'interval year to month', - 'interval day to hour', - 'interval day to minute', - 'interval day to second', - 'interval hour to minute', - 'interval hour to second', - 'interval minute to second', -]); - -const isPgNativeType = (it: string) => { - if (pgNativeTypes.has(it)) return true; - const toCheck = it.replace(/ /g, ''); - return ( - toCheck.startsWith('varchar(') - || toCheck.startsWith('char(') - || toCheck.startsWith('numeric(') - || toCheck.startsWith('timestamp(') - || toCheck.startsWith('doubleprecision[') - || toCheck.startsWith('intervalyear(') - || toCheck.startsWith('intervalmonth(') - || toCheck.startsWith('intervalday(') - || toCheck.startsWith('intervalhour(') - || toCheck.startsWith('intervalminute(') - || toCheck.startsWith('intervalsecond(') - || toCheck.startsWith('intervalyeartomonth(') - || toCheck.startsWith('intervaldaytohour(') - || toCheck.startsWith('intervaldaytominute(') - || toCheck.startsWith('intervaldaytosecond(') - || toCheck.startsWith('intervalhourtominute(') - || toCheck.startsWith('intervalhourtosecond(') - || toCheck.startsWith('intervalminutetosecond(') - || toCheck.startsWith('vector(') - || toCheck.startsWith('geometry(') - || /^(\w+)(\[\d*])+$/.test(it) - ); +import { escapeSingleQuotes } from './utils'; + +const parseType = (schemaPrefix: string, type: string) => { + const pgNativeTypes = [ + 'uuid', + 'smallint', + 'integer', + 'bigint', + 'boolean', + 'text', + 'varchar', + 'serial', + 'bigserial', + 'decimal', + 'numeric', + 'real', + 'json', + 'jsonb', + 'time', + 'time with time zone', + 'time without time zone', + 'time', + 'timestamp', + 'timestamp with time zone', + 'timestamp without time zone', + 'date', + 'interval', + 'bigint', + 'bigserial', + 'double precision', + 'interval year', + 'interval month', + 'interval day', + 'interval hour', + 'interval minute', + 'interval second', + 'interval year to month', + 'interval day to hour', + 'interval day to minute', + 'interval day to second', + 'interval hour to minute', + 'interval hour to second', + 'interval minute to second', + 'char', + 'vector', + 'geometry', + ]; + const arrayDefinitionRegex = /\[\d*(?:\[\d*\])*\]/g; + const arrayDefinition = (type.match(arrayDefinitionRegex) ?? []).join(''); + const withoutArrayDefinition = type.replace(arrayDefinitionRegex, ''); + return pgNativeTypes.some((it) => type.startsWith(it)) + ? `${withoutArrayDefinition}${arrayDefinition}` + : `${schemaPrefix}"${withoutArrayDefinition}"${arrayDefinition}`; }; abstract class Convertor { @@ -419,9 +403,7 @@ class PgCreateTableConvertor extends Convertor { ? `"${column.typeSchema}".` : ''; - const type = isPgNativeType(column.type) - ? column.type - : `${schemaPrefix}"${column.type}"`; + const type = parseType(schemaPrefix, column.type); const generated = column.generated; const generatedStatement = generated ? ` GENERATED ALWAYS AS (${generated?.as}) STORED` : ''; @@ -1296,7 +1278,7 @@ class CreateTypeEnumConvertor extends Convertor { const enumNameWithSchema = schema ? `"${schema}"."${name}"` : `"${name}"`; let valuesStatement = '('; - valuesStatement += values.map((it) => `'${it}'`).join(', '); + valuesStatement += values.map((it) => `'${escapeSingleQuotes(it)}'`).join(', '); valuesStatement += ')'; // TODO do we need this? @@ -1604,9 +1586,7 @@ class PgAlterTableAddColumnConvertor extends Convertor { ? `"${column.typeSchema}".` : ''; - const fixedType = isPgNativeType(column.type) - ? column.type - : `${schemaPrefix}"${column.type}"`; + const fixedType = parseType(schemaPrefix, column.type); const notNullStatement = `${notNull ? ' NOT NULL' : ''}`; @@ -2530,9 +2510,10 @@ class PgAlterTableAlterCompositePrimaryKeyConvertor extends Convertor { ? `"${statement.schema}"."${statement.tableName}"` : `"${statement.tableName}"`; - return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT ${statement.oldConstraintName};\n${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT ${statement.newConstraintName} PRIMARY KEY(${ - newColumns.join(',') - });`; + console.log(statement.oldConstraintName, statement.newConstraintName); + return `ALTER TABLE ${tableNameWithSchema} DROP CONSTRAINT "${statement.oldConstraintName}";\n${BREAKPOINT}ALTER TABLE ${tableNameWithSchema} ADD CONSTRAINT "${statement.newConstraintName}" PRIMARY KEY("${ + newColumns.join('","') + }");`; } } diff --git a/drizzle-kit/src/utils.ts b/drizzle-kit/src/utils.ts index f26624969..685e2efb5 100644 --- a/drizzle-kit/src/utils.ts +++ b/drizzle-kit/src/utils.ts @@ -4,6 +4,7 @@ import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from import { join } from 'path'; import { parse } from 'url'; import type { NamedWithSchema } from './cli/commands/migrate'; +import { CasingType } from './cli/validations/common'; import { info } from './cli/views'; import { assertUnreachable, snapshotVersion } from './global'; import type { Dialect } from './schemaValidator'; @@ -356,3 +357,12 @@ export function findAddedAndRemoved(columnNames1: string[], columnNames2: string return { addedColumns, removedColumns }; } + +export function escapeSingleQuotes(str: string) { + return str.replace(/'/g, "''"); +} + +export function unescapeSingleQuotes(str: string, ignoreFirstAndLastChar: boolean) { + const regex = ignoreFirstAndLastChar ? /(? { + const issues = analyzeImports({ + basePath: '.', + localPaths: ['src'], + whiteList: [ + '@drizzle-team/brocli', + 'json-diff', + 'path', + 'fs', + 'fs/*', + 'url', + 'zod', + 'node:*', + 'hono', + 'glob', + 'hono/*', + 'hono/**/*', + '@hono/*', + 'crypto', + 'hanji', + 'chalk', + 'dotenv/config', + 'camelcase', + 'semver', + 'env-paths', + ], + entry: 'src/cli/index.ts', + logger: true, + ignoreTypes: true, + }).issues; + + const chainToString = (chains: ChainLink[]) => { + if (chains.length === 0) throw new Error(); + + let out = chains[0]!.file + '\n'; + let indentation = 0; + for (let chain of chains) { + out += ' '.repeat(indentation) + + '└' + + chain.import + + ` ${chalk.gray(chain.file)}\n`; + indentation += 1; + } + return out; + }; + + console.log(); + for (const issue of issues) { + console.log(chalk.red(issue.imports.map((it) => it.name).join('\n'))); + console.log(issue.accessChains.map((it) => chainToString(it)).join('\n')); + } + + assert.equal(issues.length, 0); +}); diff --git a/drizzle-kit/tests/indexes/pg.test.ts b/drizzle-kit/tests/indexes/pg.test.ts index 9958a2356..b9ff36020 100644 --- a/drizzle-kit/tests/indexes/pg.test.ts +++ b/drizzle-kit/tests/indexes/pg.test.ts @@ -125,12 +125,12 @@ const pgSuite: DialectSuite = { expect(sqlStatements).toStrictEqual([ 'DROP INDEX IF EXISTS "indx";', 'DROP INDEX IF EXISTS "indx1";', - // 'DROP INDEX IF EXISTS "indx2";', + 'DROP INDEX IF EXISTS "indx2";', 'DROP INDEX IF EXISTS "indx3";', 'CREATE INDEX IF NOT EXISTS "indx4" ON "users" USING btree (lower(id)) WHERE true;', 'CREATE INDEX IF NOT EXISTS "indx" ON "users" USING btree ("name" DESC NULLS LAST);', 'CREATE INDEX IF NOT EXISTS "indx1" ON "users" USING btree ("name" DESC NULLS LAST) WHERE false;', - // 'CREATE INDEX IF NOT EXISTS "indx2" ON "users" USING btree ("name" test) WHERE true;', + 'CREATE INDEX IF NOT EXISTS "indx2" ON "users" USING btree ("name" test) WHERE true;', 'CREATE INDEX IF NOT EXISTS "indx3" ON "users" USING btree (lower("id")) WHERE true;', ]); }, diff --git a/drizzle-kit/tests/introspect/mysql.test.ts b/drizzle-kit/tests/introspect/mysql.test.ts index 024300bea..2db33416b 100644 --- a/drizzle-kit/tests/introspect/mysql.test.ts +++ b/drizzle-kit/tests/introspect/mysql.test.ts @@ -1,12 +1,30 @@ +import 'dotenv/config'; import Docker from 'dockerode'; import { SQL, sql } from 'drizzle-orm'; -import { char, check, int, mysqlTable, mysqlView, serial, text, varchar } from 'drizzle-orm/mysql-core'; +import { + bigint, + char, + check, + decimal, + double, + float, + int, + mediumint, + mysqlEnum, + mysqlTable, + mysqlView, + serial, + smallint, + text, + tinyint, + varchar, +} from 'drizzle-orm/mysql-core'; import * as fs from 'fs'; import getPort from 'get-port'; import { Connection, createConnection } from 'mysql2/promise'; import { introspectMySQLToFile } from 'tests/schemaDiffer'; import { v4 as uuid } from 'uuid'; -import { afterAll, beforeAll, expect, test } from 'vitest'; +import { afterAll, beforeAll, beforeEach, expect, test } from 'vitest'; let client: Connection; let mysqlContainer: Docker.Container; @@ -71,6 +89,12 @@ afterAll(async () => { await mysqlContainer?.stop().catch(console.error); }); +beforeEach(async () => { + await client.query(`drop database if exists \`drizzle\`;`); + await client.query(`create database \`drizzle\`;`); + await client.query(`use \`drizzle\`;`); +}); + if (!fs.existsSync('tests/introspect/mysql')) { fs.mkdirSync('tests/introspect/mysql'); } @@ -95,8 +119,6 @@ test('generated always column: link to another column', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); - - await client.query(`drop table users;`); }); test('generated always column virtual: link to another column', async () => { @@ -120,8 +142,6 @@ test('generated always column virtual: link to another column', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); - - await client.query(`drop table users;`); }); test('Default value of character type column: char', async () => { @@ -141,8 +161,6 @@ test('Default value of character type column: char', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); - - await client.query(`drop table users;`); }); test('Default value of character type column: varchar', async () => { @@ -162,8 +180,6 @@ test('Default value of character type column: varchar', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); - - await client.query(`drop table users;`); }); test('introspect checks', async () => { @@ -186,8 +202,6 @@ test('introspect checks', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); - - await client.query(`drop table users;`); }); test('view #1', async () => { @@ -210,14 +224,9 @@ test('view #1', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); - - await client.query(`drop view some_view;`); - await client.query(`drop table users;`); }); test('view #2', async () => { - // await client.query(`drop view some_view;`); - const users = mysqlTable('some_users', { id: int('id') }); const testView = mysqlView('some_view', { id: int('id') }).algorithm('temptable').sqlSecurity('definer').as( sql`SELECT * FROM ${users}`, @@ -237,6 +246,74 @@ test('view #2', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); +}); + +test('handle float type', async () => { + const schema = { + table: mysqlTable('table', { + col1: float(), + col2: float({ precision: 2 }), + col3: float({ precision: 2, scale: 1 }), + }), + }; + + const { statements, sqlStatements } = await introspectMySQLToFile( + client, + schema, + 'handle-float-type', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('handle unsigned numerical types', async () => { + const schema = { + table: mysqlTable('table', { + col1: int({ unsigned: true }), + col2: tinyint({ unsigned: true }), + col3: smallint({ unsigned: true }), + col4: mediumint({ unsigned: true }), + col5: bigint({ mode: 'number', unsigned: true }), + col6: float({ unsigned: true }), + col7: float({ precision: 2, scale: 1, unsigned: true }), + col8: double({ unsigned: true }), + col9: double({ precision: 2, scale: 1, unsigned: true }), + col10: decimal({ unsigned: true }), + col11: decimal({ precision: 2, scale: 1, unsigned: true }), + }), + }; + + const { statements, sqlStatements } = await introspectMySQLToFile( + client, + schema, + 'handle-unsigned-numerical-types', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + +test('instrospect strings with single quotes', async () => { + const schema = { + columns: mysqlTable('columns', { + enum: mysqlEnum('my_enum', ['escape\'s quotes "', 'escape\'s quotes 2 "']).default('escape\'s quotes "'), + text: text('text').default('escape\'s quotes " '), + varchar: varchar('varchar', { length: 255 }).default('escape\'s quotes " '), + }), + }; + + const { statements, sqlStatements } = await introspectMySQLToFile( + client, + schema, + 'introspect-strings-with-single-quotes', + 'drizzle', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); - await client.query(`drop table some_users;`); + await client.query(`drop table columns;`); }); diff --git a/drizzle-kit/tests/introspect/pg.test.ts b/drizzle-kit/tests/introspect/pg.test.ts index 6762ef27a..1d9f0f18c 100644 --- a/drizzle-kit/tests/introspect/pg.test.ts +++ b/drizzle-kit/tests/introspect/pg.test.ts @@ -255,8 +255,12 @@ test('instrospect all column types', async () => { time2: time('time2').defaultNow(), timestamp1: timestamp('timestamp1', { withTimezone: true, precision: 6 }).default(new Date()), timestamp2: timestamp('timestamp2', { withTimezone: true, precision: 6 }).defaultNow(), + timestamp3: timestamp('timestamp3', { withTimezone: true, precision: 6 }).default( + sql`timezone('utc'::text, now())`, + ), date1: date('date1').default('2024-01-01'), date2: date('date2').defaultNow(), + date3: date('date3').default(sql`CURRENT_TIMESTAMP`), uuid1: uuid('uuid1').default('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'), uuid2: uuid('uuid2').defaultRandom(), inet: inet('inet').default('127.0.0.1'), @@ -418,6 +422,29 @@ test('introspect enum with similar name to native type', async () => { expect(sqlStatements.length).toBe(0); }); +test('instrospect strings with single quotes', async () => { + const client = new PGlite(); + + const myEnum = pgEnum('my_enum', ['escape\'s quotes " ']); + const schema = { + enum_: myEnum, + columns: pgTable('columns', { + enum: myEnum('my_enum').default('escape\'s quotes " '), + text: text('text').default('escape\'s quotes " '), + varchar: varchar('varchar').default('escape\'s quotes " '), + }), + }; + + const { statements, sqlStatements } = await introspectPgToFile( + client, + schema, + 'introspect-strings-with-single-quotes', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + test('introspect checks', async () => { const client = new PGlite(); diff --git a/drizzle-kit/tests/introspect/sqlite.test.ts b/drizzle-kit/tests/introspect/sqlite.test.ts index 89cdf590e..de13d4e81 100644 --- a/drizzle-kit/tests/introspect/sqlite.test.ts +++ b/drizzle-kit/tests/introspect/sqlite.test.ts @@ -56,6 +56,25 @@ test('generated always column virtual: link to another column', async () => { expect(sqlStatements.length).toBe(0); }); +test('instrospect strings with single quotes', async () => { + const sqlite = new Database(':memory:'); + + const schema = { + columns: sqliteTable('columns', { + text: text('text').default('escape\'s quotes " '), + }), + }; + + const { statements, sqlStatements } = await introspectSQLiteToFile( + sqlite, + schema, + 'introspect-strings-with-single-quotes', + ); + + expect(statements.length).toBe(0); + expect(sqlStatements.length).toBe(0); +}); + test('introspect checks', async () => { const sqlite = new Database(':memory:'); diff --git a/drizzle-kit/tests/mysql.test.ts b/drizzle-kit/tests/mysql.test.ts index 183464ec0..881b05ef7 100644 --- a/drizzle-kit/tests/mysql.test.ts +++ b/drizzle-kit/tests/mysql.test.ts @@ -4,6 +4,7 @@ import { index, int, json, + mysqlEnum, mysqlSchema, mysqlTable, primaryKey, @@ -11,6 +12,7 @@ import { text, unique, uniqueIndex, + varchar, } from 'drizzle-orm/mysql-core'; import { expect, test } from 'vitest'; import { diffTestSchemasMysql } from './schemaDiffer'; @@ -533,6 +535,32 @@ test('drop index', async () => { expect(sqlStatements[0]).toBe('DROP INDEX `name_idx` ON `table`;'); }); +test('drop unique constraint', async () => { + const from = { + users: mysqlTable( + 'table', + { + name: text('name'), + }, + (t) => { + return { + uq: unique('name_uq').on(t.name), + }; + }, + ), + }; + + const to = { + users: mysqlTable('table', { + name: text('name'), + }), + }; + + const { sqlStatements } = await diffTestSchemasMysql(from, to, []); + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toBe('ALTER TABLE `table` DROP INDEX `name_uq`;'); +}); + test('add table with indexes', async () => { const from = {}; @@ -578,6 +606,80 @@ test('add table with indexes', async () => { ]); }); +test('varchar and text default values escape single quotes', async (t) => { + const schema1 = { + table: mysqlTable('table', { + id: serial('id').primaryKey(), + }), + }; + + const schem2 = { + table: mysqlTable('table', { + id: serial('id').primaryKey(), + enum: mysqlEnum('enum', ["escape's quotes", "escape's quotes 2"]).default("escape's quotes"), + text: text('text').default("escape's quotes"), + varchar: varchar('varchar', { length: 255 }).default("escape's quotes"), + }), + }; + + const { sqlStatements } = await diffTestSchemasMysql(schema1, schem2, []); + + expect(sqlStatements.length).toBe(3); + expect(sqlStatements[0]).toStrictEqual( + "ALTER TABLE `table` ADD `enum` enum('escape''s quotes','escape''s quotes 2') DEFAULT 'escape''s quotes';", + ); + expect(sqlStatements[1]).toStrictEqual( + "ALTER TABLE `table` ADD `text` text DEFAULT ('escape''s quotes');", + ); + expect(sqlStatements[2]).toStrictEqual( + "ALTER TABLE `table` ADD `varchar` varchar(255) DEFAULT 'escape''s quotes';", + ); +}); + +test('composite primary key', async () => { + const from = {}; + const to = { + table: mysqlTable('works_to_creators', { + workId: int('work_id').notNull(), + creatorId: int('creator_id').notNull(), + classification: text('classification').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.workId, t.creatorId, t.classification], + }), + })), + }; + + const { sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE `works_to_creators` (\n\t`work_id` int NOT NULL,\n\t`creator_id` int NOT NULL,\n\t`classification` text NOT NULL,\n\tCONSTRAINT `works_to_creators_work_id_creator_id_classification_pk` PRIMARY KEY(`work_id`,`creator_id`,`classification`)\n);\n', + ]); +}); + +test('add column before creating unique constraint', async () => { + const from = { + table: mysqlTable('table', { + id: serial('id').primaryKey(), + }), + }; + const to = { + table: mysqlTable('table', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }, (t) => ({ + uq: unique('uq').on(t.name), + })), + }; + + const { sqlStatements } = await diffTestSchemasMysql(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `table` ADD `name` text NOT NULL;', + 'ALTER TABLE `table` ADD CONSTRAINT `uq` UNIQUE(`name`);', + ]); +}); + test('optional db aliases (snake case)', async () => { const from = {}; diff --git a/drizzle-kit/tests/pg-columns.test.ts b/drizzle-kit/tests/pg-columns.test.ts index cffeed3ed..ddd744a81 100644 --- a/drizzle-kit/tests/pg-columns.test.ts +++ b/drizzle-kit/tests/pg-columns.test.ts @@ -1,4 +1,4 @@ -import { integer, pgTable, primaryKey, serial, text, uuid } from 'drizzle-orm/pg-core'; +import { integer, pgTable, primaryKey, serial, text, uuid, varchar } from 'drizzle-orm/pg-core'; import { expect, test } from 'vitest'; import { diffTestSchemas } from './schemaDiffer'; @@ -456,3 +456,29 @@ test('add multiple constraints #3', async (t) => { expect(statements.length).toBe(6); }); + +test('varchar and text default values escape single quotes', async (t) => { + const schema1 = { + table: pgTable('table', { + id: serial('id').primaryKey(), + }), + }; + + const schem2 = { + table: pgTable('table', { + id: serial('id').primaryKey(), + text: text('text').default("escape's quotes"), + varchar: varchar('varchar').default("escape's quotes"), + }), + }; + + const { sqlStatements } = await diffTestSchemas(schema1, schem2, []); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements[0]).toStrictEqual( + 'ALTER TABLE "table" ADD COLUMN "text" text DEFAULT \'escape\'\'s quotes\';', + ); + expect(sqlStatements[1]).toStrictEqual( + 'ALTER TABLE "table" ADD COLUMN "varchar" varchar DEFAULT \'escape\'\'s quotes\';', + ); +}); diff --git a/drizzle-kit/tests/pg-enums.test.ts b/drizzle-kit/tests/pg-enums.test.ts index 99a3dca7e..2af691d46 100644 --- a/drizzle-kit/tests/pg-enums.test.ts +++ b/drizzle-kit/tests/pg-enums.test.ts @@ -1,4 +1,4 @@ -import { pgEnum, pgSchema, pgTable } from 'drizzle-orm/pg-core'; +import { integer, pgEnum, pgSchema, pgTable, serial } from 'drizzle-orm/pg-core'; import { expect, test } from 'vitest'; import { diffTestSchemas } from './schemaDiffer'; @@ -506,6 +506,77 @@ test('enums #18', async () => { }); }); +test('enums #19', async () => { + const myEnum = pgEnum('my_enum', ["escape's quotes"]); + + const from = {}; + + const to = { myEnum }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toStrictEqual( + 'CREATE TYPE "public"."my_enum" AS ENUM(\'escape\'\'s quotes\');', + ); +}); + +test('enums #20', async () => { + const myEnum = pgEnum('my_enum', ['one', 'two', 'three']); + + const from = { + myEnum, + table: pgTable('table', { + id: serial('id').primaryKey(), + }), + }; + + const to = { + myEnum, + table: pgTable('table', { + id: serial('id').primaryKey(), + col1: myEnum('col1'), + col2: integer('col2'), + }), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "table" ADD COLUMN "col1" "my_enum";', + 'ALTER TABLE "table" ADD COLUMN "col2" integer;', + ]); +}); + +test('enums #21', async () => { + const myEnum = pgEnum('my_enum', ['one', 'two', 'three']); + + const from = { + myEnum, + table: pgTable('table', { + id: serial('id').primaryKey(), + }), + }; + + const to = { + myEnum, + table: pgTable('table', { + id: serial('id').primaryKey(), + col1: myEnum('col1').array(), + col2: integer('col2').array(), + }), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements.length).toBe(2); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "table" ADD COLUMN "col1" "my_enum"[];', + 'ALTER TABLE "table" ADD COLUMN "col2" integer[];', + ]); +}); + test('drop enum value', async () => { const enum1 = pgEnum('enum', ['value1', 'value2', 'value3']); diff --git a/drizzle-kit/tests/pg-tables.test.ts b/drizzle-kit/tests/pg-tables.test.ts index 1f2885f92..6ea6e472a 100644 --- a/drizzle-kit/tests/pg-tables.test.ts +++ b/drizzle-kit/tests/pg-tables.test.ts @@ -676,6 +676,106 @@ test('create table with tsvector', async () => { ]); }); +test('composite primary key', async () => { + const from = {}; + const to = { + table: pgTable('works_to_creators', { + workId: integer('work_id').notNull(), + creatorId: integer('creator_id').notNull(), + classification: text('classification').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.workId, t.creatorId, t.classification], + }), + })), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE IF NOT EXISTS "works_to_creators" (\n\t"work_id" integer NOT NULL,\n\t"creator_id" integer NOT NULL,\n\t"classification" text NOT NULL,\n\tCONSTRAINT "works_to_creators_work_id_creator_id_classification_pk" PRIMARY KEY("work_id","creator_id","classification")\n);\n', + ]); +}); + +test('add column before creating unique constraint', async () => { + const from = { + table: pgTable('table', { + id: serial('id').primaryKey(), + }), + }; + const to = { + table: pgTable('table', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }, (t) => ({ + uq: unique('uq').on(t.name), + })), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "table" ADD COLUMN "name" text NOT NULL;', + 'ALTER TABLE "table" ADD CONSTRAINT "uq" UNIQUE("name");', + ]); +}); + +test('alter composite primary key', async () => { + const from = { + table: pgTable('table', { + col1: integer('col1').notNull(), + col2: integer('col2').notNull(), + col3: text('col3').notNull(), + }, (t) => ({ + pk: primaryKey({ + name: 'table_pk', + columns: [t.col1, t.col2], + }), + })), + }; + const to = { + table: pgTable('table', { + col1: integer('col1').notNull(), + col2: integer('col2').notNull(), + col3: text('col3').notNull(), + }, (t) => ({ + pk: primaryKey({ + name: 'table_pk', + columns: [t.col2, t.col3], + }), + })), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "table" DROP CONSTRAINT "table_pk";\n--> statement-breakpoint\nALTER TABLE "table" ADD CONSTRAINT "table_pk" PRIMARY KEY("col2","col3");', + ]); +}); + +test('add index with op', async () => { + const from = { + users: pgTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }), + }; + const to = { + users: pgTable('users', { + id: serial('id').primaryKey(), + name: text('name').notNull(), + }, (t) => ({ + nameIdx: index().using('gin', t.name.op('gin_trgm_ops')), + })), + }; + + const { sqlStatements } = await diffTestSchemas(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE INDEX IF NOT EXISTS "users_name_index" ON "users" USING gin ("name" gin_trgm_ops);', + ]); +}); + test('optional db aliases (snake case)', async () => { const from = {}; diff --git a/drizzle-kit/tests/push/common.ts b/drizzle-kit/tests/push/common.ts index 0c679ca6f..627070f11 100644 --- a/drizzle-kit/tests/push/common.ts +++ b/drizzle-kit/tests/push/common.ts @@ -1,4 +1,4 @@ -import { afterAll, beforeAll, test } from 'vitest'; +import { afterAll, beforeAll, beforeEach, test } from 'vitest'; export interface DialectSuite { allTypes(context?: any): Promise; @@ -15,6 +15,8 @@ export interface DialectSuite { dropGeneratedConstraint(context?: any): Promise; alterGeneratedConstraint(context?: any): Promise; createTableWithGeneratedConstraint(context?: any): Promise; + createCompositePrimaryKey(context?: any): Promise; + renameTableWithCompositePrimaryKey(context?: any): Promise; case1(): Promise; } @@ -22,10 +24,13 @@ export const run = ( suite: DialectSuite, beforeAllFn?: (context: any) => Promise, afterAllFn?: (context: any) => Promise, + beforeEachFn?: (context: any) => Promise, ) => { let context: any = {}; beforeAll(beforeAllFn ? () => beforeAllFn(context) : () => {}); + beforeEach(beforeEachFn ? () => beforeEachFn(context) : () => {}); + test('No diffs for all database types', () => suite.allTypes(context)); test('Adding basic indexes', () => suite.addBasicIndexes(context)); test('Dropping basic index', () => suite.dropIndex(context)); @@ -45,6 +50,9 @@ export const run = ( // should ignore on push test('Alter generated constraint', () => suite.alterGeneratedConstraint(context)); test('Create table with generated column', () => suite.createTableWithGeneratedConstraint(context)); + test('Rename table with composite primary key', () => suite.renameTableWithCompositePrimaryKey(context)); + + test('Create composite primary key', () => suite.createCompositePrimaryKey(context)); afterAll(afterAllFn ? () => afterAllFn(context) : () => {}); }; diff --git a/drizzle-kit/tests/push/mysql.test.ts b/drizzle-kit/tests/push/mysql.test.ts index 5cad140be..6c7f5efc2 100644 --- a/drizzle-kit/tests/push/mysql.test.ts +++ b/drizzle-kit/tests/push/mysql.test.ts @@ -1,3 +1,4 @@ +import 'dotenv/config'; import Docker from 'dockerode'; import { SQL, sql } from 'drizzle-orm'; import { @@ -14,6 +15,7 @@ import { mediumint, mysqlEnum, mysqlTable, + primaryKey, serial, smallint, text, @@ -28,7 +30,7 @@ import getPort from 'get-port'; import { Connection, createConnection } from 'mysql2/promise'; import { diffTestSchemasMysql, diffTestSchemasPushMysql } from 'tests/schemaDiffer'; import { v4 as uuid } from 'uuid'; -import { expect } from 'vitest'; +import { expect, test } from 'vitest'; import { DialectSuite, run } from './common'; async function createDockerDB(context: any): Promise { @@ -662,6 +664,88 @@ const mysqlSuite: DialectSuite = { createTableWithGeneratedConstraint: function(context?: any): Promise { return {} as any; }, + createCompositePrimaryKey: async function(context: any): Promise { + const schema1 = {}; + + const schema2 = { + table: mysqlTable('table', { + col1: int('col1').notNull(), + col2: int('col2').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.col1, t.col2], + }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPushMysql( + context.client as Connection, + schema1, + schema2, + [], + 'drizzle', + false, + ); + + expect(statements).toStrictEqual([ + { + type: 'create_table', + tableName: 'table', + schema: undefined, + internals: { + indexes: {}, + tables: {}, + }, + compositePKs: ['table_col1_col2_pk;col1,col2'], + compositePkName: 'table_col1_col2_pk', + uniqueConstraints: [], + checkConstraints: [], + columns: [ + { name: 'col1', type: 'int', primaryKey: false, notNull: true, autoincrement: false }, + { name: 'col2', type: 'int', primaryKey: false, notNull: true, autoincrement: false }, + ], + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE `table` (\n\t`col1` int NOT NULL,\n\t`col2` int NOT NULL,\n\tCONSTRAINT `table_col1_col2_pk` PRIMARY KEY(`col1`,`col2`)\n);\n', + ]); + }, + renameTableWithCompositePrimaryKey: async function(context?: any): Promise { + const productsCategoriesTable = (tableName: string) => { + return mysqlTable(tableName, { + productId: varchar('product_id', { length: 10 }).notNull(), + categoryId: varchar('category_id', { length: 10 }).notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.productId, t.categoryId], + }), + })); + }; + + const schema1 = { + table: productsCategoriesTable('products_categories'), + }; + const schema2 = { + test: productsCategoriesTable('products_to_categories'), + }; + + const { sqlStatements } = await diffTestSchemasPushMysql( + context.client as Connection, + schema1, + schema2, + ['public.products_categories->public.products_to_categories'], + 'drizzle', + false, + ); + + expect(sqlStatements).toStrictEqual([ + 'RENAME TABLE `products_categories` TO `products_to_categories`;', + 'ALTER TABLE `products_to_categories` DROP PRIMARY KEY;', + 'ALTER TABLE `products_to_categories` ADD PRIMARY KEY(`product_id`,`category_id`);', + ]); + + await context.client.query(`DROP TABLE \`products_categories\``); + }, }; run( @@ -696,4 +780,9 @@ run( await context.client?.end().catch(console.error); await context.mysqlContainer?.stop().catch(console.error); }, + async (context: any) => { + await context.client?.query(`drop database if exists \`drizzle\`;`); + await context.client?.query(`create database \`drizzle\`;`); + await context.client?.query(`use \`drizzle\`;`); + }, ); diff --git a/drizzle-kit/tests/push/pg.test.ts b/drizzle-kit/tests/push/pg.test.ts index 51e6fe73a..44ec786b6 100644 --- a/drizzle-kit/tests/push/pg.test.ts +++ b/drizzle-kit/tests/push/pg.test.ts @@ -22,6 +22,7 @@ import { pgSequence, pgTable, pgView, + primaryKey, real, serial, smallint, @@ -914,6 +915,89 @@ const pgSuite: DialectSuite = { expect(shouldAskForApprove).toBeFalsy(); }, + async createCompositePrimaryKey() { + const client = new PGlite(); + + const schema1 = {}; + + const schema2 = { + table: pgTable('table', { + col1: integer('col1').notNull(), + col2: integer('col2').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.col1, t.col2], + }), + })), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + type: 'create_table', + tableName: 'table', + schema: '', + compositePKs: ['col1,col2;table_col1_col2_pk'], + compositePkName: 'table_col1_col2_pk', + isRLSEnabled: false, + policies: [], + uniqueConstraints: [], + checkConstraints: [], + columns: [ + { name: 'col1', type: 'integer', primaryKey: false, notNull: true }, + { name: 'col2', type: 'integer', primaryKey: false, notNull: true }, + ], + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE IF NOT EXISTS "table" (\n\t"col1" integer NOT NULL,\n\t"col2" integer NOT NULL,\n\tCONSTRAINT "table_col1_col2_pk" PRIMARY KEY("col1","col2")\n);\n', + ]); + }, + + async renameTableWithCompositePrimaryKey() { + const client = new PGlite(); + + const productsCategoriesTable = (tableName: string) => { + return pgTable(tableName, { + productId: text('product_id').notNull(), + categoryId: text('category_id').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.productId, t.categoryId], + }), + })); + }; + + const schema1 = { + table: productsCategoriesTable('products_categories'), + }; + const schema2 = { + test: productsCategoriesTable('products_to_categories'), + }; + + const { sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + ['public.products_categories->public.products_to_categories'], + false, + ['public'], + ); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE "products_categories" RENAME TO "products_to_categories";', + 'ALTER TABLE "products_to_categories" DROP CONSTRAINT "products_categories_product_id_category_id_pk";', + 'ALTER TABLE "products_to_categories" ADD CONSTRAINT "products_to_categories_product_id_category_id_pk" PRIMARY KEY("product_id","category_id");', + ]); + }, + // async addVectorIndexes() { // const client = new PGlite(); @@ -2104,6 +2188,81 @@ test('drop check constraint', async () => { ]); }); +test('Column with same name as enum', async () => { + const client = new PGlite(); + const statusEnum = pgEnum('status', ['inactive', 'active', 'banned']); + + const schema1 = { + statusEnum, + table1: pgTable('table1', { + id: serial('id').primaryKey(), + }), + }; + + const schema2 = { + statusEnum, + table1: pgTable('table1', { + id: serial('id').primaryKey(), + status: statusEnum('status').default('inactive'), + }), + table2: pgTable('table2', { + id: serial('id').primaryKey(), + status: statusEnum('status').default('inactive'), + }), + }; + + const { statements, sqlStatements } = await diffTestSchemasPush( + client, + schema1, + schema2, + [], + false, + ['public'], + ); + + expect(statements).toStrictEqual([ + { + type: 'create_table', + tableName: 'table2', + schema: '', + compositePKs: [], + compositePkName: '', + isRLSEnabled: false, + policies: [], + uniqueConstraints: [], + checkConstraints: [], + columns: [ + { name: 'id', type: 'serial', primaryKey: true, notNull: true }, + { + name: 'status', + type: 'status', + typeSchema: 'public', + primaryKey: false, + notNull: false, + default: "'inactive'", + }, + ], + }, + { + type: 'alter_table_add_column', + tableName: 'table1', + schema: '', + column: { + name: 'status', + type: 'status', + typeSchema: 'public', + primaryKey: false, + notNull: false, + default: "'inactive'", + }, + }, + ]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE IF NOT EXISTS "table2" (\n\t"id" serial PRIMARY KEY NOT NULL,\n\t"status" "status" DEFAULT \'inactive\'\n);\n', + 'ALTER TABLE "table1" ADD COLUMN "status" "status" DEFAULT \'inactive\';', + ]); +}); + test('db has checks. Push with same names', async () => { const client = new PGlite(); diff --git a/drizzle-kit/tests/push/sqlite.test.ts b/drizzle-kit/tests/push/sqlite.test.ts index 5ac6f996c..dd1d88fe3 100644 --- a/drizzle-kit/tests/push/sqlite.test.ts +++ b/drizzle-kit/tests/push/sqlite.test.ts @@ -9,6 +9,7 @@ import { int, integer, numeric, + primaryKey, real, sqliteTable, sqliteView, @@ -1534,3 +1535,79 @@ test('alter view ".as"', async () => { expect(statements.length).toBe(0); expect(sqlStatements.length).toBe(0); }); + +test('create composite primary key', async (t) => { + const client = new Database(':memory:'); + + const schema1 = {}; + + const schema2 = { + table: sqliteTable('table', { + col1: integer('col1').notNull(), + col2: integer('col2').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.col1, t.col2], + }), + })), + }; + + const { + statements, + sqlStatements, + } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + [], + ); + + expect(statements).toStrictEqual([{ + type: 'sqlite_create_table', + tableName: 'table', + compositePKs: [['col1', 'col2']], + uniqueConstraints: [], + referenceData: [], + checkConstraints: [], + columns: [ + { name: 'col1', type: 'integer', primaryKey: false, notNull: true, autoincrement: false }, + { name: 'col2', type: 'integer', primaryKey: false, notNull: true, autoincrement: false }, + ], + }]); + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE `table` (\n\t`col1` integer NOT NULL,\n\t`col2` integer NOT NULL,\n\tPRIMARY KEY(`col1`, `col2`)\n);\n', + ]); +}); + +test('rename table with composite primary key', async () => { + const client = new Database(':memory:'); + + const productsCategoriesTable = (tableName: string) => { + return sqliteTable(tableName, { + productId: text('product_id').notNull(), + categoryId: text('category_id').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.productId, t.categoryId], + }), + })); + }; + + const schema1 = { + table: productsCategoriesTable('products_categories'), + }; + const schema2 = { + test: productsCategoriesTable('products_to_categories'), + }; + + const { sqlStatements } = await diffTestSchemasPushSqlite( + client, + schema1, + schema2, + ['public.products_categories->public.products_to_categories'], + false, + ); + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `products_categories` RENAME TO `products_to_categories`;', + ]); +}); diff --git a/drizzle-kit/tests/sqlite-columns.test.ts b/drizzle-kit/tests/sqlite-columns.test.ts index b7b4c7f6b..0cb34c220 100644 --- a/drizzle-kit/tests/sqlite-columns.test.ts +++ b/drizzle-kit/tests/sqlite-columns.test.ts @@ -1025,3 +1025,25 @@ test('recreate table with nested references', async (t) => { expect(sqlStatements[4]).toBe(`ALTER TABLE \`__new_users\` RENAME TO \`users\`;`); expect(sqlStatements[5]).toBe(`PRAGMA foreign_keys=ON;`); }); + +test('text default values escape single quotes', async (t) => { + const schema1 = { + table: sqliteTable('table', { + id: integer('id').primaryKey(), + }), + }; + + const schem2 = { + table: sqliteTable('table', { + id: integer('id').primaryKey(), + text: text('text').default("escape's quotes"), + }), + }; + + const { sqlStatements } = await diffTestSchemasSqlite(schema1, schem2, []); + + expect(sqlStatements.length).toBe(1); + expect(sqlStatements[0]).toStrictEqual( + "ALTER TABLE `table` ADD `text` text DEFAULT 'escape''s quotes';", + ); +}); diff --git a/drizzle-kit/tests/sqlite-tables.test.ts b/drizzle-kit/tests/sqlite-tables.test.ts index 8d8eae298..651c3633c 100644 --- a/drizzle-kit/tests/sqlite-tables.test.ts +++ b/drizzle-kit/tests/sqlite-tables.test.ts @@ -418,6 +418,50 @@ test('add table with indexes', async () => { ]); }); +test('composite primary key', async () => { + const from = {}; + const to = { + table: sqliteTable('works_to_creators', { + workId: int('work_id').notNull(), + creatorId: int('creator_id').notNull(), + classification: text('classification').notNull(), + }, (t) => ({ + pk: primaryKey({ + columns: [t.workId, t.creatorId, t.classification], + }), + })), + }; + + const { sqlStatements } = await diffTestSchemasSqlite(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'CREATE TABLE `works_to_creators` (\n\t`work_id` integer NOT NULL,\n\t`creator_id` integer NOT NULL,\n\t`classification` text NOT NULL,\n\tPRIMARY KEY(`work_id`, `creator_id`, `classification`)\n);\n', + ]); +}); + +test('add column before creating unique constraint', async () => { + const from = { + table: sqliteTable('table', { + id: int('id').primaryKey(), + }), + }; + const to = { + table: sqliteTable('table', { + id: int('id').primaryKey(), + name: text('name').notNull(), + }, (t) => ({ + uq: unique('uq').on(t.name), + })), + }; + + const { sqlStatements } = await diffTestSchemasSqlite(from, to, []); + + expect(sqlStatements).toStrictEqual([ + 'ALTER TABLE `table` ADD `name` text NOT NULL;', + 'CREATE UNIQUE INDEX `uq` ON `table` (`name`);', + ]); +}); + test('optional db aliases (snake case)', async () => { const from = {}; diff --git a/drizzle-orm/package.json b/drizzle-orm/package.json index e2b17a1af..598ee9a1e 100644 --- a/drizzle-orm/package.json +++ b/drizzle-orm/package.json @@ -1,6 +1,6 @@ { "name": "drizzle-orm", - "version": "0.36.0", + "version": "0.36.1", "description": "Drizzle ORM package for SQL databases", "type": "module", "scripts": { @@ -203,4 +203,4 @@ "zod": "^3.20.2", "zx": "^7.2.2" } -} +} \ No newline at end of file diff --git a/drizzle-orm/src/mysql-core/columns/decimal.ts b/drizzle-orm/src/mysql-core/columns/decimal.ts index 1e5f78679..67cefb531 100644 --- a/drizzle-orm/src/mysql-core/columns/decimal.ts +++ b/drizzle-orm/src/mysql-core/columns/decimal.ts @@ -20,10 +20,11 @@ export class MySqlDecimalBuilder< > extends MySqlColumnBuilderWithAutoIncrement { static override readonly [entityKind]: string = 'MySqlDecimalBuilder'; - constructor(name: T['name'], precision?: number, scale?: number) { + constructor(name: T['name'], config: MySqlDecimalConfig | undefined) { super(name, 'string', 'MySqlDecimal'); - this.config.precision = precision; - this.config.scale = scale; + this.config.precision = config?.precision; + this.config.scale = config?.scale; + this.config.unsigned = config?.unsigned; } /** @internal */ @@ -44,21 +45,26 @@ export class MySqlDecimal> readonly precision: number | undefined = this.config.precision; readonly scale: number | undefined = this.config.scale; + readonly unsigned: boolean | undefined = this.config.unsigned; getSQLType(): string { + let type = ''; if (this.precision !== undefined && this.scale !== undefined) { - return `decimal(${this.precision},${this.scale})`; + type += `decimal(${this.precision},${this.scale})`; } else if (this.precision === undefined) { - return 'decimal'; + type += 'decimal'; } else { - return `decimal(${this.precision})`; + type += `decimal(${this.precision})`; } + type = type === 'decimal(10,0)' || type === 'decimal(10)' ? 'decimal' : type; + return this.unsigned ? `${type} unsigned` : type; } } export interface MySqlDecimalConfig { precision?: number; scale?: number; + unsigned?: boolean; } export function decimal(): MySqlDecimalBuilderInitial<''>; @@ -71,5 +77,5 @@ export function decimal( ): MySqlDecimalBuilderInitial; export function decimal(a?: string | MySqlDecimalConfig, b: MySqlDecimalConfig = {}) { const { name, config } = getColumnNameAndConfig(a, b); - return new MySqlDecimalBuilder(name, config.precision, config.scale); + return new MySqlDecimalBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/columns/double.ts b/drizzle-orm/src/mysql-core/columns/double.ts index c9f95fd04..dfe5fca2e 100644 --- a/drizzle-orm/src/mysql-core/columns/double.ts +++ b/drizzle-orm/src/mysql-core/columns/double.ts @@ -24,6 +24,7 @@ export class MySqlDoubleBuilder> { static override readonly [entityKind]: string = 'MySqlDouble'; - precision: number | undefined = this.config.precision; - scale: number | undefined = this.config.scale; + readonly precision: number | undefined = this.config.precision; + readonly scale: number | undefined = this.config.scale; + readonly unsigned: boolean | undefined = this.config.unsigned; getSQLType(): string { + let type = ''; if (this.precision !== undefined && this.scale !== undefined) { - return `double(${this.precision},${this.scale})`; + type += `double(${this.precision},${this.scale})`; } else if (this.precision === undefined) { - return 'double'; + type += 'double'; } else { - return `double(${this.precision})`; + type += `double(${this.precision})`; } + return this.unsigned ? `${type} unsigned` : type; } } export interface MySqlDoubleConfig { precision?: number; scale?: number; + unsigned?: boolean; } export function double(): MySqlDoubleBuilderInitial<''>; diff --git a/drizzle-orm/src/mysql-core/columns/float.ts b/drizzle-orm/src/mysql-core/columns/float.ts index d7c3e586b..12ebd3e74 100644 --- a/drizzle-orm/src/mysql-core/columns/float.ts +++ b/drizzle-orm/src/mysql-core/columns/float.ts @@ -2,6 +2,7 @@ import type { ColumnBuilderBaseConfig, ColumnBuilderRuntimeConfig, MakeColumnCon import type { ColumnBaseConfig } from '~/column.ts'; import { entityKind } from '~/entity.ts'; import type { AnyMySqlTable } from '~/mysql-core/table.ts'; +import { getColumnNameAndConfig } from '~/utils.ts'; import { MySqlColumnBuilderWithAutoIncrement, MySqlColumnWithAutoIncrement } from './common.ts'; export type MySqlFloatBuilderInitial = MySqlFloatBuilder<{ @@ -15,12 +16,15 @@ export type MySqlFloatBuilderInitial = MySqlFloatBuilder<{ }>; export class MySqlFloatBuilder> - extends MySqlColumnBuilderWithAutoIncrement + extends MySqlColumnBuilderWithAutoIncrement { static override readonly [entityKind]: string = 'MySqlFloatBuilder'; - constructor(name: T['name']) { + constructor(name: T['name'], config: MySqlFloatConfig | undefined) { super(name, 'number', 'MySqlFloat'); + this.config.precision = config?.precision; + this.config.scale = config?.scale; + this.config.unsigned = config?.unsigned; } /** @internal */ @@ -31,16 +35,43 @@ export class MySqlFloatBuilder> extends MySqlColumnWithAutoIncrement { +export class MySqlFloat> + extends MySqlColumnWithAutoIncrement +{ static override readonly [entityKind]: string = 'MySqlFloat'; + readonly precision: number | undefined = this.config.precision; + readonly scale: number | undefined = this.config.scale; + readonly unsigned: boolean | undefined = this.config.unsigned; + getSQLType(): string { - return 'float'; + let type = ''; + if (this.precision !== undefined && this.scale !== undefined) { + type += `float(${this.precision},${this.scale})`; + } else if (this.precision === undefined) { + type += 'float'; + } else { + type += `float(${this.precision})`; + } + return this.unsigned ? `${type} unsigned` : type; } } +export interface MySqlFloatConfig { + precision?: number; + scale?: number; + unsigned?: boolean; +} + export function float(): MySqlFloatBuilderInitial<''>; -export function float(name: TName): MySqlFloatBuilderInitial; -export function float(name?: string) { - return new MySqlFloatBuilder(name ?? ''); +export function float( + config?: MySqlFloatConfig, +): MySqlFloatBuilderInitial<''>; +export function float( + name: TName, + config?: MySqlFloatConfig, +): MySqlFloatBuilderInitial; +export function float(a?: string | MySqlFloatConfig, b?: MySqlFloatConfig) { + const { name, config } = getColumnNameAndConfig(a, b); + return new MySqlFloatBuilder(name, config); } diff --git a/drizzle-orm/src/mysql-core/query-builders/select.ts b/drizzle-orm/src/mysql-core/query-builders/select.ts index 95f67827b..63c4b903e 100644 --- a/drizzle-orm/src/mysql-core/query-builders/select.ts +++ b/drizzle-orm/src/mysql-core/query-builders/select.ts @@ -17,7 +17,7 @@ import type { } from '~/query-builders/select.types.ts'; import { QueryPromise } from '~/query-promise.ts'; import { SelectionProxyHandler } from '~/selection-proxy.ts'; -import type { ColumnsSelection, Query } from '~/sql/sql.ts'; +import type { ColumnsSelection, Placeholder, Query } from '~/sql/sql.ts'; import { SQL, View } from '~/sql/sql.ts'; import { Subquery } from '~/subquery.ts'; import { Table } from '~/table.ts'; @@ -811,7 +811,7 @@ export abstract class MySqlSelectQueryBuilderBase< * await db.select().from(people).limit(10); * ``` */ - limit(limit: number): MySqlSelectWithout { + limit(limit: number | Placeholder): MySqlSelectWithout { if (this.config.setOperators.length > 0) { this.config.setOperators.at(-1)!.limit = limit; } else { @@ -836,7 +836,7 @@ export abstract class MySqlSelectQueryBuilderBase< * await db.select().from(people).offset(10).limit(10); * ``` */ - offset(offset: number): MySqlSelectWithout { + offset(offset: number | Placeholder): MySqlSelectWithout { if (this.config.setOperators.length > 0) { this.config.setOperators.at(-1)!.offset = offset; } else { diff --git a/drizzle-orm/src/sqlite-core/columns/blob.ts b/drizzle-orm/src/sqlite-core/columns/blob.ts index b7cd90be1..22deb3a84 100644 --- a/drizzle-orm/src/sqlite-core/columns/blob.ts +++ b/drizzle-orm/src/sqlite-core/columns/blob.ts @@ -41,8 +41,8 @@ export class SQLiteBigInt> return 'blob'; } - override mapFromDriverValue(value: Buffer): bigint { - return BigInt(value.toString()); + override mapFromDriverValue(value: Buffer | Uint8Array): bigint { + return BigInt(Buffer.isBuffer(value) ? value.toString() : String.fromCodePoint(...value)); } override mapToDriverValue(value: bigint): Buffer { @@ -87,8 +87,8 @@ export class SQLiteBlobJson return 'blob'; } - override mapFromDriverValue(value: Buffer): T['data'] { - return JSON.parse(value.toString()); + override mapFromDriverValue(value: Buffer | Uint8Array): T['data'] { + return JSON.parse(Buffer.isBuffer(value) ? value.toString() : String.fromCodePoint(...value)); } override mapToDriverValue(value: T['data']): Buffer { diff --git a/drizzle-orm/src/supabase/rls.ts b/drizzle-orm/src/supabase/rls.ts index 20fea7355..d5f813ac6 100644 --- a/drizzle-orm/src/supabase/rls.ts +++ b/drizzle-orm/src/supabase/rls.ts @@ -1,4 +1,4 @@ -import { bigserial, pgSchema, text, uuid } from '~/pg-core/index.ts'; +import { bigserial, pgSchema, text, timestamp, uuid, varchar } from '~/pg-core/index.ts'; import { pgRole } from '~/pg-core/roles.ts'; import { sql } from '~/sql/sql.ts'; @@ -13,6 +13,13 @@ const auth = pgSchema('auth'); export const authUsers = auth.table('users', { id: uuid().primaryKey().notNull(), + email: varchar({ length: 255 }), + phone: text().unique(), + emailConfirmedAt: timestamp('email_confirmed_at', { withTimezone: true }), + phoneConfirmedAt: timestamp('phone_confirmed_at', { withTimezone: true }), + lastSignInAt: timestamp('last_sign_in_at', { withTimezone: true }), + createdAt: timestamp('created_at', { withTimezone: true }), + updatedAt: timestamp('updated_at', { withTimezone: true }), }); /* ------------------------------ realtime schema; ------------------------------- */ diff --git a/drizzle-orm/type-tests/mysql/tables.ts b/drizzle-orm/type-tests/mysql/tables.ts index aca5c63d7..adc8e8eb8 100644 --- a/drizzle-orm/type-tests/mysql/tables.ts +++ b/drizzle-orm/type-tests/mysql/tables.ts @@ -864,6 +864,9 @@ Expect< enum: mysqlEnum('enum', ['a', 'b', 'c']), enumdef: mysqlEnum('enumdef', ['a', 'b', 'c']).default('a'), float: float('float'), + float2: float('float2', { precision: 10 }), + float3: float('float3', { scale: 2 }), + float4: float('float4', { precision: 10, scale: 2 }), floatdef: float('floatdef').default(0), int: int('int'), int2: int('int2', { unsigned: true }), @@ -961,6 +964,9 @@ Expect< enum: mysqlEnum(['a', 'b', 'c']), enumdef: mysqlEnum(['a', 'b', 'c']).default('a'), float: float(), + float2: float({ precision: 10 }), + float3: float({ scale: 2 }), + float4: float({ precision: 10, scale: 2 }), floatdef: float().default(0), int: int(), int2: int({ unsigned: true }), diff --git a/integration-tests/tests/bun/sqlite.test.ts b/integration-tests/tests/bun/sqlite.test.ts index 0065b1928..c6ce9d4d1 100644 --- a/integration-tests/tests/bun/sqlite.test.ts +++ b/integration-tests/tests/bun/sqlite.test.ts @@ -1,41 +1,34 @@ -/// import { Database } from 'bun:sqlite'; -import { DefaultLogger, sql } from 'drizzle-orm'; +import { beforeAll, beforeEach, expect, test } from 'bun:test'; +import { sql } from 'drizzle-orm'; import type { BunSQLiteDatabase } from 'drizzle-orm/bun-sqlite'; import { drizzle } from 'drizzle-orm/bun-sqlite'; import { blob, integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'; -import { suite } from 'uvu'; -import * as assert from 'uvu/assert'; const usersTable = sqliteTable('users', { id: integer('id').primaryKey(), name: text('name').notNull(), verified: integer('verified').notNull().default(0), json: blob('json', { mode: 'json' }).$type(), - createdAt: integer('created_at', { mode: 'timestamp' }).notNull().defaultNow(), + bigInt: blob('big_int', { mode: 'bigint' }), + createdAt: integer('created_at', { mode: 'timestamp_ms' }).notNull().default(sql`strftime('%s', 'now')`), }); -interface Context { - db: BunSQLiteDatabase; -} +let db: BunSQLiteDatabase; -const test = suite('sqlite-bun'); - -test.before((ctx) => { +beforeAll(async () => { try { const dbPath = process.env['SQLITE_DB_PATH'] ?? ':memory:'; const client = new Database(dbPath); - ctx.db = drizzle(client, { logger: new DefaultLogger() }); + db = drizzle(client); } catch (e) { console.error(e); } }); -test.before.each((ctx) => { +beforeEach(async () => { try { - const { db } = ctx; - db.run(sql`drop table if exists ${usersTable}`); db.run(sql` create table ${usersTable} ( @@ -43,7 +36,8 @@ test.before.each((ctx) => { name text not null, verified integer not null default 0, json blob, - created_at text not null default (strftime('%s', 'now')) + big_int blob, + created_at integer not null default (strftime('%s', 'now')) ) `); } catch (e) { @@ -51,34 +45,30 @@ test.before.each((ctx) => { } }); -test.skip('select large integer', async (ctx) => { +test.skip('select large integer', () => { const a = 1667476703000; - const res = await ctx.db.all<{ a: number }>(sql`select ${sql.raw(String(a))} as a`); + const res = db.all<{ a: number }>(sql`select ${sql.raw(String(a))} as a`); const result = res[0]!; - assert.equal(result.a, a); + expect(result.a).toEqual(a); }); -test('select all fields', (ctx) => { - const { db } = ctx; - +test('select all fields', () => { const now = Date.now(); db.insert(usersTable).values({ name: 'John' }).run(); const result = db.select().from(usersTable).all()[0]!; - assert.ok(result.createdAt instanceof Date, 'createdAt is a Date'); // eslint-disable-line no-instanceof/no-instanceof - assert.ok( - Math.abs(result.createdAt.getTime() - now) < 100, - `${result.createdAt.getTime()} is within 100ms of ${now}`, - ); - assert.equal( - result, - { id: 1, name: 'John', verified: 0, json: null, createdAt: result.createdAt }, - 'result is correct', - ); + expect(result.createdAt).toBeInstanceOf(Date); + expect(Math.abs(result.createdAt.getTime() - now)).toBeLessThan(100); + expect(result).toEqual({ id: 1, name: 'John', verified: 0, json: null, createdAt: result.createdAt, bigInt: null }); }); -test.run(); +test('select bigint', () => { + db.insert(usersTable).values({ name: 'John', bigInt: BigInt(100) }).run(); + const result = db.select({ bigInt: usersTable.bigInt }).from(usersTable).all()[0]!; + + expect(result).toEqual({ bigInt: BigInt(100) }); +}); // test.serial('select partial', (t) => { // const { db } = t.context; diff --git a/integration-tests/tests/mysql/mysql-common.ts b/integration-tests/tests/mysql/mysql-common.ts index 45b96f391..5dde42934 100644 --- a/integration-tests/tests/mysql/mysql-common.ts +++ b/integration-tests/tests/mysql/mysql-common.ts @@ -19,7 +19,6 @@ import { min, Name, notInArray, - placeholder, sql, sum, sumDistinct, @@ -1184,7 +1183,7 @@ export function tests(driver?: string) { const stmt = db.insert(usersTable).values({ verified: true, - name: placeholder('name'), + name: sql.placeholder('name'), }).prepare(); for (let i = 0; i < 10; i++) { @@ -1219,13 +1218,75 @@ export function tests(driver?: string) { id: usersTable.id, name: usersTable.name, }).from(usersTable) - .where(eq(usersTable.id, placeholder('id'))) + .where(eq(usersTable.id, sql.placeholder('id'))) .prepare(); const result = await stmt.execute({ id: 1 }); expect(result).toEqual([{ id: 1, name: 'John' }]); }); + test('prepared statement with placeholder in .limit', async (ctx) => { + const { db } = ctx.mysql; + + await db.insert(usersTable).values({ name: 'John' }); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .where(eq(usersTable.id, sql.placeholder('id'))) + .limit(sql.placeholder('limit')) + .prepare(); + + const result = await stmt.execute({ id: 1, limit: 1 }); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + expect(result).toHaveLength(1); + }); + + test('prepared statement with placeholder in .offset', async (ctx) => { + const { db } = ctx.mysql; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'John1' }]); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .limit(sql.placeholder('limit')) + .offset(sql.placeholder('offset')) + .prepare(); + + const result = await stmt.execute({ limit: 1, offset: 1 }); + + expect(result).toEqual([{ id: 2, name: 'John1' }]); + }); + + test('prepared statement built using $dynamic', async (ctx) => { + const { db } = ctx.mysql; + + function withLimitOffset(qb: any) { + return qb.limit(sql.placeholder('limit')).offset(sql.placeholder('offset')); + } + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'John1' }]); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .$dynamic(); + withLimitOffset(stmt).prepare('stmt_limit'); + + const result = await stmt.execute({ limit: 1, offset: 1 }); + + expect(result).toEqual([{ id: 2, name: 'John1' }]); + expect(result).toHaveLength(1); + }); + test('migrator', async (ctx) => { const { db } = ctx.mysql; diff --git a/integration-tests/tests/pg/pg-common.ts b/integration-tests/tests/pg/pg-common.ts index 3b3e4cb4d..c7f4b9be7 100644 --- a/integration-tests/tests/pg/pg-common.ts +++ b/integration-tests/tests/pg/pg-common.ts @@ -1260,6 +1260,29 @@ export function tests() { expect(result).toEqual([{ id: 2, name: 'John1' }]); }); + test('prepared statement built using $dynamic', async (ctx) => { + const { db } = ctx.pg; + + function withLimitOffset(qb: any) { + return qb.limit(sql.placeholder('limit')).offset(sql.placeholder('offset')); + } + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'John1' }]); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .$dynamic(); + withLimitOffset(stmt).prepare('stmt_limit'); + + const result = await stmt.execute({ limit: 1, offset: 1 }); + + expect(result).toEqual([{ id: 2, name: 'John1' }]); + expect(result).toHaveLength(1); + }); + // TODO change tests to new structure test('Query check: Insert all defaults in 1 row', async (ctx) => { const { db } = ctx.pg; @@ -5041,5 +5064,29 @@ export function tests() { { count: 3 }, ]); }); + + test('insert multiple rows into table with generated identity column', async (ctx) => { + const { db } = ctx.pg; + + const users = pgTable('users', { + id: integer('id').primaryKey().generatedAlwaysAsIdentity(), + name: text('name').notNull(), + }); + + await db.execute(sql`drop table if exists ${users}`); + await db.execute(sql`create table ${users} ("id" integer generated always as identity primary key, "name" text)`); + + const result = await db.insert(users).values([ + { name: 'John' }, + { name: 'Jane' }, + { name: 'Bob' }, + ]).returning(); + + expect(result).toEqual([ + { id: 1, name: 'John' }, + { id: 2, name: 'Jane' }, + { id: 3, name: 'Bob' }, + ]); + }); }); } diff --git a/integration-tests/tests/sqlite/sqlite-common.ts b/integration-tests/tests/sqlite/sqlite-common.ts index 83beff74d..a20ce5bbf 100644 --- a/integration-tests/tests/sqlite/sqlite-common.ts +++ b/integration-tests/tests/sqlite/sqlite-common.ts @@ -906,6 +906,68 @@ export function tests() { expect(result).toEqual([{ id: 1, name: 'John' }]); }); + test('prepared statement with placeholder in .limit', async (ctx) => { + const { db } = ctx.sqlite; + + await db.insert(usersTable).values({ name: 'John' }).run(); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .where(eq(usersTable.id, sql.placeholder('id'))) + .limit(sql.placeholder('limit')) + .prepare(); + + const result = await stmt.all({ id: 1, limit: 1 }); + + expect(result).toEqual([{ id: 1, name: 'John' }]); + expect(result).toHaveLength(1); + }); + + test('prepared statement with placeholder in .offset', async (ctx) => { + const { db } = ctx.sqlite; + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'John1' }]).run(); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .limit(sql.placeholder('limit')) + .offset(sql.placeholder('offset')) + .prepare(); + + const result = await stmt.all({ limit: 1, offset: 1 }); + + expect(result).toEqual([{ id: 2, name: 'John1' }]); + }); + + test('prepared statement built using $dynamic', async (ctx) => { + const { db } = ctx.sqlite; + + function withLimitOffset(qb: any) { + return qb.limit(sql.placeholder('limit')).offset(sql.placeholder('offset')); + } + + await db.insert(usersTable).values([{ name: 'John' }, { name: 'John1' }]).run(); + const stmt = db + .select({ + id: usersTable.id, + name: usersTable.name, + }) + .from(usersTable) + .$dynamic(); + withLimitOffset(stmt).prepare('stmt_limit'); + + const result = await stmt.all({ limit: 1, offset: 1 }); + + expect(result).toEqual([{ id: 2, name: 'John1' }]); + expect(result).toHaveLength(1); + }); + test('select with group by as field', async (ctx) => { const { db } = ctx.sqlite; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ed86a8353..468f12ca6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -40,7 +40,7 @@ importers: version: link:drizzle-orm/dist drizzle-orm-old: specifier: npm:drizzle-orm@^0.27.2 - version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) + version: drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7) eslint: specifier: ^8.50.0 version: 8.50.0 @@ -73,7 +73,7 @@ importers: version: 0.8.16(typescript@5.6.3) tsup: specifier: ^7.2.0 - version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3) + version: 7.2.0(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3))(typescript@5.6.3) tsx: specifier: ^4.10.5 version: 4.10.5 @@ -141,6 +141,9 @@ importers: '@types/json-diff': specifier: ^1.0.3 version: 1.0.3 + '@types/micromatch': + specifier: ^4.0.9 + version: 4.0.9 '@types/minimatch': specifier: ^5.1.2 version: 5.1.2 @@ -231,6 +234,9 @@ importers: json-diff: specifier: 1.0.6 version: 1.0.6 + micromatch: + specifier: ^4.0.8 + version: 4.0.8 minimatch: specifier: ^7.4.3 version: 7.4.6 @@ -240,6 +246,9 @@ importers: node-fetch: specifier: ^3.3.2 version: 3.3.2 + ohm-js: + specifier: ^17.1.0 + version: 17.1.0 pg: specifier: ^8.11.5 version: 8.11.5 @@ -2001,9 +2010,11 @@ packages: '@esbuild-kit/core-utils@3.1.0': resolution: {integrity: sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==} + deprecated: 'Merged into tsx: https://tsx.is' '@esbuild-kit/esm-loader@2.5.5': resolution: {integrity: sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==} + deprecated: 'Merged into tsx: https://tsx.is' '@esbuild-plugins/node-globals-polyfill@0.2.3': resolution: {integrity: sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==} @@ -2990,10 +3001,12 @@ packages: '@humanwhocodes/config-array@0.11.11': resolution: {integrity: sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/config-array@0.11.13': resolution: {integrity: sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==} engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead '@humanwhocodes/config-array@0.11.14': resolution: {integrity: sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==} @@ -3006,9 +3019,11 @@ packages: '@humanwhocodes/object-schema@1.2.1': resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + deprecated: Use @eslint/object-schema instead '@humanwhocodes/object-schema@2.0.1': resolution: {integrity: sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==} + deprecated: Use @eslint/object-schema instead '@humanwhocodes/object-schema@2.0.3': resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} @@ -4012,6 +4027,9 @@ packages: '@types/body-parser@1.19.5': resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} + '@types/braces@3.0.4': + resolution: {integrity: sha512-0WR3b8eaISjEW7RpZnclONaLFDf7buaowRHdqLp4vLj54AsSAYWfh3DRbfiYJY9XDxMgx1B4sE1Afw2PGpuHOA==} + '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} @@ -4066,6 +4084,9 @@ packages: '@types/jsonfile@6.1.4': resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} + '@types/micromatch@4.0.9': + resolution: {integrity: sha512-7V+8ncr22h4UoYRLnLXSpTxjQrNUXtWHGeMPRJt1nULXI57G9bIcpyrHlmrQ7QK24EyyuXvYcSSWAM8GA9nqCg==} + '@types/mime@1.3.5': resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} @@ -4556,6 +4577,7 @@ packages: are-we-there-yet@3.0.1: resolution: {integrity: sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -4780,10 +4802,6 @@ packages: brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} - braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} - braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -5971,16 +5989,19 @@ packages: eslint@8.50.0: resolution: {integrity: sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true eslint@8.53.0: resolution: {integrity: sha512-N4VuiPjXDUa4xVeV/GC/RV3hQW9Nw+Y463lkWaKKXKYMvmRiRDAtfpuPFLN+E1/6ZhyR8J2ig+eVREnYgUsiag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true eslint@8.57.0: resolution: {integrity: sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true esm@3.2.25: @@ -6186,10 +6207,6 @@ packages: file-uri-to-path@1.0.0: resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} - fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} @@ -6347,6 +6364,7 @@ packages: gauge@4.0.4: resolution: {integrity: sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. generate-function@2.3.1: resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==} @@ -7166,10 +7184,12 @@ packages: libsql@0.3.19: resolution: {integrity: sha512-Aj5cQ5uk/6fHdmeW0TiXK42FqUlwx7ytmMLPSaUQPin5HKKKuUPD62MAbN4OEweGBBI7q1BekoEN4gPUEL6MZA==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] libsql@0.4.1: resolution: {integrity: sha512-qZlR9Yu1zMBeLChzkE/cKfoKV3Esp9cn9Vx5Zirn4AVhDWPcjYhKwbtJcMuHehgk3mH+fJr9qW+3vesBWbQpBg==} + cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lighthouse-logger@1.4.2: @@ -7549,14 +7569,14 @@ packages: engines: {node: '>=18'} hasBin: true - micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} - micromatch@4.0.7: resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} engines: {node: '>=8.6'} + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -7862,6 +7882,7 @@ packages: npmlog@6.0.2: resolution: {integrity: sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + deprecated: This package is no longer supported. npx-import@1.1.4: resolution: {integrity: sha512-3ShymTWOgqGyNlh5lMJAejLuIv3W1K3fbI5Ewc6YErZU3Sp0PqsNs8UIU1O8z5+KVl/Du5ag56Gza9vdorGEoA==} @@ -7913,6 +7934,10 @@ packages: obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + ohm-js@17.1.0: + resolution: {integrity: sha512-xc3B5dgAjTBQGHaH7B58M2Pmv6WvzrJ/3/7LeUzXNg0/sY3jQPdSd/S2SstppaleO77rifR1tyhdfFGNIwxf2Q==} + engines: {node: '>=0.12.1'} + oidc-token-hash@5.0.3: resolution: {integrity: sha512-IF4PcGgzAr6XXSff26Sk/+P4KZFJVuHAJZj3wgO3vX2bMdNVp/QXTP3P7CEm9V1IdG8lDLY3HhiqpsE/nOwpPw==} engines: {node: ^10.13.0 || >=12.0.0} @@ -8682,6 +8707,7 @@ packages: rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported hasBin: true rimraf@5.0.0: @@ -10245,7 +10271,7 @@ snapshots: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.569.0 - '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/core': 3.567.0 '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) '@aws-sdk/middleware-host-header': 3.567.0 @@ -10386,7 +10412,7 @@ snapshots: dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/core': 3.567.0 '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) '@aws-sdk/middleware-host-header': 3.567.0 @@ -10646,58 +10672,13 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/client-sts@3.569.0': - dependencies: - '@aws-crypto/sha256-browser': 3.0.0 - '@aws-crypto/sha256-js': 3.0.0 - '@aws-sdk/client-sso-oidc': 3.569.0 - '@aws-sdk/core': 3.567.0 - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) - '@aws-sdk/middleware-host-header': 3.567.0 - '@aws-sdk/middleware-logger': 3.568.0 - '@aws-sdk/middleware-recursion-detection': 3.567.0 - '@aws-sdk/middleware-user-agent': 3.567.0 - '@aws-sdk/region-config-resolver': 3.567.0 - '@aws-sdk/types': 3.567.0 - '@aws-sdk/util-endpoints': 3.567.0 - '@aws-sdk/util-user-agent-browser': 3.567.0 - '@aws-sdk/util-user-agent-node': 3.568.0 - '@smithy/config-resolver': 2.2.0 - '@smithy/core': 1.4.2 - '@smithy/fetch-http-handler': 2.5.0 - '@smithy/hash-node': 2.2.0 - '@smithy/invalid-dependency': 2.2.0 - '@smithy/middleware-content-length': 2.2.0 - '@smithy/middleware-endpoint': 2.5.1 - '@smithy/middleware-retry': 2.3.1 - '@smithy/middleware-serde': 2.3.0 - '@smithy/middleware-stack': 2.2.0 - '@smithy/node-config-provider': 2.3.0 - '@smithy/node-http-handler': 2.5.0 - '@smithy/protocol-http': 3.3.0 - '@smithy/smithy-client': 2.5.1 - '@smithy/types': 2.12.0 - '@smithy/url-parser': 2.2.0 - '@smithy/util-base64': 2.3.0 - '@smithy/util-body-length-browser': 2.2.0 - '@smithy/util-body-length-node': 2.3.0 - '@smithy/util-defaults-mode-browser': 2.2.1 - '@smithy/util-defaults-mode-node': 2.3.1 - '@smithy/util-endpoints': 1.2.0 - '@smithy/util-middleware': 2.2.0 - '@smithy/util-retry': 2.2.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 - transitivePeerDependencies: - - aws-crt - '@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)': dependencies: '@aws-crypto/sha256-browser': 3.0.0 '@aws-crypto/sha256-js': 3.0.0 '@aws-sdk/client-sso-oidc': 3.569.0 '@aws-sdk/core': 3.567.0 - '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0) '@aws-sdk/middleware-host-header': 3.567.0 '@aws-sdk/middleware-logger': 3.568.0 '@aws-sdk/middleware-recursion-detection': 3.567.0 @@ -10881,23 +10862,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': - dependencies: - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-env': 3.568.0 - '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/types': 3.567.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - aws-crt - '@aws-sdk/credential-provider-ini@3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': dependencies: '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) @@ -10921,7 +10885,7 @@ snapshots: '@aws-sdk/credential-provider-env': 3.568.0 '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -10965,25 +10929,6 @@ snapshots: transitivePeerDependencies: - aws-crt - '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': - dependencies: - '@aws-sdk/credential-provider-env': 3.568.0 - '@aws-sdk/credential-provider-http': 3.568.0 - '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/credential-provider-process': 3.568.0 - '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) - '@aws-sdk/types': 3.567.0 - '@smithy/credential-provider-imds': 2.3.0 - '@smithy/property-provider': 2.2.0 - '@smithy/shared-ini-file-loader': 2.4.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - transitivePeerDependencies: - - '@aws-sdk/client-sso-oidc' - - '@aws-sdk/client-sts' - - aws-crt - '@aws-sdk/credential-provider-node@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)(@aws-sdk/client-sts@3.569.0)': dependencies: '@aws-sdk/credential-provider-env': 3.568.0 @@ -11010,7 +10955,7 @@ snapshots: '@aws-sdk/credential-provider-ini': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -11123,17 +11068,9 @@ snapshots: '@smithy/types': 2.12.0 tslib: 2.6.2 - '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0))': - dependencies: - '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) - '@aws-sdk/types': 3.567.0 - '@smithy/property-provider': 2.2.0 - '@smithy/types': 2.12.0 - tslib: 2.6.2 - '@aws-sdk/credential-provider-web-identity@3.568.0(@aws-sdk/client-sts@3.569.0)': dependencies: - '@aws-sdk/client-sts': 3.569.0 + '@aws-sdk/client-sts': 3.569.0(@aws-sdk/client-sso-oidc@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/types': 2.12.0 @@ -11159,7 +11096,7 @@ snapshots: '@aws-sdk/credential-provider-node': 3.569.0(@aws-sdk/client-sso-oidc@3.583.0)(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) '@aws-sdk/credential-provider-process': 3.568.0 '@aws-sdk/credential-provider-sso': 3.568.0(@aws-sdk/client-sso-oidc@3.583.0) - '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0(@aws-sdk/client-sso-oidc@3.569.0)) + '@aws-sdk/credential-provider-web-identity': 3.568.0(@aws-sdk/client-sts@3.569.0) '@aws-sdk/types': 3.567.0 '@smithy/credential-provider-imds': 2.3.0 '@smithy/property-provider': 2.2.0 @@ -13239,7 +13176,7 @@ snapshots: find-up: 5.0.0 find-yarn-workspace-root: 2.0.0 js-yaml: 3.14.1 - micromatch: 4.0.7 + micromatch: 4.0.8 npm-package-arg: 7.0.0 ora: 3.4.0 split: 1.0.1 @@ -14731,6 +14668,8 @@ snapshots: '@types/connect': 3.4.38 '@types/node': 20.12.12 + '@types/braces@3.0.4': {} + '@types/connect@3.4.38': dependencies: '@types/node': 20.12.12 @@ -14798,6 +14737,10 @@ snapshots: dependencies: '@types/node': 20.12.12 + '@types/micromatch@4.0.9': + dependencies: + '@types/braces': 3.0.4 + '@types/mime@1.3.5': {} '@types/minimatch@5.1.2': {} @@ -15737,10 +15680,6 @@ snapshots: dependencies: balanced-match: 1.0.2 - braces@3.0.2: - dependencies: - fill-range: 7.0.1 - braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -16493,7 +16432,7 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0)(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): + drizzle-orm@0.27.2(@aws-sdk/client-rds-data@3.583.0)(@cloudflare/workers-types@4.20241004.0)(@libsql/client@0.10.0(bufferutil@4.0.8)(utf-8-validate@6.0.3))(@neondatabase/serverless@0.9.3)(@opentelemetry/api@1.8.0)(@planetscale/database@1.18.0)(@types/better-sqlite3@7.6.10)(@types/pg@8.11.6)(@types/sql.js@1.4.9)(@vercel/postgres@0.8.0)(better-sqlite3@9.6.0)(bun-types@1.0.3)(knex@2.5.1(better-sqlite3@9.6.0)(mysql2@3.11.0)(pg@8.11.5)(sqlite3@5.1.7))(kysely@0.25.0)(mysql2@3.11.0)(pg@8.11.5)(postgres@3.4.4)(sql.js@1.10.3)(sqlite3@5.1.7): optionalDependencies: '@aws-sdk/client-rds-data': 3.583.0 '@cloudflare/workers-types': 4.20241004.0 @@ -17456,7 +17395,7 @@ snapshots: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 + micromatch: 4.0.7 fast-glob@3.3.2: dependencies: @@ -17526,10 +17465,6 @@ snapshots: file-uri-to-path@1.0.0: {} - fill-range@7.0.1: - dependencies: - to-regex-range: 5.0.1 - fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 @@ -17585,7 +17520,7 @@ snapshots: find-yarn-workspace-root@2.0.0: dependencies: - micromatch: 4.0.7 + micromatch: 4.0.8 flat-cache@3.1.0: dependencies: @@ -18299,7 +18234,7 @@ snapshots: '@types/stack-utils': 2.0.3 chalk: 4.1.2 graceful-fs: 4.2.11 - micromatch: 4.0.7 + micromatch: 4.0.8 pretty-format: 29.7.0 slash: 3.0.0 stack-utils: 2.0.6 @@ -18393,7 +18328,7 @@ snapshots: chalk: 4.1.2 flow-parser: 0.236.0 graceful-fs: 4.2.11 - micromatch: 4.0.7 + micromatch: 4.0.8 neo-async: 2.6.2 node-dir: 0.1.17 recast: 0.21.5 @@ -18903,7 +18838,7 @@ snapshots: graceful-fs: 4.2.11 invariant: 2.2.4 jest-worker: 29.7.0 - micromatch: 4.0.7 + micromatch: 4.0.8 node-abort-controller: 3.1.1 nullthrows: 1.1.1 walker: 1.0.8 @@ -19027,12 +18962,12 @@ snapshots: - supports-color - utf-8-validate - micromatch@4.0.5: + micromatch@4.0.7: dependencies: - braces: 3.0.2 + braces: 3.0.3 picomatch: 2.3.1 - micromatch@4.0.7: + micromatch@4.0.8: dependencies: braces: 3.0.3 picomatch: 2.3.1 @@ -19403,6 +19338,8 @@ snapshots: obuf@1.1.2: {} + ohm-js@17.1.0: {} + oidc-token-hash@5.0.3: {} on-finished@2.3.0: @@ -19715,7 +19652,7 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)): + postcss-load-config@4.0.1(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3)): dependencies: lilconfig: 2.1.0 yaml: 2.3.1 @@ -20986,7 +20923,7 @@ snapshots: tslib@2.6.2: {} - tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3))(typescript@5.6.3): + tsup@7.2.0(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3))(typescript@5.6.3): dependencies: bundle-require: 4.0.2(esbuild@0.18.20) cac: 6.7.14 @@ -20996,7 +20933,7 @@ snapshots: execa: 5.1.1 globby: 11.1.0 joycon: 3.1.1 - postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(typescript@5.6.3)) + postcss-load-config: 4.0.1(postcss@8.4.39)(ts-node@10.9.2(@types/node@20.12.12)(typescript@5.6.3)) resolve-from: 5.0.0 rollup: 3.27.2 source-map: 0.8.0-beta.0