sqllens 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (244) hide show
  1. package/LICENSE +0 -10
  2. package/README.md +95 -85
  3. package/THIRD-PARTY-NOTICES.md +70 -5
  4. package/dist/api.d.ts +5 -3
  5. package/dist/api.js +17 -4
  6. package/dist/bigquery/behavior.d.ts +2 -0
  7. package/dist/bigquery/behavior.js +20 -0
  8. package/dist/bigquery/dot-path.d.ts +0 -2
  9. package/dist/bigquery/dot-path.js +0 -1
  10. package/dist/bigquery/fold.d.ts +8 -0
  11. package/dist/bigquery/fold.js +39 -0
  12. package/dist/bigquery/index.d.ts +7 -0
  13. package/dist/bigquery/index.js +10 -0
  14. package/dist/{infer/bigquery.d.ts → bigquery/infer.d.ts} +2 -2
  15. package/dist/{infer/bigquery.js → bigquery/infer.js} +4 -3
  16. package/dist/bigquery/lower.js +35 -12
  17. package/dist/bigquery/signatures.generated.d.ts +6 -0
  18. package/dist/bigquery/signatures.generated.js +1068 -0
  19. package/dist/completion/atn-walk.d.ts +13 -2
  20. package/dist/completion/atn-walk.js +13 -10
  21. package/dist/completion/complete.d.ts +4 -3
  22. package/dist/completion/complete.js +101 -45
  23. package/dist/completion/config.js +66 -0
  24. package/dist/completion/jinja-slot.d.ts +24 -0
  25. package/dist/completion/jinja-slot.js +126 -0
  26. package/dist/completion/parser-factory.d.ts +13 -1
  27. package/dist/completion/parser-factory.js +48 -0
  28. package/dist/databricks/behavior.d.ts +2 -0
  29. package/dist/databricks/behavior.js +19 -0
  30. package/dist/databricks/fold.d.ts +8 -0
  31. package/dist/databricks/fold.js +27 -0
  32. package/dist/databricks/index.d.ts +7 -0
  33. package/dist/databricks/index.js +10 -0
  34. package/dist/databricks/infer.d.ts +6 -0
  35. package/dist/databricks/infer.js +638 -0
  36. package/dist/databricks/signatures.generated.d.ts +6 -0
  37. package/dist/databricks/signatures.generated.js +1745 -0
  38. package/dist/derived-dialects.js +19 -1
  39. package/dist/dialect-behavior/behavior.d.ts +26 -0
  40. package/dist/dialect-behavior/behavior.js +1 -0
  41. package/dist/dialect-behavior/carrier.d.ts +5 -0
  42. package/dist/dialect-behavior/carrier.js +5 -0
  43. package/dist/dialect-behavior/coerce-rules.d.ts +7 -0
  44. package/dist/dialect-behavior/coerce-rules.js +69 -0
  45. package/dist/dialect-behavior/public-fold.d.ts +6 -0
  46. package/dist/dialect-behavior/public-fold.js +9 -0
  47. package/dist/dialect-behavior/registry.d.ts +6 -0
  48. package/dist/dialect-behavior/registry.js +34 -0
  49. package/dist/dialect-symbols.js +22 -17
  50. package/dist/dialect.d.ts +2 -2
  51. package/dist/document/document.d.ts +1 -1
  52. package/dist/document/document.js +8 -7
  53. package/dist/duckdb/behavior.d.ts +2 -0
  54. package/dist/duckdb/behavior.js +21 -0
  55. package/dist/duckdb/fold.d.ts +8 -0
  56. package/dist/duckdb/fold.js +29 -0
  57. package/dist/duckdb/index.d.ts +7 -0
  58. package/dist/duckdb/index.js +10 -0
  59. package/dist/{infer/duckdb.d.ts → duckdb/infer.d.ts} +2 -2
  60. package/dist/{infer/duckdb.js → duckdb/infer.js} +4 -3
  61. package/dist/duckdb/lower.js +47 -15
  62. package/dist/duckdb/signatures.generated.d.ts +6 -0
  63. package/dist/duckdb/signatures.generated.js +1072 -0
  64. package/dist/generated/bigquery/GoogleSQLParser.js +0 -7060
  65. package/dist/generated/databricks/DatabricksParser.js +0 -4800
  66. package/dist/generated/duckdb/DuckdbParser.js +0 -9100
  67. package/dist/generated/minijinja/MinijinjaParser.js +0 -380
  68. package/dist/generated/mysql/MysqlLexer.js +7357 -0
  69. package/dist/generated/mysql/MysqlParser.js +78520 -0
  70. package/dist/generated/postgres/PostgresParser.js +0 -8530
  71. package/dist/generated/redshift/RedshiftParser.js +0 -10970
  72. package/dist/generated/snowflake/SnowflakeParser.js +0 -7320
  73. package/dist/generated/sqlite/SqliteLexer.js +945 -0
  74. package/dist/generated/sqlite/SqliteParser.js +14682 -0
  75. package/dist/generated/trino/TrinoParser.js +0 -3770
  76. package/dist/generated/tsql/TSqlParser.js +0 -8420
  77. package/dist/ident/fold.d.ts +24 -15
  78. package/dist/ident/fold.js +12 -145
  79. package/dist/index.d.ts +6 -2
  80. package/dist/index.js +14 -8
  81. package/dist/infer/functions.d.ts +22 -11
  82. package/dist/infer/functions.js +26 -888
  83. package/dist/infer/infer.js +16 -14
  84. package/dist/infer/nullability.js +3 -4
  85. package/dist/infer/types.d.ts +1 -1
  86. package/dist/infer/types.js +7 -7
  87. package/dist/ir/ir.d.ts +26 -17
  88. package/dist/ir/part-span.d.ts +16 -1
  89. package/dist/ir/part-span.js +38 -10
  90. package/dist/ir/span.js +0 -2
  91. package/dist/ir/walk.js +3 -3
  92. package/dist/lineage/hops.js +13 -10
  93. package/dist/lineage/lineage.js +10 -7
  94. package/dist/minijinja/apply-tags.d.ts +14 -7
  95. package/dist/minijinja/apply-tags.js +66 -121
  96. package/dist/minijinja/parse.js +6 -6
  97. package/dist/minijinja/tag-ast.d.ts +29 -36
  98. package/dist/minijinja/tag-ast.js +210 -90
  99. package/dist/mysql/behavior.d.ts +2 -0
  100. package/dist/mysql/behavior.js +21 -0
  101. package/dist/mysql/fold.d.ts +8 -0
  102. package/dist/mysql/fold.js +49 -0
  103. package/dist/mysql/index.d.ts +7 -0
  104. package/dist/mysql/index.js +10 -0
  105. package/dist/mysql/infer.d.ts +20 -0
  106. package/dist/mysql/infer.js +156 -0
  107. package/dist/mysql/lower.d.ts +13 -0
  108. package/dist/mysql/lower.js +1443 -0
  109. package/dist/mysql/parse.d.ts +10 -0
  110. package/dist/mysql/parse.js +70 -0
  111. package/dist/mysql/signatures.generated.d.ts +6 -0
  112. package/dist/mysql/signatures.generated.js +508 -0
  113. package/dist/postgres/behavior.d.ts +2 -0
  114. package/dist/postgres/behavior.js +19 -0
  115. package/dist/postgres/fold.d.ts +8 -0
  116. package/dist/postgres/fold.js +30 -0
  117. package/dist/postgres/index.d.ts +7 -0
  118. package/dist/postgres/index.js +10 -0
  119. package/dist/{infer/postgres.d.ts → postgres/infer.d.ts} +2 -2
  120. package/dist/{infer/postgres.js → postgres/infer.js} +4 -3
  121. package/dist/postgres/lower.js +2 -2
  122. package/dist/postgres/signatures.generated.d.ts +6 -0
  123. package/dist/postgres/signatures.generated.js +2973 -0
  124. package/dist/qualify/check-calls.js +80 -134
  125. package/dist/qualify/qualify.js +16 -14
  126. package/dist/qualify/schema-provider.js +2 -2
  127. package/dist/qualify/schema.js +3 -3
  128. package/dist/qualify/template-provider.d.ts +45 -12
  129. package/dist/qualify/template-provider.js +69 -38
  130. package/dist/redshift/behavior.d.ts +2 -0
  131. package/dist/redshift/behavior.js +19 -0
  132. package/dist/redshift/fold.d.ts +8 -0
  133. package/dist/redshift/fold.js +31 -0
  134. package/dist/redshift/index.d.ts +7 -0
  135. package/dist/redshift/index.js +10 -0
  136. package/dist/{infer/redshift.d.ts → redshift/infer.d.ts} +2 -2
  137. package/dist/{infer/redshift.js → redshift/infer.js} +4 -3
  138. package/dist/redshift/lower.js +2 -2
  139. package/dist/redshift/signatures.generated.d.ts +6 -0
  140. package/dist/redshift/signatures.generated.js +757 -0
  141. package/dist/references/references.js +17 -12
  142. package/dist/scope/like-pattern.d.ts +2 -0
  143. package/dist/scope/like-pattern.js +15 -0
  144. package/dist/scope/scope.d.ts +5 -5
  145. package/dist/scope/scope.js +48 -42
  146. package/dist/sema/resolve.js +17 -12
  147. package/dist/session.d.ts +2 -2
  148. package/dist/signature/signature.d.ts +14 -6
  149. package/dist/signature/signature.js +30 -22
  150. package/dist/signature/signatures.d.ts +14 -12
  151. package/dist/signature/signatures.js +42 -582
  152. package/dist/snowflake/behavior.d.ts +2 -0
  153. package/dist/snowflake/behavior.js +22 -0
  154. package/dist/snowflake/fold.d.ts +8 -0
  155. package/dist/snowflake/fold.js +25 -0
  156. package/dist/snowflake/index.d.ts +7 -0
  157. package/dist/snowflake/index.js +10 -0
  158. package/dist/{infer/snowflake.d.ts → snowflake/infer.d.ts} +2 -2
  159. package/dist/{infer/snowflake.js → snowflake/infer.js} +4 -3
  160. package/dist/snowflake/lower.js +59 -19
  161. package/dist/snowflake/signatures.generated.d.ts +6 -0
  162. package/dist/snowflake/signatures.generated.js +2080 -0
  163. package/dist/sqlite/behavior.d.ts +2 -0
  164. package/dist/sqlite/behavior.js +19 -0
  165. package/dist/sqlite/fold.d.ts +8 -0
  166. package/dist/sqlite/fold.js +41 -0
  167. package/dist/sqlite/index.d.ts +7 -0
  168. package/dist/sqlite/index.js +10 -0
  169. package/dist/sqlite/infer.d.ts +12 -0
  170. package/dist/sqlite/infer.js +122 -0
  171. package/dist/sqlite/lower.d.ts +11 -0
  172. package/dist/sqlite/lower.js +1093 -0
  173. package/dist/sqlite/parse.d.ts +10 -0
  174. package/dist/sqlite/parse.js +70 -0
  175. package/dist/sqlite/signatures.generated.d.ts +6 -0
  176. package/dist/sqlite/signatures.generated.js +277 -0
  177. package/dist/symbols/symbols.js +14 -12
  178. package/dist/token/classify.js +31 -0
  179. package/dist/token/tokenize.js +4 -0
  180. package/dist/trino/behavior.d.ts +2 -0
  181. package/dist/trino/behavior.js +21 -0
  182. package/dist/trino/fold.d.ts +8 -0
  183. package/dist/trino/fold.js +39 -0
  184. package/dist/trino/index.d.ts +7 -0
  185. package/dist/trino/index.js +10 -0
  186. package/dist/{infer/trino.d.ts → trino/infer.d.ts} +2 -2
  187. package/dist/{infer/trino.js → trino/infer.js} +4 -3
  188. package/dist/trino/lower.js +5 -5
  189. package/dist/trino/signatures.generated.d.ts +6 -0
  190. package/dist/trino/signatures.generated.js +968 -0
  191. package/dist/tsql/behavior.d.ts +2 -0
  192. package/dist/tsql/behavior.js +20 -0
  193. package/dist/tsql/fold.d.ts +8 -0
  194. package/dist/tsql/fold.js +34 -0
  195. package/dist/tsql/index.d.ts +7 -0
  196. package/dist/tsql/index.js +10 -0
  197. package/dist/tsql/infer.d.ts +16 -0
  198. package/dist/tsql/infer.js +289 -0
  199. package/dist/tsql/lower.js +4 -4
  200. package/dist/tsql/signatures.generated.d.ts +6 -0
  201. package/dist/tsql/signatures.generated.js +640 -0
  202. package/package.json +15 -11
  203. package/dist/generated/bigquery/GoogleSQLLexer.d.ts +0 -407
  204. package/dist/generated/bigquery/GoogleSQLParser.d.ts +0 -9558
  205. package/dist/generated/bigquery/GoogleSQLParserListener.d.ts +0 -7777
  206. package/dist/generated/bigquery/GoogleSQLParserListener.js +0 -7070
  207. package/dist/generated/databricks/DatabricksLexer.d.ts +0 -566
  208. package/dist/generated/databricks/DatabricksParser.d.ts +0 -7771
  209. package/dist/generated/databricks/DatabricksParserListener.d.ts +0 -5737
  210. package/dist/generated/databricks/DatabricksParserListener.js +0 -5256
  211. package/dist/generated/duckdb/DuckdbLexer.d.ts +0 -691
  212. package/dist/generated/duckdb/DuckdbParser.d.ts +0 -13932
  213. package/dist/generated/duckdb/DuckdbParserListener.d.ts +0 -10049
  214. package/dist/generated/duckdb/DuckdbParserListener.js +0 -9138
  215. package/dist/generated/minijinja/MinijinjaLexer.d.ts +0 -108
  216. package/dist/generated/minijinja/MinijinjaParser.d.ts +0 -604
  217. package/dist/generated/minijinja/MinijinjaParserListener.d.ts +0 -449
  218. package/dist/generated/minijinja/MinijinjaParserListener.js +0 -410
  219. package/dist/generated/postgres/PostgresLexer.d.ts +0 -663
  220. package/dist/generated/postgres/PostgresParser.d.ts +0 -12963
  221. package/dist/generated/postgres/PostgresParserListener.d.ts +0 -9408
  222. package/dist/generated/postgres/PostgresParserListener.js +0 -8554
  223. package/dist/generated/redshift/RedshiftLexer.d.ts +0 -954
  224. package/dist/generated/redshift/RedshiftParser.d.ts +0 -16939
  225. package/dist/generated/redshift/RedshiftParserListener.d.ts +0 -12092
  226. package/dist/generated/redshift/RedshiftParserListener.js +0 -10994
  227. package/dist/generated/snowflake/SnowflakeLexer.d.ts +0 -1046
  228. package/dist/generated/snowflake/SnowflakeParser.d.ts +0 -14196
  229. package/dist/generated/snowflake/SnowflakeParserListener.d.ts +0 -8063
  230. package/dist/generated/snowflake/SnowflakeParserListener.js +0 -7330
  231. package/dist/generated/trino/TrinoLexer.d.ts +0 -381
  232. package/dist/generated/trino/TrinoParser.d.ts +0 -5340
  233. package/dist/generated/trino/TrinoParserListener.d.ts +0 -4704
  234. package/dist/generated/trino/TrinoParserListener.js +0 -4326
  235. package/dist/generated/tsql/TSqlLexer.d.ts +0 -1278
  236. package/dist/generated/tsql/TSqlParser.d.ts +0 -17267
  237. package/dist/generated/tsql/TSqlParserListener.d.ts +0 -9697
  238. package/dist/generated/tsql/TSqlParserListener.js +0 -8854
  239. package/dist/infer/dialect.d.ts +0 -21
  240. package/dist/infer/dialect.js +0 -74
  241. package/dist/infer/literals.d.ts +0 -6
  242. package/dist/infer/literals.js +0 -44
  243. package/dist/signature/generated/tsql.d.ts +0 -3
  244. package/dist/signature/generated/tsql.js +0 -260
@@ -0,0 +1,2 @@
1
+ import type { DialectBehavior } from "../dialect-behavior/behavior.js";
2
+ export declare const sqliteBehavior: DialectBehavior;
@@ -0,0 +1,19 @@
1
+ import { acceptsFor } from "../dialect-behavior/coerce-rules.js";
2
+ import { likePatternToRegExp } from "../scope/like-pattern.js";
3
+ import { SIGNATURES } from "../signature/signatures.js";
4
+ import { displayName, fold, foldTableName, matchesSourceKey } from "./fold.js";
5
+ import { sqliteLiteral, sqliteParseType, SQLITE_FUNCTION_RETURNS } from "./infer.js";
6
+ export const sqliteBehavior = {
7
+ fold,
8
+ displayName,
9
+ foldTableName,
10
+ matchesSourceKey,
11
+ likeMatch: (pattern, value) => likePatternToRegExp(pattern).test(value),
12
+ literal: sqliteLiteral,
13
+ parseType: sqliteParseType,
14
+ functions: SQLITE_FUNCTION_RETURNS,
15
+ division: "integer",
16
+ signatures: SIGNATURES.sqlite,
17
+ // SQLite implicit coercion: TEXT containing a number coerces to numeric (STR_TO_NUM=true), no bool<->num (BOOL_NUM=false).
18
+ accepts: (argType, paramText) => acceptsFor(sqliteParseType, true, false, argType, paramText),
19
+ };
@@ -0,0 +1,8 @@
1
+ import { type FoldRule, type IdentKind } from "../ident/fold.js";
2
+ export declare const SQLITE_FOLD_RULE: FoldRule;
3
+ /** Fold an identifier to its SQLite identity key. */
4
+ export declare function fold(raw: string, kind?: IdentKind): string;
5
+ /** Presentation twin: strip delimiters, no case change. */
6
+ export declare function displayName(raw: string): string;
7
+ export declare function foldTableName(parts: string[]): string[];
8
+ export declare function matchesSourceKey(key: string, rawPart: string): boolean;
@@ -0,0 +1,41 @@
1
+ // SQLite identifier folding. The FoldRule plus its bound engine, colocated here because BOTH the
2
+ // upstream lower() and the downstream DialectBehavior need it (the fold rule is the one dialect concern
3
+ // used at two stages).
4
+ //
5
+ // sqlite.org/lang_keywords.html — verified live: SQLite recognizes three identifier-quoting
6
+ // delimiters, each documented only as "is an identifier" (double-quote, square-bracket, and
7
+ // grave-accent/backtick forms) with no case-sensitivity distinction drawn between them or
8
+ // against the unquoted form. SQLite's own grammar (IDENTIFIER token) treats `"x"`, `` `x` ``,
9
+ // `[x]` and bare `x` as the same lexical category, and SQLite's C-level identifier compare
10
+ // (sqlite3StrICmp) is ASCII case-insensitive regardless of how the name was spelled — the
11
+ // documented quirk this module's brief calls out: unlike Postgres/Snowflake, quoting an
12
+ // identifier does NOT make it case-sensitive in SQLite. So both unquoted AND quoted fold to
13
+ // lower here (same shape as redshift/duckdb/trino). SQLite's own documented fold is
14
+ // ASCII-only (it does not case-fold non-ASCII), but this module's shared applyCase uses JS
15
+ // toLowerCase() — a Unicode-wide fold — so a rare non-ASCII identifier pair (Ä vs ä) that
16
+ // SQLite would keep distinct conflates here: a known shared-engine limitation, consistent
17
+ // across every dialect in this table. Bracket delimiters have no escape mechanism (the
18
+ // lexer's `[`...`]` body is `~']'*` — no doubling), so a doubled `]]` inside `[...]` is not
19
+ // unescaped, same as this module's tsql bracket handling.
20
+ import { displayWith, foldWith } from "../ident/fold.js";
21
+ const DOUBLE_QUOTE = ['"', '"'];
22
+ const BACKTICK = ["`", "`"];
23
+ export const SQLITE_FOLD_RULE = {
24
+ delimiters: [DOUBLE_QUOTE, BACKTICK, ["[", "]"]],
25
+ unquoted: "lower",
26
+ quoted: "lower",
27
+ };
28
+ /** Fold an identifier to its SQLite identity key. */
29
+ export function fold(raw, kind = "other") {
30
+ return foldWith(SQLITE_FOLD_RULE, raw, kind);
31
+ }
32
+ /** Presentation twin: strip delimiters, no case change. */
33
+ export function displayName(raw) {
34
+ return displayWith(SQLITE_FOLD_RULE, raw);
35
+ }
36
+ export function foldTableName(parts) {
37
+ return parts.map((p) => fold(p, "table"));
38
+ }
39
+ export function matchesSourceKey(key, rawPart) {
40
+ return key === fold(rawPart) || key === fold(rawPart, "table");
41
+ }
@@ -0,0 +1,7 @@
1
+ import { lower } from "./lower.js";
2
+ import { parseSqlite } from "./parse.js";
3
+ export declare const sqlite: {
4
+ parse: typeof parseSqlite;
5
+ lower: typeof lower;
6
+ behavior: import("../dialect-behavior/behavior.js").DialectBehavior;
7
+ };
@@ -0,0 +1,10 @@
1
+ // The complete sqlite dialect module: parse + lower (front end) and behavior (semantic knowledge).
2
+ // The registry wires this; to understand everything sqllens does for sqlite, read this folder.
3
+ import { sqliteBehavior } from "./behavior.js";
4
+ import { lower } from "./lower.js";
5
+ import { parseSqlite } from "./parse.js";
6
+ export const sqlite = {
7
+ parse: parseSqlite,
8
+ lower,
9
+ behavior: sqliteBehavior,
10
+ };
@@ -0,0 +1,12 @@
1
+ import { type Type } from "../infer/types.js";
2
+ import type { FnRule } from "../infer/functions.js";
3
+ export declare const SQLITE_ALIASES: Record<string, string>;
4
+ export declare function sqliteParseType(text: string): Type;
5
+ /** SQLite literal forms, by storage class (sqlite.org/datatype3.html has exactly five: NULL,
6
+ * INTEGER, REAL, TEXT, BLOB — there is no native BOOLEAN or DATE/TIME/TIMESTAMP class).
7
+ * TRUE/FALSE are literal aliases for the integers 1/0, not a boolean type
8
+ * (sqlite.org/lang_expr.html#literal_values_constants_). CURRENT_TIME/CURRENT_DATE/
9
+ * CURRENT_TIMESTAMP expand to a formatted TEXT value (sqlite.org/lang_createtable.html
10
+ * §"The DEFAULT clause"), not a date/time type. */
11
+ export declare function sqliteLiteral(text: string): Type;
12
+ export declare const SQLITE_FUNCTION_RETURNS: Record<string, FnRule>;
@@ -0,0 +1,122 @@
1
+ import { commonType, widenSum } from "../infer/coerce.js";
2
+ import { parseType, scalar, UNKNOWN } from "../infer/types.js";
3
+ import { fold } from "./fold.js";
4
+ // ---------------------------------------------------------------------------
5
+ // SQLite inference knowledge. Literal typing (A-R4) is storage-class-faithful (sqlite.org/
6
+ // datatype3.html has exactly five: NULL/INTEGER/REAL/TEXT/BLOB — no native BOOLEAN or DATE/TIME/
7
+ // TIMESTAMP class, so this file never reaches for a `boolean` scalar). The function-return
8
+ // registry (R5) is worked through the core/aggregate/date/math references — lang_corefunc.html,
9
+ // lang_aggfunc.html, lang_datefunc.html, lang_mathfunc.html — and stays deliberately incomplete:
10
+ // SQLite's dynamic/flexible typing (lang_expr.html, datatype3.html) makes several documented
11
+ // "returns a number" functions genuinely value- or modifier-dependent (SUM/AVG/MAX/MIN's
12
+ // argument-shaped results, unixepoch()'s subsec-modifier int/float switch, every lang_mathfunc.html
13
+ // entry's undocumented storage class for its "representable integer" wording) — those stay
14
+ // unregistered by design, not by oversight. SQLITE_ALIASES stays empty: a CREATE TABLE column's
15
+ // declared type name is matched by SUBSTRING against a small pattern set to pick one of five
16
+ // *type affinities* (datatype3.html §3.1 "Determination Of Column Affinity"), not looked up in a
17
+ // fixed alias table the way other dialects' declared types are — that affinity algorithm is a
18
+ // distinct, not-yet-built feature, not a registration gap. Contract holds throughout: an absent
19
+ // rule yields `unknown`, never a guess.
20
+ // ---------------------------------------------------------------------------
21
+ export const SQLITE_ALIASES = {};
22
+ export function sqliteParseType(text) {
23
+ return parseType(text, SQLITE_ALIASES, fold);
24
+ }
25
+ const S = scalar("string");
26
+ const I = scalar("int");
27
+ const BIG = scalar("bigint");
28
+ const D = scalar("double");
29
+ const BIN = scalar("binary");
30
+ const fixed = (t) => () => t;
31
+ /** "returns argument X unchanged" (likelihood/likely/unlikely) / plain numeric passthrough (abs). */
32
+ const firstArg = (args) => args[0] ?? UNKNOWN;
33
+ /** coalesce/ifnull: "returns a copy of its first non-NULL argument" — the common type of the args
34
+ * (falls back to unknown, never a guess, when they don't agree). */
35
+ const common = (args) => commonType(args);
36
+ function group(rule, names) {
37
+ return Object.fromEntries(names.map((n) => [n, rule]));
38
+ }
39
+ /** SQLite literal forms, by storage class (sqlite.org/datatype3.html has exactly five: NULL,
40
+ * INTEGER, REAL, TEXT, BLOB — there is no native BOOLEAN or DATE/TIME/TIMESTAMP class).
41
+ * TRUE/FALSE are literal aliases for the integers 1/0, not a boolean type
42
+ * (sqlite.org/lang_expr.html#literal_values_constants_). CURRENT_TIME/CURRENT_DATE/
43
+ * CURRENT_TIMESTAMP expand to a formatted TEXT value (sqlite.org/lang_createtable.html
44
+ * §"The DEFAULT clause"), not a date/time type. */
45
+ export function sqliteLiteral(text) {
46
+ const t = text.trim();
47
+ if (/^'/.test(t))
48
+ return S; // STRING_LITERAL
49
+ if (/^x'/i.test(t))
50
+ return BIN; // BLOB_LITERAL — X'...'
51
+ if (/^null$/i.test(t))
52
+ return UNKNOWN;
53
+ if (/^(true|false)$/i.test(t))
54
+ return I; // integer aliases, not a boolean type
55
+ if (/^current_(time|date|timestamp)$/i.test(t))
56
+ return S;
57
+ if (/^[+-]?0x[0-9a-f](_?[0-9a-f])*$/i.test(t))
58
+ return I; // hex integer literal
59
+ if (/^[+-]?\d(_?\d)*$/.test(t))
60
+ return I; // plain integer, no '.' or exponent
61
+ if (/^[+-]?(\d(_?\d)*)?\.(\d(_?\d)*)?([eE][+-]?\d+)?$/.test(t) && /\d/.test(t))
62
+ return D; // has a '.'
63
+ if (/^[+-]?\d(_?\d)*[eE][+-]?\d+$/.test(t))
64
+ return D; // exponent form, no '.'
65
+ return UNKNOWN;
66
+ }
67
+ export const SQLITE_FUNCTION_RETURNS = {
68
+ // --- string — lang_corefunc.html: each of these is documented as unconditionally returning a
69
+ // string, independent of the argument's own storage class ------------------------------------
70
+ ...group(fixed(S), [
71
+ "upper", // "returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent"
72
+ "lower", // "returns a copy of string X with all ASCII characters converted to lower case"
73
+ "typeof", // "returns a string that indicates the datatype of the expression X: null, integer, real, text, or blob"
74
+ "hex", // "returns a string which is the upper-case hexadecimal rendering of the content of that blob"
75
+ "quote", // "returns the text of an SQL literal which is the value of its argument suitable for inclusion into an SQL statement"
76
+ "ltrim", // "returns a string formed by removing any and all characters that appear in Y from the left side"
77
+ "rtrim", // "returns a string formed by removing any and all characters that appear in Y from the right side"
78
+ "trim", // "returns a string formed by removing any and all characters that appear in Y from both ends of X"
79
+ "replace", // "returns a string formed by substituting string Z for every occurrence of string Y in string X"
80
+ "soundex", // "returns a string that is the soundex encoding of the string X"
81
+ ]),
82
+ // --- date/time — lang_datefunc.html: date/time/datetime/strftime/timediff all format to TEXT.
83
+ // unixepoch() is the one date function left OUT — its optional subsec modifier switches the
84
+ // return between integer and floating-point, a call-shape (not argument-type) dependency this
85
+ // registry has no precedent for modelling -----------------------------------------------------
86
+ ...group(fixed(S), ["date", "time", "datetime", "strftime", "timediff"]),
87
+ // --- aggregate text — lang_aggfunc.html ---------------------------------------------------------
88
+ ...group(fixed(S), ["group_concat", "string_agg"]), // "returns a string which is the concatenation of all non-NULL values of X"
89
+ // --- integer — lang_corefunc.html ---------------------------------------------------------------
90
+ ...group(fixed(I), [
91
+ "length", // text: "number of Unicode code points"; blob: "number of bytes" — an integer either way
92
+ "octet_length", // "returns the number of bytes in the encoding of text string X"
93
+ "unicode", // "returns the numeric unicode code point corresponding to the first character of the string X"
94
+ "instr", // "returns the number of prior characters plus 1, or 0 if Y is nowhere found within X"
95
+ "sign", // "returns -1, 0, or +1" — always one of those three integers, regardless of whether X is REAL or INTEGER
96
+ ]),
97
+ // --- bigint — values documented across the full 64-bit signed range --------------------------
98
+ count: fixed(BIG), // lang_aggfunc.html: "returns a count of the number of times that X is not NULL in a group"
99
+ random: fixed(BIG), // lang_corefunc.html: "returns a pseudo-random integer between -9223372036854775807 and +9223372036854775807"
100
+ // --- real/double ---------------------------------------------------------------------------------
101
+ round: fixed(D), // lang_corefunc.html: "returns a floating-point value X rounded to Y digits" — always real, even round(X) with no Y
102
+ total: fixed(D), // lang_aggfunc.html: "result of total() is always a floating point value" (documented always-float, unlike sum())
103
+ avg: fixed(D), // lang_aggfunc.html: "is always a floating point value whenever there is at least one non-NULL input" — unlike other dialects' input-typed AVG
104
+ julianday: fixed(D), // lang_datefunc.html: "the Julian day - the fractional number of days since noon in Greenwich..."
105
+ // --- blob ------------------------------------------------------------------------------------------
106
+ ...group(fixed(BIN), [
107
+ "unhex", // "returns a BLOB value which is the decoding of the hexadecimal string X"
108
+ "zeroblob", // "returns a BLOB consisting of N bytes of 0x00"
109
+ "randomblob", // "return an N-byte blob containing pseudo-random bytes"
110
+ ]),
111
+ // --- passthrough — lang_corefunc.html -----------------------------------------------------------
112
+ abs: firstArg, // "returns the absolute value of the numeric argument X" — same numeric family as its input (firstArg is the universal cross-dialect precedent for abs)
113
+ ...group(firstArg, ["likelihood", "likely", "unlikely"]), // each: "returns argument X unchanged"
114
+ // --- aggregate widening ------------------------------------------------------------------------
115
+ // lang_aggfunc.html: "sum(X) ... Returns an integer if all inputs are integers; otherwise
116
+ // returns floating-point" — exactly the int-family→bigint / float→double / decimal→decimal
117
+ // shape widenSum already encodes (the same rule databricks/snowflake/redshift use verbatim).
118
+ sum: (args) => widenSum(args[0] ?? UNKNOWN),
119
+ // --- common-type — lang_corefunc.html: "returns a copy of its first non-NULL argument" -----------
120
+ coalesce: common,
121
+ ifnull: common,
122
+ };
@@ -0,0 +1,11 @@
1
+ import { ParserRuleContext } from "antlr4ng";
2
+ import type { QueryExpr } from "../ir/ir.js";
3
+ import { type StatementCategory } from "../ir/statement.js";
4
+ /** Lower a parsed SQLite file (`parse`: a `;`-separated sql_stmt_list) into the IR. A single
5
+ * SELECT/VALUES statement lowers fully; anything else (DDL/DML/pragma/utility, multi-statement
6
+ * batches, EXPLAIN) becomes a flagged non-query body — a valid parse never throws. */
7
+ export declare function lower(tree: ParserRuleContext): QueryExpr;
8
+ /** Per-statement categories for every `sql_stmt` in a parsed `parse`, in source order — the
9
+ * file-level view behind statementCategory (which folds >1 into "compound"). Parity with the
10
+ * other dialects; feeds the corpus reclassifier. */
11
+ export declare function statementCategories(tree: ParserRuleContext): StatementCategory[];