Predicates
Predicates are the building blocks for filtering in TypeGraph queries. Each data type has its own set of predicates optimized for that type.
How Predicates Work
Section titled “How Predicates Work”Predicates are accessed through property accessors in whereNode() and whereEdge():
.whereNode("p", (p) => p.name.eq("Alice"))// ^accessor ^predicateThe accessor provides type-safe access to the field, and returns a predicate builder with methods appropriate for that field’s type. Edge fields work the same way:
.whereEdge("e", (e) => e.role.eq("admin"))Predicate Types
Section titled “Predicate Types”| Type | Predicates | Section |
|---|---|---|
| All types | eq, neq, in, notIn, isNull, isNotNull | Common |
| String | contains, startsWith, endsWith, like, ilike | String |
| Number | gt, gte, lt, lte, between | Number |
| Boolean | (common only) | Boolean |
| Date | gt, gte, lt, lte, between | Date |
| Array | contains, containsAll, containsAny, isEmpty, isNotEmpty, lengthEq/Gt/Gte/Lt/Lte | Array |
| Object | get, field, hasKey, hasPath, pathEquals, pathContains, pathIsNull, pathIsNotNull | Object |
| Embedding | similarTo | Embedding |
| Subquery | exists, notExists, inSubquery, notInSubquery | Subqueries |
Combining Predicates
Section titled “Combining Predicates”All predicates can be combined using logical operators:
p.status.eq("active").and(p.role.eq("admin"))p.role.eq("admin").or(p.role.eq("moderator"))p.status.eq("deleted").not()Complex Combinations
Section titled “Complex Combinations”p.status .eq("active") .and(p.role.eq("admin").or(p.role.eq("moderator")))Parenthesization is handled automatically. Vector similarity predicates cannot be nested under
OR or NOT.
Common Predicates
Section titled “Common Predicates”These predicates are available on all field types:
| Predicate | Description | SQL |
|---|---|---|
eq(value) | Equals | = value |
neq(value) | Not equals | != value |
in(values[]) | Value is in array | IN (...) |
notIn(values[]) | Value is not in array | NOT IN (...) |
isNull() | Is null/undefined | IS NULL |
isNotNull() | Is not null | IS NOT NULL |
eq and neq accept param() references for prepared queries.
in and notIn do not support param() because the array length must be known at compile time.
String
Section titled “String”String predicates for text matching and pattern searches.
Equality
Section titled “Equality”p.name.eq("Alice") // Exact matchp.name.neq("Bob") // Not equalSubstring Match
Section titled “Substring Match”p.name.contains("ali") // Case-insensitive substring matchPrefix/Suffix
Section titled “Prefix/Suffix”p.name.startsWith("A") // Case-insensitive prefix matchp.name.endsWith("ice") // Case-insensitive suffix matchPattern Matching
Section titled “Pattern Matching”p.email.like("%@example.com") // SQL LIKE (case-sensitive) — % = any chars, _ = single charp.name.ilike("alice%") // Case-insensitive LIKEList Membership
Section titled “List Membership”p.status.in(["active", "pending"])p.status.notIn(["archived", "deleted"])Null Checks
Section titled “Null Checks”p.email.isNull()p.email.isNotNull()Reference
Section titled “Reference”| Predicate | Accepts | Description | SQL | Case |
|---|---|---|---|---|
eq(value) | string | param() | Exact match | = | sensitive |
neq(value) | string | param() | Not equal | != | sensitive |
contains(str) | string | param() | Substring match | ILIKE '%str%' | insensitive |
startsWith(str) | string | param() | Prefix match | ILIKE 'str%' | insensitive |
endsWith(str) | string | param() | Suffix match | ILIKE '%str' | insensitive |
like(pattern) | string | param() | SQL LIKE pattern | LIKE | sensitive |
ilike(pattern) | string | param() | Case-insensitive LIKE | ILIKE | insensitive |
in(values[]) | string[] | In array | IN (...) | sensitive |
notIn(values[]) | string[] | Not in array | NOT IN (...) | sensitive |
isNull() | — | Is null | IS NULL | — |
isNotNull() | — | Is not null | IS NOT NULL | — |
Wildcard escaping: User input passed to
contains,startsWith, andendsWithis automatically escaped —%and_characters are treated as literals. Uselikeorilikewhen you need wildcard control.
Number
Section titled “Number”Number predicates for numeric comparisons and ranges.
Equality
Section titled “Equality”p.age.eq(30)p.age.neq(0)Comparisons
Section titled “Comparisons”p.salary.gt(50000) // Greater thanp.salary.gte(50000) // Greater than or equalp.age.lt(65) // Less thanp.age.lte(65) // Less than or equalp.age.between(18, 65) // Inclusive on both boundsList Membership
Section titled “List Membership”p.priority.in([1, 2, 3])p.priority.notIn([0])Null Checks
Section titled “Null Checks”p.score.isNull()p.score.isNotNull()Reference
Section titled “Reference”| Predicate | Accepts | Description | SQL |
|---|---|---|---|
eq(value) | number | param() | Equals | = |
neq(value) | number | param() | Not equals | != |
gt(value) | number | param() | Greater than | > |
gte(value) | number | param() | Greater than or equal | >= |
lt(value) | number | param() | Less than | < |
lte(value) | number | param() | Less than or equal | <= |
between(lo, hi) | number | param() | Inclusive range | BETWEEN lo AND hi |
in(values[]) | number[] | In array | IN (...) |
notIn(values[]) | number[] | Not in array | NOT IN (...) |
isNull() | — | Is null | IS NULL |
isNotNull() | — | Is not null | IS NOT NULL |
Boolean
Section titled “Boolean”Boolean fields support only the common predicates:
p.isActive.eq(true)p.isActive.neq(false)p.isVerified.isNull()p.role.in(["admin", "moderator"]) // works on string enums tooNo additional boolean-specific predicates are provided — eq(true) and eq(false) cover the
typical cases.
Date predicates for temporal comparisons. Accepts Date objects or ISO 8601 strings.
Equality
Section titled “Equality”p.createdAt.eq("2024-01-01")p.createdAt.neq(new Date("2024-01-01"))Comparisons
Section titled “Comparisons”p.createdAt.gt("2024-01-01") // Afterp.createdAt.gte("2024-01-01") // On or afterp.createdAt.lt(new Date()) // Before nowp.createdAt.lte("2024-12-31") // On or beforep.createdAt.between("2024-01-01", "2024-12-31")List Membership
Section titled “List Membership”p.birthday.in(["2024-01-01", "2024-07-04"])Null Checks
Section titled “Null Checks”p.deletedAt.isNull()p.verifiedAt.isNotNull()Reference
Section titled “Reference”| Predicate | Accepts | Description | SQL |
|---|---|---|---|
eq(value) | Date | string | param() | Equals | = |
neq(value) | Date | string | param() | Not equals | != |
gt(value) | Date | string | param() | After | > |
gte(value) | Date | string | param() | On or after | >= |
lt(value) | Date | string | param() | Before | < |
lte(value) | Date | string | param() | On or before | <= |
between(lo, hi) | Date | string | param() | Inclusive range | BETWEEN lo AND hi |
in(values[]) | (Date | string)[] | In array | IN (...) |
notIn(values[]) | (Date | string)[] | Not in array | NOT IN (...) |
isNull() | — | Is null | IS NULL |
isNotNull() | — | Is not null | IS NOT NULL |
Array predicates for fields that contain arrays (e.g., tags: z.array(z.string())).
Containment
Section titled “Containment”p.tags.contains("typescript") // Has specific valuep.tags.containsAll(["typescript", "nodejs"]) // Has ALL valuesp.tags.containsAny(["typescript", "rust"]) // Has ANY valueContainment predicates (contains, containsAll, containsAny) are only available when the
array element type is a scalar — string, number, boolean, or Date. They will not
type-check for arrays of objects or arrays.
Empty Checks
Section titled “Empty Checks”p.tags.isEmpty() // Empty array OR nullp.tags.isNotEmpty() // Has at least one elementLength Predicates
Section titled “Length Predicates”p.scores.lengthEq(3) // Exactly 3 elementsp.scores.lengthGt(0) // More than 0 elementsp.scores.lengthGte(3) // 3 or more elementsp.scores.lengthLt(10) // Fewer than 10 elementsp.scores.lengthLte(5) // 5 or fewer elementsReference
Section titled “Reference”| Predicate | Accepts | Description | SQL |
|---|---|---|---|
contains(value) | T | Has value | JSON array contains |
containsAll(values[]) | T[] | Has all values | AND of contains |
containsAny(values[]) | T[] | Has any value | OR of contains |
isEmpty() | — | Empty or null | IS NULL OR length = 0 |
isNotEmpty() | — | Has elements | IS NOT NULL AND length > 0 |
lengthEq(n) | number | Exactly n elements | json_array_length(col) = n |
lengthGt(n) | number | More than n | json_array_length(col) > n |
lengthGte(n) | number | n or more | json_array_length(col) >= n |
lengthLt(n) | number | Fewer than n | json_array_length(col) < n |
lengthLte(n) | number | n or fewer | json_array_length(col) <= n |
Note:
isEmpty()matches both empty arrays ([]) and null/undefined values. UseisNull()to check specifically for null.
Object
Section titled “Object”Object predicates for JSON/object fields. Supports both fluent chaining with get() and
JSON Pointer syntax for deep access.
Nested Access with get()
Section titled “Nested Access with get()”Type-safe chaining through known keys:
p.metadata.get("theme").eq("dark")p.settings.get("notifications").get("email").eq(true)get() returns a typed field builder — if the nested field is a string you get string predicates,
if it’s a number you get number predicates, and so on.
Nested Access with field()
Section titled “Nested Access with field()”Access nested fields by JSON Pointer path:
p.config.field("/settings/theme").eq("dark")p.config.field(["settings", "theme"]).eq("dark") // Array formLike get(), field() returns a typed field builder for the resolved path. Use field() when
you need to reach deeply nested paths in a single call.
Key Existence
Section titled “Key Existence”p.metadata.hasKey("theme") // Has top-level keyPath Operations
Section titled “Path Operations”p.config.hasPath("/nested/key") // Has nested pathp.config.pathEquals("/settings/theme", "dark") // Value at path equals scalarp.config.pathContains("/tags", "featured") // Array at path contains valuep.config.pathIsNull("/optional") // Value at path is nullp.config.pathIsNotNull("/required") // Value at path is not nullReference
Section titled “Reference”| Predicate | Accepts | Description |
|---|---|---|
get(key) | string (key name) | Access nested field, returns typed field builder |
field(pointer) | string | string[] (JSON Pointer) | Access field by path, returns typed field builder |
hasKey(key) | string | Has top-level key |
hasPath(pointer) | string | string[] | Has nested path |
pathEquals(pointer, value) | pointer + string | number | boolean | Date | Value at path equals scalar |
pathContains(pointer, value) | pointer + string | number | boolean | Date | Array at path contains value |
pathIsNull(pointer) | string | string[] | Value at path is null |
pathIsNotNull(pointer) | string | string[] | Value at path is not null |
JSON Pointer syntax: Use
/key/nested/valuestring form or["key", "nested", "value"]array form.pathEqualsonly works on scalar values (not objects or arrays).pathContainsrequires the path to point to an array.
Embedding
Section titled “Embedding”Embedding predicates for vector similarity search on embedding fields.
similarTo()
Section titled “similarTo()”Find similar vectors using distance metrics:
p.embedding.similarTo(queryEmbedding, 10) // Top 10 similar (cosine)With Options
Section titled “With Options”p.embedding.similarTo(queryEmbedding, 10, { metric: "cosine", // "cosine" | "l2" | "inner_product" minScore: 0.8, // Minimum similarity threshold})Reference
Section titled “Reference”| Predicate | Accepts | Description |
|---|---|---|
similarTo(embedding, k) | number[], number | Top k most similar vectors (cosine) |
similarTo(embedding, k, opts) | number[], number, SimilarToOptions | Top k with custom metric and threshold |
Distance Metrics
Section titled “Distance Metrics”| Metric | Description | Range | Default | Best For |
|---|---|---|---|---|
cosine | Cosine similarity | 0–1 (1 = identical) | Yes | Normalized embeddings, semantic similarity |
l2 | Euclidean distance | 0–∞ (0 = identical) | Absolute distances, unnormalized vectors | |
inner_product | Inner product (PostgreSQL only) | -∞ to ∞ | Maximum Inner Product Search (MIPS) |
Example: Semantic Search
Section titled “Example: Semantic Search”const similar = await store .query() .from("Document", "d") .whereNode("d", (d) => d.embedding.similarTo(queryEmbedding, 20, { metric: "cosine", minScore: 0.7, }) ) .select((ctx) => ({ id: ctx.d.id, title: ctx.d.title, content: ctx.d.content, })) .execute();Limitations: Results are automatically ordered by similarity (most similar first).
similarTocannot be nested underORorNOT. SQLite does not support embeddings — vector search requires PostgreSQL with pgvector.
Parameterized Predicates
Section titled “Parameterized Predicates”Use param(name) to create a named placeholder for prepared queries.
import { param } from "@nicia-ai/typegraph";
const prepared = store .query() .from("Person", "p") .whereNode("p", (p) => p.name.eq(param("name"))) .select((ctx) => ctx.p) .prepare();
const results = await prepared.execute({ name: "Alice" });Supported Positions
Section titled “Supported Positions”| Position | Supported | Example |
|---|---|---|
Scalar comparisons (eq, neq, gt, gte, lt, lte) | Yes | p.age.gt(param("minAge")) |
between bounds | Yes | p.age.between(param("lo"), param("hi")) |
String operations (contains, startsWith, endsWith, like, ilike) | Yes | p.name.contains(param("search")) |
in / notIn | No | Array length must be known at compile time |
| Array predicates | No | — |
| Subquery predicates | No | — |
See Prepared Queries for full usage and performance details.
Next Steps
Section titled “Next Steps”- Filter — Using predicates in queries
- Subqueries —
exists(),notExists(),inSubquery(),notInSubquery() - Overview — Query builder categories