or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

connections.mdindex.mdpool-clusters.mdpools.mdpromises.mdqueries.mdserver.mdsql-utilities.md

sql-utilities.mddocs/

0

# SQL Utilities

1

2

SQL string manipulation and escaping utilities for safe query construction, SQL injection prevention, and dynamic query building with proper value formatting.

3

4

## Capabilities

5

6

### Escape Function

7

8

Escapes SQL values to prevent SQL injection attacks and ensure proper value formatting.

9

10

```javascript { .api }

11

/**

12

* Escape SQL value to prevent injection

13

* @param value - Value to escape (any type)

14

* @param stringifyObjects - Convert objects to JSON strings

15

* @param timeZone - Timezone for date formatting

16

* @returns Safely escaped SQL value string

17

*/

18

function escape(value: any, stringifyObjects?: boolean, timeZone?: string): string;

19

```

20

21

**Usage Examples:**

22

23

```javascript

24

const mysql = require('mysql2');

25

26

// Escape different value types

27

console.log(mysql.escape('Hello "World"')); // '"Hello \"World\""'

28

console.log(mysql.escape(123)); // '123'

29

console.log(mysql.escape(true)); // 'true'

30

console.log(mysql.escape(false)); // 'false'

31

console.log(mysql.escape(null)); // 'NULL'

32

console.log(mysql.escape(undefined)); // 'NULL'

33

console.log(mysql.escape(new Date())); // '"2023-12-01 10:30:45"'

34

console.log(mysql.escape(['a', 'b', 'c'])); // '"a", "b", "c"'

35

console.log(mysql.escape([1, 2, 3])); // '1, 2, 3'

36

37

// Escape objects (stringified as JSON)

38

console.log(mysql.escape({name: 'John', age: 30})); // '"{\"name\":\"John\",\"age\":30}"'

39

40

// With stringifyObjects option

41

console.log(mysql.escape({id: 1, active: true}, true)); // '"{\"id\":1,\"active\":true}"'

42

43

// With timezone for dates

44

const date = new Date('2023-12-01T10:30:45.000Z');

45

console.log(mysql.escape(date, false, 'UTC')); // '"2023-12-01 10:30:45"'

46

console.log(mysql.escape(date, false, 'local')); // '"2023-12-01 05:30:45"'

47

```

48

49

### Escape Identifier Function

50

51

Escapes SQL identifiers (table names, column names) to handle reserved words and special characters.

52

53

```javascript { .api }

54

/**

55

* Escape SQL identifier

56

* @param value - Identifier to escape (string or array of strings)

57

* @param forbidQualified - Disallow qualified identifiers (table.column)

58

* @returns Safely escaped SQL identifier

59

*/

60

function escapeId(value: string | string[], forbidQualified?: boolean): string;

61

```

62

63

**Usage Examples:**

64

65

```javascript

66

// Escape table and column names

67

console.log(mysql.escapeId('user')); // '`user`'

68

console.log(mysql.escapeId('user_profile')); // '`user_profile`'

69

console.log(mysql.escapeId('select')); // '`select`' (reserved word)

70

console.log(mysql.escapeId('table.column')); // '`table`.`column`'

71

72

// Escape array of identifiers

73

console.log(mysql.escapeId(['table', 'column'])); // '`table`.`column`'

74

75

// Forbid qualified identifiers

76

console.log(mysql.escapeId('table.column', true)); // Throws error

77

78

// Handle special characters

79

console.log(mysql.escapeId('my-table')); // '`my-table`'

80

console.log(mysql.escapeId('table with spaces')); // '`table with spaces`'

81

```

82

83

### Format Function

84

85

Formats SQL queries by replacing placeholders with escaped values.

86

87

```javascript { .api }

88

/**

89

* Format SQL query with values

90

* @param sql - SQL query string with placeholders

91

* @param values - Values to replace placeholders (optional)

92

* @param stringifyObjects - Convert objects to JSON strings

93

* @param timeZone - Timezone for date formatting

94

* @returns Formatted SQL query string

95

*/

96

function format(sql: string): string;

97

function format(sql: string, values: any | any[], stringifyObjects?: boolean, timeZone?: string): string;

98

```

99

100

**Usage Examples:**

101

102

```javascript

103

// Format with positional placeholders

104

const sql1 = mysql.format('SELECT * FROM users WHERE id = ?', [123]);

105

console.log(sql1); // 'SELECT * FROM users WHERE id = 123'

106

107

const sql2 = mysql.format('SELECT * FROM users WHERE name = ? AND age > ?', ['John', 25]);

108

console.log(sql2); // 'SELECT * FROM users WHERE name = "John" AND age > 25'

109

110

// Format with named placeholders

111

const sql3 = mysql.format('SELECT * FROM users WHERE name = :name AND age > :age', {

112

name: 'John',

113

age: 25

114

});

115

console.log(sql3); // 'SELECT * FROM users WHERE name = "John" AND age > 25'

116

117

// Format identifiers with ??

118

const sql4 = mysql.format('SELECT ?? FROM ?? WHERE ?? = ?', ['name', 'users', 'id', 123]);

119

console.log(sql4); // 'SELECT `name` FROM `users` WHERE `id` = 123'

120

121

// Complex formatting

122

const sql5 = mysql.format(

123

'INSERT INTO ?? (??) VALUES ?',

124

['users', ['name', 'email', 'age'], [['John', 'john@example.com', 30]]]

125

);

126

console.log(sql5); // 'INSERT INTO `users` (`name`, `email`, `age`) VALUES ("John", "john@example.com", 30)'

127

```

128

129

### Raw Function

130

131

Creates raw SQL objects that bypass escaping for trusted SQL fragments.

132

133

```javascript { .api }

134

/**

135

* Create raw SQL object that won't be escaped

136

* @param sql - Raw SQL string

137

* @returns Object with toSqlString method

138

*/

139

function raw(sql: string): { toSqlString: () => string };

140

```

141

142

**Usage Examples:**

143

144

```javascript

145

// Use raw SQL for functions and expressions

146

const query = mysql.format('SELECT * FROM users WHERE created_at > ? AND status = ?', [

147

mysql.raw('DATE_SUB(NOW(), INTERVAL 1 DAY)'),

148

'active'

149

]);

150

console.log(query);

151

// 'SELECT * FROM users WHERE created_at > DATE_SUB(NOW(), INTERVAL 1 DAY) AND status = "active"'

152

153

// Raw SQL for complex expressions

154

const updateQuery = mysql.format('UPDATE users SET login_count = ? WHERE id = ?', [

155

mysql.raw('login_count + 1'),

156

123

157

]);

158

console.log(updateQuery);

159

// 'UPDATE users SET login_count = login_count + 1 WHERE id = 123'

160

161

// Raw SQL for subqueries

162

const subquery = mysql.format('SELECT * FROM orders WHERE user_id IN (?)', [

163

mysql.raw('SELECT id FROM users WHERE active = 1')

164

]);

165

console.log(subquery);

166

// 'SELECT * FROM orders WHERE user_id IN (SELECT id FROM users WHERE active = 1)'

167

```

168

169

## Advanced Usage Patterns

170

171

### Dynamic Query Building

172

173

```javascript

174

function buildSelectQuery(table, conditions, orderBy, limit) {

175

let sql = 'SELECT * FROM ??';

176

const params = [table];

177

178

if (conditions && Object.keys(conditions).length > 0) {

179

const whereClause = Object.keys(conditions).map(key => '?? = ?').join(' AND ');

180

sql += ' WHERE ' + whereClause;

181

182

Object.keys(conditions).forEach(key => {

183

params.push(key, conditions[key]);

184

});

185

}

186

187

if (orderBy) {

188

sql += ' ORDER BY ??';

189

params.push(orderBy);

190

}

191

192

if (limit) {

193

sql += ' LIMIT ?';

194

params.push(limit);

195

}

196

197

return mysql.format(sql, params);

198

}

199

200

// Usage

201

const query = buildSelectQuery('users', { active: true, role: 'admin' }, 'created_at', 10);

202

console.log(query);

203

// 'SELECT * FROM `users` WHERE `active` = true AND `role` = "admin" ORDER BY `created_at` LIMIT 10'

204

```

205

206

### Bulk Insert Helper

207

208

```javascript

209

function buildBulkInsert(table, columns, rows) {

210

const sql = 'INSERT INTO ?? (??) VALUES ?';

211

return mysql.format(sql, [table, columns, rows]);

212

}

213

214

// Usage

215

const insertQuery = buildBulkInsert('users', ['name', 'email'], [

216

['John', 'john@example.com'],

217

['Jane', 'jane@example.com'],

218

['Bob', 'bob@example.com']

219

]);

220

221

console.log(insertQuery);

222

// 'INSERT INTO `users` (`name`, `email`) VALUES ("John", "john@example.com"), ("Jane", "jane@example.com"), ("Bob", "bob@example.com")'

223

```

224

225

### Search Query Builder

226

227

```javascript

228

function buildSearchQuery(table, searchTerm, searchColumns) {

229

const conditions = searchColumns.map(() => '?? LIKE ?').join(' OR ');

230

const sql = `SELECT * FROM ?? WHERE ${conditions}`;

231

232

const params = [table];

233

searchColumns.forEach(column => {

234

params.push(column, `%${searchTerm}%`);

235

});

236

237

return mysql.format(sql, params);

238

}

239

240

// Usage

241

const searchQuery = buildSearchQuery('products', 'laptop', ['name', 'description', 'tags']);

242

console.log(searchQuery);

243

// 'SELECT * FROM `products` WHERE `name` LIKE "%laptop%" OR `description` LIKE "%laptop%" OR `tags` LIKE "%laptop%"'

244

```

245

246

## Security Best Practices

247

248

### Always Escape User Input

249

250

```javascript

251

// NEVER do this (vulnerable to SQL injection)

252

const badQuery = `SELECT * FROM users WHERE name = '${userInput}'`;

253

254

// Always do this instead

255

const goodQuery = mysql.format('SELECT * FROM users WHERE name = ?', [userInput]);

256

```

257

258

### Use Identifiers Escaping for Dynamic Table/Column Names

259

260

```javascript

261

// Safe dynamic table queries

262

function queryTable(tableName, columnName, value) {

263

return mysql.format('SELECT * FROM ?? WHERE ?? = ?', [tableName, columnName, value]);

264

}

265

```

266

267

### Validate Input Before Escaping

268

269

```javascript

270

function safeQuery(table, column, value) {

271

// Validate table and column names against whitelist

272

const allowedTables = ['users', 'products', 'orders'];

273

const allowedColumns = ['id', 'name', 'email', 'status'];

274

275

if (!allowedTables.includes(table)) {

276

throw new Error('Invalid table name');

277

}

278

279

if (!allowedColumns.includes(column)) {

280

throw new Error('Invalid column name');

281

}

282

283

return mysql.format('SELECT * FROM ?? WHERE ?? = ?', [table, column, value]);

284

}

285

```

286

287

## Type-Specific Escaping

288

289

### Date Handling

290

291

```javascript

292

// Dates are automatically formatted

293

const date = new Date('2023-12-01T10:30:45.000Z');

294

const query = mysql.format('SELECT * FROM events WHERE created_at > ?', [date]);

295

// 'SELECT * FROM events WHERE created_at > "2023-12-01 10:30:45"'

296

297

// Custom date formatting

298

const customDate = mysql.format('SELECT * FROM events WHERE created_at > ?', [

299

mysql.raw(`'${date.toISOString().slice(0, 19).replace('T', ' ')}'`)

300

]);

301

```

302

303

### Buffer Handling

304

305

```javascript

306

// Buffers are escaped as hex strings

307

const buffer = Buffer.from('Hello World', 'utf8');

308

const query = mysql.format('INSERT INTO files (name, content) VALUES (?, ?)', ['test.txt', buffer]);

309

// 'INSERT INTO files (name, content) VALUES ("test.txt", 0x48656c6c6f20576f726c64)'

310

```

311

312

### Array and Object Handling

313

314

```javascript

315

// Arrays are expanded for IN clauses

316

const ids = [1, 2, 3, 4, 5];

317

const query = mysql.format('SELECT * FROM users WHERE id IN (?)', [ids]);

318

// 'SELECT * FROM users WHERE id IN (1, 2, 3, 4, 5)'

319

320

// Objects are JSON stringified

321

const metadata = { tags: ['admin', 'user'], preferences: { theme: 'dark' } };

322

const updateQuery = mysql.format('UPDATE users SET metadata = ? WHERE id = ?', [metadata, 123]);

323

// 'UPDATE users SET metadata = "{"tags":["admin","user"],"preferences":{"theme":"dark"}}" WHERE id = 123'

324

```