@deterministic-code/datasources 0.1.15 → 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.
@@ -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 rows = options?.rowConverter ?? RowTypeConverter.from(this.driver.rowTypeConverters, columnsOf(type));
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 rows = options?.rowConverter ?? RowTypeConverter.from(this.driver.rowTypeConverters, columnsOf(type));
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
  };
@@ -0,0 +1,4 @@
1
+ export declare class Schema {
2
+ readonly columns: Readonly<Record<string, string>>;
3
+ constructor(columns: Readonly<Record<string, string>>);
4
+ }
package/dist/Schema.js ADDED
@@ -0,0 +1,6 @@
1
+ export class Schema {
2
+ columns;
3
+ constructor(columns) {
4
+ this.columns = columns;
5
+ }
6
+ }
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,5 @@
1
+ import type { IMapper } from "./IMapper.js";
2
+ export declare class DeterministicTypeMapper implements IMapper<string, string> {
3
+ map: (value: string) => string;
4
+ reverseMap: (value: string) => string;
5
+ }
@@ -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,6 +1,8 @@
1
+ import { brand } from "./brand.js";
1
2
  export class ArrayExpression {
2
3
  elements;
3
4
  constructor(elements) {
4
5
  this.elements = elements;
5
6
  }
6
7
  }
8
+ brand(ArrayExpression);
@@ -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,8 +8,12 @@ export class ConditionRenderer {
6
8
  }
7
9
  render = (condition) => condition.accept(this);
8
10
  visit(where) {
9
- return where instanceof Where || where.constructor.name === "Where"
11
+ return is(where, Where)
10
12
  ? this.expressions.render(where.condition)
11
- : where.rawText;
13
+ : is(where, WhereText)
14
+ ? where.rawText
15
+ : (() => {
16
+ throw new Error("empty expression");
17
+ })();
12
18
  }
13
19
  }
@@ -1,73 +1,65 @@
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";
5
6
  import { Subquery } from "./Subquery.js";
6
7
  import { Where } from "./Where.js";
7
- const is = (value, type, name) => value instanceof type || value.constructor.name === name;
8
8
  export class ExpressionRenderer {
9
9
  text;
10
10
  constructor(text) {
11
11
  this.text = text;
12
12
  }
13
13
  render = (expression) => {
14
- if (is(expression, Where, "Where"))
14
+ if (is(expression, Where))
15
15
  return this.render(expression.condition);
16
- if (is(expression, Identifier, "Identifier"))
16
+ if (is(expression, Identifier))
17
17
  return expression.name;
18
- if (is(expression, Literal, "Literal"))
18
+ if (is(expression, Literal))
19
19
  return inline(expression.value);
20
- if (is(expression, ArrayExpression, "ArrayExpression"))
20
+ if (is(expression, ArrayExpression))
21
21
  return expression.elements.map((e) => this.render(e)).join(", ");
22
- if (is(expression, Operator.Not, "Not"))
22
+ if (is(expression, Operator.Not))
23
23
  return `NOT (${this.render(expression.argument)})`;
24
- if (is(expression, Operator.IsNull, "IsNull"))
24
+ if (is(expression, Operator.IsNull))
25
25
  return `${this.render(expression.argument)} IS NULL`;
26
- if (is(expression, Operator.IsNotNull, "IsNotNull"))
26
+ if (is(expression, Operator.IsNotNull))
27
27
  return `${this.render(expression.argument)} IS NOT NULL`;
28
- if (is(expression, Operator.Exists, "Exists"))
28
+ if (is(expression, Operator.Exists))
29
29
  return `EXISTS ${this.render(expression.argument)}`;
30
- if (is(expression, Subquery, "Subquery"))
30
+ if (is(expression, Subquery))
31
31
  return `(${this.text.render(expression.query)})`;
32
- if (is(expression, Operator.In, "In") &&
33
- is(expression.left, Identifier, "Identifier") &&
34
- is(expression.right, ArrayExpression, "ArrayExpression"))
32
+ if (is(expression, Operator.In) && is(expression.left, Identifier) && is(expression.right, ArrayExpression))
35
33
  return expression.right.elements.length === 0
36
34
  ? "1 = 0"
37
35
  : `${expression.left.name} IN (${slots(expression.left.name, expression.right.elements.length)})`;
38
- if (is(expression, Operator.In, "In") &&
39
- is(expression.left, Identifier, "Identifier") &&
40
- is(expression.right, Subquery, "Subquery"))
36
+ if (is(expression, Operator.In) && is(expression.left, Identifier) && is(expression.right, Subquery))
41
37
  return `${expression.left.name} IN ${this.render(expression.right)}`;
42
- if (is(expression, Operator.NotIn, "NotIn") &&
43
- is(expression.left, Identifier, "Identifier") &&
44
- is(expression.right, ArrayExpression, "ArrayExpression"))
38
+ if (is(expression, Operator.NotIn) && is(expression.left, Identifier) && is(expression.right, ArrayExpression))
45
39
  return expression.right.elements.length === 0
46
40
  ? "1 = 1"
47
41
  : `${expression.left.name} NOT IN (${slots(expression.left.name, expression.right.elements.length)})`;
48
- if (is(expression, Operator.NotIn, "NotIn") &&
49
- is(expression.left, Identifier, "Identifier") &&
50
- is(expression.right, Subquery, "Subquery"))
42
+ if (is(expression, Operator.NotIn) && is(expression.left, Identifier) && is(expression.right, Subquery))
51
43
  return `${expression.left.name} NOT IN ${this.render(expression.right)}`;
52
- if ((is(expression, Operator.Between, "Between") || is(expression, Operator.NotBetween, "NotBetween")) &&
53
- is(expression.value, Identifier, "Identifier") &&
54
- is(expression.low, Literal, "Literal") &&
55
- is(expression.high, Literal, "Literal")) {
56
- const word = is(expression, Operator.NotBetween, "NotBetween") ? "NOT BETWEEN" : "BETWEEN";
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";
57
49
  return `${expression.value.name} ${word} $${parameterName(expression.value.name)}_0 AND $${parameterName(expression.value.name)}_1`;
58
50
  }
59
- if (is(expression, Operator.Between, "Between"))
51
+ if (is(expression, Operator.Between))
60
52
  return `${this.render(expression.value)} BETWEEN ${this.render(expression.low)} AND ${this.render(expression.high)}`;
61
- if (is(expression, Operator.NotBetween, "NotBetween"))
53
+ if (is(expression, Operator.NotBetween))
62
54
  return `${this.render(expression.value)} NOT BETWEEN ${this.render(expression.low)} AND ${this.render(expression.high)}`;
63
- if (is(expression, Operator.And, "And"))
55
+ if (is(expression, Operator.And))
64
56
  return `${this.wrap(expression.left, true)} AND ${this.wrap(expression.right, true)}`;
65
- if (is(expression, Operator.Or, "Or"))
57
+ if (is(expression, Operator.Or))
66
58
  return `${this.wrap(expression.left, false)} OR ${this.wrap(expression.right, false)}`;
67
59
  const operands = pair(expression);
68
- if (operands && is(operands.left, Identifier, "Identifier") && is(operands.right, Literal, "Literal"))
60
+ if (operands && is(operands.left, Identifier) && is(operands.right, Literal))
69
61
  return `${operands.left.name} ${symbol(expression)} $${parameterName(operands.left.name)}`;
70
- if (operands && is(operands.left, Literal, "Literal") && is(operands.right, Literal, "Literal"))
62
+ if (operands && is(operands.left, Literal) && is(operands.right, Literal))
71
63
  return `${inline(operands.left.value)} ${symbol(expression)} ${inline(operands.right.value)}`;
72
64
  if (operands)
73
65
  return `${this.render(operands.left)} ${symbol(expression)} ${this.render(operands.right)}`;
@@ -75,34 +67,27 @@ export class ExpressionRenderer {
75
67
  };
76
68
  wrap = (child, and) => needsParens(child, and) ? `(${this.render(child)})` : this.render(child);
77
69
  }
78
- const symbols = {
79
- Equals: "=",
80
- NotEquals: "<>",
81
- GreaterThan: ">",
82
- LessThan: "<",
83
- GreaterThanOrEqual: ">=",
84
- LessThanOrEqual: "<=",
85
- Like: "LIKE",
86
- NotLike: "NOT LIKE",
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");
87
90
  };
88
- const symbol = (op) => symbols[op.constructor.name] ??
89
- (is(op, Operator.Equals, "Equals")
90
- ? "="
91
- : is(op, Operator.NotEquals, "NotEquals")
92
- ? "<>"
93
- : is(op, Operator.GreaterThan, "GreaterThan")
94
- ? ">"
95
- : is(op, Operator.LessThan, "LessThan")
96
- ? "<"
97
- : is(op, Operator.GreaterThanOrEqual, "GreaterThanOrEqual")
98
- ? ">="
99
- : is(op, Operator.LessThanOrEqual, "LessThanOrEqual")
100
- ? "<="
101
- : is(op, Operator.Like, "Like")
102
- ? "LIKE"
103
- : is(op, Operator.NotLike, "NotLike")
104
- ? "NOT LIKE"
105
- : "IN");
106
91
  const inline = (value) => value === null
107
92
  ? "null"
108
93
  : typeof value === "boolean"
@@ -110,24 +95,25 @@ const inline = (value) => value === null
110
95
  : typeof value === "string"
111
96
  ? `'${value.replace(/'/g, "''")}'`
112
97
  : String(value);
113
- const needsParens = (child, and) => is(child, Where, "Where")
98
+ const needsParens = (child, and) => is(child, Where)
114
99
  ? needsParens(child.condition, and)
115
- : is(child, Operator.Not, "Not") ||
116
- is(child, Operator.In, "In") ||
117
- is(child, Operator.NotIn, "NotIn") ||
118
- (is(child, Operator.And, "And") && !and) ||
119
- (is(child, Operator.Or, "Or") && and);
120
- const pair = (expression) => is(expression, Operator.Equals, "Equals") ||
121
- is(expression, Operator.NotEquals, "NotEquals") ||
122
- is(expression, Operator.GreaterThan, "GreaterThan") ||
123
- is(expression, Operator.LessThan, "LessThan") ||
124
- is(expression, Operator.GreaterThanOrEqual, "GreaterThanOrEqual") ||
125
- is(expression, Operator.LessThanOrEqual, "LessThanOrEqual") ||
126
- is(expression, Operator.And, "And") ||
127
- is(expression, Operator.Or, "Or") ||
128
- is(expression, Operator.In, "In") ||
129
- is(expression, Operator.Like, "Like") ||
130
- is(expression, Operator.NotLike, "NotLike")
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)
131
117
  ? expression
132
118
  : undefined;
133
119
  const parameterName = (name) => parts(name)
@@ -1,6 +1,8 @@
1
+ import { brand } from "./brand.js";
1
2
  export class Identifier {
2
3
  name;
3
4
  constructor(name) {
4
5
  this.name = name;
5
6
  }
6
7
  }
8
+ brand(Identifier);
@@ -1,6 +1,8 @@
1
+ import { brand } from "./brand.js";
1
2
  export class Literal {
2
3
  value;
3
4
  constructor(value) {
4
5
  this.value = value;
5
6
  }
6
7
  }
8
+ brand(Literal);
@@ -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
- if (target.constructor.name === "Where" || target.constructor.name === "WhereText") {
16
- return target.accept(this.conditions);
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
  }
@@ -1,6 +1,8 @@
1
+ import { brand } from "./brand.js";
1
2
  export class Subquery {
2
3
  query;
3
4
  constructor(query) {
4
5
  this.query = query;
5
6
  }
6
7
  }
8
+ brand(Subquery);
@@ -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);
@@ -1,3 +1,4 @@
1
+ import { brand } from "./brand.js";
1
2
  export class WhereText {
2
3
  text;
3
4
  constructor(text) {
@@ -8,3 +9,4 @@ export class WhereText {
8
9
  }
9
10
  accept = (visitor) => visitor.visit(this);
10
11
  }
12
+ brand(WhereText);
@@ -0,0 +1,5 @@
1
+ export declare const brand: (type: {
2
+ name: string;
3
+ prototype: object;
4
+ }) => void;
5
+ export declare const is: <T extends object>(value: object, type: abstract new (...args: never[]) => T) => value is T;
@@ -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)]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deterministic-code/datasources",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.js",