@stamhoofd/sql 2.108.0 → 2.109.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/index.d.ts +1 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +1 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/src/SQL.d.ts +6 -3
  6. package/dist/src/SQL.d.ts.map +1 -1
  7. package/dist/src/SQL.js +10 -1
  8. package/dist/src/SQL.js.map +1 -1
  9. package/dist/src/SQLExpressions.d.ts +11 -0
  10. package/dist/src/SQLExpressions.d.ts.map +1 -1
  11. package/dist/src/SQLExpressions.js +33 -1
  12. package/dist/src/SQLExpressions.js.map +1 -1
  13. package/dist/src/SQLJoin.d.ts.map +1 -1
  14. package/dist/src/SQLJoin.js +16 -0
  15. package/dist/src/SQLJoin.js.map +1 -1
  16. package/dist/src/SQLJsonExpressions.d.ts +5 -0
  17. package/dist/src/SQLJsonExpressions.d.ts.map +1 -1
  18. package/dist/src/SQLJsonExpressions.js +15 -1
  19. package/dist/src/SQLJsonExpressions.js.map +1 -1
  20. package/dist/src/SQLSelect.d.ts +11 -0
  21. package/dist/src/SQLSelect.d.ts.map +1 -1
  22. package/dist/src/SQLSelect.js +17 -2
  23. package/dist/src/SQLSelect.js.map +1 -1
  24. package/dist/src/SQLTranslatedStringHelper.d.ts +10 -0
  25. package/dist/src/SQLTranslatedStringHelper.d.ts.map +1 -0
  26. package/dist/src/SQLTranslatedStringHelper.js +37 -0
  27. package/dist/src/SQLTranslatedStringHelper.js.map +1 -0
  28. package/dist/src/filters/SQLSorter.d.ts +4 -4
  29. package/dist/src/filters/SQLSorter.d.ts.map +1 -1
  30. package/dist/tests/filters/$contains.test.js +4 -4
  31. package/dist/tests/filters/$contains.test.js.map +1 -1
  32. package/dist/tests/filters/$eq.test.js +6 -6
  33. package/dist/tests/filters/$eq.test.js.map +1 -1
  34. package/dist/tests/filters/$gt.test.js +4 -4
  35. package/dist/tests/filters/$gt.test.js.map +1 -1
  36. package/dist/tests/filters/$gte.test.js +3 -3
  37. package/dist/tests/filters/$gte.test.js.map +1 -1
  38. package/dist/tests/filters/$in.test.js +2 -2
  39. package/dist/tests/filters/$in.test.js.map +1 -1
  40. package/dist/tests/filters/$lt.test.js +3 -3
  41. package/dist/tests/filters/$lt.test.js.map +1 -1
  42. package/dist/tests/filters/$lte.test.js +3 -3
  43. package/dist/tests/filters/$lte.test.js.map +1 -1
  44. package/dist/tests/filters/SQLTranslatedStringHelper.test.d.ts +2 -0
  45. package/dist/tests/filters/SQLTranslatedStringHelper.test.d.ts.map +1 -0
  46. package/dist/tests/filters/SQLTranslatedStringHelper.test.js +491 -0
  47. package/dist/tests/filters/SQLTranslatedStringHelper.test.js.map +1 -0
  48. package/dist/tests/filters/dot-syntax.test.js +4 -4
  49. package/dist/tests/filters/dot-syntax.test.js.map +1 -1
  50. package/dist/tests/filters/wildcard.test.js +2 -2
  51. package/dist/tests/filters/wildcard.test.js.map +1 -1
  52. package/dist/tsconfig.tsbuildinfo +1 -1
  53. package/package.json +2 -2
  54. package/src/SQL.ts +16 -4
  55. package/src/SQLExpressions.ts +31 -0
  56. package/src/SQLJoin.ts +17 -0
  57. package/src/SQLJsonExpressions.ts +16 -0
  58. package/src/SQLSelect.ts +23 -2
  59. package/src/SQLTranslatedStringHelper.ts +40 -0
  60. package/src/filters/SQLSorter.ts +4 -4
@@ -421,6 +421,21 @@ export class SQLColumnExpression implements SQLExpression {
421
421
  }
422
422
  }
423
423
 
424
+ export class SQLIfNull implements SQLExpression {
425
+ constructor(private readonly columnExpression: SQLColumnExpression, private readonly value: string | number) {
426
+ }
427
+
428
+ getSQL(options?: SQLExpressionOptions): SQLQuery {
429
+ return joinSQLQuery([
430
+ 'IFNULL(',
431
+ this.columnExpression.getSQL(options),
432
+ ',',
433
+ new SQLSafeValue(this.value).getSQL(),
434
+ ')',
435
+ ]);
436
+ }
437
+ }
438
+
424
439
  export class SQLTableExpression implements SQLNamedExpression {
425
440
  /**
426
441
  * By default the table name will be used as the namespace by MySQL.
@@ -539,3 +554,19 @@ export class SQLIf implements SQLExpression {
539
554
  ]);
540
555
  }
541
556
  }
557
+
558
+ export class SQLCoalesce implements SQLExpression {
559
+ expressions: SQLExpression[] = [];
560
+
561
+ constructor(...expressions: SQLExpression[]) {
562
+ this.expressions = expressions;
563
+ }
564
+
565
+ getSQL(options?: SQLExpressionOptions): SQLQuery {
566
+ return joinSQLQuery([
567
+ 'COALESCE(',
568
+ joinSQLQuery(this.expressions.map(e => e.getSQL(options)), ', '),
569
+ ')',
570
+ ]);
571
+ }
572
+ }
package/src/SQLJoin.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { SQLExpression, SQLExpressionOptions, SQLNamedExpression, SQLQuery, joinSQLQuery } from './SQLExpression';
2
+ import { SQLSelect } from './SQLSelect';
2
3
  import { Whereable } from './SQLWhere';
3
4
 
4
5
  export enum SQLJoinType {
@@ -29,6 +30,22 @@ export class SQLJoin extends Whereable(EmptyClass) implements SQLExpression {
29
30
  }
30
31
 
31
32
  getSQL(options?: SQLExpressionOptions): SQLQuery {
33
+ // add parenthesis if the table is a select
34
+ if (this.table instanceof SQLSelect) {
35
+ return joinSQLQuery([
36
+ this.getJoinPrefix(),
37
+ '(',
38
+ this.table?.getSQL(options),
39
+ `) as ${this.table.getName()}`,
40
+ this._where ? 'ON' : undefined,
41
+ this._where?.getSQL({
42
+ ...options,
43
+ parentNamespace: options?.defaultNamespace,
44
+ defaultNamespace: this.table.getName(),
45
+ }),
46
+ ], ' ');
47
+ }
48
+
32
49
  return joinSQLQuery([
33
50
  this.getJoinPrefix(),
34
51
  this.table?.getSQL(options),
@@ -99,6 +99,22 @@ export class SQLJsonExtract implements SQLExpression {
99
99
  }
100
100
  }
101
101
 
102
+ export class SQLJsonType implements SQLExpression {
103
+ target: SQLExpression;
104
+
105
+ constructor(target: SQLExpression) {
106
+ this.target = target;
107
+ }
108
+
109
+ getSQL(options?: SQLExpressionOptions): SQLQuery {
110
+ return joinSQLQuery([
111
+ 'JSON_TYPE(',
112
+ this.target.getSQL(options),
113
+ ')',
114
+ ]);
115
+ }
116
+ }
117
+
102
118
  /**
103
119
  * Same as target->path, JSON_EXTRACT(target, path)
104
120
  */
package/src/SQLSelect.ts CHANGED
@@ -29,6 +29,8 @@ export type IterableSQLSelectOptions = {
29
29
  maxQueries?: number;
30
30
  };
31
31
 
32
+ export type SQLNamedSelect<T extends object = SQLResultNamespacedRow> = SQLSelect<T> & { getName(): string };
33
+
32
34
  export class SQLSelect<T extends object = SQLResultNamespacedRow> extends Whereable(Orderable(EmptyClass)) implements SQLExpression {
33
35
  _columns: SQLExpression[];
34
36
  _from: SQLNamedExpression;
@@ -38,6 +40,7 @@ export class SQLSelect<T extends object = SQLResultNamespacedRow> extends Wherea
38
40
  _groupBy: SQLExpression[] = [];
39
41
  _joins: (InstanceType<typeof SQLJoin>)[] = [];
40
42
  _max_execution_time: number | null = null;
43
+ private _name: string | null = null;
41
44
 
42
45
  _transformer: ((row: SQLResultNamespacedRow) => T) | null = null;
43
46
 
@@ -74,7 +77,11 @@ export class SQLSelect<T extends object = SQLResultNamespacedRow> extends Wherea
74
77
  }
75
78
 
76
79
  join(join: InstanceType<typeof SQLJoin>): this {
77
- this._joins.push(join);
80
+ // prevent duplicate joins (reference of join should be the same)
81
+ if (!this._joins.includes(join)) {
82
+ this._joins.push(join);
83
+ }
84
+
78
85
  return this;
79
86
  }
80
87
 
@@ -248,7 +255,6 @@ export class SQLSelect<T extends object = SQLResultNamespacedRow> extends Wherea
248
255
  this._orderBy = null;
249
256
 
250
257
  const { query, params } = normalizeSQLQuery(this.getSQL());
251
- // console.log(query, params);
252
258
 
253
259
  const [rows] = await Database.select(query, params, { nestTables: true });
254
260
  if (rows.length === 1) {
@@ -489,4 +495,19 @@ export class SQLSelect<T extends object = SQLResultNamespacedRow> extends Wherea
489
495
  },
490
496
  } as IterableSQLSelect<T[]> as any;
491
497
  }
498
+
499
+ getName(): string | null {
500
+ return this._name;
501
+ }
502
+
503
+ /**
504
+ * By calling this method we make sure a name is set so we can return an SQLNamedSelect.
505
+ * @param name name of the select
506
+ * @returns an SQLNamedSelect
507
+ */
508
+ as(name: string): SQLNamedSelect {
509
+ this._name = name;
510
+
511
+ return this as SQLNamedSelect;
512
+ }
492
513
  }
@@ -0,0 +1,40 @@
1
+ import { SQL, SQLColumnExpression, SQLExpression, SQLExpressionOptions, SQLQuery } from '@stamhoofd/sql';
2
+ import { Language } from '@stamhoofd/structures';
3
+
4
+ export class SQLTranslatedStringHelper implements SQLExpression {
5
+ constructor(private columnExpression: SQLColumnExpression, private path: string, private getLanguage: () => Language) {
6
+ }
7
+
8
+ getSQL(options?: SQLExpressionOptions): SQLQuery {
9
+ const currentLanguage = this.getLanguage();
10
+
11
+ const languageOrder: Language[] = [
12
+ Language.English,
13
+ Language.Dutch,
14
+ Language.French,
15
+ ];
16
+
17
+ const languages = moveToFront(languageOrder, currentLanguage);
18
+
19
+ const languageValues: SQLExpression[] = languages.map((language) => {
20
+ return SQL.jsonValue(this.columnExpression, `${this.path}.${language}`, 'CHAR');
21
+ });
22
+
23
+ const type: SQLExpression = SQL.jsonType(SQL.jsonExtract(this.columnExpression, this.path));
24
+
25
+ return SQL.if(
26
+ type, '=', 'STRING',
27
+ ).then(
28
+ SQL.jsonValue(this.columnExpression, this.path, 'CHAR'),
29
+ ).else(
30
+ SQL.coalesce(...languageValues) as SQLExpression,
31
+ ).getSQL(options);
32
+ }
33
+ }
34
+
35
+ function moveToFront<T>(arr: T[], value: T): T[] {
36
+ const index = arr.indexOf(value);
37
+ if (index === -1 || index === 0) return arr;
38
+
39
+ return [arr[index], ...arr.slice(0, index), ...arr.slice(index + 1)];
40
+ }
@@ -2,10 +2,10 @@ import { PlainObject } from '@simonbackx/simple-encoding';
2
2
  import { SortDefinition, SortList } from '@stamhoofd/structures';
3
3
 
4
4
  import { SimpleError } from '@simonbackx/simple-errors';
5
- import { SQLExpression } from '../SQLExpression';
6
- import { SQLJoin } from '../SQLJoin';
7
- import { SQLOrderBy, SQLOrderByDirection } from '../SQLOrderBy';
8
- import { SQLSelect } from '../SQLSelect';
5
+ import { SQLExpression } from '../SQLExpression.js';
6
+ import { SQLJoin } from '../SQLJoin.js';
7
+ import { SQLOrderBy, SQLOrderByDirection } from '../SQLOrderBy.js';
8
+ import { SQLSelect } from '../SQLSelect.js';
9
9
 
10
10
  export type SQLSortDefinition<T, B extends PlainObject | Date = PlainObject | Date> = SortDefinition<T, B> & {
11
11
  toSQL(direction: SQLOrderByDirection): SQLOrderBy;