predicates — search & criteria condition semantics
cyoda-go version 0.8.3
predicates
Section titled “predicates”predicates — operator catalog and evaluation semantics for the Condition DSL used by search (cyoda help search) and workflow/transition criteria (cyoda help workflows). Both consume the same kernel, so everything here applies identically to both.
OPERATORS
Section titled “OPERATORS”Unary (test presence, no operand type constraint):
IS_NULL— the leaf is absent or JSONnull.NOT_NULL— the leaf is present and non-null.
Range (operand is a two-element [low, high] array):
BETWEEN— exclusive bounds.BETWEEN_INCLUSIVE— inclusive bounds.
Binary — comparison (same-type compareTo):
EQUALS,NOT_EQUAL,GREATER_THAN,GREATER_OR_EQUAL,LESS_THAN,LESS_OR_EQUAL.IEQUALS(case-insensitive equals),INOT_EQUAL(case-insensitive not-equal).
Binary — string (case-sensitive; I*/INOT_* fold both sides):
CONTAINS,STARTS_WITH,ENDS_WITH, and theirNOT_*inverses.ICONTAINS/INOT_CONTAINS,ISTARTS_WITH/INOT_STARTS_WITH,IENDS_WITH/INOT_ENDS_WITH.
Binary — pattern:
LIKE— anchored glob, see LIKE GRAMMAR below.MATCHES_PATTERN— anchored regular expression, see MATCHES_PATTERN below.
Not supported: IS_CHANGED/IS_UNCHANGED are change-generation operators, not search predicates — cyoda-go does not implement them.
TYPE-DIRECTED COMPARISON
Section titled “TYPE-DIRECTED COMPARISON”A condition’s operand is compared against the target field’s declared type(s) (a leaf may carry more than one, e.g. a field seen as both an integer and a string across entities). The operand is treated as a string and parse-tested against every declared type — a numeric-looking string operand ("30") and a JSON number operand (30) are parsed identically and are treated the same. There is no cross-type coincidental matching: an operand that parses as a number only compares against numerically-stored values; an operand that parses only as a string compares against string-stored values. Numbers compare precisely (arbitrary-precision, not float64 — correct beyond 2^53). Comparing against MATCHES_PATTERN/LIKE and string ops evaluate against textual stored values only; a string op against a non-textual stored value is a non-match, not an error.
NULL SEMANTICS
Section titled “NULL SEMANTICS”A missing (absent) or JSON-null leaf never matches any binary operator — including negatives. NOT_EQUAL, NOT_CONTAINS, INOT_*, and every other negated op are null-guarded to non-match, not !positive — a null/absent field does not satisfy a negative condition just because it fails the positive one. IS_NULL / NOT_NULL are the only operators that test presence directly.
LIKE GRAMMAR
Section titled “LIKE GRAMMAR”LIKE compiles its operand to an anchored regular expression:
%— matches any sequence of characters (including empty)._— matches exactly one character.\— escapes a following%,_, or\to its literal form.- The match is whole-string anchored (the entire stored value must match, not a substring) and case-sensitive.
MATCHES_PATTERN
Section titled “MATCHES_PATTERN”MATCHES_PATTERN compiles the operand as a Go RE2 regular expression, whole-string anchored (equivalent to Java’s Pattern.matches), case-sensitive. RE2 and the Java regex dialect diverge on some constructs (e.g. backreferences, some lookaround); this is an accepted, bounded divergence — not reconciled.
VALIDATION
Section titled “VALIDATION”Validation is parse-based, evaluated at request time against the target model:
400 CONDITION_TYPE_MISMATCH— the operand parses into none of the field’s declared types (comparison and range operators only; string operators and unary presence tests carry no operand-type constraint and are always accepted).400 INVALID_FIELD_PATH— the field path is unknown to the model, or it names a pure-container (object) path: a scalar operator cannot compare against structure — navigate to a scalar leaf sub-path instead. (A path observed as both an object and a scalar across entities remains searchable via its scalar type — seecyoda help search.)IS_NULL/NOT_NULLare exempt from the container-path rejection since they test presence, not a value.400 INVALID_CONDITION— the operand isnullon a binary/range operator, a range operator’s value is not a two-element array, or the operand is an object/complex value.
There is no operator-versus-field-type rejection: CONTAINS on a numeric field or GREATER_THAN on a boolean field are accepted requests — they parse and simply evaluate to a (non-)match.
SEE ALSO
Section titled “SEE ALSO”- search
- workflows
- errors.CONDITION_TYPE_MISMATCH
- errors.INVALID_FIELD_PATH
- errors.INVALID_CONDITION
See also
Section titled “See also”cyoda help search— Search operates against a specific entity model(entityName, modelVersion). Two modes are supported:cyoda help workflows— A workflow definition is a named finite state machine attached to an entity model. Workflows are stored per model reference(entityName, modelVersion). A model may have multiple workflow definitions; the engine selects the matching one per entity using the workflow-levelcriterionfield evaluated at entity creation time. When nocriterionmatches, the engine uses the default built-in workflow.cyoda help errors CONDITION_TYPE_MISMATCH— Validation is parse-based: a comparison or range operand is rejected only when it parses into none of the field’s declared DataTypes. For example"abc"against a DOUBLE field is rejected — it is not a number. A numeric-looking string against a polymorphic[INTEGER, STRING]field is accepted (it parses as STRING).cyoda help errors INVALID_FIELD_PATH— Before executing a search, the server validates that every data-field path referenced by the condition (e.g.$.price,$.profile.email) resolves against the target model’s locked schema. Lifecycle paths (state,previousTransition, etc.) and meta paths ($._meta.*) bypass this check.cyoda help errors INVALID_CONDITION— Endpoints that accept a search-style condition in the request body — grouped statistics and the conditional form of delete-by-model — reject a body whose condition cannot be parsed or is otherwise structurally invalid. The condition type is unrecognised, a nested clause is malformed, the JSON does not match the expected condition envelope, anoperatorTypeis not one of the canonical operators, aMATCHES_PATTERNregex is malformed, or aBETWEEN/BETWEEN_INCLUSIVEoperator’s value is not a two-element array.
Raw formats
Section titled “Raw formats”/help/predicates.json— full descriptor (matchesGET /help/{topic}envelope)/help/predicates.md— body only