@deterministic-code/datasources 0.1.14 → 0.1.16
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.
- package/dist/BatchCommandIBulkWriteStrategy.js +1 -1
- package/dist/CRUDRepository.d.ts +2 -0
- package/dist/CRUDRepository.js +3 -1
- package/dist/Datasource.js +7 -21
- package/dist/IReadonlyRepository.d.ts +1 -0
- package/dist/ReadonlyRepository.d.ts +1 -0
- package/dist/ReadonlyRepository.js +1 -0
- package/dist/ReadonlyRepositoryMappingOptions.d.ts +2 -0
- package/dist/Schema.d.ts +4 -0
- package/dist/Schema.js +6 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/mappers/DeterministicTypeMapper.d.ts +5 -0
- package/dist/mappers/DeterministicTypeMapper.js +21 -0
- package/dist/statements/ArrayExpression.js +2 -0
- package/dist/statements/ConditionRenderer.js +9 -1
- package/dist/statements/ExpressionRenderer.js +65 -67
- package/dist/statements/Identifier.js +2 -0
- package/dist/statements/Literal.js +2 -0
- package/dist/statements/Operator.js +19 -0
- package/dist/statements/StatementTextRenderer.js +4 -11
- package/dist/statements/Subquery.js +2 -0
- package/dist/statements/Where.js +2 -0
- package/dist/statements/WhereText.js +2 -0
- package/dist/statements/brand.d.ts +5 -0
- package/dist/statements/brand.js +5 -0
- package/package.json +1 -1
|
@@ -83,7 +83,7 @@ export class BatchCommandIBulkWriteStrategy {
|
|
|
83
83
|
return { result: null, rowsAffected };
|
|
84
84
|
};
|
|
85
85
|
mappedInsert = (item) => {
|
|
86
|
-
const record = this.reverse(item);
|
|
86
|
+
const record = this.repo.fillCreateZeros(this.reverse(item));
|
|
87
87
|
const statement = this.statements().insert(this.fields(record, (col) => listed(this.options.createProperties, col, !this.ids.includes(col) || assigned(record[col] ?? null))));
|
|
88
88
|
return { table: statement.table, fields: statement.fields };
|
|
89
89
|
};
|
package/dist/CRUDRepository.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export declare class CRUDRepository<T = Cells> extends ReadonlyRepository<T> imp
|
|
|
14
14
|
readonly ids: readonly string[];
|
|
15
15
|
private readonly createProperties?;
|
|
16
16
|
private readonly updateProperties?;
|
|
17
|
+
protected createZeros?: Cells;
|
|
17
18
|
private readonly crudStatements;
|
|
18
19
|
private readonly tree;
|
|
19
20
|
private readonly write;
|
|
@@ -36,6 +37,7 @@ export declare class CRUDRepository<T = Cells> extends ReadonlyRepository<T> imp
|
|
|
36
37
|
private save;
|
|
37
38
|
private remove;
|
|
38
39
|
private byId;
|
|
40
|
+
fillCreateZeros: (record: Cells) => Cells;
|
|
39
41
|
private reverseConvert;
|
|
40
42
|
private idWhere;
|
|
41
43
|
protected enrichmentInto: (name: string) => boolean;
|
package/dist/CRUDRepository.js
CHANGED
|
@@ -37,6 +37,7 @@ export class CRUDRepository extends ReadonlyRepository {
|
|
|
37
37
|
ids;
|
|
38
38
|
createProperties;
|
|
39
39
|
updateProperties;
|
|
40
|
+
createZeros;
|
|
40
41
|
crudStatements;
|
|
41
42
|
tree;
|
|
42
43
|
write;
|
|
@@ -118,7 +119,7 @@ export class CRUDRepository extends ReadonlyRepository {
|
|
|
118
119
|
readSingleById = async (id) => this.readSingle(this.byId(id));
|
|
119
120
|
insert = async (item) => {
|
|
120
121
|
const extras = lookupKeys(item);
|
|
121
|
-
const record = this.reverseConvert(item);
|
|
122
|
+
const record = this.fillCreateZeros(this.reverseConvert(item));
|
|
122
123
|
const fields = fieldsOf(record, (col) => extras.has(col) || listed(this.createProperties, col, !this.ids.includes(col) || assigned(record[col] ?? null)), extras, this.cell, this.enrichmentInto, this.crudStatements.readColumns, this.column);
|
|
123
124
|
const statement = this.crudStatements.insert(fields);
|
|
124
125
|
const response = await execute(this.command(), statement, statement.fields);
|
|
@@ -181,6 +182,7 @@ export class CRUDRepository extends ReadonlyRepository {
|
|
|
181
182
|
throw new DatasourceError("Composite id requires a row keyed by each Id column");
|
|
182
183
|
return this.idWhere({ [this.ids[0]]: id });
|
|
183
184
|
};
|
|
185
|
+
fillCreateZeros = (record) => this.createZeros === undefined ? record : { ...this.createZeros, ...record };
|
|
184
186
|
reverseConvert = (item) => {
|
|
185
187
|
const row = this.objectConverter.reverseConvert(item);
|
|
186
188
|
const converted = this.rowConverter ? this.rowConverter.reverseConvert(row) : row;
|
package/dist/Datasource.js
CHANGED
|
@@ -4,6 +4,7 @@ import { ReadonlyRepository } from "./ReadonlyRepository.js";
|
|
|
4
4
|
import { RepositoryFactory } from "./RepositoryFactory.js";
|
|
5
5
|
import { RepositoryNotRegisteredError } from "./RepositoryNotRegisteredError.js";
|
|
6
6
|
import { RowTypeConverter } from "./converters/RowTypeConverter.js";
|
|
7
|
+
import { Schema } from "./Schema.js";
|
|
7
8
|
import { createCRUDRepositoryOptions } from "./createCRUDRepositoryOptions.js";
|
|
8
9
|
import { createReadonlyRepositoryMappingOptions } from "./createReadonlyRepositoryMappingOptions.js";
|
|
9
10
|
export class Datasource {
|
|
@@ -41,10 +42,12 @@ export class Datasource {
|
|
|
41
42
|
applyCrud = (type, options) => {
|
|
42
43
|
const built = createCRUDRepositoryOptions(type, this.driver.rowTypeConverters);
|
|
43
44
|
const types = this.driver.rowTypeConverters;
|
|
44
|
-
const
|
|
45
|
+
const schema = options?.schema ?? new Schema({});
|
|
46
|
+
const rows = options?.rowConverter ?? RowTypeConverter.from(this.driver.rowTypeConverters, schema.columns);
|
|
45
47
|
return {
|
|
46
48
|
...(options ?? built),
|
|
47
49
|
entity: options?.entity ?? built.entity,
|
|
50
|
+
schema,
|
|
48
51
|
rowConverter: rows,
|
|
49
52
|
rowTypeConverters: types,
|
|
50
53
|
type,
|
|
@@ -53,10 +56,12 @@ export class Datasource {
|
|
|
53
56
|
applyReadonly = (type, options) => {
|
|
54
57
|
const built = createReadonlyRepositoryMappingOptions(type, this.driver.rowTypeConverters);
|
|
55
58
|
const types = this.driver.rowTypeConverters;
|
|
56
|
-
const
|
|
59
|
+
const schema = options?.schema ?? new Schema({});
|
|
60
|
+
const rows = options?.rowConverter ?? RowTypeConverter.from(this.driver.rowTypeConverters, schema.columns);
|
|
57
61
|
return {
|
|
58
62
|
...(options ?? built),
|
|
59
63
|
entity: options?.entity ?? built.entity,
|
|
64
|
+
schema,
|
|
60
65
|
rowConverter: rows,
|
|
61
66
|
rowTypeConverters: types,
|
|
62
67
|
type,
|
|
@@ -77,22 +82,3 @@ export class Datasource {
|
|
|
77
82
|
return Datasource.create();
|
|
78
83
|
}
|
|
79
84
|
}
|
|
80
|
-
const columnsOf = (type) => {
|
|
81
|
-
const instance = new type();
|
|
82
|
-
const columns = {};
|
|
83
|
-
for (const [name, value] of Object.entries(instance)) {
|
|
84
|
-
if (Array.isArray(value))
|
|
85
|
-
continue;
|
|
86
|
-
const canonical = canonicalOf(value);
|
|
87
|
-
if (canonical)
|
|
88
|
-
columns[name] = canonical;
|
|
89
|
-
}
|
|
90
|
-
return columns;
|
|
91
|
-
};
|
|
92
|
-
const canonicalOf = (value) => typeof value === "boolean"
|
|
93
|
-
? "bool"
|
|
94
|
-
: value instanceof Date
|
|
95
|
-
? "datetime"
|
|
96
|
-
: value instanceof Uint8Array
|
|
97
|
-
? "binary"
|
|
98
|
-
: undefined;
|
|
@@ -6,6 +6,7 @@ import type { IWhere } from "./statements/IWhere.js";
|
|
|
6
6
|
import type { ReadonlyRepositoryMappingOptions } from "./ReadonlyRepositoryMappingOptions.js";
|
|
7
7
|
export type ReadQuery = ISelectStatement | IWhere | IExecuteStoredProcedureStatement;
|
|
8
8
|
export interface IReadonlyRepository<T = unknown> extends IRepository<T> {
|
|
9
|
+
readonly isSchemaRequired: boolean;
|
|
9
10
|
readSingle(query?: ReadQuery, parameters?: Parameter[], options?: ReadonlyRepositoryMappingOptions<T>): Promise<T | undefined>;
|
|
10
11
|
read(query?: ReadQuery, parameters?: Parameter[], options?: ReadonlyRepositoryMappingOptions<T>): AsyncIterable<T>;
|
|
11
12
|
}
|
|
@@ -23,6 +23,7 @@ export declare const isBuilt: <T>(value: IConnection | BuiltRepository<T>) => va
|
|
|
23
23
|
export declare const builtOf: <T>(typeOrConnectionOrBuilt: Constructable<T> | IConnection | BuiltRepository<T>, connectionOrOptions?: IConnection | ReadonlyRepositoryMappingOptions<T>) => BuiltRepository<T> | undefined;
|
|
24
24
|
export declare class ReadonlyRepository<T> implements IReadonlyRepository<T>, IEnriched<T> {
|
|
25
25
|
readonly type: Constructable<T>;
|
|
26
|
+
readonly isSchemaRequired = false;
|
|
26
27
|
private connection?;
|
|
27
28
|
protected rowConverter?: TypeConverter<Cells, Cells>;
|
|
28
29
|
protected objectConverter?: TypeConverter<T, Cells>;
|
|
@@ -22,6 +22,7 @@ export const builtOf = (typeOrConnectionOrBuilt, connectionOrOptions) => typeof
|
|
|
22
22
|
: new ReadonlyRepositoryBuilder().parts(typeOrConnectionOrBuilt, connectionOrOptions);
|
|
23
23
|
export class ReadonlyRepository {
|
|
24
24
|
type;
|
|
25
|
+
isSchemaRequired = false;
|
|
25
26
|
connection;
|
|
26
27
|
rowConverter;
|
|
27
28
|
objectConverter;
|
|
@@ -2,6 +2,7 @@ import type { Cell, Cells } from "./converters/Cell.js";
|
|
|
2
2
|
import type { Constructable } from "./converters/Constructable.js";
|
|
3
3
|
import type { TypeConverter } from "./converters/TypeConverter.js";
|
|
4
4
|
import type { IMapper } from "./mappers/IMapper.js";
|
|
5
|
+
import type { Schema } from "./Schema.js";
|
|
5
6
|
export type ReadonlyRepositoryMappingOptions<T = Cells> = {
|
|
6
7
|
entity?: string;
|
|
7
8
|
entityMapper?: IMapper<string, string>;
|
|
@@ -11,4 +12,5 @@ export type ReadonlyRepositoryMappingOptions<T = Cells> = {
|
|
|
11
12
|
type?: Constructable<T>;
|
|
12
13
|
rowTypeConverters?: Record<string, TypeConverter<Cell, Cell>>;
|
|
13
14
|
readProperties?: string[];
|
|
15
|
+
schema?: Schema;
|
|
14
16
|
};
|
package/dist/Schema.d.ts
ADDED
package/dist/Schema.js
ADDED
package/dist/index.d.ts
CHANGED
|
@@ -118,6 +118,8 @@ export type { TypeMapGroup } from "./mappers/TypeMapGroup.js";
|
|
|
118
118
|
export { FlatToNestedMapper } from "./mappers/FlatToNestedMapper.js";
|
|
119
119
|
export { ChangeCasingMapper } from "./mappers/ChangeCasingMapper.js";
|
|
120
120
|
export { DictionaryMapper } from "./mappers/DictionaryMapper.js";
|
|
121
|
+
export { DeterministicTypeMapper } from "./mappers/DeterministicTypeMapper.js";
|
|
122
|
+
export { Schema } from "./Schema.js";
|
|
121
123
|
export { IdentityMapper } from "./mappers/IdentityMapper.js";
|
|
122
124
|
export { PluralizerMapper } from "./mappers/PluralizerMapper.js";
|
|
123
125
|
export { TransformMapper } from "./mappers/TransformMapper.js";
|
package/dist/index.js
CHANGED
|
@@ -72,6 +72,8 @@ export { ReplaceConverter } from "./converters/ReplaceConverter.js";
|
|
|
72
72
|
export { FlatToNestedMapper } from "./mappers/FlatToNestedMapper.js";
|
|
73
73
|
export { ChangeCasingMapper } from "./mappers/ChangeCasingMapper.js";
|
|
74
74
|
export { DictionaryMapper } from "./mappers/DictionaryMapper.js";
|
|
75
|
+
export { DeterministicTypeMapper } from "./mappers/DeterministicTypeMapper.js";
|
|
76
|
+
export { Schema } from "./Schema.js";
|
|
75
77
|
export { IdentityMapper } from "./mappers/IdentityMapper.js";
|
|
76
78
|
export { PluralizerMapper } from "./mappers/PluralizerMapper.js";
|
|
77
79
|
export { TransformMapper } from "./mappers/TransformMapper.js";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const forward = {
|
|
2
|
+
boolean: "boolean",
|
|
3
|
+
Boolean: "boolean",
|
|
4
|
+
number: "integer",
|
|
5
|
+
Number: "integer",
|
|
6
|
+
bigint: "biginteger",
|
|
7
|
+
BigInt: "biginteger",
|
|
8
|
+
Date: "datetime",
|
|
9
|
+
Uint8Array: "binary",
|
|
10
|
+
};
|
|
11
|
+
const reverse = {
|
|
12
|
+
boolean: "boolean",
|
|
13
|
+
integer: "number",
|
|
14
|
+
biginteger: "bigint",
|
|
15
|
+
datetime: "Date",
|
|
16
|
+
binary: "Uint8Array",
|
|
17
|
+
};
|
|
18
|
+
export class DeterministicTypeMapper {
|
|
19
|
+
map = (value) => forward[value] ?? "";
|
|
20
|
+
reverseMap = (value) => reverse[value] ?? "";
|
|
21
|
+
}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { is } from "./brand.js";
|
|
1
2
|
import { Where } from "./Where.js";
|
|
3
|
+
import { WhereText } from "./WhereText.js";
|
|
2
4
|
export class ConditionRenderer {
|
|
3
5
|
expressions;
|
|
4
6
|
constructor(expressions) {
|
|
@@ -6,6 +8,12 @@ export class ConditionRenderer {
|
|
|
6
8
|
}
|
|
7
9
|
render = (condition) => condition.accept(this);
|
|
8
10
|
visit(where) {
|
|
9
|
-
return where
|
|
11
|
+
return is(where, Where)
|
|
12
|
+
? this.expressions.render(where.condition)
|
|
13
|
+
: is(where, WhereText)
|
|
14
|
+
? where.rawText
|
|
15
|
+
: (() => {
|
|
16
|
+
throw new Error("empty expression");
|
|
17
|
+
})();
|
|
10
18
|
}
|
|
11
19
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ArrayExpression } from "./ArrayExpression.js";
|
|
2
|
+
import { is } from "./brand.js";
|
|
2
3
|
import { Identifier } from "./Identifier.js";
|
|
3
4
|
import { Literal } from "./Literal.js";
|
|
4
5
|
import { Operator } from "./Operator.js";
|
|
@@ -10,63 +11,55 @@ export class ExpressionRenderer {
|
|
|
10
11
|
this.text = text;
|
|
11
12
|
}
|
|
12
13
|
render = (expression) => {
|
|
13
|
-
if (expression
|
|
14
|
+
if (is(expression, Where))
|
|
14
15
|
return this.render(expression.condition);
|
|
15
|
-
if (expression
|
|
16
|
+
if (is(expression, Identifier))
|
|
16
17
|
return expression.name;
|
|
17
|
-
if (expression
|
|
18
|
+
if (is(expression, Literal))
|
|
18
19
|
return inline(expression.value);
|
|
19
|
-
if (expression
|
|
20
|
+
if (is(expression, ArrayExpression))
|
|
20
21
|
return expression.elements.map((e) => this.render(e)).join(", ");
|
|
21
|
-
if (expression
|
|
22
|
+
if (is(expression, Operator.Not))
|
|
22
23
|
return `NOT (${this.render(expression.argument)})`;
|
|
23
|
-
if (expression
|
|
24
|
+
if (is(expression, Operator.IsNull))
|
|
24
25
|
return `${this.render(expression.argument)} IS NULL`;
|
|
25
|
-
if (expression
|
|
26
|
+
if (is(expression, Operator.IsNotNull))
|
|
26
27
|
return `${this.render(expression.argument)} IS NOT NULL`;
|
|
27
|
-
if (expression
|
|
28
|
+
if (is(expression, Operator.Exists))
|
|
28
29
|
return `EXISTS ${this.render(expression.argument)}`;
|
|
29
|
-
if (expression
|
|
30
|
+
if (is(expression, Subquery))
|
|
30
31
|
return `(${this.text.render(expression.query)})`;
|
|
31
|
-
if (expression
|
|
32
|
-
expression.left instanceof Identifier &&
|
|
33
|
-
expression.right instanceof ArrayExpression)
|
|
32
|
+
if (is(expression, Operator.In) && is(expression.left, Identifier) && is(expression.right, ArrayExpression))
|
|
34
33
|
return expression.right.elements.length === 0
|
|
35
34
|
? "1 = 0"
|
|
36
35
|
: `${expression.left.name} IN (${slots(expression.left.name, expression.right.elements.length)})`;
|
|
37
|
-
if (expression
|
|
38
|
-
expression.left instanceof Identifier &&
|
|
39
|
-
expression.right instanceof Subquery)
|
|
36
|
+
if (is(expression, Operator.In) && is(expression.left, Identifier) && is(expression.right, Subquery))
|
|
40
37
|
return `${expression.left.name} IN ${this.render(expression.right)}`;
|
|
41
|
-
if (expression
|
|
42
|
-
expression.left instanceof Identifier &&
|
|
43
|
-
expression.right instanceof ArrayExpression)
|
|
38
|
+
if (is(expression, Operator.NotIn) && is(expression.left, Identifier) && is(expression.right, ArrayExpression))
|
|
44
39
|
return expression.right.elements.length === 0
|
|
45
40
|
? "1 = 1"
|
|
46
41
|
: `${expression.left.name} NOT IN (${slots(expression.left.name, expression.right.elements.length)})`;
|
|
47
|
-
if (expression
|
|
48
|
-
expression.left instanceof Identifier &&
|
|
49
|
-
expression.right instanceof Subquery)
|
|
42
|
+
if (is(expression, Operator.NotIn) && is(expression.left, Identifier) && is(expression.right, Subquery))
|
|
50
43
|
return `${expression.left.name} NOT IN ${this.render(expression.right)}`;
|
|
51
|
-
if ((expression
|
|
52
|
-
expression.value
|
|
53
|
-
expression.low
|
|
54
|
-
expression.high
|
|
55
|
-
const word = expression
|
|
44
|
+
if ((is(expression, Operator.Between) || is(expression, Operator.NotBetween)) &&
|
|
45
|
+
is(expression.value, Identifier) &&
|
|
46
|
+
is(expression.low, Literal) &&
|
|
47
|
+
is(expression.high, Literal)) {
|
|
48
|
+
const word = is(expression, Operator.NotBetween) ? "NOT BETWEEN" : "BETWEEN";
|
|
56
49
|
return `${expression.value.name} ${word} $${parameterName(expression.value.name)}_0 AND $${parameterName(expression.value.name)}_1`;
|
|
57
50
|
}
|
|
58
|
-
if (expression
|
|
51
|
+
if (is(expression, Operator.Between))
|
|
59
52
|
return `${this.render(expression.value)} BETWEEN ${this.render(expression.low)} AND ${this.render(expression.high)}`;
|
|
60
|
-
if (expression
|
|
53
|
+
if (is(expression, Operator.NotBetween))
|
|
61
54
|
return `${this.render(expression.value)} NOT BETWEEN ${this.render(expression.low)} AND ${this.render(expression.high)}`;
|
|
62
|
-
if (expression
|
|
55
|
+
if (is(expression, Operator.And))
|
|
63
56
|
return `${this.wrap(expression.left, true)} AND ${this.wrap(expression.right, true)}`;
|
|
64
|
-
if (expression
|
|
57
|
+
if (is(expression, Operator.Or))
|
|
65
58
|
return `${this.wrap(expression.left, false)} OR ${this.wrap(expression.right, false)}`;
|
|
66
|
-
const operands =
|
|
67
|
-
if (operands && operands.left
|
|
59
|
+
const operands = pair(expression);
|
|
60
|
+
if (operands && is(operands.left, Identifier) && is(operands.right, Literal))
|
|
68
61
|
return `${operands.left.name} ${symbol(expression)} $${parameterName(operands.left.name)}`;
|
|
69
|
-
if (operands && operands.left
|
|
62
|
+
if (operands && is(operands.left, Literal) && is(operands.right, Literal))
|
|
70
63
|
return `${inline(operands.left.value)} ${symbol(expression)} ${inline(operands.right.value)}`;
|
|
71
64
|
if (operands)
|
|
72
65
|
return `${this.render(operands.left)} ${symbol(expression)} ${this.render(operands.right)}`;
|
|
@@ -74,23 +67,27 @@ export class ExpressionRenderer {
|
|
|
74
67
|
};
|
|
75
68
|
wrap = (child, and) => needsParens(child, and) ? `(${this.render(child)})` : this.render(child);
|
|
76
69
|
}
|
|
77
|
-
const symbol = (op) =>
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
70
|
+
const symbol = (op) => {
|
|
71
|
+
if (is(op, Operator.Equals))
|
|
72
|
+
return "=";
|
|
73
|
+
if (is(op, Operator.NotEquals))
|
|
74
|
+
return "<>";
|
|
75
|
+
if (is(op, Operator.GreaterThan))
|
|
76
|
+
return ">";
|
|
77
|
+
if (is(op, Operator.LessThan))
|
|
78
|
+
return "<";
|
|
79
|
+
if (is(op, Operator.GreaterThanOrEqual))
|
|
80
|
+
return ">=";
|
|
81
|
+
if (is(op, Operator.LessThanOrEqual))
|
|
82
|
+
return "<=";
|
|
83
|
+
if (is(op, Operator.Like))
|
|
84
|
+
return "LIKE";
|
|
85
|
+
if (is(op, Operator.NotLike))
|
|
86
|
+
return "NOT LIKE";
|
|
87
|
+
if (is(op, Operator.In))
|
|
88
|
+
return "IN";
|
|
89
|
+
throw new Error("empty expression");
|
|
90
|
+
};
|
|
94
91
|
const inline = (value) => value === null
|
|
95
92
|
? "null"
|
|
96
93
|
: typeof value === "boolean"
|
|
@@ -98,24 +95,25 @@ const inline = (value) => value === null
|
|
|
98
95
|
: typeof value === "string"
|
|
99
96
|
? `'${value.replace(/'/g, "''")}'`
|
|
100
97
|
: String(value);
|
|
101
|
-
const needsParens = (child, and) => child
|
|
98
|
+
const needsParens = (child, and) => is(child, Where)
|
|
102
99
|
? needsParens(child.condition, and)
|
|
103
|
-
: child
|
|
104
|
-
child
|
|
105
|
-
child
|
|
106
|
-
(child
|
|
107
|
-
(child
|
|
108
|
-
const pair = (expression) => expression
|
|
109
|
-
expression
|
|
110
|
-
expression
|
|
111
|
-
expression
|
|
112
|
-
expression
|
|
113
|
-
expression
|
|
114
|
-
expression
|
|
115
|
-
expression
|
|
116
|
-
expression
|
|
117
|
-
expression
|
|
118
|
-
expression
|
|
100
|
+
: is(child, Operator.Not) ||
|
|
101
|
+
is(child, Operator.In) ||
|
|
102
|
+
is(child, Operator.NotIn) ||
|
|
103
|
+
(is(child, Operator.And) && !and) ||
|
|
104
|
+
(is(child, Operator.Or) && and);
|
|
105
|
+
const pair = (expression) => is(expression, Operator.Equals) ||
|
|
106
|
+
is(expression, Operator.NotEquals) ||
|
|
107
|
+
is(expression, Operator.GreaterThan) ||
|
|
108
|
+
is(expression, Operator.LessThan) ||
|
|
109
|
+
is(expression, Operator.GreaterThanOrEqual) ||
|
|
110
|
+
is(expression, Operator.LessThanOrEqual) ||
|
|
111
|
+
is(expression, Operator.And) ||
|
|
112
|
+
is(expression, Operator.Or) ||
|
|
113
|
+
is(expression, Operator.In) ||
|
|
114
|
+
is(expression, Operator.Like) ||
|
|
115
|
+
is(expression, Operator.NotLike) ||
|
|
116
|
+
is(expression, Operator.NotIn)
|
|
119
117
|
? expression
|
|
120
118
|
: undefined;
|
|
121
119
|
const parameterName = (name) => parts(name)
|
|
@@ -2,6 +2,7 @@ import { ArrayExpression } from "./ArrayExpression.js";
|
|
|
2
2
|
import { Condition } from "./Condition.js";
|
|
3
3
|
import { Identifier } from "./Identifier.js";
|
|
4
4
|
import { Literal } from "./Literal.js";
|
|
5
|
+
import { brand } from "./brand.js";
|
|
5
6
|
const pair = (left, right) => typeof left === "string"
|
|
6
7
|
? [new Identifier(left), new Literal(right)]
|
|
7
8
|
: [left, right];
|
|
@@ -205,3 +206,21 @@ export class Operator extends Condition {
|
|
|
205
206
|
}
|
|
206
207
|
Operator.Exists = Exists;
|
|
207
208
|
})(Operator || (Operator = {}));
|
|
209
|
+
brand(Operator.Equals);
|
|
210
|
+
brand(Operator.NotEquals);
|
|
211
|
+
brand(Operator.GreaterThan);
|
|
212
|
+
brand(Operator.LessThan);
|
|
213
|
+
brand(Operator.GreaterThanOrEqual);
|
|
214
|
+
brand(Operator.LessThanOrEqual);
|
|
215
|
+
brand(Operator.And);
|
|
216
|
+
brand(Operator.Or);
|
|
217
|
+
brand(Operator.In);
|
|
218
|
+
brand(Operator.Not);
|
|
219
|
+
brand(Operator.IsNull);
|
|
220
|
+
brand(Operator.IsNotNull);
|
|
221
|
+
brand(Operator.Like);
|
|
222
|
+
brand(Operator.NotLike);
|
|
223
|
+
brand(Operator.Between);
|
|
224
|
+
brand(Operator.NotBetween);
|
|
225
|
+
brand(Operator.NotIn);
|
|
226
|
+
brand(Operator.Exists);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { is } from "./brand.js";
|
|
1
2
|
import { ConditionRenderer } from "./ConditionRenderer.js";
|
|
2
3
|
import { ExpressionRenderer } from "./ExpressionRenderer.js";
|
|
3
4
|
import { StatementRenderer } from "./StatementRenderer.js";
|
|
@@ -12,16 +13,8 @@ export class StatementTextRenderer {
|
|
|
12
13
|
this.conditions = conditions?.(expressionRenderer) ?? new ConditionRenderer(expressionRenderer);
|
|
13
14
|
}
|
|
14
15
|
render(target) {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (target.constructor.name.endsWith("Statement")) {
|
|
19
|
-
return target.accept(this.statements);
|
|
20
|
-
}
|
|
21
|
-
if (target instanceof Where || target instanceof WhereText)
|
|
22
|
-
return target.accept(this.conditions);
|
|
23
|
-
return "where" in target || "fields" in target || "joins" in target || "column" in target
|
|
24
|
-
? target.accept(this.statements)
|
|
25
|
-
: target.accept(this.conditions);
|
|
16
|
+
return is(target, Where) || is(target, WhereText)
|
|
17
|
+
? target.accept(this.conditions)
|
|
18
|
+
: target.accept(this.statements);
|
|
26
19
|
}
|
|
27
20
|
}
|
package/dist/statements/Where.js
CHANGED
|
@@ -5,6 +5,7 @@ import { Operator } from "./Operator.js";
|
|
|
5
5
|
import { eq } from "./Cmp.js";
|
|
6
6
|
import { SelectStatement } from "./SelectStatement.js";
|
|
7
7
|
import { Subquery } from "./Subquery.js";
|
|
8
|
+
import { brand } from "./brand.js";
|
|
8
9
|
const pair = (expression) => expression instanceof Operator.Equals ||
|
|
9
10
|
expression instanceof Operator.NotEquals ||
|
|
10
11
|
expression instanceof Operator.GreaterThan ||
|
|
@@ -181,3 +182,4 @@ export class Where {
|
|
|
181
182
|
return collect(this.condition);
|
|
182
183
|
}
|
|
183
184
|
}
|
|
185
|
+
brand(Where);
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
const key = (name) => Symbol.for(`@deterministic-code/datasources/${name}`);
|
|
2
|
+
export const brand = (type) => {
|
|
3
|
+
Object.defineProperty(type.prototype, key(type.name), { value: true });
|
|
4
|
+
};
|
|
5
|
+
export const is = (value, type) => value instanceof type || Boolean(value[key(type.name)]);
|