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

Loading…
Cancel
Save