From 47d3f5141f84ceee6946e535744b613fdd17d7c6 Mon Sep 17 00:00:00 2001 From: Ben Merckx Date: Tue, 7 May 2024 09:40:38 +0200 Subject: [PATCH] Interim --- src/core/Column.ts | 4 +- src/core/Constraint.ts | 2 +- src/core/Emitter.ts | 2 +- src/core/Functions.ts | 15 -- src/core/Index.ts | 2 +- src/core/Internal.ts | 2 +- src/core/Selection.ts | 3 +- src/core/Sql.ts | 2 +- src/core/Table.ts | 5 +- src/core/Virtual.ts | 2 +- src/core/expr/Aggregate.ts | 36 +++++ src/core/{Expr.ts => expr/Conditions.ts} | 26 ++-- src/core/{ => expr}/Field.ts | 4 +- src/core/expr/Functions.ts | 14 ++ src/core/expr/Input.ts | 11 ++ src/core/query/Insert.ts | 2 +- src/core/query/Select.ts | 4 +- src/core/query/Update.ts | 2 +- src/index.ts | 2 +- src/sqlite/SqliteFunctions.ts | 172 +++++++++++------------ test/core/Expr.test.ts | 2 +- test/query/Delete.test.ts | 2 +- test/query/Select.test.ts | 2 +- 23 files changed, 181 insertions(+), 137 deletions(-) delete mode 100644 src/core/Functions.ts create mode 100644 src/core/expr/Aggregate.ts rename src/core/{Expr.ts => expr/Conditions.ts} (88%) rename src/core/{ => expr}/Field.ts (84%) create mode 100644 src/core/expr/Functions.ts create mode 100644 src/core/expr/Input.ts diff --git a/src/core/Column.ts b/src/core/Column.ts index d674944..542faa3 100644 --- a/src/core/Column.ts +++ b/src/core/Column.ts @@ -1,8 +1,8 @@ -import {input, type Input} from './Expr.ts' -import type {Field, FieldData} from './Field.ts' import type {HasColumn, HasSql} from './Internal.ts' import {getField, internalColumn} from './Internal.ts' import type {Sql} from './Sql.ts' +import type {Field, FieldData} from './expr/Field.ts' +import {input, type Input} from './expr/Input.ts' export class ColumnData { type!: Sql diff --git a/src/core/Constraint.ts b/src/core/Constraint.ts index 2cc82e7..947a22a 100644 --- a/src/core/Constraint.ts +++ b/src/core/Constraint.ts @@ -1,4 +1,3 @@ -import type {Field, FieldData} from './Field.ts' import { getData, getField, @@ -8,6 +7,7 @@ import { type HasData } from './Internal.ts' import {sql} from './Sql.ts' +import type {Field, FieldData} from './expr/Field.ts' export interface UniqueConstraintData { fields: Array diff --git a/src/core/Emitter.ts b/src/core/Emitter.ts index a852802..4153b79 100644 --- a/src/core/Emitter.ts +++ b/src/core/Emitter.ts @@ -1,5 +1,4 @@ import type {ColumnData} from './Column.ts' -import type {FieldData} from './Field.ts' import { getData, getQuery, @@ -11,6 +10,7 @@ import { } from './Internal.ts' import {ValueParam, type Param} from './Param.ts' import {sql} from './Sql.ts' +import type {FieldData} from './expr/Field.ts' import type {Create} from './query/CreateTable.ts' import type {Delete} from './query/Delete.ts' import type {Drop} from './query/DropTable.ts' diff --git a/src/core/Functions.ts b/src/core/Functions.ts deleted file mode 100644 index 86217c6..0000000 --- a/src/core/Functions.ts +++ /dev/null @@ -1,15 +0,0 @@ -import {input, type Input} from './Expr.ts' -import type {HasSql} from './Internal.ts' -import {sql} from './Sql.ts' - -function get(target: Record, method: string) { - return (target[method] ??= (...args: Array>) => { - return sql`${sql.identifier(method)}(${sql.join(args.map(input), sql`, `)})` - }) -} - -export const Functions = new Proxy(Object.create(null), {get}) as Functions - -export type Functions = { - [key: string]: (...args: Array>) => HasSql -} diff --git a/src/core/Index.ts b/src/core/Index.ts index f6138fe..e18d0d3 100644 --- a/src/core/Index.ts +++ b/src/core/Index.ts @@ -1,4 +1,3 @@ -import type {Field, FieldData} from './Field.ts' import { getData, getField, @@ -6,6 +5,7 @@ import { type HasData, type HasSql } from './Internal.ts' +import type {Field, FieldData} from './expr/Field.ts' export interface IndexData { fields: Array diff --git a/src/core/Internal.ts b/src/core/Internal.ts index 92d269e..385f4d3 100644 --- a/src/core/Internal.ts +++ b/src/core/Internal.ts @@ -1,10 +1,10 @@ import type {ColumnData} from './Column.ts' -import type {FieldData} from './Field.ts' import type {QueryMeta} from './MetaData.ts' import type {Resolver} from './Resolver.ts' import type {Selection} from './Selection.ts' import type {Sql} from './Sql.ts' import type {TableApi, TableDefinition} from './Table.ts' +import type {FieldData} from './expr/Field.ts' export const internalData = Symbol() export const internalSql = Symbol() diff --git a/src/core/Selection.ts b/src/core/Selection.ts index 1bb8a5a..44c3416 100644 --- a/src/core/Selection.ts +++ b/src/core/Selection.ts @@ -57,7 +57,8 @@ export class Selection implements HasSql { const expr = this.#exprOf(input) if (expr) { const value = values.shift() - if (expr.mapFromDriverValue) return expr.mapFromDriverValue(value) + if (value !== null && expr.mapFromDriverValue) + return expr.mapFromDriverValue(value) return value } const result: Record = {} diff --git a/src/core/Sql.ts b/src/core/Sql.ts index 5cc5d4d..cfa83cf 100644 --- a/src/core/Sql.ts +++ b/src/core/Sql.ts @@ -1,6 +1,6 @@ import type {Emitter} from './Emitter.ts' -import type {FieldData} from './Field.ts' import {getSql, internalSql, type HasSql} from './Internal.ts' +import type {FieldData} from './expr/Field.ts' type EmitMethods = { [K in keyof Emitter as K extends `emit${string}` ? K : never]: Emitter[K] diff --git a/src/core/Table.ts b/src/core/Table.ts index 8e7a80b..40058b4 100644 --- a/src/core/Table.ts +++ b/src/core/Table.ts @@ -4,8 +4,6 @@ import type { PrimaryKeyConstraint, UniqueConstraint } from './Constraint.ts' -import {jsonExpr, type Input, type JsonExpr} from './Expr.ts' -import {Field} from './Field.ts' import type {Index} from './Index.ts' import { getColumn, @@ -20,6 +18,9 @@ import { type HasTarget } from './Internal.ts' import {sql, type Sql} from './Sql.ts' +import {jsonExpr, type JsonExpr} from './expr/Conditions.ts' +import {Field} from './expr/Field.ts' +import type {Input} from './expr/Input.ts' const {assign, fromEntries, entries} = Object diff --git a/src/core/Virtual.ts b/src/core/Virtual.ts index 8d8ec5d..be4fa91 100644 --- a/src/core/Virtual.ts +++ b/src/core/Virtual.ts @@ -1,6 +1,6 @@ -import {Field} from './Field.ts' import {getSql, hasSql} from './Internal.ts' import type {SelectionInput} from './Selection.ts' +import {Field} from './expr/Field.ts' export function virtual( alias: string, diff --git a/src/core/expr/Aggregate.ts b/src/core/expr/Aggregate.ts new file mode 100644 index 0000000..568d5f8 --- /dev/null +++ b/src/core/expr/Aggregate.ts @@ -0,0 +1,36 @@ +import {getSql, type HasSql} from '../Internal.ts' +import {sql, type Sql} from '../Sql.ts' +import {distinct} from './Conditions.ts' +import {Functions} from './Functions.ts' + +export function count(input?: HasSql): Sql { + return Functions.count(input ?? sql`*`).mapWith(Number) +} + +export function countDistinct(input: HasSql): Sql { + return Functions.count(distinct(input)).mapWith(Number) +} + +export function avg(input: HasSql): Sql { + return Functions.avg(input).mapWith(String) +} + +export function avgDistinct(input: HasSql): Sql { + return Functions.avg(distinct(input)).mapWith(String) +} + +export function sum(input: HasSql): HasSql { + return Functions.sum(input).mapWith(String) +} + +export function sumDistinct(input: HasSql): HasSql { + return Functions.sum(distinct(input)).mapWith(String) +} + +export function max(input: HasSql) { + return Functions.max(input).mapWith(getSql(input)) +} + +export function min(input: HasSql) { + return Functions.min(input).mapWith(getSql(input)) +} diff --git a/src/core/Expr.ts b/src/core/expr/Conditions.ts similarity index 88% rename from src/core/Expr.ts rename to src/core/expr/Conditions.ts index 81db980..c6bcec1 100644 --- a/src/core/Expr.ts +++ b/src/core/expr/Conditions.ts @@ -1,14 +1,6 @@ -import {getSql, getTable, hasSql, hasTable, type HasSql} from './Internal.ts' -import {sql, type Sql} from './Sql.ts' - -export type Input = HasSql | T - -export function input(value: Input): HasSql { - if (typeof value !== 'object' || value === null) return sql.value(value) - if (hasTable(value)) return sql.identifier(getTable(value).name) - if (hasSql(value)) return getSql(value) as Sql - return sql.value(value) -} +import type {HasSql} from '../Internal.ts' +import {sql, type Sql} from '../Sql.ts' +import {type Input, input} from './Input.ts' export function eq(left: Input, right: Input): HasSql { return sql`${input(left)} = ${input(right)}` @@ -148,12 +140,16 @@ export function arrayOverlaps( return sql`${input(left)} && ${input(right)}` } -export function asc(column: HasSql): Sql { - return sql`${column} asc` +export function asc(input: HasSql): Sql { + return sql`${input} asc` +} + +export function desc(input: HasSql): Sql { + return sql`${input} desc` } -export function desc(column: HasSql): Sql { - return sql`${column} desc` +export function distinct(input: HasSql): Sql { + return sql`distinct ${input}` } export interface JsonArrayHasSql extends HasSql { diff --git a/src/core/Field.ts b/src/core/expr/Field.ts similarity index 84% rename from src/core/Field.ts rename to src/core/expr/Field.ts index 3bfe51b..5186674 100644 --- a/src/core/Field.ts +++ b/src/core/expr/Field.ts @@ -1,5 +1,5 @@ -import {internalField, internalSql, type HasSql} from './Internal.ts' -import {sql, type Sql} from './Sql.ts' +import {internalField, internalSql, type HasSql} from '../Internal.ts' +import {sql, type Sql} from '../Sql.ts' export interface FieldData { targetName: string diff --git a/src/core/expr/Functions.ts b/src/core/expr/Functions.ts new file mode 100644 index 0000000..c8dd6cd --- /dev/null +++ b/src/core/expr/Functions.ts @@ -0,0 +1,14 @@ +import {sql, type Sql} from '../Sql.ts' +import {input, type Input} from './Input.ts' + +function get(target: Record, method: string) { + return (target[method] ??= (...args: Array>) => { + return sql`${sql.identifier(method)}(${sql.join(args.map(input), sql`, `)})` + }) +} + +export const Functions = new Proxy(Object.create(null), {get}) + +export type Functions = { + [key: string]: (...args: Array>) => Sql +} diff --git a/src/core/expr/Input.ts b/src/core/expr/Input.ts new file mode 100644 index 0000000..7b72a96 --- /dev/null +++ b/src/core/expr/Input.ts @@ -0,0 +1,11 @@ +import {getSql, getTable, hasSql, hasTable, type HasSql} from '../Internal.ts' +import {sql, type Sql} from '../Sql.ts' + +export type Input = HasSql | T + +export function input(value: Input): HasSql { + if (typeof value !== 'object' || value === null) return sql.value(value) + if (hasTable(value)) return sql.identifier(getTable(value).name) + if (hasSql(value)) return getSql(value) as Sql + return sql.value(value) +} diff --git a/src/core/query/Insert.ts b/src/core/query/Insert.ts index 5eeffcc..d972cf8 100644 --- a/src/core/query/Insert.ts +++ b/src/core/query/Insert.ts @@ -1,4 +1,3 @@ -import {input, type Input} from '../Expr.ts' import { getColumn, getData, @@ -24,6 +23,7 @@ import type { TableRow, TableUpdate } from '../Table.ts' +import {input, type Input} from '../expr/Input.ts' class InsertIntoData extends QueryData { into!: HasTable diff --git a/src/core/query/Select.ts b/src/core/query/Select.ts index 17b9f23..d717538 100644 --- a/src/core/query/Select.ts +++ b/src/core/query/Select.ts @@ -1,5 +1,3 @@ -import {input, type Input as UserInput} from '../Expr.ts' -import type {Field} from '../Field.ts' import { getData, getQuery, @@ -29,6 +27,8 @@ import { import {sql} from '../Sql.ts' import type {Table, TableDefinition, TableFields} from '../Table.ts' import type {Expand} from '../Types.ts' +import type {Field} from '../expr/Field.ts' +import {input, type Input as UserInput} from '../expr/Input.ts' import {Union} from './Union.ts' export type SelectionType = 'selection' | 'allFrom' | 'joinTables' diff --git a/src/core/query/Update.ts b/src/core/query/Update.ts index 3293586..a404c8b 100644 --- a/src/core/query/Update.ts +++ b/src/core/query/Update.ts @@ -1,4 +1,3 @@ -import {input} from '../Expr.ts' import { getData, internalData, @@ -17,6 +16,7 @@ import { } from '../Selection.ts' import {sql, type Sql} from '../Sql.ts' import type {TableDefinition, TableUpdate} from '../Table.ts' +import {input} from '../expr/Input.ts' export class UpdateData< Meta extends QueryMeta = QueryMeta diff --git a/src/index.ts b/src/index.ts index 5f1859f..8fbe52d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,12 +2,12 @@ export * from './core/Column.ts' export * from './core/Constraint.ts' export * from './core/Database.ts' export * from './core/Driver.ts' -export * from './core/Expr.ts' export * from './core/Index.ts' export * from './core/Query.ts' export * from './core/Selection.ts' export * from './core/Sql.ts' export * from './core/Table.ts' +export * from './core/expr/Conditions.ts' export * from './core/query/CreateTable.ts' export * from './core/query/Delete.ts' export * from './core/query/Insert.ts' diff --git a/src/sqlite/SqliteFunctions.ts b/src/sqlite/SqliteFunctions.ts index a979e5c..de6573e 100644 --- a/src/sqlite/SqliteFunctions.ts +++ b/src/sqlite/SqliteFunctions.ts @@ -1,17 +1,17 @@ -import {input, type Input} from '../core/Expr.ts' -import {Functions} from '../core/Functions.ts' import type {HasQuery, HasSql, HasTable} from '../core/Internal.ts' -import {sql} from '../core/Sql.ts' +import {sql, type Sql} from '../core/Sql.ts' +import {Functions} from '../core/expr/Functions.ts' +import {input, type Input} from '../core/expr/Input.ts' -const SqliteFunctions = Functions as SqliteFunctions +const SqliteFunctions = Functions -type SqliteFunctions = { +interface SqliteFunctions extends Functions { /* json(json: HasSql): HasSql jsonb(json: HasSql): HasSql - json_array(...values: HasSql): HasSql> - jsonb_array(...values: HasSql): HasSql> - json_array_length(json: HasSql>): HasSql + json_array(...values: Sql): Sql> + jsonb_array(...values: Sql): Sql> + json_array_length(json: Sql>): Sql json_array_length(json,path) json_error_position(json) json_extract(json,path,...) @@ -39,21 +39,21 @@ type SqliteFunctions = { jsonb_group_object(name,value)*/ /** The count(X) function returns a count of the number of times that X is not NULL in a group. The count(*) function (with no arguments) returns the total number of rows in the group. */ - count(x?: HasSql): HasSql + count(x?: HasSql): Sql /** The iif(X,Y,Z) function returns the value Y if X is true, and Z otherwise. The iif(X,Y,Z) function is logically equivalent to and generates the same bytecode as the CASE HasSql "CASE WHEN X THEN Y ELSE Z END".*/ - iif(x: Input, y: Input, z: Input): HasSql + iif(x: Input, y: Input, z: Input): Sql /** * The EXISTS operator always evaluates to one of the integer values 0 and 1. If executing the SELECT statement specified as the right-hand operand of the EXISTS operator would return one or more rows, then the EXISTS operator evaluates to 1. If executing the SELECT would return no rows at all, then the EXISTS operator evaluates to 0. */ - exists(cursor: HasQuery): HasSql + exists(cursor: HasQuery): Sql /** Use the match operator for the FTS5 module */ - match(table: HasTable, searchTerm: Input): HasSql + match(table: HasTable, searchTerm: Input): Sql /** Returns a real value reflecting the accuracy of the current match */ - bm25(table: HasTable, ...weights: Array>): HasSql + bm25(table: HasTable, ...weights: Array>): Sql /** The highlight() function returns a copy of the text from a specified column of the current row with extra markup text inserted to mark the start and end of phrase matches. */ highlight( @@ -61,7 +61,7 @@ type SqliteFunctions = { index: Input, insertBefore: Input, insertAfter: Input - ): HasSql + ): Sql /** The snippet() function is similar to highlight(), except that instead of returning entire column values, it automatically selects and extracts a short fragment of document text to process and return. */ snippet( @@ -71,125 +71,125 @@ type SqliteFunctions = { insertAfter: Input, snip: Input, maxTokens: Input - ): HasSql + ): Sql // ===================================================== // https://www.sqlite.org/lang_corefunc.html // ===================================================== /** The abs(X) function returns the absolute value of the numeric argument X. Abs(X) returns NULL if X is NULL. Abs(X) returns 0.0 if X is a string or blob that cannot be converted to a numeric value. If X is the numbereger -9223372036854775808 then abs(X) throws an numbereger overflow error since there is no equivalent positive 64-bit two complement value.*/ - abs(x: Input): HasSql + abs(x: Input): Sql /** The changes() function returns the number of database rows that were changed or inserted or deleted by the most recently completed INSERT, DELETE, or UPDATE statement, exclusive of statements in lower-level triggers. The changes() SQL function is a wrapper around the sqlite3_changes() C/C++ function and hence follows the same rules for counting changes.*/ - changes(): HasSql + changes(): Sql /** The char(X1,X2,...,XN) function returns a string composed of characters having the unicode code ponumber values of numberegers X1 through XN, respectively.*/ - char(...arg: Array>): HasSql + char(...arg: Array>): Sql /** The coalesce() function returns a copy of its first non-NULL argument, or NULL if all arguments are NULL. Coalesce() must have at least 2 arguments.*/ - coalesce(x: Input, y: Input, ...rest: Array): HasSql + coalesce(x: Input, y: Input, ...rest: Array): Sql /** The hex() function numbererprets its argument as a BLOB and returns a string which is the upper-case hexadecimal rendering of the content of that blob. If the argument X in "hex(X)" is an numbereger or numbering ponumber number, then "numbererprets its argument as a BLOB" means that the binary number is first converted numbero a UTF8 text representation, then that text is numbererpreted as a BLOB. Hence, "hex(12345678)" renders as "3132333435363738" not the binary representation of the numbereger value "0000000000BC614E".*/ - // hex(x:Input): HasSql { + // hex(x:Input): Sql { // return new HasSql(Call('hex', [expr(x)])); // } /** The ifnull() function returns a copy of its first non-NULL argument, or NULL if both arguments are NULL. Ifnull() must have exactly 2 arguments. The ifnull() function is equivalent to coalesce() with two arguments.*/ - ifnull(x: Input, y: Input): HasSql + ifnull(x: Input, y: Input): Sql /** The instr(X,Y) function finds the first occurrence of string Y within string X and returns the number of prior characters plus 1, or 0 if Y is nowhere found within X. Or, if X and Y are both BLOBs, then instr(X,Y) returns one more than the number bytes prior to the first occurrence of Y, or 0 if Y does not occur anywhere within X. If both arguments X and Y to instr(X,Y) are non-NULL and are not BLOBs then both are numbererpreted as strings. If either X or Y are NULL in instr(X,Y) then the result is NULL.*/ - instr(x: Input, y: Input): HasSql + instr(x: Input, y: Input): Sql /** The last_insert_rowid() function returns the ROWID of the last row insert from the database connection which invoked the function. The last_insert_rowid() SQL function is a wrapper around the sqlite3_last_insert_rowid() C/C++ numbererface function.*/ - last_insert_rowid(): HasSql + last_insert_rowid(): Sql /** For a string value X, the length(X) function returns the number of characters (not bytes) in X prior to the first NUL character. Since SQLite strings do not normally contain NUL characters, the length(X) function will usually return the total number of characters in the string X. For a blob value X, length(X) returns the number of bytes in the blob. If X is NULL then length(X) is NULL. If X is numeric then length(X) returns the length of a string representation of X.*/ - length(x: Input): HasSql + length(x: Input): Sql /** The likelihood(X,Y) function returns argument X unchanged. The value Y in likelihood(X,Y) must be a numbering ponumber constant between 0.0 and 1.0, inclusive. The likelihood(X) function is a no-op that the code generator optimizes away so that it consumes no CPU cycles during run-time (that is, during calls to sqlite3_step()). The purpose of the likelihood(X,Y) function is to provide a hnumber to the query planner that the argument X is a boolean that is true with a probability of approximately Y. The unlikely(X) function is short-hand for likelihood(X,0.0625). The likely(X) function is short-hand for likelihood(X,0.9375).*/ - likelihood(x: Input, y: number): HasSql + likelihood(x: Input, y: number): Sql /** The likely(X) function returns the argument X unchanged. The likely(X) function is a no-op that the code generator optimizes away so that it consumes no CPU cycles at run-time (that is, during calls to sqlite3_step()). The purpose of the likely(X) function is to provide a hnumber to the query planner that the argument X is a boolean value that is usually true. The likely(X) function is equivalent to likelihood(X,0.9375). See also: unlikely(X).*/ - likely(x: Input): HasSql + likely(x: Input): Sql /** The lower(X) function returns a copy of string X with all ASCII characters converted to lower case. The default built-in lower() function works for ASCII characters only. To do case conversions on non-ASCII characters, load the ICU extension.*/ - lower(x: Input): HasSql + lower(x: Input): Sql /** The ltrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the left side of X. If the Y argument is omitted, ltrim(X) removes spaces from the left side of X.**/ - ltrim(x: Input, y?: Input): HasSql + ltrim(x: Input, y?: Input): Sql /** The multi-argument max() function returns the argument with the maximum value, or return NULL if any argument is NULL. The multi-argument max() function searches its arguments from left to right for an argument that defines a collating function and uses that collating function for all string comparisons. If none of the arguments to max() define a collating function, then the BINARY collating function is used. Note that max() is a simple function when it has 2 or more arguments but operates as an aggregate function if given only a single argument.*/ - max(x: Input, ...rest: Array>): HasSql + max(x: Input, ...rest: Array>): Sql /** The multi-argument min() function returns the argument with the minimum value. The multi-argument min() function searches its arguments from left to right for an argument that defines a collating function and uses that collating function for all string comparisons. If none of the arguments to min() define a collating function, then the BINARY collating function is used. Note that min() is a simple function when it has 2 or more arguments but operates as an aggregate function if given only a single argument.*/ - min(x: Input, ...rest: Array>): HasSql + min(x: Input, ...rest: Array>): Sql /** The nullif(X,Y) function returns its first argument if the arguments are different and NULL if the arguments are the same. The nullif(X,Y) function searches its arguments from left to right for an argument that defines a collating function and uses that collating function for all string comparisons. If neither argument to nullif() defines a collating function then the BINARY is used.*/ - nullif(x: Input, y: Input): HasSql + nullif(x: Input, y: Input): Sql /** The prnumberf(FORMAT,...) SQL function works like the sqlite3_mprnumberf() C-language function and the prnumberf() function from the standard C library. The first argument is a format string that specifies how to construct the output string using values taken from subsequent arguments. If the FORMAT argument is missing or NULL then the result is NULL. The %n format is silently ignored and does not consume an argument. The %p format is an alias for %X. The %z format is numbererchangeable with %s. If there are too few arguments in the argument list, missing arguments are assumed to have a NULL value, which is translated numbero 0 or 0.0 for numeric formats or an empty string for %s. See the built-in prnumberf() documentation for additional information.*/ - prnumberf(format: string, ...rest: Array): HasSql + prnumberf(format: string, ...rest: Array): Sql /** The quote(X) function returns the text of an SQL literal which is the value of its argument suitable for inclusion numbero an SQL statement. strings are surrounded by single-quotes with escapes on numbererior quotes as needed. BLOBs are encoded as hexadecimal literals. strings with embedded NUL characters cannot be represented as string literals in SQL and hence the returned string literal is truncated prior to the first NUL.*/ - quote(x: Input): HasSql + quote(x: Input): Sql /** The random() function returns a pseudo-random numbereger between -9223372036854775808 and +9223372036854775807.*/ - random(): HasSql + random(): Sql /** The randomblob(N) function return an N-byte blob containing pseudo-random bytes. If N is less than 1 then a 1-byte random blob is returned.*/ - // randomblob(x:Input): HasSql { + // randomblob(x:Input): Sql { // return new HasSql(Call('randomblob', [expr(x)])); // } /** The replace(X,Y,Z) function returns a string formed by substituting string Z for every occurrence of string Y in string X. The BINARY collating sequence is used for comparisons. If Y is an empty string then return X unchanged. If Z is not initially a string, it is cast to a UTF-8 string prior to processing.*/ - replace(x: Input, y: Input, z: Input): HasSql + replace(x: Input, y: Input, z: Input): Sql /** The round(X,Y) function returns a numbering-ponumber value X rounded to Y digits to the right of the decimal ponumber. If the Y argument is omitted, it is assumed to be 0.*/ - round(x: Input, y?: Input): HasSql + round(x: Input, y?: Input): Sql /** The rtrim(X,Y) function returns a string formed by removing any and all characters that appear in Y from the right side of X. If the Y argument is omitted, rtrim(X) removes spaces from the right side of X.*/ - rtrim(x: Input, y?: Input): HasSql + rtrim(x: Input, y?: Input): Sql /** The sign(X) function returns -1, 0, or +1 if the argument X is a numeric value that is negative, zero, or positive, respectively. If the argument to sign(X) is NULL or is a string or blob that cannot be losslessly converted numbero a number, then sign(X) return NULL.*/ - sign(x: Input): HasSql + sign(x: Input): Sql /** The soundex(X) function returns a string that is the soundex encoding of the string X. The string "?000" is returned if the argument is NULL or contains no ASCII alphabetic characters. This function is omitted from SQLite by default. It is only available if the SQLITE_SOUNDEX compile-time option is used when SQLite is built.*/ - soundex(x: Input): HasSql + soundex(x: Input): Sql /** The sqlite_version() function returns the version string for the SQLite library that is running. This function is an SQL wrapper around the sqlite3_libversion() C-numbererface.*/ - sqlite_version(): HasSql + sqlite_version(): Sql /** The substr(X,Y,Z) function returns a substring of input string X that begins with the Y-th character and which is Z characters long. If Z is omitted then substr(X,Y) returns all characters through the end of the string X beginning with the Y-th. The left-most character of X is number 1. If Y is negative then the first character of the substring is found by counting from the right rather than the left. If Z is negative then the abs(Z) characters preceding the Y-th character are returned. If X is a string then characters indices refer to actual UTF-8 characters. If X is a BLOB then the indices refer to bytes.*/ - substr(x: Input, y: Input, z?: Input): HasSql + substr(x: Input, y: Input, z?: Input): Sql /** The total_changes() function returns the number of row changes caused by INSERT, UPDATE or DELETE statements since the current database connection was opened. This function is a wrapper around the sqlite3_total_changes() C/C++ numbererface.*/ - total_changes(): HasSql + total_changes(): Sql /** The trim(X,Y) function returns a string formed by removing any and all characters that appear in Y from both ends of X. If the Y argument is omitted, trim(X) removes spaces from both ends of X.*/ - trim(x: Input, Y: Input): HasSql + trim(x: Input, Y: Input): Sql /** The typeof(X) function returns a string that indicates the datatype of the HasSql X: "null", "numbereger", "real", "text", or "blob".*/ - typeof(x: Input): HasSql + typeof(x: Input): Sql /** The unicode(X) function returns the numeric unicode code ponumber corresponding to the first character of the string X. If the argument to unicode(X) is not a string then the result is undefined.*/ - unicode(x: Input): HasSql + unicode(x: Input): Sql /** The unlikely(X) function returns the argument X unchanged. The unlikely(X) function is a no-op that the code generator optimizes away so that it consumes no CPU cycles at run-time (that is, during calls to sqlite3_step()). The purpose of the unlikely(X) function is to provide a hnumber to the query planner that the argument X is a boolean value that is usually not true. The unlikely(X) function is equivalent to likelihood(X, 0.0625).*/ - unlikely(x: Input): HasSql + unlikely(x: Input): Sql /** The upper(X) function returns a copy of input string X in which all lower-case ASCII characters are converted to their upper-case equivalent.*/ - upper(x: Input): HasSql + upper(x: Input): Sql // ===================================================== // http://www.sqlite.org/lang_aggfunc.html // ===================================================== /** The avg() function returns the average value of all non-NULL X within a group. string and BLOB values that do not look like numbers are numbererpreted as 0. The result of avg() is always a numbering ponumber value as long as at there is at least one non-NULL input even if all inputs are numberegers. The result of avg() is NULL if and only if there are no non-NULL inputs. */ - avg(x: HasSql): HasSql + avg(x: Sql): Sql /** The group_concat() function returns a string which is the concatenation of all non-NULL values of X. If parameter Y is present then it is used as the separator between instances of X. A comma (",") is used as the separator if Y is omitted. The order of the concatenated elements is arbitrary. */ - group_concat(x: Input, y?: Input): HasSql + group_concat(x: Input, y?: Input): Sql /** The sum() and total() aggregate functions return sum of all non-NULL values in the group. If there are no non-NULL input rows then sum() returns NULL but total() returns 0.0. NULL is not normally a helpful result for the sum of no rows but the SQL standard requires it and most other SQL database engines implement sum() that way so SQLite does it in the same way in order to be compatible. The non-standard total() function is provided as a convenient way to work around this design problem in the SQL language. @@ -197,110 +197,110 @@ type SqliteFunctions = { Sum() will throw an "numbereger overflow" exception if all inputs are numberegers or NULL and an numbereger overflow occurs at any ponumber during the computation. Total() never throws an numbereger overflow. */ - sum(x: Input): HasSql + sum(x: Input): Sql // ===================================================== // http://www.sqlite.org/lang_mathfunc.html // ===================================================== /** Return the arccosine of X. The result is in radians. */ - acos(x: Input): HasSql + acos(x: Input): Sql /** Return the hyperbolic arccosine of X. */ - acosh(x: Input): HasSql + acosh(x: Input): Sql /** Return the arcsine of X. The result is in radians. */ - asin(x: Input): HasSql + asin(x: Input): Sql /** Return the hyperbolic arcsine of X. */ - asinh(x: Input): HasSql + asinh(x: Input): Sql /** Return the arctangent of X. The result is in radians. */ - atan(x: Input): HasSql + atan(x: Input): Sql /** Return the arctangent of Y/X. The result is in radians. The result is placed numbero correct quadrant depending on the signs of X and Y. */ - atan2(x: Input, y: Input): HasSql + atan2(x: Input, y: Input): Sql /** Return the hyperbolic arctangent of X. */ - atanh(x: Input): HasSql + atanh(x: Input): Sql /** Return the first representable numbereger value greater than or equal to X. For positive values of X, this routine rounds away from zero. For negative values of X, this routine rounds toward zero. */ - ceil(x: Input): HasSql + ceil(x: Input): Sql /** Return the cosine of X. X is in radians. */ - cos(x: Input): HasSql + cos(x: Input): Sql /** Return the hyperbolic cosine of X. */ - cosh(x: Input): HasSql + cosh(x: Input): Sql /** Convert value X from radians numbero degrees. */ - degrees(x: Input): HasSql + degrees(x: Input): Sql /** Compute e (Euler's number, approximately 2.71828182845905) raised to the power X. */ - exp(x: Input): HasSql + exp(x: Input): Sql /** Return the first representable numbereger value less than or equal to X. For positive numbers, this function rounds toward zero. For negative numbers, this function rounds away from zero. */ - floor(x: Input): HasSql + floor(x: Input): Sql /** Return the natural logarithm of X. */ - ln(x: Input): HasSql + ln(x: Input): Sql /** Return the base-10 logarithm for X. Or, for the two-argument version, return the base-B logarithm of X. Compatibility note: SQLite works like PostgreSQL in that the log() function computes a base-10 logarithm. Most other SQL database engines compute a natural logarithm for log(). In the two-argument version of log(B,X), the first argument is the base and the second argument is the operand. This is the same as in PostgreSQL and MySQL, but is reversed from SQL Server which uses the second argument as the base and the first argument as the operand. */ // TODO: log10(X) overload: log(B,X) - log(x: Input, y?: Input): HasSql + log(x: Input, y?: Input): Sql /** Return the logarithm base-2 for the number X. */ - log2(x: Input): HasSql + log2(x: Input): Sql /** Return the remainder after dividing X by Y. This is similar to the '%' operator, except that it works for non-numbereger arguments. */ - mod(x: Input, y: Input): HasSql + mod(x: Input, y: Input): Sql /** Return an approximation for π. */ - pi(): HasSql + pi(): Sql /** Compute X raised to the power Y. */ - pow(x: Input, y: Input): HasSql + pow(x: Input, y: Input): Sql /** Convert X from degrees numbero radians. */ - radians(x: Input): HasSql + radians(x: Input): Sql /** Return the sine of X. X is in radians. */ - sin(x: Input): HasSql + sin(x: Input): Sql /** Return the hyperbolic sine of X. */ - sinh(x: Input): HasSql + sinh(x: Input): Sql /** Return the square root of X. NULL is returned if X is negative. */ - sqrt(x: Input): HasSql + sqrt(x: Input): Sql /** Return the tangent of X. X is in radians. */ - tan(x: Input): HasSql + tan(x: Input): Sql /** Return the hyperbolic tangent of X. */ - tanh(x: Input): HasSql + tanh(x: Input): Sql /** Return the representable numbereger in between X and 0 (inclusive) that is furthest away from zero. Or, in other words, return the numbereger part of X, rounding toward zero. The trunc() function is similar to ceiling(X) and floor(X) except that it always rounds toward zero whereas ceiling(X) and floor(X) round up and down, respectively. */ - trunc(x: Input): HasSql + trunc(x: Input): Sql // ===================================================== // https://www.sqlite.org/lang_datefunc.html // ===================================================== - date(timeValue: Input, ...rest: Array>): HasSql + date(timeValue: Input, ...rest: Array>): Sql - time(timeValue: Input, ...rest: Array>): HasSql + time(timeValue: Input, ...rest: Array>): Sql - datetime(timeValue: Input, ...rest: Array>): HasSql + datetime(timeValue: Input, ...rest: Array>): Sql - julianday(timeValue: Input, ...rest: Array>): HasSql + julianday(timeValue: Input, ...rest: Array>): Sql strftime( format: Input, timeValue: Input, ...rest: Array> - ): HasSql + ): Sql } export const { @@ -377,10 +377,10 @@ export const { strftime } = SqliteFunctions -export function cast(x: Input, type: 'text'): HasSql -export function cast(x: Input, type: 'real'): HasSql -export function cast(x: Input, type: 'integer'): HasSql -export function cast(x: Input, type: 'numeric'): HasSql +export function cast(x: Input, type: 'text'): Sql +export function cast(x: Input, type: 'real'): Sql +export function cast(x: Input, type: 'integer'): Sql +export function cast(x: Input, type: 'numeric'): Sql export function cast(x: Input, type: string): HasSql { return sql`cast(${input(x)} as ${sql.identifier(type)})` } diff --git a/test/core/Expr.test.ts b/test/core/Expr.test.ts index 9290168..3035ae6 100644 --- a/test/core/Expr.test.ts +++ b/test/core/Expr.test.ts @@ -1,6 +1,6 @@ import {Assert, Test} from '@sinclair/carbon' -import * as e from '../../src/core/Expr.ts' import {sql} from '../../src/core/Sql.ts' +import * as e from '../../src/core/expr/Conditions.ts' import {emit} from '../TestUtils.ts' Test.describe('Expr', () => { diff --git a/test/query/Delete.test.ts b/test/query/Delete.test.ts index 1338c43..846a2a4 100644 --- a/test/query/Delete.test.ts +++ b/test/query/Delete.test.ts @@ -1,6 +1,6 @@ import {Assert, Test} from '@sinclair/carbon' -import {eq} from '../../src/core/Expr.ts' import {table} from '../../src/core/Table.ts' +import {eq} from '../../src/core/expr/Conditions.ts' import {integer} from '../../src/sqlite/SqliteColumns.ts' import {builder, emit} from '../TestUtils.ts' diff --git a/test/query/Select.test.ts b/test/query/Select.test.ts index b44a193..e87ea45 100644 --- a/test/query/Select.test.ts +++ b/test/query/Select.test.ts @@ -1,6 +1,6 @@ import {Assert, Test} from '@sinclair/carbon' -import {eq} from '../../src/core/Expr.ts' import {alias, table} from '../../src/core/Table.ts' +import {eq} from '../../src/core/expr/Conditions.ts' import {integer, text} from '../../src/sqlite/SqliteColumns.ts' import {builder, emit} from '../TestUtils.ts'