@fui-org/fui-cli 2.1.4 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -7
- package/dist/fui-qrb1j9jz.js +397 -0
- package/dist/fui.js +1 -1
- package/package.json +1 -1
- package/skills/fui/SKILL.md +143 -38
- package/skills/fui/agents/fui-builder.md +62 -0
- package/skills/fui/agents/fui-tester.md +77 -0
- package/skills/{fui-skill → fui}/assets/projectdefaultstyle.css +489 -489
- package/skills/{fui-skill → fui}/examples/component.vue +162 -162
- package/skills/{fui-skill → fui}/references/INDEX.md +5 -4
- package/skills/{fui-skill → fui}/references/advanced-techniques.md +170 -168
- package/skills/{fui-skill → fui}/references/component-design.md +2 -2
- package/skills/{fui-skill → fui}/references/component-quickref.md +78 -78
- package/skills/{fui-skill → fui}/references/component-table.md +287 -287
- package/skills/{fui-skill → fui}/references/components-dialog.md +191 -191
- package/skills/{fui-skill → fui}/references/components-display.md +141 -141
- package/skills/{fui-skill → fui}/references/components-echart.md +316 -316
- package/skills/{fui-skill → fui}/references/components-input.md +335 -335
- package/skills/{fui-skill → fui}/references/controls-patterns.md +2 -2
- package/skills/{fui-skill → fui}/references/controls-styling-vocabulary.md +173 -173
- package/skills/{fui-skill → fui}/references/db-workflow.md +9 -9
- package/skills/{fui-skill → fui}/references/default-function.md +456 -456
- package/skills/{fui-skill → fui}/references/design-modes.md +57 -57
- package/skills/{fui-skill → fui}/references/echart-templates.md +489 -489
- package/skills/{fui-skill → fui}/references/fastproject.md +99 -99
- package/skills/{fui-skill → fui}/references/fullstack-workflow.md +314 -313
- package/skills/{fui-skill → fui}/references/module-data-patterns.md +117 -117
- package/skills/{fui-skill → fui}/references/module-json-anatomy.md +132 -132
- package/skills/{fui-skill → fui}/references/module-structure.md +144 -144
- package/skills/{fui-skill → fui}/references/new-session.md +1 -2
- package/skills/{fui-skill → fui}/references/pdfmake.md +60 -60
- package/skills/{fui-skill → fui}/references/permission-system.md +1 -1
- package/skills/{fui-skill → fui}/references/platform-architecture.md +269 -269
- package/skills/{fui-skill → fui}/references/project-config.md +303 -303
- package/skills/{fui-skill → fui}/references/project-provisioning.md +4 -4
- package/skills/{fui-skill → fui}/references/script-map.md +262 -262
- package/skills/{fui-skill → fui}/references/sql-clr-functions.md +225 -225
- package/skills/{fui-skill → fui}/references/system-design.md +2 -2
- package/skills/{fui-skill → fui}/references/tapi-permission-patterns.md +156 -156
- package/skills/{fui-skill → fui}/references/tapi-reference.md +474 -474
- package/skills/fui/references/team-run.md +141 -0
- package/skills/fui/references/tools-registry.md +211 -0
- package/skills/{fui-skill → fui}/references/ui-crosswindow-patterns.md +321 -321
- package/skills/{fui-skill → fui}/references/ui-dialog-patterns.md +255 -255
- package/skills/{fui-skill → fui}/references/ui-layout-patterns.md +176 -176
- package/skills/{fui-skill → fui}/references/ui-patterns.md +303 -303
- package/skills/{fui-skill → fui}/references/ui-screenshot-review.md +95 -95
- package/skills/{fui-skill → fui}/references/ui-table-cell-patterns.md +318 -318
- package/skills/{fui-skill → fui}/references/verification.md +11 -11
- package/skills/{fui-skill → fui}/references/watcher-patterns.md +163 -163
- package/skills/{fui-skill → fui}/references/websocket-realtime.md +271 -271
- package/skills/{fui-skill → fui}/scripts/component-3.0.js +2715 -2715
- package/skills/{fui-skill → fui}/scripts/component.js +3147 -3147
- package/skills/{fui-skill → fui}/scripts/componentTable-3.0.js +1038 -1038
- package/skills/{fui-skill → fui}/scripts/componentTable.js +891 -891
- package/skills/{fui-skill → fui}/scripts/defaultfunction-3.0.js +866 -866
- package/skills/{fui-skill → fui}/scripts/defaultfunction.js +1051 -1051
- package/skills/{fui-skill → fui}/scripts/fastproject-3.0.js +870 -870
- package/skills/{fui-skill → fui}/scripts/fastproject.js +828 -828
- package/dist/fui-h4z7zhk2.js +0 -381
- package/skills/fui-skill/SKILL.md +0 -139
- package/skills/fui-skill/references/tools-registry.md +0 -84
- /package/skills/{fui-skill → fui}/assets/projectdefaultstyle-3.0.css +0 -0
- /package/skills/{fui-skill → fui}/design-md/airbnb/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/airbnb/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/airtable/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/airtable/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/apple/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/apple/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/asu/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/asu/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/binance/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/binance/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/bmw/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/bmw/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/bmw-m/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/bmw-m/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/bugatti/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/bugatti/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/cal/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/cal/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/claude/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/claude/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/clay/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/clay/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/clickhouse/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/clickhouse/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/cohere/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/cohere/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/coinbase/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/coinbase/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/composio/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/composio/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/cursor/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/cursor/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/elevenlabs/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/elevenlabs/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/expo/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/expo/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/ferrari/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/ferrari/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/figma/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/figma/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/framer/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/framer/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/fui/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/hashicorp/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/hashicorp/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/ibm/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/ibm/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/intercom/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/intercom/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/kraken/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/kraken/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/lamborghini/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/lamborghini/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/linear.app/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/linear.app/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/lovable/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/lovable/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mastercard/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mastercard/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/meta/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/meta/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/minimax/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/minimax/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mintlify/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mintlify/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/miro/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/miro/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mistral.ai/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mistral.ai/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mongodb/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/mongodb/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/nike/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/nike/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/notion/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/notion/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/nvidia/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/nvidia/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/ollama/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/ollama/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/opencode.ai/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/opencode.ai/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/pinterest/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/pinterest/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/playstation/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/playstation/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/posthog/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/posthog/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/raycast/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/raycast/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/renault/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/renault/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/replicate/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/replicate/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/resend/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/resend/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/revolut/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/revolut/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/runwayml/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/runwayml/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/sanity/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/sanity/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/sentry/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/sentry/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/shopify/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/shopify/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/slack/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/spacex/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/spacex/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/spotify/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/spotify/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/starbucks/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/starbucks/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/stripe/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/stripe/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/supabase/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/supabase/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/superhuman/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/superhuman/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/tesla/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/tesla/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/theverge/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/theverge/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/together.ai/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/together.ai/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/uber/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/uber/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/vercel/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/vercel/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/vodafone/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/vodafone/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/voltagent/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/voltagent/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/warp/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/warp/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/webflow/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/webflow/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/wired/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/wired/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/wise/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/wise/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/x.ai/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/x.ai/README.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/zapier/DESIGN.md +0 -0
- /package/skills/{fui-skill → fui}/design-md/zapier/README.md +0 -0
- /package/skills/{fui-skill → fui}/examples/f-table-patterns.json +0 -0
- /package/skills/{fui-skill → fui}/examples/module-patterns.json +0 -0
- /package/skills/{fui-skill → fui}/examples/project-patterns.json +0 -0
- /package/skills/{fui-skill → fui}/references/coding-standards.md +0 -0
- /package/skills/{fui-skill → fui}/references/db-table-design.md +0 -0
- /package/skills/{fui-skill → fui}/references/fsheet.md +0 -0
- /package/skills/{fui-skill → fui}/references/tapi-file-api.md +0 -0
- /package/skills/{fui-skill → fui}/references/ui-templates.md +0 -0
- /package/skills/{fui-skill → fui}/scripts/fechart.js +0 -0
- /package/skills/{fui-skill → fui}/scripts/fsheet.js +0 -0
|
@@ -1,225 +1,225 @@
|
|
|
1
|
-
# SQL CLR Functions — DLL-backed SQL Server functions
|
|
2
|
-
|
|
3
|
-
> Owns: **SQL CLR functions: httpCall, sendMail, ImageResize, FileReader, RegexMatch...**
|
|
4
|
-
|
|
5
|
-
A project DB may have **SQL CLR scalar functions** (precompiled .NET DLL, registered via `CREATE ASSEMBLY` + `CREATE FUNCTION ... EXTERNAL NAME`). If they appear in `fui schema` or in an existing SP definition, **call them directly in T-SQL** like built-ins — no install, no need to know the C#.
|
|
6
|
-
|
|
7
|
-
A needed function is not in the DB → **do not invent it**; tell the user the DB lacks it.
|
|
8
|
-
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
## 1. `SQLImageHelper` — images
|
|
12
|
-
|
|
13
|
-
### `dbo.ImageResize`
|
|
14
|
-
|
|
15
|
-
```sql
|
|
16
|
-
dbo.ImageResize(@extension nvarchar(10), @OriginalImage varbinary(max), @maxWidth int, @maxHeight int, @preserverAspectRatio bit, @quality int)
|
|
17
|
-
RETURNS varbinary(max)
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
Resizes to at most `@maxWidth` x `@maxHeight`.
|
|
21
|
-
|
|
22
|
-
| Param | Meaning |
|
|
23
|
-
| ------------------------- | ------------------------------------------------------------------------------ |
|
|
24
|
-
| `@extension` | Output format, e.g. `'jpg'`, `'png'` |
|
|
25
|
-
| `@OriginalImage` | Source image `varbinary` |
|
|
26
|
-
| `@maxWidth`, `@maxHeight` | Max size (px) |
|
|
27
|
-
| `@preserverAspectRatio` | `1` = keep ratio, fit longest side; `0` = force exactly `maxWidth`x`maxHeight` |
|
|
28
|
-
| `@quality` | Compression quality (usually 1-100) |
|
|
29
|
-
|
|
30
|
-
Returns resized `varbinary` — write to a `varbinary` column/file or return via tAPI File.
|
|
31
|
-
|
|
32
|
-
### `dbo.ImageCrop`
|
|
33
|
-
|
|
34
|
-
```sql
|
|
35
|
-
dbo.ImageCrop(@OriginalImage varbinary(max), @StartAtX int, @StartAtY int, @Width int, @Height int)
|
|
36
|
-
RETURNS varbinary(max)
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
Crops a `@Width` x `@Height` rectangle starting at `(@StartAtX, @StartAtY)`.
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## 2. `SQLHttpHelper` — HTTP, public value store, mail
|
|
44
|
-
|
|
45
|
-
### `dbo.publicValueUUID` / `publicValueGet` / `publicValueSet`
|
|
46
|
-
|
|
47
|
-
Server-level shared key-value store (not a SQL table) — keeps temp state across SP calls without a table.
|
|
48
|
-
|
|
49
|
-
```sql
|
|
50
|
-
dbo.publicValueUUID() RETURNS nvarchar(max) -- sinh 1 UUID mới, dùng làm key
|
|
51
|
-
dbo.publicValueGet(@name nvarchar(max)) RETURNS nvarchar(max) -- đọc value theo key
|
|
52
|
-
dbo.publicValueSet(@name nvarchar(max), @Data nvarchar(max)) RETURNS int -- ghi value theo key
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### `dbo.httpCall` / `dbo.httpAPI` — HTTP from T-SQL
|
|
56
|
-
|
|
57
|
-
```sql
|
|
58
|
-
dbo.httpCall(@Method nvarchar(max), @URL nvarchar(max), @Header nvarchar(max), @Data nvarchar(max))
|
|
59
|
-
RETURNS nvarchar(max)
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
`httpAPI` has the **identical** signature (different internals): use `httpAPI` for internal tAPI calls, `httpCall` for general outbound HTTP.
|
|
63
|
-
|
|
64
|
-
| Param | Meaning |
|
|
65
|
-
| --------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
|
66
|
-
| `@Method` | `'GET'`, `'POST'`, `'PUT'`, `'DELETE'`... (case-insensitive; empty → `GET`) |
|
|
67
|
-
| `@URL` | Full, valid absolute URL |
|
|
68
|
-
| `@Header` | Header list, syntax below — `''` for none |
|
|
69
|
-
| `@Data` | JSON string body — **sent only when Method is not GET/HEAD**; always `Content-Type: application/json` unless `@Header` overrides |
|
|
70
|
-
|
|
71
|
-
**Example:**
|
|
72
|
-
|
|
73
|
-
```sql
|
|
74
|
-
SELECT dbo.httpCall('POST', 'https://tapi.example.vn/me/auth/ApplicationList', '', '')
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
#### `@Header` syntax — pipe-delimited `Key: Value`
|
|
78
|
-
|
|
79
|
-
Most important part. One string; pairs separated by `|`; each pair `Key: Value`, split on the **first** `:` (the rest, including further `:`, is the value):
|
|
80
|
-
|
|
81
|
-
```
|
|
82
|
-
"Authorization: Bearer eyJhbGciOi...|X-Custom-Header: abc123"
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
Header names are **case-insensitive**; special handling:
|
|
86
|
-
|
|
87
|
-
| Header name | Behavior |
|
|
88
|
-
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
89
|
-
| `Authorization`, `X-*`, any other | Added to request headers as-is (`TryAddWithoutValidation`) — tokens, API keys |
|
|
90
|
-
| `referer` / `referrer` | Parsed to URI → `request.Headers.Referrer` |
|
|
91
|
-
| `user-agent` | Overrides default `User-Agent` |
|
|
92
|
-
| `accept` | Overrides `Accept` |
|
|
93
|
-
| `accept-language` | Overrides `Accept-Language` |
|
|
94
|
-
| `accept-encoding` | Overrides `Accept-Encoding` |
|
|
95
|
-
| `content-type` | With body (Method not GET/HEAD) → `Content.Headers.Content-Type` (overrides default `application/json`); no body → normal request headers |
|
|
96
|
-
| Any other `content-*` | With body → routed to `Content.Headers` instead of request headers |
|
|
97
|
-
|
|
98
|
-
**Bearer token + custom header:**
|
|
99
|
-
|
|
100
|
-
```sql
|
|
101
|
-
SELECT dbo.httpCall(
|
|
102
|
-
'POST',
|
|
103
|
-
'https://api.example.com/data',
|
|
104
|
-
'Authorization: Bearer abc123xyz|Content-Type: application/json; charset=utf-8',
|
|
105
|
-
'{"key":"value"}'
|
|
106
|
-
)
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
**Joining headers:** exactly one `|` between pairs, no extra/missing `|`. A pair without `:` is **silently skipped** (no error).
|
|
110
|
-
|
|
111
|
-
#### `httpCall`/`httpAPI` response
|
|
112
|
-
|
|
113
|
-
- Status **200**: raw response body verbatim (JSON, text, anything).
|
|
114
|
-
- Status **not 200** (400, 401, 404, 500...): wrapped JSON:
|
|
115
|
-
```json
|
|
116
|
-
{ "httpErrorCode": 404, "responseData": "<nội dung body, hoặc escaped string nếu không phải JSON>" }
|
|
117
|
-
```
|
|
118
|
-
→ in SPs, always check for an `httpErrorCode` field to tell error from success.
|
|
119
|
-
- Invalid URL: `{"httpErrorCode":0,"responseData":"Invalid URL"}`.
|
|
120
|
-
- Timeout/other exception: plain-text error message (not JSON) — check the format before `OPENJSON`.
|
|
121
|
-
|
|
122
|
-
### `dbo.sendMail`
|
|
123
|
-
|
|
124
|
-
```sql
|
|
125
|
-
dbo.sendMail(@email_to nvarchar(max), @subject nvarchar(max), @content nvarchar(max), @from nvarchar(max), @fromDisplayName nvarchar(max), @smtp_server nvarchar(max), @smtp_port int, @userName nvarchar(max), @Password nvarchar(max), @EnableSSL bit)
|
|
126
|
-
RETURNS nvarchar(max)
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
Sends email over SMTP from T-SQL.
|
|
130
|
-
|
|
131
|
-
| Param | Meaning |
|
|
132
|
-
| ---------------------------- | ---------------------------------------------------------- |
|
|
133
|
-
| `@email_to` | Recipient |
|
|
134
|
-
| `@subject` | Subject |
|
|
135
|
-
| `@content` | Body (HTML or text) |
|
|
136
|
-
| `@from` | Sender address (must match/be allowed by the SMTP account) |
|
|
137
|
-
| `@fromDisplayName` | Sender display name |
|
|
138
|
-
| `@smtp_server`, `@smtp_port` | e.g. `'smtp.gmail.com'`, `587` |
|
|
139
|
-
| `@userName`, `@Password` | SMTP auth account |
|
|
140
|
-
| `@EnableSSL` | `1` = SSL/TLS (required for Gmail SMTP) |
|
|
141
|
-
|
|
142
|
-
```sql
|
|
143
|
-
SELECT dbo.sendMail('user@example.vn','Tiêu đề','Nội dung','noreply@example.vn','My System','smtp.gmail.com',587,'noreply@example.vn','app-password',1)
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
> **Security:** avoid hardcoding the SMTP `@Password` in the SP — store it via `publicValueSet`/`publicValueGet` or a permission-restricted config table so it is not exposed in the SP definition.
|
|
147
|
-
|
|
148
|
-
---
|
|
149
|
-
|
|
150
|
-
## 3. `SQLFileSystem` — server files
|
|
151
|
-
|
|
152
|
-
```sql
|
|
153
|
-
dbo.FileCreateFolder(@Path nvarchar(max)) RETURNS nvarchar(max)
|
|
154
|
-
dbo.FileReader(@Path nvarchar(max)) RETURNS varbinary(max)
|
|
155
|
-
dbo.FileWriter(@Content varbinary(max), @Path nvarchar(max)) RETURNS nvarchar(max)
|
|
156
|
-
dbo.FileExists(@Path nvarchar(max)) RETURNS bit
|
|
157
|
-
dbo.FileDelete(@Path nvarchar(max)) RETURNS nvarchar(max)
|
|
158
|
-
dbo.FileMove(@SourceFileName nvarchar(max), @DestFileName nvarchar(max)) RETURNS nvarchar(max)
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
Operates on the **SQL Server machine's** filesystem (not the client); `@Path` is an absolute server path. Use when an SP saves output (e.g. `ImageResize` result, exported PDF) to a fixed folder served by tAPI File API or IIS.
|
|
162
|
-
|
|
163
|
-
| Function | Meaning |
|
|
164
|
-
| ------------------ | ------------------------------------------------------------- |
|
|
165
|
-
| `FileCreateFolder` | Creates folder (nested too), returns result message |
|
|
166
|
-
| `FileReader` | Reads whole file as `varbinary` |
|
|
167
|
-
| `FileWriter` | Writes `@Content` (varbinary) to `@Path`, create or overwrite |
|
|
168
|
-
| `FileExists` | Returns `bit` |
|
|
169
|
-
| `FileDelete` | Deletes file |
|
|
170
|
-
| `FileMove` | Moves/renames `@SourceFileName` → `@DestFileName` |
|
|
171
|
-
|
|
172
|
-
> Real server disk: add a permission check in the SP before letting client input drive `FileDelete`/`FileWriter` — same DDL/DML guard principle as `fui exec`.
|
|
173
|
-
|
|
174
|
-
---
|
|
175
|
-
|
|
176
|
-
## 4. `SQLExpansionFunction` — regex & string compare
|
|
177
|
-
|
|
178
|
-
```sql
|
|
179
|
-
dbo.RegexReplace(@Input nvarchar(max), @Pattern nvarchar(1000), @Replacement nvarchar(4000)) RETURNS nvarchar(max)
|
|
180
|
-
dbo.RegexIsMatch(@Input nvarchar(max), @Pattern nvarchar(1000)) RETURNS bit
|
|
181
|
-
dbo.RegexMatch(@Input nvarchar(max), @Pattern nvarchar(1000)) RETURNS nvarchar(max)
|
|
182
|
-
dbo.RegexMatchArray(@Input nvarchar(max), @Pattern nvarchar(1000)) RETURNS nvarchar(max)
|
|
183
|
-
dbo.CompareWord(@String1 nvarchar(max), @String2 nvarchar(max)) RETURNS int
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
| Function | Meaning |
|
|
187
|
-
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
188
|
-
| `RegexReplace` | .NET regex replace — when T-SQL `REPLACE` (literal only) is not enough |
|
|
189
|
-
| `RegexIsMatch` | `bit` match test — validate format (email, phone, codes...) in the SP |
|
|
190
|
-
| `RegexMatch` | **First match** only (`Match.Value`, whole match, no groups); empty if none |
|
|
191
|
-
| `RegexMatchArray` | **All matches with each capture group**, as a **flat JSON object** (not array) — see below |
|
|
192
|
-
| `CompareWord` | Similarity of 2 strings as `int` (likely differing-char count or a score — check the scale with `SELECT dbo.CompareWord('a','b')` if needed) |
|
|
193
|
-
|
|
194
|
-
`@Pattern` is standard .NET regex (`\d`, `\w`, `^$`, groups `()`...), not T-SQL `LIKE`. All 4 regex functions **always** use `IgnoreCase | Multiline | Singleline`: case-insensitive, `^`/`$` per line, `.` matches newlines — cannot be turned off.
|
|
195
|
-
|
|
196
|
-
#### `RegexMatchArray` shape — JSON object, not array
|
|
197
|
-
|
|
198
|
-
Flat object (`{...}`, not `[...]`), keys `"M{m}G{g}"`:
|
|
199
|
-
|
|
200
|
-
- `m` = match index in `@Input`, from 1.
|
|
201
|
-
- `g` = group index **within that match**, from 1: `G1` is always the **whole match** (`Match.Groups[0]`, same as `RegexMatch`); `G2`, `G3`... are the capture groups `(...)` in `@Pattern`, if any.
|
|
202
|
-
- No match → `"{}"`.
|
|
203
|
-
- Values have tab/newline/CR (`\t`, `\n`, `\r`) removed and `"` escaped.
|
|
204
|
-
|
|
205
|
-
`RegexMatchArray('SDT: 0901 - 0902', '(\d{4})')` (one group) returns:
|
|
206
|
-
|
|
207
|
-
```json
|
|
208
|
-
{ "M1G1": "0901", "M1G2": "0901", "M2G1": "0902", "M2G2": "0902" }
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
(G1 = G2 here because the whole match equals the only group; with no groups each match yields only `G1`.)
|
|
212
|
-
|
|
213
|
-
Parsing in T-SQL (it is an object):
|
|
214
|
-
|
|
215
|
-
- `OPENJSON(@result)` still works but returns `key/value/type` rows (one row per key like `"M1G1"`), not one structured row per match.
|
|
216
|
-
- One known match/group: `JSON_VALUE(@result, '$."M1G1"')`.
|
|
217
|
-
- Iterate all: `OPENJSON(@result)` without path, parse the `M{m}G{g}` prefix from `key` to group by match.
|
|
218
|
-
|
|
219
|
-
---
|
|
220
|
-
|
|
221
|
-
## 5. When to use them in SPs
|
|
222
|
-
|
|
223
|
-
- Always confirm the function exists first (`fui schema` filtered to functions, or `SELECT * FROM sys.objects WHERE type='FS'`) — usable only if the assembly was `CREATE ASSEMBLY`'d on that DB. Not every DB has them.
|
|
224
|
-
- Use in `spAPI_*` when needed: external API (`httpCall`), uploaded image processing (`ImageResize`/`ImageCrop`), notification email (`sendMail`), regex validation (`RegexIsMatch`), saving files to server disk (`FileWriter`).
|
|
225
|
-
- JSON `nvarchar(max)` results (`httpCall`, `RegexMatchArray`) → parse with `OPENJSON`/`JSON_VALUE` in T-SQL before returning via tAPI.
|
|
1
|
+
# SQL CLR Functions — DLL-backed SQL Server functions
|
|
2
|
+
|
|
3
|
+
> Owns: **SQL CLR functions: httpCall, sendMail, ImageResize, FileReader, RegexMatch...**
|
|
4
|
+
|
|
5
|
+
A project DB may have **SQL CLR scalar functions** (precompiled .NET DLL, registered via `CREATE ASSEMBLY` + `CREATE FUNCTION ... EXTERNAL NAME`). If they appear in `fui schema` or in an existing SP definition, **call them directly in T-SQL** like built-ins — no install, no need to know the C#.
|
|
6
|
+
|
|
7
|
+
A needed function is not in the DB → **do not invent it**; tell the user the DB lacks it.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 1. `SQLImageHelper` — images
|
|
12
|
+
|
|
13
|
+
### `dbo.ImageResize`
|
|
14
|
+
|
|
15
|
+
```sql
|
|
16
|
+
dbo.ImageResize(@extension nvarchar(10), @OriginalImage varbinary(max), @maxWidth int, @maxHeight int, @preserverAspectRatio bit, @quality int)
|
|
17
|
+
RETURNS varbinary(max)
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Resizes to at most `@maxWidth` x `@maxHeight`.
|
|
21
|
+
|
|
22
|
+
| Param | Meaning |
|
|
23
|
+
| ------------------------- | ------------------------------------------------------------------------------ |
|
|
24
|
+
| `@extension` | Output format, e.g. `'jpg'`, `'png'` |
|
|
25
|
+
| `@OriginalImage` | Source image `varbinary` |
|
|
26
|
+
| `@maxWidth`, `@maxHeight` | Max size (px) |
|
|
27
|
+
| `@preserverAspectRatio` | `1` = keep ratio, fit longest side; `0` = force exactly `maxWidth`x`maxHeight` |
|
|
28
|
+
| `@quality` | Compression quality (usually 1-100) |
|
|
29
|
+
|
|
30
|
+
Returns resized `varbinary` — write to a `varbinary` column/file or return via tAPI File.
|
|
31
|
+
|
|
32
|
+
### `dbo.ImageCrop`
|
|
33
|
+
|
|
34
|
+
```sql
|
|
35
|
+
dbo.ImageCrop(@OriginalImage varbinary(max), @StartAtX int, @StartAtY int, @Width int, @Height int)
|
|
36
|
+
RETURNS varbinary(max)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Crops a `@Width` x `@Height` rectangle starting at `(@StartAtX, @StartAtY)`.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 2. `SQLHttpHelper` — HTTP, public value store, mail
|
|
44
|
+
|
|
45
|
+
### `dbo.publicValueUUID` / `publicValueGet` / `publicValueSet`
|
|
46
|
+
|
|
47
|
+
Server-level shared key-value store (not a SQL table) — keeps temp state across SP calls without a table.
|
|
48
|
+
|
|
49
|
+
```sql
|
|
50
|
+
dbo.publicValueUUID() RETURNS nvarchar(max) -- sinh 1 UUID mới, dùng làm key
|
|
51
|
+
dbo.publicValueGet(@name nvarchar(max)) RETURNS nvarchar(max) -- đọc value theo key
|
|
52
|
+
dbo.publicValueSet(@name nvarchar(max), @Data nvarchar(max)) RETURNS int -- ghi value theo key
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### `dbo.httpCall` / `dbo.httpAPI` — HTTP from T-SQL
|
|
56
|
+
|
|
57
|
+
```sql
|
|
58
|
+
dbo.httpCall(@Method nvarchar(max), @URL nvarchar(max), @Header nvarchar(max), @Data nvarchar(max))
|
|
59
|
+
RETURNS nvarchar(max)
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
`httpAPI` has the **identical** signature (different internals): use `httpAPI` for internal tAPI calls, `httpCall` for general outbound HTTP.
|
|
63
|
+
|
|
64
|
+
| Param | Meaning |
|
|
65
|
+
| --------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
|
66
|
+
| `@Method` | `'GET'`, `'POST'`, `'PUT'`, `'DELETE'`... (case-insensitive; empty → `GET`) |
|
|
67
|
+
| `@URL` | Full, valid absolute URL |
|
|
68
|
+
| `@Header` | Header list, syntax below — `''` for none |
|
|
69
|
+
| `@Data` | JSON string body — **sent only when Method is not GET/HEAD**; always `Content-Type: application/json` unless `@Header` overrides |
|
|
70
|
+
|
|
71
|
+
**Example:**
|
|
72
|
+
|
|
73
|
+
```sql
|
|
74
|
+
SELECT dbo.httpCall('POST', 'https://tapi.example.vn/me/auth/ApplicationList', '', '')
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
#### `@Header` syntax — pipe-delimited `Key: Value`
|
|
78
|
+
|
|
79
|
+
Most important part. One string; pairs separated by `|`; each pair `Key: Value`, split on the **first** `:` (the rest, including further `:`, is the value):
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
"Authorization: Bearer eyJhbGciOi...|X-Custom-Header: abc123"
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Header names are **case-insensitive**; special handling:
|
|
86
|
+
|
|
87
|
+
| Header name | Behavior |
|
|
88
|
+
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
89
|
+
| `Authorization`, `X-*`, any other | Added to request headers as-is (`TryAddWithoutValidation`) — tokens, API keys |
|
|
90
|
+
| `referer` / `referrer` | Parsed to URI → `request.Headers.Referrer` |
|
|
91
|
+
| `user-agent` | Overrides default `User-Agent` |
|
|
92
|
+
| `accept` | Overrides `Accept` |
|
|
93
|
+
| `accept-language` | Overrides `Accept-Language` |
|
|
94
|
+
| `accept-encoding` | Overrides `Accept-Encoding` |
|
|
95
|
+
| `content-type` | With body (Method not GET/HEAD) → `Content.Headers.Content-Type` (overrides default `application/json`); no body → normal request headers |
|
|
96
|
+
| Any other `content-*` | With body → routed to `Content.Headers` instead of request headers |
|
|
97
|
+
|
|
98
|
+
**Bearer token + custom header:**
|
|
99
|
+
|
|
100
|
+
```sql
|
|
101
|
+
SELECT dbo.httpCall(
|
|
102
|
+
'POST',
|
|
103
|
+
'https://api.example.com/data',
|
|
104
|
+
'Authorization: Bearer abc123xyz|Content-Type: application/json; charset=utf-8',
|
|
105
|
+
'{"key":"value"}'
|
|
106
|
+
)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Joining headers:** exactly one `|` between pairs, no extra/missing `|`. A pair without `:` is **silently skipped** (no error).
|
|
110
|
+
|
|
111
|
+
#### `httpCall`/`httpAPI` response
|
|
112
|
+
|
|
113
|
+
- Status **200**: raw response body verbatim (JSON, text, anything).
|
|
114
|
+
- Status **not 200** (400, 401, 404, 500...): wrapped JSON:
|
|
115
|
+
```json
|
|
116
|
+
{ "httpErrorCode": 404, "responseData": "<nội dung body, hoặc escaped string nếu không phải JSON>" }
|
|
117
|
+
```
|
|
118
|
+
→ in SPs, always check for an `httpErrorCode` field to tell error from success.
|
|
119
|
+
- Invalid URL: `{"httpErrorCode":0,"responseData":"Invalid URL"}`.
|
|
120
|
+
- Timeout/other exception: plain-text error message (not JSON) — check the format before `OPENJSON`.
|
|
121
|
+
|
|
122
|
+
### `dbo.sendMail`
|
|
123
|
+
|
|
124
|
+
```sql
|
|
125
|
+
dbo.sendMail(@email_to nvarchar(max), @subject nvarchar(max), @content nvarchar(max), @from nvarchar(max), @fromDisplayName nvarchar(max), @smtp_server nvarchar(max), @smtp_port int, @userName nvarchar(max), @Password nvarchar(max), @EnableSSL bit)
|
|
126
|
+
RETURNS nvarchar(max)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Sends email over SMTP from T-SQL.
|
|
130
|
+
|
|
131
|
+
| Param | Meaning |
|
|
132
|
+
| ---------------------------- | ---------------------------------------------------------- |
|
|
133
|
+
| `@email_to` | Recipient |
|
|
134
|
+
| `@subject` | Subject |
|
|
135
|
+
| `@content` | Body (HTML or text) |
|
|
136
|
+
| `@from` | Sender address (must match/be allowed by the SMTP account) |
|
|
137
|
+
| `@fromDisplayName` | Sender display name |
|
|
138
|
+
| `@smtp_server`, `@smtp_port` | e.g. `'smtp.gmail.com'`, `587` |
|
|
139
|
+
| `@userName`, `@Password` | SMTP auth account |
|
|
140
|
+
| `@EnableSSL` | `1` = SSL/TLS (required for Gmail SMTP) |
|
|
141
|
+
|
|
142
|
+
```sql
|
|
143
|
+
SELECT dbo.sendMail('user@example.vn','Tiêu đề','Nội dung','noreply@example.vn','My System','smtp.gmail.com',587,'noreply@example.vn','app-password',1)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
> **Security:** avoid hardcoding the SMTP `@Password` in the SP — store it via `publicValueSet`/`publicValueGet` or a permission-restricted config table so it is not exposed in the SP definition.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## 3. `SQLFileSystem` — server files
|
|
151
|
+
|
|
152
|
+
```sql
|
|
153
|
+
dbo.FileCreateFolder(@Path nvarchar(max)) RETURNS nvarchar(max)
|
|
154
|
+
dbo.FileReader(@Path nvarchar(max)) RETURNS varbinary(max)
|
|
155
|
+
dbo.FileWriter(@Content varbinary(max), @Path nvarchar(max)) RETURNS nvarchar(max)
|
|
156
|
+
dbo.FileExists(@Path nvarchar(max)) RETURNS bit
|
|
157
|
+
dbo.FileDelete(@Path nvarchar(max)) RETURNS nvarchar(max)
|
|
158
|
+
dbo.FileMove(@SourceFileName nvarchar(max), @DestFileName nvarchar(max)) RETURNS nvarchar(max)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Operates on the **SQL Server machine's** filesystem (not the client); `@Path` is an absolute server path. Use when an SP saves output (e.g. `ImageResize` result, exported PDF) to a fixed folder served by tAPI File API or IIS.
|
|
162
|
+
|
|
163
|
+
| Function | Meaning |
|
|
164
|
+
| ------------------ | ------------------------------------------------------------- |
|
|
165
|
+
| `FileCreateFolder` | Creates folder (nested too), returns result message |
|
|
166
|
+
| `FileReader` | Reads whole file as `varbinary` |
|
|
167
|
+
| `FileWriter` | Writes `@Content` (varbinary) to `@Path`, create or overwrite |
|
|
168
|
+
| `FileExists` | Returns `bit` |
|
|
169
|
+
| `FileDelete` | Deletes file |
|
|
170
|
+
| `FileMove` | Moves/renames `@SourceFileName` → `@DestFileName` |
|
|
171
|
+
|
|
172
|
+
> Real server disk: add a permission check in the SP before letting client input drive `FileDelete`/`FileWriter` — same DDL/DML guard principle as `fui exec`.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## 4. `SQLExpansionFunction` — regex & string compare
|
|
177
|
+
|
|
178
|
+
```sql
|
|
179
|
+
dbo.RegexReplace(@Input nvarchar(max), @Pattern nvarchar(1000), @Replacement nvarchar(4000)) RETURNS nvarchar(max)
|
|
180
|
+
dbo.RegexIsMatch(@Input nvarchar(max), @Pattern nvarchar(1000)) RETURNS bit
|
|
181
|
+
dbo.RegexMatch(@Input nvarchar(max), @Pattern nvarchar(1000)) RETURNS nvarchar(max)
|
|
182
|
+
dbo.RegexMatchArray(@Input nvarchar(max), @Pattern nvarchar(1000)) RETURNS nvarchar(max)
|
|
183
|
+
dbo.CompareWord(@String1 nvarchar(max), @String2 nvarchar(max)) RETURNS int
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
| Function | Meaning |
|
|
187
|
+
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
188
|
+
| `RegexReplace` | .NET regex replace — when T-SQL `REPLACE` (literal only) is not enough |
|
|
189
|
+
| `RegexIsMatch` | `bit` match test — validate format (email, phone, codes...) in the SP |
|
|
190
|
+
| `RegexMatch` | **First match** only (`Match.Value`, whole match, no groups); empty if none |
|
|
191
|
+
| `RegexMatchArray` | **All matches with each capture group**, as a **flat JSON object** (not array) — see below |
|
|
192
|
+
| `CompareWord` | Similarity of 2 strings as `int` (likely differing-char count or a score — check the scale with `SELECT dbo.CompareWord('a','b')` if needed) |
|
|
193
|
+
|
|
194
|
+
`@Pattern` is standard .NET regex (`\d`, `\w`, `^$`, groups `()`...), not T-SQL `LIKE`. All 4 regex functions **always** use `IgnoreCase | Multiline | Singleline`: case-insensitive, `^`/`$` per line, `.` matches newlines — cannot be turned off.
|
|
195
|
+
|
|
196
|
+
#### `RegexMatchArray` shape — JSON object, not array
|
|
197
|
+
|
|
198
|
+
Flat object (`{...}`, not `[...]`), keys `"M{m}G{g}"`:
|
|
199
|
+
|
|
200
|
+
- `m` = match index in `@Input`, from 1.
|
|
201
|
+
- `g` = group index **within that match**, from 1: `G1` is always the **whole match** (`Match.Groups[0]`, same as `RegexMatch`); `G2`, `G3`... are the capture groups `(...)` in `@Pattern`, if any.
|
|
202
|
+
- No match → `"{}"`.
|
|
203
|
+
- Values have tab/newline/CR (`\t`, `\n`, `\r`) removed and `"` escaped.
|
|
204
|
+
|
|
205
|
+
`RegexMatchArray('SDT: 0901 - 0902', '(\d{4})')` (one group) returns:
|
|
206
|
+
|
|
207
|
+
```json
|
|
208
|
+
{ "M1G1": "0901", "M1G2": "0901", "M2G1": "0902", "M2G2": "0902" }
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
(G1 = G2 here because the whole match equals the only group; with no groups each match yields only `G1`.)
|
|
212
|
+
|
|
213
|
+
Parsing in T-SQL (it is an object):
|
|
214
|
+
|
|
215
|
+
- `OPENJSON(@result)` still works but returns `key/value/type` rows (one row per key like `"M1G1"`), not one structured row per match.
|
|
216
|
+
- One known match/group: `JSON_VALUE(@result, '$."M1G1"')`.
|
|
217
|
+
- Iterate all: `OPENJSON(@result)` without path, parse the `M{m}G{g}` prefix from `key` to group by match.
|
|
218
|
+
|
|
219
|
+
---
|
|
220
|
+
|
|
221
|
+
## 5. When to use them in SPs
|
|
222
|
+
|
|
223
|
+
- Always confirm the function exists first (`fui schema` filtered to functions, or `SELECT * FROM sys.objects WHERE type='FS'`) — usable only if the assembly was `CREATE ASSEMBLY`'d on that DB. Not every DB has them.
|
|
224
|
+
- Use in `spAPI_*` when needed: external API (`httpCall`), uploaded image processing (`ImageResize`/`ImageCrop`), notification email (`sendMail`), regex validation (`RegexIsMatch`), saving files to server disk (`FileWriter`).
|
|
225
|
+
- JSON `nvarchar(max)` results (`httpCall`, `RegexMatchArray`) → parse with `OPENJSON`/`JSON_VALUE` in T-SQL before returning via tAPI.
|
|
@@ -36,7 +36,7 @@ Before any module.json:
|
|
|
36
36
|
|
|
37
37
|
1. Tables + PK + FK for **all** entities. Per [db-table-design.md](db-table-design.md): `tbl` + PascalCase, PK `[Entity]ID`, audit `CreateUser/CreateTime/UpdateUser/UpdateTime`.
|
|
38
38
|
2. n-n → junction table (e.g. `tblUserRole`).
|
|
39
|
-
3. **`CREATE TABLE` is run by the developer** — fui
|
|
39
|
+
3. **`CREATE TABLE` is run by the developer** — fui has no guard for it, so do not run it yourself; present DDL for review. Existing tables, gated by data loss: `ALTER TABLE ... ADD` and `DROP CONSTRAINT` run directly; `ALTER COLUMN` needs `--confirm-write`; `DROP COLUMN`/`DROP TABLE`/`SWITCH` hard-blocked.
|
|
40
40
|
4. Design lookup/catalog tables early (shared dropdowns).
|
|
41
41
|
|
|
42
42
|
**Output:** tables + relations, user-confirmed.
|
|
@@ -57,7 +57,7 @@ Each entity → standard set `List/Get/Insert/Update/Delete` + `AUTH_*Options` f
|
|
|
57
57
|
|
|
58
58
|
## Step 4b — Create right DEFINITIONS before any guarded module.json
|
|
59
59
|
|
|
60
|
-
A code exists only as a row in the project's `acc.tblSysRight`/`acc.tblFunction`. `FunctionRight.includes('42')` **does not create** 42; a missing code silently hides the control ([permission-system.md](permission-system.md) §"
|
|
60
|
+
A code exists only as a row in the project's `acc.tblSysRight`/`acc.tblFunction`. `FunctionRight.includes('42')` **does not create** 42; a missing code silently hides the control ([permission-system.md](permission-system.md) §"A right code must EXIST before guarding with it"). Often forgotten: it is not in the project DB, schema, or any workspace file.
|
|
61
61
|
|
|
62
62
|
1. `fui right system list` + `fui right function list` — see what exists (new projects usually empty); writes cache `_db/rights.json` **keyed by `apiName`** for `fui module validate`. Multi-alias → run **per alias**; never reuse one alias's cache for another.
|
|
63
63
|
2. Each Step-0 role → a `SystemRight` level (`fui right system new`, level + note). `9` = Project Admin exists already.
|