Search Grammar
Type like you think. The search understands.
JinDesk search bar accepts a progressive grammar — beginners type words, experts type expressions, both get results.
Six Levels of Syntax
Section titled “Six Levels of Syntax”Level 1 — Just type
Section titled “Level 1 — Just type”The simplest case: type any words. Each word is matched as a word-start — the term must appear at the start of a word in one of the visible columns (a word ends at a space, underscore, hyphen, or dot). Multiple words become AND filters. Double-quote an exact phrase.
paracetamol → any word starts with "paracetamol"hip replacement → AND of two word-start matches"Scalpel Blade" → the phrase at a word boundaryIf you want “contains anywhere” (not just word-start), use ~ — see Level 3.
Level 2 — Operators
Section titled “Level 2 — Operators”Comparisons on numeric and date columns. Ranges with ...
>1000 → any numeric column > 1000<50 → any numeric column < 50100..500 → any numeric column between 100 and 5002025-01..2025-06 → any date column in this range>=high → ordinal: low < medium < highRanges also work for dates at month granularity (2025-01..2025-06), day granularity (2025-04-01..2025-04-30), or mixed.
Level 3 — Match operators
Section titled “Level 3 — Match operators”Three prefixes control how a term matches:
| Prefix | Meaning |
|---|---|
| (none) | word-starts-with (default) |
= | exact match |
~ | regex — also how you do “contains anywhere” |
Applies both to bare terms and to field-qualified ones (next level):
ortho → any word starts with "ortho"=ortho → exactly "ortho"~ortho → regex / contains "ortho" anywhere~^ortho → regex anchored to column startLevel 4 — Field-specific filters
Section titled “Level 4 — Field-specific filters”Scope a match to a single column with !field:value. The three prefixes above apply here too:
!amount:>1000 → amount column > 1000!date:2025-01..2025-06 → date in range!material_id:630664 → word-start on material_id!material_id:=630664 → exact match!name:~hip|knee → regex on name column!status:null → IS NULL-!status:null → IS NOT NULL (negation; there is no separate "not_null" syntax)!is_active:true → booleanField filters compose naturally — use them for one column, leave plain words for the rest.
Level 5 — Logic
Section titled “Level 5 — Logic”Combine terms with OR, exclude with -, group with parentheses.
hip OR knee → either term matcheship | knee → shorthand for OR-consumable → NOT: exclude rows matching "consumable"!cat:ortho -!s:pending → ortho category, NOT pending statuship (ortho | cardiac) → hip AND (ortho OR cardiac)Whitespace between terms is AND. OR / | between terms is OR. - in front of a term (or -!field:value) negates it.
Level 6 — Smart date tokens
Section titled “Level 6 — Smart date tokens”Natural dates that expand to real date ranges against any date column. this-* tokens use the full calendar period (not “up to today”) so the result stays the same whether you ask on the 1st or the 30th of the month.
yesterday → yesterday's date (one day)today → today (one day)tomorrow → tomorrow (one day)
last-7d → last 7 days, ending todaylast-30d → last 30 days, ending todaynext-7d → next 7 days, starting todaynext-30d → next 30 days, starting todaylast-Nd / next-Nd → any N works
last-week → full previous weekthis-week → full current weeknext-week → full following week
last-month → full previous calendar monththis-month → full current calendar monthnext-month → full following calendar month
last-year → full previous calendar yearthis-year → full current calendar yearnext-year → full following calendar year
last-week-3 → the week that was 3 weeks agonext-week-2 → the week 2 weeks from nowlast-month-12 → the month 12 months agonext-year-5 → the year 5 years from nowThe stepped forms (last-week-N, last-month-N, last-year-N and their next- counterparts) give you any offset without reaching for literal dates. Three handy identities: last-week-1 ≡ last-week; last-week-0 ≡ this-week; a “trailing 12 months” window is simply last-month-12..last-month-1.
The next-* family lands squarely on future dates — useful for columns that store intent (material expiration, contract end, scheduled admission, warranty boundary).
Week boundaries follow display.search.week_start (default: Monday, per ISO 8601 / DACH convention). Set it to sunday in config.yml if you want calendar-week semantics instead.
Smart date tokens also compose inside ranges — either or both sides of .. can be a token:
last-year..this-year → start of last year to end of this yeartoday..next-week → today through end of next weekthis-week..today → Monday of this week through todaylast-month..2026-06-30 → full previous month through that literal dateThe left side of the range uses the token’s start; the right side uses its end. Everything else the range accepts (ISO dates, pure numbers) still works on either side.
Range bounds are order-agnostic. 500..100 means the same as 100..500; next-year..last-year means the same as last-year..next-year. The parser / SQL layer always binds the interval as (min, max), so misordered bounds never silently return zero rows.
Period + day truncation (the useful special case). When a period token (this-month, this-year, etc.) is combined with a single-day token (today), the range uses the period’s inner edge, giving you the common month-to-date / year-to-date / week-to-date idioms:
this-month..today → 1st of this month through today (MTD)this-year..today → Jan 1 through today (YTD)this-week..today → Monday of this week through today (WTD)today..this-week → today through Sunday of this weekUnder the hood: the left bound contributes its .start, the right bound contributes its .end. If that produces a reversed pair (e.g. next-year..last-year), the parser falls back to the union of both spans — so order-agnostic symmetry still holds for reversed inputs.
Open ranges. Leave one side blank to make the range unbounded on that side — X.. means “from X onwards,” ..Y means “up to and including Y.” Works for numbers, ISO dates, and smart date tokens:
100.. → any numeric column >= 100..500 → any numeric column <= 500today.. → from today onwards (today or later)..next-month → up to the end of next monthlast-year.. → from Jan 1 of last year onwards!expires:today..next-month → anything expiring between now and end of next month!shipped:..yesterday → everything shipped before todayOpen ranges are often what you actually want for expiration, renewal, or shipment-date filters. last-year..this-year gives you a fixed 2-year window; last-year.. keeps rolling forward forever as time passes.
Parsing Rules
Section titled “Parsing Rules”- Whitespace splits terms (AND by default).
- Quoted strings are single terms:
"hip replacement". ORor|between terms creates an OR group.-prefix negates:-term,-!field:value.!field:valueis a field filter.>,<,>=,<=before a number = comparison.N..M= range (numeric or date).- Smart tokens (
today,this-month,last-7d) expand to date ranges. - Parentheses group OR expressions:
(a | b) c. - Backslash escapes let you embed spaces, quotes, or parens in an unquoted value:
!name:hip\ replacement,!note:\"quoted\".\d,\.,\[etc. pass through unchanged so regex patterns work.
Finding help while you type
Section titled “Finding help while you type”Every search bar has an ⓘ button on the right. Click it for a compact quick-reference of the grammar — Basic / Operators / Field filters / Numbers / Logic / Dates — with a single literal example per row. Press ESC or click outside to close.
The URL updates when you press Enter or when the input loses focus. Typing itself is purely local — no re-render mid-keystroke.
Worked Examples
Section titled “Worked Examples”Filter 68,000 cases down to what you care about
Section titled “Filter 68,000 cases down to what you care about”“High-severity materials over CHF 1,000 from last year”
!severity:=high !price:>1000 !date:2025-01..2025-12Three field filters composed with implicit AND. One input, one query.
Find all ortho or cardiac cases that are not pending
Section titled “Find all ortho or cardiac cases that are not pending”!cat:=ortho | !cat:=cardiac -!status:=pendingOR at the top level, then a negated exact field filter.
Find expensive recent findings
Section titled “Find expensive recent findings”CHF >10000 last-30dShorthand + smart token. Works in finding views where CHF maps to money_at_risk.
Pin a specific material
Section titled “Pin a specific material”=635465Exact match across all visible columns — any column whose value equals 635465 matches.
Configuring the word-boundary set
Section titled “Configuring the word-boundary set”Per tenant, in config.yml:
display: search: case_sensitive: false # default word_separators: " _-." # chars that start a new "word" week_start: monday # `monday` (default) or `sunday`Tighten the separator set for stricter word-start matching; widen it to find substrings inside more identifier shapes. week_start changes what last-week / this-week / next-week consider a “week.”
Related
Section titled “Related”- JinDesk Guide — where search lives in the UI