From fcc9acc82963830eb46f70ae24f4c80655fd48cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?SAL=C4=B0H=20=C3=96ZKARA?= Date: Thu, 5 Mar 2026 15:51:41 +0300 Subject: [PATCH] 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. --- docs/en/low-code/custom-endpoints.md | 4 +- docs/en/low-code/scripting-api.md | 94 +++++++++++++++++----------- 2 files changed, 60 insertions(+), 38 deletions(-) diff --git a/docs/en/low-code/custom-endpoints.md b/docs/en/low-code/custom-endpoints.md index ad0057df70..b3af587707 100644 --- a/docs/en/low-code/custom-endpoints.md +++ b/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 })));" } ``` diff --git a/docs/en/low-code/scripting-api.md b/docs/en/low-code/scripting-api.md index a08b1107ec..5cd790b7aa 100644 --- a/docs/en/low-code/scripting-api.md +++ b/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` | | `isEmpty()` | Check if no results | `Promise` | | `isSingle()` | Check if exactly one result | `Promise` | -| `first()` / `firstOrDefault()` | Return first match or null | `Promise` | -| `last()` / `lastOrDefault()` | Return last match or null | `Promise` | -| `single()` / `singleOrDefault()` | Return single match or null | `Promise` | +| `first()` | Return first match, throws if empty | `Promise` | +| `firstOrDefault()` | Return first match or null | `Promise` | +| `last()` | Return last match, throws if empty | `Promise` | +| `lastOrDefault()` | Return last match or null | `Promise` | +| `single()` | Return single match, throws if empty/multiple | `Promise` | +| `singleOrDefault()` | Return single match or null (throws if multiple) | `Promise` | | `elementAt(index)` | Return element at index | `Promise` | | `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` | ```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,