Browse Source

Standardize query usage in low-code docs

Refactor scripting examples to consistently await db.query(...) into named table variables (e.g. productTable, customerTable, orderTable, entityTable, orderLineTable) and use those variables for subsequent operations. Adjusted examples to await where() when needed and updated aggregation/collection examples accordingly. Also clarified semantics for first/last/single variants in the API table. Changes applied to docs/en/low-code/scripting-api.md and docs/en/low-code/custom-endpoints.md to keep example patterns consistent and clearer for consumers.
pull/25021/head
SALİH ÖZKARA 4 weeks ago
parent
commit
fcc9acc829
  1. 4
      docs/en/low-code/custom-endpoints.md
  2. 94
      docs/en/low-code/scripting-api.md

4
docs/en/low-code/custom-endpoints.md

@ -106,7 +106,7 @@ The full [Scripting API](scripting-api.md) (`db` object) is available for queryi
"route": "/api/custom/products/stats",
"method": "GET",
"requireAuthentication": false,
"javascript": "var totalCount = await db.count('LowCodeDemo.Products.Product');\nvar avgPrice = totalCount > 0 ? await db.query('LowCodeDemo.Products.Product').average(p => p.Price) : 0;\nreturn ok({ totalProducts: totalCount, averagePrice: avgPrice });"
"javascript": "var totalCount = await db.count('LowCodeDemo.Products.Product');\nvar productTable = await db.query('LowCodeDemo.Products.Product');\nvar avgPrice = totalCount > 0 ? await productTable.average(p => p.Price) : 0;\nreturn ok({ totalProducts: totalCount, averagePrice: avgPrice });"
}
```
@ -118,7 +118,7 @@ The full [Scripting API](scripting-api.md) (`db` object) is available for queryi
"route": "/api/custom/customers/search",
"method": "GET",
"requireAuthentication": true,
"javascript": "var searchTerm = query.q || '';\nvar customers = await db.query('LowCodeDemo.Customers.Customer')\n .where(c => c.Name.toLowerCase().includes(searchTerm.toLowerCase()))\n .take(10)\n .toList();\nreturn ok(customers.map(c => ({ id: c.Id, name: c.Name, email: c.EmailAddress })));"
"javascript": "var searchTerm = query.q || '';\nvar customerTable = await db.query('LowCodeDemo.Customers.Customer');\nvar customers = await customerTable\n .where(c => c.Name.toLowerCase().includes(searchTerm.toLowerCase()))\n .take(10)\n .toList();\nreturn ok(customers.map(c => ({ id: c.Id, name: c.Name, email: c.EmailAddress })));"
}
```

94
docs/en/low-code/scripting-api.md

@ -21,7 +21,8 @@ The `db` object is the main entry point for all data operations.
```javascript
// Immutable pattern — each call creates a new builder
var baseQuery = db.query('Entity').where(x => x.Active);
var entityTable = await db.query('Entity');
var baseQuery = await entityTable.where(x => x.Active);
var cheap = baseQuery.where(x => x.Price < 100); // baseQuery unchanged
var expensive = baseQuery.where(x => x.Price > 500); // baseQuery unchanged
```
@ -31,13 +32,15 @@ var expensive = baseQuery.where(x => x.Price > 500); // baseQuery unchanged
### Basic Queries
```javascript
var products = await db.query('LowCodeDemo.Products.Product')
var productTable = await db.query('LowCodeDemo.Products.Product');
var products = await productTable
.where(x => x.Price > 100)
.orderBy(x => x.Price)
.take(10)
.toList();
var result = await db.query('LowCodeDemo.Products.Product')
var resultTable = await db.query('LowCodeDemo.Products.Product');
var result = await resultTable
.where(x => x.Price > 100 && x.Price < 500)
.where(x => x.StockCount > 0)
.orderByDescending(x => x.Price)
@ -63,9 +66,12 @@ var result = await db.query('LowCodeDemo.Products.Product')
| `all(x => condition)` | Check if all records match | `Promise<boolean>` |
| `isEmpty()` | Check if no results | `Promise<boolean>` |
| `isSingle()` | Check if exactly one result | `Promise<boolean>` |
| `first()` / `firstOrDefault()` | Return first match or null | `Promise<object\|null>` |
| `last()` / `lastOrDefault()` | Return last match or null | `Promise<object\|null>` |
| `single()` / `singleOrDefault()` | Return single match or null | `Promise<object\|null>` |
| `first()` | Return first match, throws if empty | `Promise<object>` |
| `firstOrDefault()` | Return first match or null | `Promise<object\|null>` |
| `last()` | Return last match, throws if empty | `Promise<object>` |
| `lastOrDefault()` | Return last match or null | `Promise<object\|null>` |
| `single()` | Return single match, throws if empty/multiple | `Promise<object>` |
| `singleOrDefault()` | Return single match or null (throws if multiple) | `Promise<object\|null>` |
| `elementAt(index)` | Return element at index | `Promise<object\|null>` |
| `select(x => projection)` | Project to custom shape | `QueryBuilder` |
| `join(entity, alias, condition)` | Inner join | `QueryBuilder` |
@ -92,16 +98,18 @@ var minPrice = 100;
var config = { minStock: 10 };
var nested = { range: { min: 50, max: 200 } };
var result = await db.query('Entity').where(x => x.Price > minPrice).toList();
var result2 = await db.query('Entity').where(x => x.StockCount > config.minStock).toList();
var result3 = await db.query('Entity').where(x => x.Price >= nested.range.min).toList();
var entityTable = await db.query('Entity');
var result = await entityTable.where(x => x.Price > minPrice).toList();
var result2 = await entityTable.where(x => x.StockCount > config.minStock).toList();
var result3 = await entityTable.where(x => x.Price >= nested.range.min).toList();
```
### Contains / IN Operator
```javascript
var targetPrices = [50, 100, 200];
var products = await db.query('Entity')
var entityTable = await db.query('Entity');
var products = await entityTable
.where(x => targetPrices.includes(x.Price))
.toList();
```
@ -109,7 +117,8 @@ var products = await db.query('Entity')
### Select Projection
```javascript
var projected = await db.query('LowCodeDemo.Products.Product')
var productTable = await db.query('LowCodeDemo.Products.Product');
var projected = await productTable
.where(x => x.Price > 0)
.select(x => ({ ProductName: x.Name, ProductPrice: x.Price }))
.toList();
@ -120,7 +129,8 @@ var projected = await db.query('LowCodeDemo.Products.Product')
### Explicit Joins
```javascript
var orderLines = await db.query('LowCodeDemo.Orders.OrderLine')
var orderLineTable = await db.query('LowCodeDemo.Orders.OrderLine');
var orderLines = await orderLineTable
.join('LowCodeDemo.Products.Product', 'p', (ol, p) => ol.ProductId === p.Id)
.take(10)
.toList();
@ -135,7 +145,8 @@ orderLines.forEach(line => {
### Left Join
```javascript
var orders = await db.query('LowCodeDemo.Orders.Order')
var orderTable = await db.query('LowCodeDemo.Orders.Order');
var orders = await orderTable
.leftJoin('LowCodeDemo.Products.Product', 'p', (o, p) => o.CustomerId === p.Id)
.toList();
@ -149,18 +160,22 @@ orders.forEach(order => {
### LINQ-Style Join
```javascript
db.query('Order')
.join('LowCodeDemo.Products.Product',
o => o.ProductId,
p => p.Id)
var orderTable = await db.query('Order');
await orderTable.join(
'LowCodeDemo.Products.Product',
o => o.ProductId,
p => p.Id
);
```
### Join with Filtered Query
```javascript
var expensiveProducts = db.query('Product').where(p => p.Price > 100);
var productTable = await db.query('Product');
var expensiveProducts = await productTable.where(p => p.Price > 100);
var orders = await db.query('OrderLine')
var orderLineTable = await db.query('OrderLine');
var orders = await orderLineTable
.join(expensiveProducts,
ol => ol.ProductId,
p => p.Id)
@ -179,8 +194,9 @@ Set operations execute at the database level using SQL:
| `except(query)` | `EXCEPT` | Elements in first, not second |
```javascript
var cheap = db.query('Product').where(x => x.Price <= 100);
var popular = db.query('Product').where(x => x.Rating > 4);
var productTable = await db.query('Product');
var cheap = await productTable.where(x => x.Price <= 100);
var popular = await productTable.where(x => x.Rating > 4);
var bestDeals = await cheap.intersect(popular).toList();
var underrated = await cheap.except(popular).toList();
@ -200,15 +216,17 @@ All aggregations execute as SQL statements:
| `groupBy(x => x.Property)` | `GROUP BY ...` | `Promise<GroupResult[]>` |
```javascript
var totalValue = await db.query('Product').sum(x => x.Price);
var avgPrice = await db.query('Product').where(x => x.InStock).average(x => x.Price);
var cheapest = await db.query('Product').min(x => x.Price);
var productTable = await db.query('Product');
var totalValue = await productTable.sum(x => x.Price);
var avgPrice = await (await productTable.where(x => x.InStock)).average(x => x.Price);
var cheapest = await productTable.min(x => x.Price);
```
### GroupBy with Select
```javascript
var grouped = await db.query('Product')
var productTable = await db.query('Product');
var grouped = await productTable
.groupBy(x => x.Category)
.select(g => ({
Category: g.Key,
@ -237,7 +255,8 @@ var grouped = await db.query('Product')
### GroupBy with Items
```javascript
var grouped = await db.query('Product')
var productTable = await db.query('Product');
var grouped = await productTable
.groupBy(x => x.Category)
.select(g => ({
Category: g.Key,
@ -258,11 +277,12 @@ var grouped = await db.query('Product')
Math functions translate to SQL functions (ROUND, FLOOR, CEILING, ABS, etc.):
```javascript
var products = await db.query('Product')
var productTable = await db.query('Product');
var products = await productTable
.where(x => Math.round(x.Price) > 100)
.toList();
var result = await db.query('Product')
var result = await productTable
.where(x => Math.abs(x.Balance) < 10 && Math.floor(x.Rating) >= 4)
.toList();
```
@ -380,7 +400,8 @@ All values are parameterized:
```javascript
var malicious = "'; DROP TABLE Products;--";
// Safely treated as a literal string — no injection
var result = await db.query('Entity').where(x => x.Name.includes(malicious)).count();
var entityTable = await db.query('Entity');
var result = await (await entityTable.where(x => x.Name.includes(malicious))).count();
```
### Blocked Features
@ -397,7 +418,8 @@ if (!context.commandArgs.getValue('Email').includes('@')) {
// Try-catch for safe execution
try {
var products = await db.query('Entity').where(x => x.Price > 0).toList();
var entityTable = await db.query('Entity');
var products = await entityTable.where(x => x.Price > 0).toList();
} catch (error) {
context.log('Query failed: ' + error.message);
}
@ -422,7 +444,8 @@ try {
var productId = context.commandArgs.getValue('ProductId');
var quantity = context.commandArgs.getValue('Quantity');
var product = await db.query('LowCodeDemo.Products.Product')
var productTable = await db.query('LowCodeDemo.Products.Product');
var product = await productTable
.where(x => x.Id === productId)
.first();
@ -435,11 +458,10 @@ context.commandArgs.setValue('TotalAmount', product.Price * quantity);
### Sales Dashboard (Custom Endpoint)
```javascript
var totalOrders = await db.query('LowCodeDemo.Orders.Order').count();
var delivered = await db.query('LowCodeDemo.Orders.Order')
.where(x => x.IsDelivered === true).count();
var revenue = await db.query('LowCodeDemo.Orders.Order')
.where(x => x.IsDelivered === true).sum(x => x.TotalAmount);
var orderTable = await db.query('LowCodeDemo.Orders.Order');
var totalOrders = await orderTable.count();
var delivered = await (await orderTable.where(x => x.IsDelivered === true)).count();
var revenue = await (await orderTable.where(x => x.IsDelivered === true)).sum(x => x.TotalAmount);
return ok({
orders: totalOrders,

Loading…
Cancel
Save