-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathBaseSQLQueryBuilder.ts
More file actions
100 lines (90 loc) · 2.63 KB
/
Copy pathBaseSQLQueryBuilder.ts
File metadata and controls
100 lines (90 loc) · 2.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import {
OrderByOrdering,
QuerySelectionModifiersWithOrderByFragment,
} from './BasePostgresEntityDatabaseAdapter';
import { SQLFragment } from './SQLOperator';
/**
* Base SQL query builder that provides common functionality for building SQL queries.
*/
export abstract class BaseSQLQueryBuilder<TFields extends Record<string, any>, TResultType> {
private executed = false;
constructor(
private readonly sqlFragment: SQLFragment,
private readonly modifiers: {
limit?: number;
offset?: number;
orderBy?: { fieldName: keyof TFields; order: OrderByOrdering }[];
orderByFragment?: SQLFragment;
},
) {}
/**
* Limit the number of results
*/
limit(n: number): this {
this.modifiers.limit = n;
return this;
}
/**
* Skip a number of results
*/
offset(n: number): this {
this.modifiers.offset = n;
return this;
}
/**
* Order by a field. Can be called multiple times to add multiple order bys.
*/
orderBy(fieldName: keyof TFields, order: OrderByOrdering = OrderByOrdering.ASCENDING): this {
this.modifiers.orderBy = [...(this.modifiers.orderBy ?? []), { fieldName, order }];
return this;
}
/**
* Order by a SQL fragment expression.
* Provides type-safe, parameterized ORDER BY clauses
*
* @example
* ```ts
* import { sql, raw } from '@expo/entity-database-adapter-knex';
*
* // Safe parameterized ordering
* .orderBySQL(sql`CASE WHEN priority = ${1} THEN 0 ELSE 1 END, created_at DESC`)
*
* // Dynamic column ordering
* const sortColumn = 'name';
* .orderBySQL(sql`${raw(sortColumn)} DESC NULLS LAST`)
*
* // Complex expressions
* .orderBySQL(sql`array_length(tags, 1) DESC, score * ${multiplier} ASC`)
* ```
*/
orderBySQL(fragment: SQLFragment): this {
this.modifiers.orderByFragment = fragment;
return this;
}
/**
* Get the current modifiers as QuerySelectionModifiersWithOrderByFragment<TFields>
*/
protected getModifiers(): QuerySelectionModifiersWithOrderByFragment<TFields> {
return this.modifiers;
}
/**
* Get the SQL fragment
*/
protected getSQLFragment(): SQLFragment {
return this.sqlFragment;
}
/**
* Execute the query and return results.
* Implementation depends on the specific loader type.
*/
public async executeAsync(): Promise<readonly TResultType[]> {
if (this.executed) {
throw new Error(
'Query has already been executed. Create a new query builder to execute again.',
);
}
this.executed = true;
return await this.executeInternalAsync();
}
protected abstract executeInternalAsync(): Promise<readonly TResultType[]>;
}