forj 0.0.1 → 0.0.3

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.
@@ -0,0 +1,32 @@
1
+ export type Operator = '=' | '<>' | '<' | '<=' | '>' | '>=' | 'begins_with' | 'between' | 'in' | 'attribute_exists' | 'attribute_not_exists' | 'attribute_type' | 'contains' | 'size'
2
+
3
+ export type Condition = {
4
+ type: 'filter' | 'keyCondition',
5
+ field: string,
6
+ operator: Operator,
7
+ value: any
8
+ }
9
+
10
+ export type ISchemaStructure = string | Record<string, ISchemaStructure[]>
11
+ export type SchemaStructure = ISchemaStructure[]
12
+
13
+ export type KeySchema = Record<'PK' | 'SK', string>
14
+ export type ModelMetadata = {
15
+ table: string,
16
+ keys?: KeySchema,
17
+ defaultSK?: string,
18
+ zip: boolean,
19
+ fields: SchemaStructure,
20
+ }
21
+
22
+ export type ModelOpts = string | {
23
+ table?: string,
24
+ partitionKey?: string,
25
+ sortKey?: string,
26
+ defaultSK?: string,
27
+ zip?: boolean,
28
+ }
29
+
30
+ export type Keys = string | [string] | [string, string]
31
+ export type Model<T extends object> = new (...args: any[]) => T
32
+ export type Filter<T> = (item: T) => boolean
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export { default as QueryBuilder } from './query-builder'
package/src/model.ts ADDED
@@ -0,0 +1,258 @@
1
+ import pluralize from 'pluralize'
2
+ import QueryBuilder from './query-builder'
3
+ import type {
4
+ Operator, OrderDirection,
5
+ WhereFn, WhereArgs,
6
+ DBSchema, Pipe,
7
+ } from './types'
8
+
9
+ export default abstract class Model<TB extends keyof DB, DB> {
10
+ // Property only for the compiler (does not exist at runtime)
11
+ readonly $DBShape!: DB
12
+ readonly $TShape!: DB[TB]
13
+
14
+ static $table: string = ''
15
+ static $schema?: DBSchema
16
+
17
+ static pipe<S, T>(): Pipe<S, T> {
18
+ throw new Error(`Database connection not provided.`) // improv this message
19
+ }
20
+
21
+ static builder<S, T>() {
22
+ const table = this.$table || pluralize(this.name.toLowerCase())
23
+
24
+ return new QueryBuilder<S, T>(table, this.$schema, this.pipe<S, T>())
25
+ }
26
+
27
+ static select< // @ts-ignore
28
+ M extends typeof Model<TB, DB>,
29
+ I extends InstanceType<M>,
30
+ T extends I['$TShape'],
31
+ C extends keyof T
32
+ >(this: M, ...columns: C[] | C[][]) {
33
+ return this.builder<I['$DBShape'], T>().select(...columns)
34
+ }
35
+
36
+ static distinct< // @ts-ignore
37
+ M extends typeof Model<TB, DB>,
38
+ I extends InstanceType<M>,
39
+ T extends I['$TShape']
40
+ >(this: M) {
41
+ return this.builder<I['$DBShape'], T>().distinct()
42
+ }
43
+
44
+ static where< // @ts-ignore
45
+ M extends typeof Model<TB, DB>,
46
+ I extends InstanceType<M>,
47
+ T extends I['$TShape'],
48
+ C extends keyof T
49
+ >(this: M, fn: WhereFn<T>): QueryBuilder<I['$DBShape'], T, C>
50
+ static where< // @ts-ignore
51
+ M extends typeof Model<TB, DB>,
52
+ I extends InstanceType<M>,
53
+ T extends I['$TShape'],
54
+ C extends keyof T
55
+ >(this: M, column: C, value: T[C]): QueryBuilder<I['$DBShape'], T, C>
56
+ static where< // @ts-ignore
57
+ M extends typeof Model<TB, DB>,
58
+ I extends InstanceType<M>,
59
+ T extends I['$TShape'],
60
+ C extends keyof T
61
+ >(this: M, column: C, operator: Operator, value: T[C]): QueryBuilder<I['$DBShape'], T, C>
62
+ static where< // @ts-ignore
63
+ M extends typeof Model<TB, DB>,
64
+ I extends InstanceType<M>,
65
+ T extends I['$TShape']
66
+ >(this: M, ...args: WhereArgs<T>) {
67
+ return this.builder<I['$DBShape'], T>().where(...args)
68
+ }
69
+
70
+ static on< // @ts-ignore
71
+ M extends typeof Model<TB, DB>,
72
+ I extends InstanceType<M>,
73
+ T extends I['$TShape'],
74
+ C extends keyof T
75
+ >(this: M, fn: WhereFn<T>): QueryBuilder<I['$DBShape'], T, C>
76
+ static on< // @ts-ignore
77
+ M extends typeof Model<TB, DB>,
78
+ I extends InstanceType<M>,
79
+ T extends I['$TShape'],
80
+ C extends keyof T
81
+ >(this: M, column: C, value: T[C]): QueryBuilder<I['$DBShape'], T, C>
82
+ static on< // @ts-ignore
83
+ M extends typeof Model<TB, DB>,
84
+ I extends InstanceType<M>,
85
+ T extends I['$TShape'],
86
+ C extends keyof T
87
+ >(this: M, column: C, operator: Operator, value: T[C]): QueryBuilder<I['$DBShape'], T, C>
88
+ static on< // @ts-ignore
89
+ M extends typeof Model<TB, DB>,
90
+ I extends InstanceType<M>,
91
+ T extends I['$TShape']
92
+ >(this: M, ...args: WhereArgs<T>) {
93
+ return this.builder<I['$DBShape'], T>().where(...args)
94
+ }
95
+
96
+ static whereIn< // @ts-ignore
97
+ M extends typeof Model<TB, DB>,
98
+ I extends InstanceType<M>,
99
+ T extends I['$TShape'],
100
+ C extends keyof T
101
+ >(this: M, column: C, value: T[C][]) {
102
+ return this.builder<I['$DBShape'], T>().whereIn(column, value)
103
+ }
104
+
105
+ static in< // @ts-ignore
106
+ M extends typeof Model<TB, DB>,
107
+ I extends InstanceType<M>,
108
+ T extends I['$TShape'],
109
+ C extends keyof T
110
+ >(this: M, column: C, value: T[C][]) {
111
+ return this.builder<I['$DBShape'], T>().whereIn(column, value)
112
+ }
113
+
114
+ static whereNotIn< // @ts-ignore
115
+ M extends typeof Model<TB, DB>,
116
+ I extends InstanceType<M>,
117
+ T extends I['$TShape'],
118
+ C extends keyof T
119
+ >(this: M, column: C, value: T[C][]) {
120
+ return this.builder<I['$DBShape'], T>().whereNotIn(column, value)
121
+ }
122
+
123
+ static notIn< // @ts-ignore
124
+ M extends typeof Model<TB, DB>,
125
+ I extends InstanceType<M>,
126
+ T extends I['$TShape'],
127
+ C extends keyof T
128
+ >(this: M, column: C, value: T[C][]) {
129
+ return this.builder<I['$DBShape'], T>().whereNotIn(column, value)
130
+ }
131
+
132
+ static whereBetween< // @ts-ignore
133
+ M extends typeof Model<TB, DB>,
134
+ I extends InstanceType<M>,
135
+ T extends I['$TShape'],
136
+ C extends keyof T
137
+ >(this: M, column: C, one: T[C], two: T[C]) {
138
+ return this.builder<I['$DBShape'], T>().whereBetween(column, one, two)
139
+ }
140
+
141
+ static between< // @ts-ignore
142
+ M extends typeof Model<TB, DB>,
143
+ I extends InstanceType<M>,
144
+ T extends I['$TShape'],
145
+ C extends keyof T
146
+ >(this: M, column: C, one: T[C], two: T[C]) {
147
+ return this.builder<I['$DBShape'], T>().whereBetween(column, one, two)
148
+ }
149
+
150
+ static whereNotBetween< // @ts-ignore
151
+ M extends typeof Model<TB, DB>,
152
+ I extends InstanceType<M>,
153
+ T extends I['$TShape'],
154
+ C extends keyof T
155
+ >(this: M, column: C, one: T[C], two: T[C]) {
156
+ return this.builder<I['$DBShape'], T>().whereNotBetween(column, one, two)
157
+ }
158
+
159
+ static notBetween< // @ts-ignore
160
+ M extends typeof Model<TB, DB>,
161
+ I extends InstanceType<M>,
162
+ T extends I['$TShape'],
163
+ C extends keyof T
164
+ >(this: M, column: C, one: T[C], two: T[C]) {
165
+ return this.builder<I['$DBShape'], T>().whereNotBetween(column, one, two)
166
+ }
167
+
168
+ static whereNull< // @ts-ignore
169
+ M extends typeof Model<TB, DB>,
170
+ I extends InstanceType<M>,
171
+ T extends I['$TShape'],
172
+ C extends keyof T
173
+ >(this: M, column: C) {
174
+ return this.builder<I['$DBShape'], T>().whereNull(column)
175
+ }
176
+
177
+ static onNull< // @ts-ignore
178
+ M extends typeof Model<TB, DB>,
179
+ I extends InstanceType<M>,
180
+ T extends I['$TShape'],
181
+ C extends keyof T
182
+ >(this: M, column: C) {
183
+ return this.builder<I['$DBShape'], T>().whereNull(column)
184
+ }
185
+
186
+ static whereNotNull< // @ts-ignore
187
+ M extends typeof Model<TB, DB>,
188
+ I extends InstanceType<M>,
189
+ T extends I['$TShape'],
190
+ C extends keyof T
191
+ >(this: M, column: C) {
192
+ return this.builder<I['$DBShape'], T>().whereNotNull(column)
193
+ }
194
+
195
+ static onNotNull< // @ts-ignore
196
+ M extends typeof Model<TB, DB>,
197
+ I extends InstanceType<M>,
198
+ T extends I['$TShape'],
199
+ C extends keyof T
200
+ >(this: M, column: C) {
201
+ return this.builder<I['$DBShape'], T>().whereNotNull(column)
202
+ }
203
+
204
+ // TODO: groupBy(...columns: string[])
205
+
206
+ static order< // @ts-ignore
207
+ M extends typeof Model<TB, DB>,
208
+ I extends InstanceType<M>,
209
+ T extends I['$TShape'],
210
+ C extends keyof T
211
+ >(this: M, column: C, direction: OrderDirection = 'ASC') {
212
+ return this.builder<I['$DBShape'], T>().order(column, direction)
213
+ }
214
+
215
+ static orderBy< // @ts-ignore
216
+ M extends typeof Model<TB, DB>,
217
+ I extends InstanceType<M>,
218
+ T extends I['$TShape'],
219
+ C extends keyof T
220
+ >(this: M, column: C, direction: OrderDirection = 'ASC') {
221
+ return this.builder<I['$DBShape'], T>().order(column, direction)
222
+ }
223
+
224
+ static asc< // @ts-ignore
225
+ M extends typeof Model<TB, DB>,
226
+ I extends InstanceType<M>,
227
+ T extends I['$TShape'],
228
+ C extends keyof T
229
+ >(this: M, column: C) {
230
+ return this.builder<I['$DBShape'], T>().asc(column)
231
+ }
232
+
233
+ static desc< // @ts-ignore
234
+ M extends typeof Model<TB, DB>,
235
+ I extends InstanceType<M>,
236
+ T extends I['$TShape'],
237
+ C extends keyof T
238
+ >(this: M, column: C) {
239
+ return this.builder<I['$DBShape'], T>().desc(column)
240
+ }
241
+
242
+ static limit< // @ts-ignore
243
+ M extends typeof Model<TB, DB>,
244
+ I extends InstanceType<M>,
245
+ T extends I['$TShape']
246
+ >(this: M, val: number | string) {
247
+ return this.builder<I['$DBShape'], T>().limit(val)
248
+ }
249
+
250
+ static offset< // @ts-ignore
251
+ M extends typeof Model<TB, DB>,
252
+ I extends InstanceType<M>,
253
+ T extends I['$TShape']
254
+ >(this: M, val: number | string) {
255
+ return this.builder<I['$DBShape'], T>().offset(val)
256
+ }
257
+
258
+ }
@@ -0,0 +1,371 @@
1
+ import ClauseBuilder from './clause-builder'
2
+ import {
3
+ isOperator,
4
+ parseColumn, parseSelectColumn,
5
+ formatValue,
6
+ isJoinCompare,
7
+ zSame, zType,
8
+ } from './utils'
9
+ import type {
10
+ IJoinBuilder, IClauseBuilder,
11
+ OrderDirection,
12
+ JoinType,
13
+ WhereArgs,
14
+ Values,
15
+ Item,
16
+ JoinArgs,
17
+ DBSchema,
18
+ Pipe,
19
+ } from './types'
20
+
21
+ export default class QueryBuilder<
22
+ S,
23
+ T,
24
+ C extends keyof T = keyof T //,
25
+ // J extends keyof S = keyof S
26
+ // T, // = any,,
27
+ // C extends keyof T = keyof T
28
+ // > {
29
+ > implements IJoinBuilder<S>, IClauseBuilder<T> {
30
+ #table!: string
31
+ #schema?: DBSchema
32
+ #selects: string[] = []
33
+ #clauses!: ClauseBuilder<T>
34
+ #groups: string[] = []
35
+ #orders: string[] = []
36
+
37
+ #distinct = false
38
+ #hasJoin = false
39
+ #limit?: number
40
+ #offset?: number
41
+
42
+ #joins: string[] = []
43
+
44
+ #pipe?: Pipe<S, T, C>
45
+
46
+ constructor(
47
+ table: string,
48
+ schema?: DBSchema,
49
+ pipe?: Pipe<S, T, C>
50
+ ) {
51
+ this.#table = table
52
+ this.#schema = schema
53
+ this.#pipe = pipe
54
+ this.#clauses = new ClauseBuilder<T>(table, schema)
55
+ }
56
+
57
+ async run() {
58
+ if (!this.#pipe?.run)
59
+ throw new Error(`No database connection.`)
60
+
61
+ return await this.#pipe?.run(this)
62
+ }
63
+
64
+ async first<K extends keyof T>(...columns: K[] | K[][]): Promise<null | Item<T, C>> {
65
+ columns?.length && this.select(...columns)
66
+ const resp = await this.run()
67
+ return resp.results?.length ? resp.results[0] : null
68
+ }
69
+
70
+ async all<K extends keyof T>(...columns: K[] | K[][]): Promise<Item<T, C>[]> {
71
+ columns?.length && this.select(...columns)
72
+ const resp = await this.run()
73
+ return resp.results
74
+ }
75
+
76
+ select<K extends keyof T>(...columns: K[] | K[][]): QueryBuilder<S, T, K> {
77
+ this.#selects.push(...columns.flat(Infinity) as string[])
78
+ return this as any
79
+ }
80
+
81
+ distinct() {
82
+ this.#distinct = true
83
+ return this
84
+ }
85
+
86
+ #join<J extends keyof S>(
87
+ type: JoinType | undefined,
88
+ table: J,
89
+ ...args: JoinArgs<S, J>
90
+ ) {
91
+ this.#hasJoin = true
92
+ const query = (type ? type + ' ' : '') + `JOIN ${table as string} ON `
93
+
94
+ if (typeof args[0] == 'function') {
95
+ const join = new ClauseBuilder<S[J]>(table as string, this.#schema)
96
+ args[0](join)
97
+
98
+ this.#joins.push(query + join.clauses.join(' '))
99
+ this.#clauses.args = join.args
100
+ return this
101
+ }
102
+
103
+ const length = args.length
104
+ let [column, operator, value, value2] = args
105
+
106
+ if (length == 2) { // @ts-ignore
107
+ value = operator
108
+ operator = '='
109
+ } else if (length == 3 && !isOperator(operator)) { // @ts-ignore
110
+ // console.log(column, operator, value, value2) // @ts-ignore
111
+ value = parseColumn(value as string, operator as string) // TODO: check if value is a valid column
112
+
113
+ if (this.#schema && !isJoinCompare(value, this.#schema))
114
+ throw new Error(`Table column '${value}' doesn't exists.`)
115
+
116
+ operator = '='
117
+ } else if (length == 4) { // @ts-ignore
118
+ // console.log(column, operator, value, value2) // @ts-ignore
119
+ value = parseColumn(value2 as string, value as string)
120
+ operator = '='
121
+ }
122
+
123
+ const col = parseColumn(String(column), String(table))
124
+ if (this.#schema && !zSame(col, value, this.#schema))
125
+ throw new Error(`Table column '${col}' of type '${zType(col, this.#schema)}' is not assignable as type of '${typeof value}'.`)
126
+
127
+ if (!isJoinCompare(value, this.#schema)) { // @ts-ignore
128
+ this.#clauses.args = [value] // @ts-ignore // TODO: https://developers.cloudflare.com/d1/worker-api/#type-conversion
129
+ value = '?'
130
+ }
131
+
132
+ // @ts-ignore
133
+ this.#joins.push(query + col + ` ${operator} ${value}`)
134
+ return this
135
+ }
136
+
137
+ join<J extends keyof S>(table: J, ...args: JoinArgs<S, J>) {
138
+ return this.#join(undefined, table, ...args)
139
+ }
140
+
141
+ innerJoin<J extends keyof S>(table: J, ...args: JoinArgs<S, J>) {
142
+ return this.#join('INNER', table, ...args)
143
+ }
144
+
145
+ leftJoin<J extends keyof S>(table: J, ...args: JoinArgs<S, J>) {
146
+ return this.#join('LEFT', table, ...args)
147
+ }
148
+
149
+ rightJoin<J extends keyof S>(table: J, ...args: JoinArgs<S, J>) {
150
+ return this.#join('RIGHT', table, ...args)
151
+ }
152
+
153
+ crossJoin<J extends keyof S>(table: J, ...args: JoinArgs<S, J>) {
154
+ return this.#join('CROSS', table, ...args)
155
+ }
156
+
157
+ where(...args: WhereArgs<T>) {
158
+ this.#clauses.where(...args)
159
+ return this
160
+ }
161
+ on(...args: WhereArgs<T>) {
162
+ return this.where(...args)
163
+ }
164
+
165
+ orWhere(...args: WhereArgs<T>) {
166
+ this.#clauses.orWhere(...args)
167
+ return this
168
+ }
169
+ orOn(...args: WhereArgs<T>) {
170
+ return this.orWhere(...args)
171
+ }
172
+
173
+ whereIn(column: C, values: T[C][]) {
174
+ this.#clauses.whereIn(column, values)
175
+ return this
176
+ }
177
+ in(column: C, values: T[C][]) {
178
+ return this.whereIn(column, values)
179
+ }
180
+
181
+ whereNotIn(column: C, values: T[C][]) {
182
+ this.#clauses.whereNotIn(column, values)
183
+ return this
184
+ }
185
+ notIn(column: C, values: T[C][]) {
186
+ return this.whereNotIn(column, values)
187
+ }
188
+
189
+ orWhereIn(column: C, values: T[C][]) {
190
+ this.#clauses.orWhereIn(column, values)
191
+ return this
192
+ }
193
+ orIn(column: C, values: T[C][]) {
194
+ return this.orWhereIn(column, values)
195
+ }
196
+
197
+ orWhereNotIn(column: C, values: T[C][]) {
198
+ this.#clauses.orWhereNotIn(column, values)
199
+ return this
200
+ }
201
+ orNotIn(column: C, values: T[C][]) {
202
+ return this.orWhereNotIn(column, values)
203
+ }
204
+
205
+ whereBetween(column: C, one: T[C], two: T[C]) {
206
+ this.#clauses.whereBetween(column, one, two)
207
+ return this
208
+ }
209
+ between(column: C, one: T[C], two: T[C]) {
210
+ return this.whereBetween(column, one, two)
211
+ }
212
+
213
+ orWhereBetween(column: C, one: T[C], two: T[C]) {
214
+ this.#clauses.orWhereBetween(column, one, two)
215
+ return this
216
+ }
217
+ orBetween(column: C, one: T[C], two: T[C]) {
218
+ return this.orWhereBetween(column, one, two)
219
+ }
220
+
221
+ whereNotBetween(column: C, one: T[C], two: T[C]) {
222
+ this.#clauses.whereNotBetween(column, one, two)
223
+ return this
224
+ }
225
+ notBetween(column: C, one: T[C], two: T[C]) {
226
+ return this.whereNotBetween(column, one, two)
227
+ }
228
+
229
+ orWhereNotBetween(column: C, one: T[C], two: T[C]) {
230
+ this.#clauses.orWhereNotBetween(column, one, two)
231
+ return this
232
+ }
233
+ orNotBetween(column: C, one: T[C], two: T[C]) {
234
+ return this.orWhereNotBetween(column, one, two)
235
+ }
236
+
237
+ whereNull(column: C) {
238
+ this.#clauses.whereNull(column)
239
+ return this
240
+ }
241
+ onNull(column: C) {
242
+ return this.whereNull(column)
243
+ }
244
+
245
+ orWhereNull(column: C) {
246
+ this.#clauses.orWhereNull(column)
247
+ return this
248
+ }
249
+ orOnNull(column: C) {
250
+ return this.orWhereNull(column)
251
+ }
252
+
253
+ whereNotNull(column: C) {
254
+ this.#clauses.whereNotNull(column)
255
+ return this
256
+ }
257
+ onNotNull(column: C) {
258
+ return this.whereNotNull(column)
259
+ }
260
+
261
+ orWhereNotNull(column: C) {
262
+ this.#clauses.orWhereNotNull(column)
263
+ return this
264
+ }
265
+ orNotNull(column: C) {
266
+ return this.orWhereNotNull(column)
267
+ }
268
+
269
+ groupBy(...columns: string[]) {
270
+ this.#groups.push(...columns)
271
+ return this
272
+ }
273
+
274
+ order(column: C, direction: OrderDirection = 'ASC') {
275
+ this.#orders.push(parseColumn(column as string, this.#table, this.#hasJoin) +' '+ direction.toUpperCase())
276
+ return this
277
+ }
278
+ orderBy(column: C, direction: OrderDirection = 'ASC') {
279
+ return this.order(column, direction)
280
+ }
281
+ asc(column: C) {
282
+ return this.order(column, 'ASC')
283
+ }
284
+ desc(column: C) {
285
+ return this.order(column, 'DESC')
286
+ }
287
+
288
+ limit(val: number | string) {
289
+ val = parseInt(String(val)) || 0
290
+ if (val) this.#limit = val
291
+ return this
292
+ }
293
+
294
+ offset(val: number | string) {
295
+ this.#offset = parseInt(String(val)) || 0
296
+ return this
297
+ }
298
+
299
+ #bind(sql: string, values: Values) {
300
+ let i = 0
301
+ let out = ''
302
+ let last = 0
303
+
304
+ for (let pos = sql.indexOf('?'); pos !== -1; pos = sql.indexOf('?', pos + 1)) {
305
+ if (i >= values.length)
306
+ throw new Error(`Missing bind value at position ${i}`)
307
+
308
+ out += sql.slice(last, pos)
309
+ out += formatValue(values[i++])
310
+ last = pos + 1
311
+ }
312
+
313
+ if (i < values.length)
314
+ throw new Error(`Too many bind values: expected ${i}, got ${values.length}`)
315
+
316
+ return out + sql.slice(last)
317
+ }
318
+
319
+ get args() {
320
+ return this.#clauses.args
321
+ }
322
+ get arguments() {
323
+ return this.args
324
+ }
325
+ get bindings() {
326
+ return this.args
327
+ }
328
+
329
+ get query() {
330
+ let sql = ''
331
+
332
+ const selects = new Set<string>()
333
+ this.#selects.forEach(column => {
334
+ column = parseSelectColumn(column, this.#table, this.#hasJoin)
335
+ !selects.has(column) && selects.add(column)
336
+ })
337
+
338
+ sql += `SELECT ${this.#distinct ? 'DISTINCT ' : ''}${
339
+ selects.size ? [...selects].join(', ') : '*'
340
+ }`
341
+
342
+ sql += ' FROM '+ this.#table
343
+
344
+ if (this.#joins.length)
345
+ sql += ' '+ this.#joins.join(' ')
346
+
347
+ if (this.#clauses.length)
348
+ sql += ' WHERE '+ this.#clauses.clauses.join(' ')
349
+
350
+ if (this.#groups.length)
351
+ sql += ' GROUP BY '+ this.#groups.join(', ')
352
+
353
+ if (this.#orders.length)
354
+ sql += ' ORDER BY '+ this.#orders.join(', ')
355
+
356
+ if (this.#limit != undefined)
357
+ sql += ' LIMIT '+ this.#limit
358
+
359
+ if (this.#offset != undefined)
360
+ sql += ' OFFSET '+ this.#offset
361
+
362
+ return sql
363
+ }
364
+
365
+ get sql() {
366
+ return this.#bind(this.query, this.#clauses.args)
367
+ }
368
+ get raw() {
369
+ return this.sql
370
+ }
371
+ }