Skip to content

Entity search

Entity search is an explicit per-definition contract. The Configuration API stores a set of field and system-target paths; the Runtime API applies one literal substring term to those paths inside the normal PostgreSQL entity query.

Read the administrative Entity Definition detail:

GET /api/workspace/admin/entity-definitions/{entityDefinitionId}

The response contains:

  • SearchTargets — resolved paths with stable field IDs, keys, display labels, field types, and optional system terminals;
  • SearchMaxPathDepth — the effective transition limit for this installation;
  • SearchMaxTargetsPerDefinition — the effective number of paths accepted for one definition;
  • RowVersion — the concurrency token required by the replace operation.

Entity Definition summaries expose SearchTargetCount. Runtime query options include the special SearchTerm target only when at least one search target is configured. Do not infer availability from a field type or UI label.

Use the search-targets operation:

PUT /api/workspace/admin/entity-definitions/{entityDefinitionId}/search-targets

The request is replace-all. It must include every target that should remain and the latest Entity Definition RowVersion:

{
"SearchTargets": [
{
"Path": [
{ "FieldId": "<title-field-id>" }
]
},
{
"Path": [
{ "FieldId": "<customer-reference-field-id>" },
{ "SystemTarget": 0 }
]
},
{
"Path": [
{ "FieldId": "<lines-table-field-id>" },
{ "FieldId": "<line-note-field-id>" }
]
},
{
"Path": [
{ "SystemTarget": 2 }
]
}
],
"RowVersion": "<current-entity-definition-row-version>"
}

Use field IDs returned by the current definition. FieldKey is also accepted and is resolved relative to the root, related entity, or child table reached by the preceding segment. Never send a display label as a key. If both FieldId and FieldKey are present, they must identify the same field.

SystemTarget is numeric in JSON:

ValueTarget
0Display name
1Number
2Comments
3Attachments

Comments and Attachments are valid only when that feature is enabled on the reached entity. Reference, Inverse reference, and Table fields are intermediate segments. Valid field terminals are String, Text, Address, and File. Address searches FullAddress; File searches the active file name and description.

Each intermediate Reference, Inverse reference, or Table counts as one transition. The terminal does not count. Read SearchMaxPathDepth rather than hard-coding the normal value of three.

The replacement must not contain more than SearchMaxTargetsPerDefinition entries. The normal installation default is 64. Oversized API, YAML, and package-owned configurations are rejected with moltaro.definitions.searchTargets.limit.exceeded.

An empty replacement disables search:

{
"SearchTargets": [],
"RowVersion": "<current-entity-definition-row-version>"
}

The response is the refreshed Entity Definition detail with a new RowVersion. On HTTP 409, read the definition again, merge the intended complete set, and retry with the new token. Never resend a stale replace-all payload blindly.

First read:

GET /api/workspace/entity/{entityIdOrKey}/instances/query/options

When search is available, the options contain a special target whose Reference.Special is 0 (SearchTerm) and whose only operator is 9 (Contains). Copy the installed option rather than guessing enum values.

Send the condition through the ordinary list query:

POST /api/workspace/entity/{entityIdOrKey}/instances/query
{
"Page": 1,
"PageSize": 25,
"ArchiveMode": 0,
"Filter": {
"Operator": 0,
"Conditions": [
{
"Field": { "Special": 0 },
"Operator": 9,
"Values": [
{
"Kind": 0,
"Value": "acme 100%"
}
]
}
]
},
"Sort": null,
"Include": null
}

The same query model is accepted by table bootstrap endpoints. The Web Application’s search URL state is translated to this SearchTerm filter; it is not a separate search service.

If an advanced filter is also present, keep the standalone search as an outer AND: SearchTerm AND (advanced A OR advanced B). This prevents an OR inside the advanced filter from broadening the search term.

  • Normal input is one case-insensitive literal substring containing 3 to 256 trimmed characters.
  • Targets are combined with OR.
  • %, _, and \ are escaped and remain literal characters.
  • #number matches only the exact root-record Number, while #{record-id} matches only the exact root-record Id; they may be shorter than three characters but remain capped at 256 characters.
  • Every related entity hop applies its own record access and archive policy, independently from the root query’s archive mode. Active related records require ordinary view access; archived related records require read-archive access.
  • Field-access rules are applied before text is allowed to match.
  • A related comment or attachment matches only when its Entity owner passes the same lifecycle check plus Comments:View or Attachments:View in the captured query snapshot. Content owned by another provider is excluded.
  • Changes are visible immediately after commit.

Search is not tokenized, stemmed, ranked, or eventually consistent. There is no external index, candidate threshold, rebuild endpoint, queue, or search-storage health state.

When no target is configured, query options omit SearchTerm, table metadata returns FullTextSearchAvailable: false, and a submitted SearchTerm condition fails with moltaro.search.notAvailable. The property name FullTextSearchAvailable remains for API compatibility; it does not indicate that a separate full-text engine exists.

Current exports use strict Entity Definition YAML version 8. The mandatory Security member embeds the Entity’s complete current Security configuration:

Version: 8
Security:
Format: MoltaroSecurityConfiguration
Version: 8
Statements: []
PermissionAssignments: []
Responsibilities: []
InitialAssignmentRules: []
AssignmentRules: []
SearchTargets:
- Path:
- FieldKey: Title
- Path:
- FieldKey: Customer
- SystemTarget: DisplayName

Portable YAML uses stable field keys; import resolves them in the reached entity or child-table scope. Versions 1 through 7 are rejected after the destructive Entity security cutover. There is no compatibility parser and legacy access modes, field rules, assignments, and inheritance are never converted. Re-export the definition as v8 and recreate its Security Statements, Permission Assignments, and Responsibilities explicitly.

Version 8 also carries structured Hierarchy Selector metadata, record-matching profiles, the Entity Manual Order capability, and typed Special: ManualOrder sort targets. The platform-managed backing rank storage is not exported. See Record matching for profile semantics.

Do not generate code or automation that uses:

  • FullTextSearchEnabled;
  • ExcludeFromFullTextSearch;
  • full-text rebuild or reindex endpoints;
  • index-storage paths, readiness checks, or polling for search consistency.

To change search, read the current Entity Definition, replace SearchTargets, then verify runtime query options. For configurator-facing setup, see Record search; for the complete filter tree, see Entity Instance Query.