|
1 | | -import { stringifyArray, stringifyTuplesArray, trimChar } from '../../utils'; |
| 1 | +import { ArrayValue, stringifyArray, stringifyTuplesArray, trimChar } from '../../utils'; |
2 | 2 | import { assertUnreachable } from '../../utils'; |
3 | 3 | import { parseArray } from '../../utils/parse-pgarray'; |
4 | 4 | import { hash } from '../common'; |
5 | | -import { Column, PostgresEntities } from './ddl'; |
| 5 | +import type { Column, PostgresEntities } from './ddl'; |
| 6 | +import type { Import } from './typescript'; |
| 7 | + |
| 8 | +export interface SqlType { |
| 9 | + is(type: string): boolean; |
| 10 | + drizzleImport(): Import; |
| 11 | + defaultFromDrizzle<MODE = unknown>(value: unknown, mode?: MODE): Column['default']; |
| 12 | + defaultArrayFromDrizzle<MODE = unknown>(value: any[], mode?: MODE): Column['default']; |
| 13 | + defaultFromIntrospect(value: string): Column['default']; |
| 14 | + defaultArrayFromIntrospect(value: ArrayValue): Column['default']; |
| 15 | + defaultToSQL(value: string): string; |
| 16 | + defaultArrayToSQL(value: any[]): string; |
| 17 | + toTs(type: string, value: string): { options?: Record<string, unknown>; default: string }; |
| 18 | + toArrayTs(type: string, value: any[]): { options?: Record<string, unknown>; default: string }; |
| 19 | +} |
6 | 20 |
|
7 | | -const columnUnknown = { |
8 | | - drizzleImport() { |
9 | | - return 'unknown'; |
| 21 | +export const SmallInt: SqlType = { |
| 22 | + is: (type: string) => /^\s*smallint(?:\s*\[\s*\])*\s*$/i.test(type), |
| 23 | + drizzleImport: () => 'smallint', |
| 24 | + defaultFromDrizzle: (value) => { |
| 25 | + return { value: String(value), type: 'unknown' }; |
10 | 26 | }, |
11 | | - canHandle(type: string) { |
12 | | - return true; |
| 27 | + defaultArrayFromDrizzle: (value) => { |
| 28 | + return { value: JSON.stringify(value), type: 'unknown' }; |
13 | 29 | }, |
14 | | - |
15 | | - defaultFromDrizzle(it: any, dimensions: number): Column['default'] { |
16 | | - return { type: 'unknown', value: String(it).replaceAll("'", "''").replaceAll('\\', '\\\\') }; |
| 30 | + defaultFromIntrospect: (value) => { |
| 31 | + return { value: trimChar(value, "'"), type: 'unknown' }; // 10, but '-10' |
17 | 32 | }, |
18 | | - |
19 | | - printToTypeScript(column: Column) { |
20 | | - return `unknown('${column.name}').default(sql\`${ |
21 | | - column.default?.value.replaceAll("''", "'").replaceAll('\\\\', '\\') |
22 | | - }\`)`; |
| 33 | + defaultArrayFromIntrospect: (value) => { |
| 34 | + const stringified = JSON.stringify(value, (_, v) => typeof v === 'string' ? Number(v) : v); |
| 35 | + return { value: stringified, type: 'unknown' }; |
23 | 36 | }, |
| 37 | + defaultToSQL: (value) => value, |
| 38 | + defaultArrayToSQL: (value) => { |
| 39 | + return `'${stringifyArray(value, 'sql', (v) => String(v))}'`; |
| 40 | + }, |
| 41 | + toTs: (_, value) => ({ default: value }), |
| 42 | + toArrayTs: (_, value) => ({ default: JSON.stringify(value) }), |
| 43 | +}; |
| 44 | + |
| 45 | +export const Int: SqlType = { |
| 46 | + is: (type: string) => /^\s*integer(?:\s*\[\s*\])*\s*$/i.test(type), |
| 47 | + drizzleImport: () => 'integer', |
| 48 | + defaultFromDrizzle: SmallInt.defaultFromDrizzle, |
| 49 | + defaultArrayFromDrizzle: SmallInt.defaultArrayFromDrizzle, |
| 50 | + defaultFromIntrospect: SmallInt.defaultFromIntrospect, |
| 51 | + defaultArrayFromIntrospect: SmallInt.defaultArrayFromIntrospect, |
| 52 | + defaultToSQL: SmallInt.defaultToSQL, |
| 53 | + defaultArrayToSQL: SmallInt.defaultArrayToSQL, |
| 54 | + toTs: SmallInt.toTs, |
| 55 | + toArrayTs: SmallInt.toArrayTs, |
| 56 | +}; |
| 57 | + |
| 58 | +export const typeFor = (type: string): SqlType | null => { |
| 59 | + if (SmallInt.is(type)) return SmallInt; |
| 60 | + if (Int.is(type)) return Int; |
| 61 | + console.log('nosqltype'); |
| 62 | + return null; |
24 | 63 | }; |
25 | 64 |
|
26 | 65 | export const splitSqlType = (sqlType: string) => { |
@@ -362,9 +401,25 @@ export const defaultForColumn = ( |
362 | 401 | return { type: 'number', value: String(def) }; |
363 | 402 | } |
364 | 403 |
|
365 | | - // trim ::type and [] |
366 | 404 | let value = trimDefaultValueSuffix(def); |
367 | 405 |
|
| 406 | + const grammarType = typeFor(type); |
| 407 | + if (grammarType) { |
| 408 | + if (dimensions > 0) { |
| 409 | + try { |
| 410 | + let trimmed = value.startsWith('(') ? value.slice(1, value.length - 1) : value; |
| 411 | + trimmed = trimChar(trimmed, "'"); |
| 412 | + const res = parseArray(trimmed); |
| 413 | + return grammarType.defaultArrayFromIntrospect(res); |
| 414 | + } catch { |
| 415 | + return { value, type: 'unknown' }; |
| 416 | + } |
| 417 | + } |
| 418 | + return grammarType.defaultFromIntrospect(String(value)); |
| 419 | + } |
| 420 | + |
| 421 | + // trim ::type and [] |
| 422 | + |
368 | 423 | if (type.startsWith('vector')) { |
369 | 424 | return { value: value, type: 'unknown' }; |
370 | 425 | } |
@@ -439,6 +494,21 @@ export const defaultToSQL = ( |
439 | 494 |
|
440 | 495 | const suffix = arrsuffix ? `::${columnType}${arrsuffix}` : ''; |
441 | 496 |
|
| 497 | + const grammarType = typeFor(it.type); |
| 498 | + if (grammarType) { |
| 499 | + if (dimensions > 0) { |
| 500 | + try { |
| 501 | + const parsed = JSON.parse(it.default.value) as any[]; |
| 502 | + if (parsed.flat(5).length === 0) return `'{}'${suffix}`; |
| 503 | + return `${grammarType.defaultArrayToSQL(parsed)}${suffix}`; |
| 504 | + } catch { |
| 505 | + return it.default; |
| 506 | + } |
| 507 | + } |
| 508 | + const value = grammarType.defaultToSQL(it.default.value); |
| 509 | + return `${value}${suffix}`; |
| 510 | + } |
| 511 | + |
442 | 512 | if (type === 'string') { |
443 | 513 | return `'${value}'${suffix}`; |
444 | 514 | } |
|
0 commit comments