-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstatement.ts
More file actions
167 lines (152 loc) · 5.98 KB
/
Copy pathstatement.ts
File metadata and controls
167 lines (152 loc) · 5.98 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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
/**
* statement.ts
*/
import { popCallback, prepareSql } from './utilities'
import { Database } from './database'
import { ErrorCallback, RowCallback, RowsCallback, RowCountCallback, ResultsCallback } from './types'
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
/** A statement generated by Database.prepare used to prepare SQL with ? bindings */
export class Statement<T> {
constructor(database: Database, sql: string, ...params: any[]) {
const { args, callback } = popCallback<ErrorCallback>(params)
this._database = database
this._sql = sql
if (args?.length > 0) {
this.bind(...args, callback)
} else {
callback?.call(this, null)
}
}
/** Statement belongs to this database */
private _database: Database
/** The SQL statement with ? binding placeholders */
private _sql: string
/** The SQL statement with binding values applied */
private _preparedSql?: string
/**
* Binds parameters to the prepared statement and calls the callback when done
* or when an error occurs. The function returns the Statement object to allow
* for function chaining. The first and only argument to the callback is null
* when binding was successful, otherwise it is the error object. Binding parameters
* with this function completely resets the statement object and row cursor and
* removes all previously bound parameters, if any. Currently bound parameters
* are escaped client side and turned into literals before being executed on the server.
*/
public bind(...params: any[]): this {
const { args, callback } = popCallback<ErrorCallback>(params)
try {
this._preparedSql = prepareSql(this._sql, ...args)
if (callback) {
callback.call(this, null)
}
} catch (error) {
this._preparedSql = undefined
if (callback) {
callback.call(this, error as Error)
}
}
return this
}
/**
* Binds parameters and executes the statement. The function returns the Statement object to
* allow for function chaining. If you specify bind parameters, they will be bound to the statement
* before it is executed. Note that the bindings and the row cursor are reset when you specify
* even a single bind parameter. The callback behavior is identical to the Database#run method
* with the difference that the statement will not be finalized after it is run. This means you
* can run it multiple times.
*/
public run(callback?: ResultsCallback<T>): this
public run(params: any, callback?: ResultsCallback<T>): this
public run(...params: any[]): this {
const { args, callback } = popCallback<ResultsCallback>(params || [])
if (args?.length > 0) {
// apply new bindings then execute
this.bind(...args, (error: Error) => {
if (error) {
callback?.call(this, error)
} else {
this._database.run(this._preparedSql || '', callback)
}
})
} else {
// execute prepared sql with same bindings
this._database.run(this._preparedSql || '', callback)
}
return this
}
/**
* Binds parameters, executes the statement and retrieves the first result row.
* The function returns the Statement object to allow for function chaining.
* The parameters are the same as the Statement#run function, with the following differences:
* The signature of the callback is function(err, row) {}. If the result set is empty,
* the second parameter is undefined, otherwise it is an object containing the values
* for the first row.
*/
public get(callback?: RowCallback<T>): this
public get(params: any, callback?: RowCallback<T>): this
public get(...params: any[]): this {
const { args, callback } = popCallback<RowCallback>(params || [])
if (args?.length > 0) {
// apply new bindings then execute
this.bind(...args, (error: Error) => {
if (error) {
callback?.call(this, error)
} else {
this._database.get(this._preparedSql || '', callback)
}
})
} else {
// execute prepared sql with same bindings
this._database.get(this._preparedSql || '', callback)
}
return this
}
/**
* Binds parameters, executes the statement and calls the callback with
* all result rows. The function returns the Statement object to allow
* for function chaining. The parameters are the same as the Statement#run function
*/
public all(callback?: RowsCallback<T>): this
public all(params: any, callback?: RowsCallback<T>): this
public all(...params: any[]): this {
const { args, callback } = popCallback<RowsCallback>(params || [])
if (args?.length > 0) {
// apply new bindings then execute
this.bind(...args, (error: Error) => {
if (error) {
callback?.call(this, error)
} else {
this._database.all(this._preparedSql || '', callback)
}
})
} else {
// execute prepared sql with same bindings
this._database.all(this._preparedSql || '', callback)
}
return this
}
/**
* Binds parameters, executes the statement and calls the callback for each result row.
* The function returns the Statement object to allow for function chaining. Parameters
* are the same as the Database#each function.
*/
public each(callback?: RowCallback<T>, complete?: RowCountCallback): this
public each(params: any, callback?: RowCallback<T>, complete?: RowCountCallback): this
public each(...params: any[]): this {
const { args, callback, complete } = popCallback<RowCallback<T>>(params)
if (args?.length > 0) {
// apply new bindings then execute
this.bind(...args, (error: Error) => {
if (error) {
callback?.call(this, error)
} else {
this._database.each(this._preparedSql || '', callback, complete as RowCountCallback)
}
})
} else {
// execute prepared sql with same bindings
this._database.each(this._preparedSql || '', callback, complete as RowCountCallback)
}
return this
}
}