or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

client-configuration.mderror-handling.mdfiltering-conditions.mdindex.mdquery-operations.mdresult-transformation.mdstored-procedures.md

stored-procedures.mddocs/

0

# Stored Procedures

1

2

Remote procedure call (RPC) functionality for executing PostgreSQL stored procedures and functions with parameter handling and result processing.

3

4

## Capabilities

5

6

### Remote Procedure Calls

7

8

Execute PostgreSQL stored procedures and functions remotely through PostgREST.

9

10

```typescript { .api }

11

/**

12

* Perform a function call

13

* @param fn - The function name to call

14

* @param args - The arguments to pass to the function call

15

* @param options - Named parameters

16

* @param options.head - When set to `true`, `data` will not be returned. Useful if you only need the count

17

* @param options.get - When set to `true`, the function will be called with read-only access mode

18

* @param options.count - Count algorithm to use to count rows returned by the function. Only applicable for set-returning functions

19

*/

20

rpc<FnName extends string & keyof Schema['Functions'], Fn extends Schema['Functions'][FnName]>(

21

fn: FnName,

22

args?: Fn['Args'],

23

options?: {

24

head?: boolean;

25

get?: boolean;

26

count?: 'exact' | 'planned' | 'estimated';

27

}

28

): PostgrestFilterBuilder<...>;

29

```

30

31

**Usage Examples:**

32

33

```typescript

34

import { PostgrestClient } from "@supabase/postgrest-js";

35

36

const client = new PostgrestClient("https://api.example.com");

37

38

// Simple function call with no arguments

39

const { data, error } = await client

40

.rpc("get_current_timestamp");

41

42

// Function call with arguments

43

const { data: userStats } = await client

44

.rpc("calculate_user_stats", {

45

user_id: 123,

46

start_date: "2023-01-01",

47

end_date: "2023-12-31"

48

});

49

50

// Function call with type safety (when using typed schema)

51

interface Database {

52

public: {

53

Functions: {

54

get_user_posts: {

55

Args: { user_id: number; limit?: number };

56

Returns: { id: number; title: string; created_at: string }[];

57

};

58

calculate_metrics: {

59

Args: { date_range: string };

60

Returns: { total_users: number; active_users: number };

61

};

62

};

63

};

64

}

65

66

const typedClient = new PostgrestClient<Database>("https://api.example.com");

67

68

const { data: posts } = await typedClient

69

.rpc("get_user_posts", { user_id: 456, limit: 10 });

70

// posts is fully typed based on the Returns type

71

```

72

73

### Function Call Methods

74

75

Control how functions are executed with different HTTP methods.

76

77

```typescript { .api }

78

// POST method (default) - for functions that modify data

79

rpc(fn: string, args?: object): PostgrestFilterBuilder<...>;

80

81

// GET method - for read-only functions

82

rpc(fn: string, args?: object, { get: true }): PostgrestFilterBuilder<...>;

83

84

// HEAD method - for count-only operations

85

rpc(fn: string, args?: object, { head: true }): PostgrestFilterBuilder<...>;

86

```

87

88

**Usage Examples:**

89

90

```typescript

91

// Default POST method for data-modifying functions

92

const { data } = await client

93

.rpc("create_user_report", {

94

user_id: 123,

95

report_type: "monthly"

96

});

97

98

// GET method for read-only functions (better caching, cleaner logs)

99

const { data: readOnlyData } = await client

100

.rpc("get_statistics", {

101

category: "sales",

102

year: 2023

103

}, { get: true });

104

105

// HEAD method when you only need count information

106

const { count } = await client

107

.rpc("get_large_dataset", {

108

filter_criteria: "active"

109

}, {

110

head: true,

111

count: 'exact'

112

});

113

114

// GET method with query parameters in URL

115

const { data: cachedResults } = await client

116

.rpc("get_cached_report", {

117

report_id: "monthly_2023",

118

format: "summary"

119

}, { get: true });

120

```

121

122

### Set-Returning Functions

123

124

Handle functions that return multiple rows with counting and filtering capabilities.

125

126

```typescript { .api }

127

/**

128

* For set-returning functions, you can use count algorithms and apply filters

129

* to the returned data

130

*/

131

rpc(

132

fn: string,

133

args?: object,

134

options?: { count?: 'exact' | 'planned' | 'estimated' }

135

): PostgrestFilterBuilder<...>;

136

```

137

138

**Usage Examples:**

139

140

```typescript

141

// Set-returning function with count

142

const { data: results, count } = await client

143

.rpc("get_user_activity", {

144

date_range: "[2023-01-01,2023-12-31]"

145

}, { count: 'exact' });

146

147

// Filter results from set-returning function

148

const { data: filteredResults } = await client

149

.rpc("get_all_transactions", { user_id: 123 })

150

.gte("amount", 100)

151

.eq("status", "completed")

152

.order("created_at", { ascending: false })

153

.limit(50);

154

155

// Complex filtering on function results

156

const { data: processedData } = await client

157

.rpc("analyze_user_behavior", {

158

analysis_type: "engagement",

159

time_period: "last_30_days"

160

})

161

.select("user_id, engagement_score, last_active")

162

.gt("engagement_score", 0.5)

163

.order("engagement_score", { ascending: false })

164

.range(0, 99); // Top 100 users

165

166

// Count-only for large datasets

167

const { count: totalRecords } = await client

168

.rpc("get_audit_logs", {

169

table_name: "users",

170

action_type: "UPDATE"

171

}, {

172

head: true,

173

count: 'planned' // Fast approximate count

174

});

175

```

176

177

### Function Parameter Handling

178

179

Handle different parameter types and optional parameters.

180

181

**Usage Examples:**

182

183

```typescript

184

// Function with optional parameters

185

const { data } = await client

186

.rpc("search_users", {

187

query: "john",

188

limit: 20, // Optional parameter

189

offset: 0 // Optional parameter

190

});

191

192

// Function with complex parameter types

193

const { data: analysisResult } = await client

194

.rpc("complex_analysis", {

195

data_points: [1, 2, 3, 4, 5], // Array parameter

196

config: { // Object parameter

197

include_metadata: true,

198

calculation_method: "weighted_average"

199

},

200

tags: ["analytics", "monthly"], // String array

201

threshold: 0.75 // Numeric parameter

202

});

203

204

// Function with date/time parameters

205

const { data: timeBasedData } = await client

206

.rpc("get_time_series_data", {

207

start_time: "2023-01-01T00:00:00Z",

208

end_time: "2023-12-31T23:59:59Z",

209

interval: "1 day",

210

timezone: "UTC"

211

});

212

213

// Function with JSON parameters

214

const { data: jsonResults } = await client

215

.rpc("process_json_data", {

216

json_input: {

217

filters: { status: "active", category: "premium" },

218

sorting: { field: "created_at", direction: "desc" },

219

pagination: { page: 1, size: 50 }

220

}

221

});

222

223

// Function with no parameters (empty object or omit args)

224

const { data: noParams1 } = await client.rpc("get_system_status");

225

const { data: noParams2 } = await client.rpc("get_system_status", {});

226

```

227

228

### Error Handling in RPC

229

230

Handle function execution errors and parameter validation.

231

232

**Usage Examples:**

233

234

```typescript

235

// Function call with error handling

236

const { data, error } = await client

237

.rpc("validate_and_process", {

238

input_data: "some data"

239

});

240

241

if (error) {

242

console.error("Function execution failed:", error.message);

243

console.error("Error details:", error.details);

244

console.error("Error code:", error.code);

245

// Handle specific error cases

246

if (error.code === "42883") {

247

console.log("Function does not exist");

248

}

249

}

250

251

// Function with validation

252

const { data: validatedData, error: validationError } = await client

253

.rpc("strict_data_validator", {

254

email: "user@example.com",

255

age: 25,

256

preferences: { newsletter: true }

257

});

258

259

// Throwing errors instead of returning them

260

const { data: strictData } = await client

261

.rpc("critical_operation", { operation_id: "abc123" })

262

.throwOnError(); // Will throw if function returns error

263

```

264

265

### Advanced RPC Patterns

266

267

Complex patterns for sophisticated database operations.

268

269

**Usage Examples:**

270

271

```typescript

272

// Chained function calls (if function returns table-like data)

273

const { data: chainedResults } = await client

274

.rpc("get_user_recommendations", { user_id: 123 })

275

.select("recommendation_id, score, item_title")

276

.gte("score", 0.8)

277

.order("score", { ascending: false })

278

.limit(10);

279

280

// Function returning single object

281

const { data: singleResult } = await client

282

.rpc("get_user_summary", { user_id: 456 })

283

.single(); // Ensure single object return

284

285

// Function with CSV output format

286

const { data: csvReport } = await client

287

.rpc("generate_report", {

288

report_type: "sales",

289

format: "detailed"

290

})

291

.csv(); // Return as CSV string

292

293

// Function with transaction control

294

const { data: testResult } = await client

295

.rpc("test_data_migration", {

296

migration_id: "test_001"

297

})

298

.rollback(); // Execute but don't commit changes

299

300

// Batch function calls

301

const batchPromises = [

302

client.rpc("process_batch", { batch_id: 1 }),

303

client.rpc("process_batch", { batch_id: 2 }),

304

client.rpc("process_batch", { batch_id: 3 })

305

];

306

307

const batchResults = await Promise.all(batchPromises);

308

309

// Function with request cancellation

310

const controller = new AbortController();

311

setTimeout(() => controller.abort(), 30000); // 30 second timeout

312

313

const { data: longRunningResult } = await client

314

.rpc("long_running_analysis", { dataset_id: "large_001" })

315

.abortSignal(controller.signal);

316

```

317

318

### Performance Optimization

319

320

Optimize function calls for better performance.

321

322

**Usage Examples:**

323

324

```typescript

325

// Use GET method for cacheable read-only functions

326

const { data: cachedStats } = await client

327

.rpc("get_daily_statistics", {

328

date: "2023-12-01"

329

}, { get: true }); // Can be cached by CDN/proxy

330

331

// Use planned count for large result sets

332

const { count: approximateCount } = await client

333

.rpc("get_massive_dataset", {

334

filter: "active"

335

}, {

336

head: true,

337

count: 'planned' // Fast approximate count

338

});

339

340

// Limit results for pagination

341

const { data: pagedResults } = await client

342

.rpc("search_comprehensive", {

343

search_term: "postgresql"

344

})

345

.order("relevance_score", { ascending: false })

346

.range(0, 49); // First 50 results

347

348

// Use specific column selection to reduce data transfer

349

const { data: optimizedResults } = await client

350

.rpc("get_detailed_analytics", {

351

analysis_id: "monthly_2023"

352

})

353

.select("id, summary, key_metrics") // Only needed columns

354

.limit(100);

355

```

356

357

### Security Considerations

358

359

Best practices for secure function calls.

360

361

**Usage Examples:**

362

363

```typescript

364

// Parameterized function calls (PostgREST handles SQL injection prevention)

365

const { data: safeResults } = await client

366

.rpc("search_secure", {

367

user_input: "'; DROP TABLE users; --", // This is safely handled

368

user_id: currentUserId

369

});

370

371

// Validate parameters before function calls

372

function validateUserId(userId: number): boolean {

373

return Number.isInteger(userId) && userId > 0;

374

}

375

376

if (validateUserId(userId)) {

377

const { data } = await client

378

.rpc("get_user_data", { user_id: userId });

379

}

380

381

// Use typed schemas to prevent parameter mistakes

382

interface StrictDatabase {

383

public: {

384

Functions: {

385

secure_user_operation: {

386

Args: {

387

user_id: number; // Required, type-checked

388

operation: 'read' | 'write'; // Limited to specific values

389

permissions?: string[]; // Optional array

390

};

391

Returns: { success: boolean; message: string };

392

};

393

};

394

};

395

}

396

397

const secureClient = new PostgrestClient<StrictDatabase>("https://api.example.com");

398

399

// Type-safe function call

400

const { data: secureResult } = await secureClient

401

.rpc("secure_user_operation", {

402

user_id: 123, // ✅ Type-safe

403

operation: "read", // ✅ Limited to valid values

404

permissions: ["read", "write"] // ✅ Optional typed array

405

// invalid_param: "value" // ❌ TypeScript error

406

});

407

```