-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
326a1a0
commit e8b39e2
Showing
14 changed files
with
859 additions
and
688 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,93 +1,86 @@ | ||
import { Ast, builder } from 'zensqlite'; | ||
import { Datatype } from './Datatype'; | ||
import { Random } from './Random'; | ||
import { PRIV, TYPES } from './utils/constants'; | ||
import { mapObject } from './utils/utils'; | ||
|
||
export type IExprInternal_Param = { readonly name?: string; readonly value: any }; | ||
|
||
export interface IExprInternal { | ||
// json option is set to true when the expression was already JSON parsed | ||
export type ExprParser<Val> = (raw: any, json: boolean) => Val; | ||
|
||
export interface IExprInternal<Val> { | ||
readonly parse: ExprParser<Val>; | ||
// used by Expr.external | ||
readonly param?: IExprInternal_Param; | ||
readonly populated?: any; | ||
} | ||
|
||
type InnerExpr = Ast.Expr; | ||
|
||
export type IExpr<Val> = InnerExpr & { readonly [TYPES]: Val; readonly [PRIV]?: IExprInternal }; | ||
|
||
export type IColumnRef<Val> = Ast.Node<'Column'> & { readonly [TYPES]: Val; readonly [PRIV]?: IExprInternal }; | ||
|
||
export interface IJson<Value> { | ||
readonly [TYPES]: Value; | ||
} | ||
|
||
// type ExprBuilder = { | ||
// functionInvocation: (name: string, ...params: IExpr<any>[]) => IExpr<any>; | ||
// literal: <Val extends string | number | boolean | null>(val: Val) => IExpr<Val>; | ||
// add: <Val extends number>(left: IExpr<Val>, right: IExpr<Val>) => IExpr<Val>; | ||
// equal: (left: IExpr<any>, right: IExpr<any>) => IExpr<boolean>; | ||
// different: (left: IExpr<any>, right: IExpr<any>) => IExpr<boolean>; | ||
// like: (left: IExpr<any>, right: IExpr<any>) => IExpr<boolean>; | ||
// or: (left: IExpr<any>, right: IExpr<any>) => IExpr<boolean>; | ||
// and: (left: IExpr<any>, right: IExpr<any>) => IExpr<boolean>; | ||
// notNull: (expr: IExpr<any>) => IExpr<boolean>; | ||
// concatenate: (left: IExpr<string>, right: IExpr<string>) => IExpr<string>; | ||
// AggregateFunctions: { | ||
// json_group_array: <Val>(expr: IExpr<Val>) => IExpr<IJson<Array<Val>>>; | ||
// count: (expr: IExpr<any>) => IExpr<number>; | ||
// }; | ||
// ScalarFunctions: { | ||
// json_array_length: (expr: IExpr<IJson<Array<any>>>) => IExpr<number>; | ||
// json_object: <Items extends Record<string, IExpr<any>>>(items: Items) => IExpr<IJson<{ [K in keyof Items]: Items[K][TYPES] }>>; | ||
// }; | ||
// }; | ||
export type IExpr<Val> = InnerExpr & { readonly [TYPES]: Val; readonly [PRIV]: IExprInternal<Val> }; | ||
|
||
export const Expr = (() => { | ||
return { | ||
functionInvocation: (name: string, ...params: IExpr<any>[]): IExpr<any> => create(builder.Expr.functionInvocation(name, ...params)), | ||
literal: <Val extends string | number | boolean | null>(val: Val): IExpr<Val> => create(builder.Expr.literal(val)), | ||
add: <Val extends number>(left: IExpr<Val>, right: IExpr<Val>): IExpr<Val> => create(builder.Expr.add(left, right)), | ||
equal: (left: IExpr<any>, right: IExpr<any>): IExpr<boolean> => create(builder.Expr.equal(left, right)), | ||
different: (left: IExpr<any>, right: IExpr<any>): IExpr<boolean> => create(builder.Expr.different(left, right)), | ||
like: (left: IExpr<any>, right: IExpr<any>): IExpr<boolean> => create(builder.Expr.like(left, right)), | ||
or: (left: IExpr<any>, right: IExpr<any>): IExpr<boolean> => create(builder.Expr.or(left, right)), | ||
and: (left: IExpr<any>, right: IExpr<any>): IExpr<boolean> => create(builder.Expr.and(left, right)), | ||
notNull: (expr: IExpr<any>): IExpr<boolean> => create(builder.Expr.notNull(expr)), | ||
concatenate: (left: IExpr<string>, right: IExpr<string>): IExpr<string> => create(builder.Expr.concatenate(left, right)), | ||
functionInvocation: <Val>(name: string, parse: ExprParser<Val>, ...params: IExpr<any>[]) => | ||
create<Val>(builder.Expr.functionInvocation(name, ...params), parse), | ||
literal: <Val extends string | number | boolean | null>(val: Val) => createLiteral<Val>(val), | ||
add: (left: IExpr<number>, right: IExpr<number>) => create<number>(builder.Expr.add(left, right), Datatype.number.parse), | ||
equal: (left: IExpr<any>, right: IExpr<any>) => create(builder.Expr.equal(left, right), Datatype.boolean.parse), | ||
different: (left: IExpr<any>, right: IExpr<any>) => create(builder.Expr.different(left, right), Datatype.boolean.parse), | ||
like: (left: IExpr<any>, right: IExpr<any>) => create(builder.Expr.like(left, right), Datatype.boolean.parse), | ||
or: (left: IExpr<any>, right: IExpr<any>) => create(builder.Expr.or(left, right), Datatype.boolean.parse), | ||
and: (left: IExpr<any>, right: IExpr<any>) => create(builder.Expr.and(left, right), Datatype.boolean.parse), | ||
notNull: (expr: IExpr<any>) => create(builder.Expr.notNull(expr), Datatype.boolean.parse), | ||
concatenate: (left: IExpr<string>, right: IExpr<string>): IExpr<string> => | ||
create(builder.Expr.concatenate(left, right), Datatype.text.parse), | ||
|
||
external: <Val extends string | number | boolean | null>(val: Val, name?: string): IExpr<Val> => { | ||
const paramName = (name ?? '') + '_' + Random.createId(); | ||
return create(builder.Expr.BindParameter.colonNamed(paramName), { name: paramName, value: val }); | ||
return create(builder.Expr.BindParameter.colonNamed(paramName), Datatype.fromLiteral(val).parse, { name: paramName, value: val }); | ||
}, | ||
|
||
column: <Val>(table: Ast.Identifier, column: string): IColumnRef<Val> => { | ||
return create<Val>(builder.Expr.column({ column, table: { table } })) as IColumnRef<Val>; | ||
column: <Val>(table: Ast.Identifier, column: string, parse: ExprParser<Val>) => { | ||
return create<Val>(builder.Expr.column({ column, table: { table } }), parse); | ||
}, | ||
|
||
AggregateFunctions: { | ||
json_group_array: <Val>(expr: IExpr<Val>): IExpr<IJson<Array<Val>>> => | ||
create(builder.Expr.AggregateFunctions.json_group_array({ params: expr })), | ||
count: (expr: IExpr<any>): IExpr<number> => create(builder.Expr.AggregateFunctions.count({ params: expr })), | ||
avg: (expr: IExpr<any>): IExpr<number> => create(builder.Expr.AggregateFunctions.avg({ params: expr })), | ||
json_group_array: <Val>(expr: IExpr<Val>): IExpr<Array<Val>> => | ||
create(builder.Expr.AggregateFunctions.json_group_array({ params: expr }), (raw, json) => { | ||
const arr = json ? raw : JSON.parse(raw); | ||
return arr.map((item: any) => parseExprVal(expr, item, true)); | ||
}), | ||
count: (expr: IExpr<any>): IExpr<number> => create(builder.Expr.AggregateFunctions.count({ params: expr }), Datatype.number.parse), | ||
avg: (expr: IExpr<number>): IExpr<number> => create(builder.Expr.AggregateFunctions.avg({ params: expr }), Datatype.number.parse), | ||
}, | ||
|
||
ScalarFunctions: { | ||
json_object: <Items extends Record<string, IExpr<any>>>(items: Items): IExpr<IJson<{ [K in keyof Items]: Items[K][TYPES] }>> => | ||
json_object: <Items extends Record<string, IExpr<any>>>(items: Items): IExpr<{ [K in keyof Items]: Items[K][TYPES] }> => | ||
create( | ||
builder.Expr.ScalarFunctions.json_object( | ||
...Object.entries(items) | ||
.map(([name, value]) => [builder.Expr.literal(name), value]) | ||
.flat() | ||
) | ||
), | ||
(raw, json) => { | ||
const obj = json ? raw : JSON.parse(raw); | ||
return mapObject(items, (name, expr) => parseExprVal(expr, obj[name], true)); | ||
} | ||
), | ||
// json_array_length: (expr: IExpr<IJson<Array<any>>>): IExpr<number> => create(builder.Expr.ScalarFunctions.json_array_length({ params: expr })), | ||
}, | ||
}; | ||
|
||
function create<Val>(expr: InnerExpr, param?: IExprInternal_Param): IExpr<Val> { | ||
if (!param) { | ||
return expr as IExpr<Val>; | ||
} | ||
function createLiteral<Val extends string | number | boolean | null>(val: Val): IExpr<Val> { | ||
return create<Val>(builder.Expr.literal(val), Datatype.fromLiteral(val).parse); | ||
} | ||
|
||
const internal: IExprInternal = { param }; | ||
function create<Val>(expr: InnerExpr, parse: ExprParser<Val>, param?: IExprInternal_Param): IExpr<Val> { | ||
const internal: IExprInternal<Val> = { parse, param }; | ||
return Object.assign(expr, { [PRIV]: internal }) as IExpr<Val>; | ||
} | ||
|
||
function parseExprVal<Val>(expr: IExpr<Val>, raw: any, json: boolean): Val { | ||
return expr[PRIV].parse(raw, json); | ||
} | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.