@dforge-core/dforge-mcp 0.2.26 → 0.2.27
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/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,24 @@ All notable changes to `@dforge-core/dforge-mcp`. This project uses semver-ish
|
|
|
4
4
|
`0.1.0-rc.N` pre-release tags; the published version is set at publish time via
|
|
5
5
|
the release workflow, so committed `package.json` versions are placeholders.
|
|
6
6
|
|
|
7
|
+
## 0.2.27
|
|
8
|
+
|
|
9
|
+
**`dforge://reference/formulas` told authors that one-hop navigation is synchronous and
|
|
10
|
+
"resolved instantly".** It is not: on the record card and in grids every `[ref].[field]`
|
|
11
|
+
resolves after the initial load. Read at face value, it made a self-referencing
|
|
12
|
+
`toString` — `[parent].[name]` behind a `{display_path}` placeholder — look safe, and in
|
|
13
|
+
platform builds before dForge-core#1247 that pattern froze the browser. The reference now
|
|
14
|
+
states the real rule, and the sync/async section says which is which.
|
|
15
|
+
|
|
16
|
+
- **Text `+` with a NULL side gives NULL**, on the card and in reports alike — documented,
|
|
17
|
+
with `COALESCE` / `IF` for a part that may be missing. The platform's client used to join
|
|
18
|
+
the NULL as empty text while SQL returned NULL; dForge-core#1247 made them agree.
|
|
19
|
+
- **New "Computed toString" example.** A `toString` placeholder may name a formula column,
|
|
20
|
+
and it now renders everywhere the display does. Evaluated for the `toString`, text `+`
|
|
21
|
+
joins a NULL side as empty text so a caption never goes blank — which is why the
|
|
22
|
+
hierarchy-path example tests the parent with `IF`, not `COALESCE(a + b, c)`.
|
|
23
|
+
- `dforge-module-build` points from its `toString` rule to that example.
|
|
24
|
+
|
|
7
25
|
## 0.2.26
|
|
8
26
|
|
|
9
27
|
`logic/stored_procedures.json` is now something this server can describe. It had no
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dforge-core/dforge-mcp",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.27",
|
|
4
4
|
"description": "MCP server for dForge module authoring. Exposes 34 scaffold/patch/validate/pack/install tools and schema resources so AI agents (Claude Code, Cursor, Zed) can create and ship dForge modules.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/iash44/dForge-core",
|
|
@@ -44,6 +44,13 @@ so `IF([completed_date] != null, 100, 0)` gives the same result on the record ca
|
|
|
44
44
|
a report. At SQL time `=` / `!=` translate to `IS NOT DISTINCT FROM` / `IS DISTINCT FROM`
|
|
45
45
|
to preserve that.
|
|
46
46
|
|
|
47
|
+
**Text `+` with a NULL side gives NULL**, on the record card and in a report alike:
|
|
48
|
+
`[first_name] + ' ' + [last_name]` is NULL when either name is missing. Wrap a part that may
|
|
49
|
+
be missing — `[first_name] + ' ' + COALESCE([last_name], '')` — or test for it with `IF`.
|
|
50
|
+
The one exception is a formula evaluated for an entity's `toString` (see
|
|
51
|
+
[Computed toString](#computed-tostring)), where a NULL side joins as empty text so a caption
|
|
52
|
+
never goes blank.
|
|
53
|
+
|
|
47
54
|
## Examples
|
|
48
55
|
|
|
49
56
|
```
|
|
@@ -205,7 +212,7 @@ and the JSON shape: `column-types.md` → "Roll-up totals over child rows — us
|
|
|
205
212
|
[account].[primary_contact].[phone] -- chained
|
|
206
213
|
```
|
|
207
214
|
|
|
208
|
-
Navigation works through `columnType: "R"` columns (reference columns) — every step except the last must be a Reference, and the last reads a field on the final referenced record.
|
|
215
|
+
Navigation works through `columnType: "R"` columns (reference columns) — every step except the last must be a Reference, and the last reads a field on the final referenced record. On the record card and in grids, any navigation — one hop or several — is **asynchronous**: the engine resolves it after the initial data load, from the referenced rows it loads alongside. A formula may navigate back into its own entity (`[parent].[name]` on a self-reference); a formula that reads itself round a loop, directly or through other records, comes back NULL.
|
|
209
216
|
|
|
210
217
|
**SQL-time (reports, filters, sorts).** Multi-hop navigation works here too: QueryBuilder pre-scans the formula and registers one `LEFT JOIN` per hop, then the translator resolves the path against the final alias. A nav path may also land on a *formula* column of the referenced entity — that formula is translated against the referenced entity's alias, and its own hops are joined off that alias. The same nav map drives formula columns in filters and ORDER BY, so filtering and sorting a report by a nav-formula column works.
|
|
211
218
|
|
|
@@ -222,8 +229,10 @@ Warning wording follows the clause, because the same unresolvable path costs a d
|
|
|
222
229
|
|
|
223
230
|
## Sync vs async formulas
|
|
224
231
|
|
|
225
|
-
- **Sync formula**:
|
|
226
|
-
- **Async formula**:
|
|
232
|
+
- **Sync formula**: no navigation — fields of the same record only. Evaluated on load and on every edit to a dependency.
|
|
233
|
+
- **Async formula**: any navigation (`[ref].[field]`). Evaluated after the initial data load, re-evaluated when a dependency changes — as is every formula that reads it.
|
|
234
|
+
|
|
235
|
+
At SQL time (reports, filters, sorts, reference display) both kinds are translated to SQL, navigation as `LEFT JOIN`s.
|
|
227
236
|
|
|
228
237
|
You don't declare which is which — the engine detects it from the formula's AST.
|
|
229
238
|
|
|
@@ -263,6 +272,32 @@ The constraint's `message` (the violation text shown to users) is **localizable*
|
|
|
263
272
|
}
|
|
264
273
|
```
|
|
265
274
|
|
|
275
|
+
### Computed toString
|
|
276
|
+
|
|
277
|
+
A `toString` placeholder may name a formula column — the way to build a display from more
|
|
278
|
+
than plain fields, e.g. a hierarchy path:
|
|
279
|
+
|
|
280
|
+
```json
|
|
281
|
+
"toString": "{display_path}",
|
|
282
|
+
"fields": {
|
|
283
|
+
"display_path": {
|
|
284
|
+
"columnType": "F",
|
|
285
|
+
"fieldTypeCd": "text",
|
|
286
|
+
"baseDatatypeCd": "string",
|
|
287
|
+
"flags": "V",
|
|
288
|
+
"formula": "IF([parent_id] = null, [name], [parent].[name] + ' / ' + [name])",
|
|
289
|
+
"description": "Display Path"
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
The formula renders wherever the `toString` does — form caption, reference cells, pickers —
|
|
295
|
+
on the client and in SQL alike. Evaluated for the `toString`, text `+` joins a NULL side as
|
|
296
|
+
empty text, so the caption never goes blank; the same column in a grid or report keeps
|
|
297
|
+
NULL. Test for a missing parent with `IF`, not `COALESCE(a + b, c)`: in the caption `a + b`
|
|
298
|
+
is not NULL when one part is missing, so the fallback never applies. The path is one level
|
|
299
|
+
deep — `[parent].[name]` reads the parent's plain name.
|
|
300
|
+
|
|
266
301
|
### Line total (quantity × price)
|
|
267
302
|
|
|
268
303
|
```json
|
|
@@ -80,6 +80,8 @@ Enough to author inline; load the linked reference for the full detail.
|
|
|
80
80
|
`created_by`/`last_updated_by` with no default — a seeded `audit-full` entity
|
|
81
81
|
must set both to `0` in every record, or use plain `audit`. → `traits`
|
|
82
82
|
- **`toString`** on every entity, `{column}` braces: `"{first_name} {last_name}"`.
|
|
83
|
+
A computed display (a hierarchy path) goes in a formula column named as the
|
|
84
|
+
placeholder. → `formulas` (Computed toString)
|
|
83
85
|
- **Data views:** `dataSources` array at root — never a root-level `entityCode` +
|
|
84
86
|
`columns`. Sort is `"order": ["-col", "col"]`. → `data-views`
|
|
85
87
|
- **Menus:** leaf items use `dataViewCode` (not `viewCode`); section nodes omit
|