0
# Script Operations
1
2
Server-side script operations including stored procedures, triggers, and user-defined functions (UDFs). The ScriptsProxy enables execution of custom JavaScript code within the Azure Cosmos DB engine for advanced data processing and business logic.
3
4
## Capabilities
5
6
### Stored Procedures
7
8
Server-side procedures written in JavaScript that execute within the database engine with transactional guarantees.
9
10
```python { .api }
11
def create_stored_procedure(self, body: dict, **kwargs):
12
"""
13
Create a new stored procedure.
14
15
Parameters:
16
- body: Stored procedure definition with 'id' and 'body' (JavaScript code)
17
- session_token: Session token for consistency
18
19
Returns:
20
Stored procedure properties
21
22
Raises:
23
CosmosResourceExistsError: If stored procedure already exists
24
"""
25
26
def list_stored_procedures(self, max_item_count: int = None, **kwargs):
27
"""
28
List all stored procedures in the container.
29
30
Parameters:
31
- max_item_count: Maximum number of procedures to return
32
- session_token: Session token for consistency
33
34
Returns:
35
Iterable of stored procedure items
36
"""
37
38
def query_stored_procedures(self, query: str, parameters: list = None, max_item_count: int = None, **kwargs):
39
"""
40
Query stored procedures using SQL syntax.
41
42
Parameters:
43
- query: SQL query string
44
- parameters: Query parameters
45
- max_item_count: Maximum items per page
46
- session_token: Session token for consistency
47
48
Returns:
49
Iterable of query results
50
"""
51
52
def get_stored_procedure(self, sproc: str, **kwargs):
53
"""
54
Get stored procedure definition.
55
56
Parameters:
57
- sproc: Stored procedure ID
58
- session_token: Session token for consistency
59
60
Returns:
61
Stored procedure properties
62
63
Raises:
64
CosmosResourceNotFoundError: If stored procedure doesn't exist
65
"""
66
67
def replace_stored_procedure(self, sproc: str, body: dict, **kwargs):
68
"""
69
Replace stored procedure definition.
70
71
Parameters:
72
- sproc: Stored procedure ID
73
- body: Updated stored procedure definition
74
- session_token: Session token for consistency
75
- etag: ETag for conditional operations
76
- match_condition: Match condition for conditional operations
77
78
Returns:
79
Updated stored procedure properties
80
"""
81
82
def delete_stored_procedure(self, sproc: str, **kwargs):
83
"""
84
Delete a stored procedure.
85
86
Parameters:
87
- sproc: Stored procedure ID
88
- session_token: Session token for consistency
89
- etag: ETag for conditional operations
90
- match_condition: Match condition for conditional operations
91
92
Raises:
93
CosmosResourceNotFoundError: If stored procedure doesn't exist
94
"""
95
96
def execute_stored_procedure(self, sproc: str, partition_key: str = None, params: list = None, enable_script_logging: bool = None, **kwargs):
97
"""
98
Execute a stored procedure.
99
100
Parameters:
101
- sproc: Stored procedure ID
102
- partition_key: Partition key value for the execution context
103
- params: Parameters to pass to the stored procedure
104
- enable_script_logging: Enable console.log output in stored procedure
105
- session_token: Session token for consistency
106
107
Returns:
108
Stored procedure execution result
109
110
Raises:
111
CosmosHttpResponseError: If execution fails
112
"""
113
```
114
115
### Triggers
116
117
Pre-triggers and post-triggers that execute automatically before or after item operations.
118
119
```python { .api }
120
def create_trigger(self, body: dict, **kwargs):
121
"""
122
Create a new trigger.
123
124
Parameters:
125
- body: Trigger definition with 'id', 'body' (JavaScript), 'triggerType', 'triggerOperation'
126
- session_token: Session token for consistency
127
128
Returns:
129
Trigger properties
130
131
Raises:
132
CosmosResourceExistsError: If trigger already exists
133
"""
134
135
def list_triggers(self, max_item_count: int = None, **kwargs):
136
"""
137
List all triggers in the container.
138
139
Parameters:
140
- max_item_count: Maximum number of triggers to return
141
- session_token: Session token for consistency
142
143
Returns:
144
Iterable of trigger items
145
"""
146
147
def query_triggers(self, query: str, parameters: list = None, max_item_count: int = None, **kwargs):
148
"""
149
Query triggers using SQL syntax.
150
151
Parameters:
152
- query: SQL query string
153
- parameters: Query parameters
154
- max_item_count: Maximum items per page
155
- session_token: Session token for consistency
156
157
Returns:
158
Iterable of query results
159
"""
160
161
def get_trigger(self, trigger: str, **kwargs):
162
"""
163
Get trigger definition.
164
165
Parameters:
166
- trigger: Trigger ID
167
- session_token: Session token for consistency
168
169
Returns:
170
Trigger properties
171
172
Raises:
173
CosmosResourceNotFoundError: If trigger doesn't exist
174
"""
175
176
def replace_trigger(self, trigger: str, body: dict, **kwargs):
177
"""
178
Replace trigger definition.
179
180
Parameters:
181
- trigger: Trigger ID
182
- body: Updated trigger definition
183
- session_token: Session token for consistency
184
- etag: ETag for conditional operations
185
- match_condition: Match condition for conditional operations
186
187
Returns:
188
Updated trigger properties
189
"""
190
191
def delete_trigger(self, trigger: str, **kwargs):
192
"""
193
Delete a trigger.
194
195
Parameters:
196
- trigger: Trigger ID
197
- session_token: Session token for consistency
198
- etag: ETag for conditional operations
199
- match_condition: Match condition for conditional operations
200
201
Raises:
202
CosmosResourceNotFoundError: If trigger doesn't exist
203
"""
204
```
205
206
### User Defined Functions
207
208
Custom JavaScript functions that can be used in queries for complex calculations and data transformations.
209
210
```python { .api }
211
def create_user_defined_function(self, body: dict, **kwargs):
212
"""
213
Create a new user-defined function.
214
215
Parameters:
216
- body: UDF definition with 'id' and 'body' (JavaScript code)
217
- session_token: Session token for consistency
218
219
Returns:
220
UDF properties
221
222
Raises:
223
CosmosResourceExistsError: If UDF already exists
224
"""
225
226
def list_user_defined_functions(self, max_item_count: int = None, **kwargs):
227
"""
228
List all user-defined functions in the container.
229
230
Parameters:
231
- max_item_count: Maximum number of UDFs to return
232
- session_token: Session token for consistency
233
234
Returns:
235
Iterable of UDF items
236
"""
237
238
def query_user_defined_functions(self, query: str, parameters: list = None, max_item_count: int = None, **kwargs):
239
"""
240
Query user-defined functions using SQL syntax.
241
242
Parameters:
243
- query: SQL query string
244
- parameters: Query parameters
245
- max_item_count: Maximum items per page
246
- session_token: Session token for consistency
247
248
Returns:
249
Iterable of query results
250
"""
251
252
def get_user_defined_function(self, udf: str, **kwargs):
253
"""
254
Get user-defined function definition.
255
256
Parameters:
257
- udf: UDF ID
258
- session_token: Session token for consistency
259
260
Returns:
261
UDF properties
262
263
Raises:
264
CosmosResourceNotFoundError: If UDF doesn't exist
265
"""
266
267
def replace_user_defined_function(self, udf: str, body: dict, **kwargs):
268
"""
269
Replace user-defined function definition.
270
271
Parameters:
272
- udf: UDF ID
273
- body: Updated UDF definition
274
- session_token: Session token for consistency
275
- etag: ETag for conditional operations
276
- match_condition: Match condition for conditional operations
277
278
Returns:
279
Updated UDF properties
280
"""
281
282
def delete_user_defined_function(self, udf: str, **kwargs):
283
"""
284
Delete a user-defined function.
285
286
Parameters:
287
- udf: UDF ID
288
- session_token: Session token for consistency
289
- etag: ETag for conditional operations
290
- match_condition: Match condition for conditional operations
291
292
Raises:
293
CosmosResourceNotFoundError: If UDF doesn't exist
294
"""
295
```
296
297
## Usage Examples
298
299
### Stored Procedures
300
301
```python
302
# Get scripts proxy
303
scripts = container.scripts
304
305
# Create a stored procedure
306
sproc_definition = {
307
"id": "createItemsProc",
308
"body": """
309
function createItemsProc(items) {
310
var context = getContext();
311
var collection = context.getCollection();
312
var response = context.getResponse();
313
314
if (!items || items.length === 0) {
315
throw new Error('Items array is required');
316
}
317
318
var created = 0;
319
320
function createNextItem(index) {
321
if (index >= items.length) {
322
response.setBody({ created: created });
323
return;
324
}
325
326
var item = items[index];
327
var isAccepted = collection.createDocument(
328
collection.getSelfLink(),
329
item,
330
function(err, doc) {
331
if (err) throw err;
332
created++;
333
createNextItem(index + 1);
334
}
335
);
336
337
if (!isAccepted) {
338
response.setBody({ created: created, stopped: true });
339
}
340
}
341
342
createNextItem(0);
343
}
344
"""
345
}
346
347
# Create the stored procedure
348
scripts.create_stored_procedure(sproc_definition)
349
350
# Execute the stored procedure
351
items_to_create = [
352
{"id": "item1", "category": "Electronics", "name": "Phone"},
353
{"id": "item2", "category": "Electronics", "name": "Tablet"}
354
]
355
356
result = scripts.execute_stored_procedure(
357
sproc="createItemsProc",
358
partition_key="Electronics",
359
params=[items_to_create],
360
enable_script_logging=True
361
)
362
print(f"Created {result['created']} items")
363
364
# List stored procedures
365
procedures = list(scripts.list_stored_procedures())
366
for proc in procedures:
367
print(f"Stored Procedure: {proc['id']}")
368
```
369
370
### Triggers
371
372
```python
373
# Create a pre-trigger for validation
374
pre_trigger = {
375
"id": "validateItem",
376
"triggerType": "Pre",
377
"triggerOperation": "Create",
378
"body": """
379
function validateItem() {
380
var context = getContext();
381
var request = context.getRequest();
382
var body = request.getBody();
383
384
// Validate required fields
385
if (!body.name || body.name.length === 0) {
386
throw new Error('Item must have a name');
387
}
388
389
if (!body.category) {
390
throw new Error('Item must have a category');
391
}
392
393
// Auto-generate timestamp
394
body.createdAt = new Date().toISOString();
395
396
request.setBody(body);
397
}
398
"""
399
}
400
401
scripts.create_trigger(pre_trigger)
402
403
# Create a post-trigger for logging
404
post_trigger = {
405
"id": "logCreation",
406
"triggerType": "Post",
407
"triggerOperation": "Create",
408
"body": """
409
function logCreation() {
410
var context = getContext();
411
var response = context.getResponse();
412
var body = response.getBody();
413
414
console.log('Item created:', body.id);
415
}
416
"""
417
}
418
419
scripts.create_trigger(post_trigger)
420
421
# Create item with triggers
422
item = {"id": "triggered_item", "category": "Electronics"}
423
created_item = container.create_item(
424
body=item,
425
pre_trigger_include="validateItem",
426
post_trigger_include="logCreation"
427
)
428
```
429
430
### User Defined Functions
431
432
```python
433
# Create a UDF for tax calculation
434
udf_definition = {
435
"id": "calculateTax",
436
"body": """
437
function calculateTax(price, taxRate) {
438
if (typeof price !== 'number' || typeof taxRate !== 'number') {
439
return 0;
440
}
441
return price * taxRate;
442
}
443
"""
444
}
445
446
scripts.create_user_defined_function(udf_definition)
447
448
# Use UDF in a query
449
query = """
450
SELECT
451
c.id,
452
c.name,
453
c.price,
454
udf.calculateTax(c.price, 0.08) as tax,
455
(c.price + udf.calculateTax(c.price, 0.08)) as totalPrice
456
FROM c
457
WHERE c.category = 'Electronics'
458
"""
459
460
items = list(container.query_items(
461
query=query,
462
enable_cross_partition_query=True
463
))
464
465
for item in items:
466
print(f"{item['name']}: ${item['price']} + ${item['tax']} = ${item['totalPrice']}")
467
468
# List UDFs
469
udfs = list(scripts.list_user_defined_functions())
470
for udf in udfs:
471
print(f"UDF: {udf['id']}")
472
```
473
474
### Advanced Stored Procedure with Error Handling
475
476
```python
477
# Stored procedure for batch processing with rollback
478
batch_sproc = {
479
"id": "batchUpdateProc",
480
"body": """
481
function batchUpdateProc(updates) {
482
var context = getContext();
483
var collection = context.getCollection();
484
var response = context.getResponse();
485
486
var updated = 0;
487
var errors = [];
488
489
function updateNextItem(index) {
490
if (index >= updates.length) {
491
response.setBody({
492
updated: updated,
493
errors: errors
494
});
495
return;
496
}
497
498
var update = updates[index];
499
500
var isAccepted = collection.replaceDocument(
501
update.link,
502
update.item,
503
function(err, doc) {
504
if (err) {
505
errors.push({
506
index: index,
507
error: err.message
508
});
509
} else {
510
updated++;
511
}
512
updateNextItem(index + 1);
513
}
514
);
515
516
if (!isAccepted) {
517
response.setBody({
518
updated: updated,
519
stopped: true,
520
errors: errors
521
});
522
}
523
}
524
525
updateNextItem(0);
526
}
527
"""
528
}
529
530
scripts.create_stored_procedure(batch_sproc)
531
532
# Execute batch update
533
updates = [
534
{
535
"link": "dbs/MyDB/colls/MyContainer/docs/item1",
536
"item": {"id": "item1", "category": "Electronics", "price": 299.99}
537
},
538
{
539
"link": "dbs/MyDB/colls/MyContainer/docs/item2",
540
"item": {"id": "item2", "category": "Electronics", "price": 199.99}
541
}
542
]
543
544
result = scripts.execute_stored_procedure(
545
sproc="batchUpdateProc",
546
partition_key="Electronics",
547
params=[updates]
548
)
549
550
print(f"Updated: {result['updated']}, Errors: {len(result.get('errors', []))}")
551
```