Appendix D: Datalog Built-Ins
This appendix lists the functions and predicates that Datalevin resolves without namespace qualification inside Datalog query clauses. It also lists the built-in aggregate functions available in :find and :having, plus the special forms that appear in :find and :where.
Most of these functions mirror clojure.core. Datalevin-specific functions are called out separately because they interact with the database, full-text search, vector indexes, idoc indexes, or runtime UDFs.
1. Where Built-Ins Can Appear
Built-ins can be used in predicate clauses:
[(> ?age 18)]
[(like ?name "A%")]
They can also be used in binding clauses:
[(+ ?subtotal ?tax) ?total]
[(get-some $ ?e :profile/email :user/email) [?attr ?email]]
Aggregate functions appear in :find and :having:
[:find ?city (count ?e)
:where [?e :user/city ?city]
:having [(> (count ?e) 10)]]
Fully qualified Clojure functions can also be used when they are available to the runtime, but they are not part of this built-in table.
On the JVM, a symbol whose name starts with . is treated as a reflective instance-method call on its first argument:
[(.toUpperCase ?name) ?upper]
This is useful for local Clojure/JVM queries, but it is not a portable cross-language pattern. Prefer documented built-ins or runtime UDFs when the query will cross process or language boundaries.
Find-only forms appear in :find, not as ordinary :where clauses:
| Form | Purpose |
|---|---|
(pull ?e pattern) |
Pull a shaped map for each entity found by the query. |
(pull $source ?e pattern) |
Pull from an explicit query source. |
(sum ?x), (count ?x), etc. |
Built-in aggregate calls. |
(+ (sum ?x) (sum ?y)) |
Arithmetic expression over aggregate results. |
(aggregate ?f ?x) |
Custom aggregate form, where ?f is an aggregate function input. |
:where also has special clause forms. These are parsed as Datalog clauses, not resolved as ordinary functions:
| Form | Purpose |
|---|---|
(or clause...) |
Match one of several alternative branches. |
(or-join [?var ...] branch...) |
Match alternatives with explicit branch output variables. |
(not clause...) |
Exclude rows for which the nested clauses match. |
(not-join [?var ...] clause...) |
Exclude rows with explicit variables connecting the nested clauses to the surrounding query. |
(and clause...) |
Group multiple clauses inside an or or or-join branch. |
Do not confuse these clause forms with predicate calls such as [(not ?flag)] or [(or ?a ?b)]. Bracketed predicate clauses call functions; the forms above contain nested Datalog clauses. Chapter 8 covers their evaluation rules and examples.
2. Predicates and Comparisons
| Function | Purpose |
|---|---|
= |
Equality predicate. |
== |
Numeric equality predicate. |
not= |
Inequality predicate. |
!= |
Alias for not=. |
< |
Datalevin typed less-than comparison. |
<= |
Datalevin typed less-than-or-equal comparison. |
> |
Datalevin typed greater-than comparison. |
>= |
Datalevin typed greater-than-or-equal comparison. |
compare |
Clojure-style comparison function. |
true? |
True only for the boolean value true. |
false? |
True only for the boolean value false. |
nil? |
True for nil. |
some? |
True for non-nil values. |
not |
Logical negation. |
and |
Logical conjunction over arguments. |
or |
Logical disjunction over arguments. |
complement |
Return a function that negates another predicate. |
identical? |
Reference identity predicate. |
zero? |
Numeric zero predicate. |
pos? |
Positive-number predicate. |
neg? |
Negative-number predicate. |
even? |
Even integer predicate. |
odd? |
Odd integer predicate. |
in |
Membership predicate, e.g. [(in ?status [:open :ready])]. |
not-in |
Negated membership predicate. |
like |
SQL LIKE-style string predicate using % and _ wildcards; accepts {:escape ?esc} as an optional third argument. |
not-like |
Negated like predicate; also accepts {:escape ?esc}. |
re-find |
Regex search. |
re-matches |
Regex full-match test. |
3. Numeric Functions
| Function | Purpose |
|---|---|
+ |
Addition. |
- |
Subtraction or numeric negation. |
* |
Multiplication. |
/ |
Division. |
quot |
Integer quotient. |
rem |
Remainder. |
mod |
Modulus. |
inc |
Increment. |
dec |
Decrement. |
min |
Minimum value using Datalevin typed comparison. |
max |
Maximum value using Datalevin typed comparison. |
rand |
Random floating-point number. |
rand-int |
Random integer below a bound. |
4. General Value and Collection Functions
| Function | Purpose |
|---|---|
identity |
Return its argument unchanged. |
ground |
Alias for identity; commonly used to bind constants or collections. |
quote |
Return its argument unchanged; useful for nested query literals in EDN strings. |
keyword |
Create a keyword. |
meta |
Return metadata. |
name |
Return the name part of a keyword or symbol. |
namespace |
Return the namespace part of a keyword or symbol. |
type |
Return the Java/Clojure runtime type. |
vector |
Construct a vector. |
list |
Construct a list. |
set |
Construct a set. |
hash-map |
Construct a hash map. |
array-map |
Construct an array map. |
count |
Count items in a collection or characters in a string. |
range |
Produce a numeric range. |
not-empty |
Return a collection if non-empty, otherwise nil. |
empty? |
True for empty collections. |
contains? |
True when a key/index is present. |
get |
Look up a value in a collection or map. |
apply |
Apply a built-in or fully qualified function to a sequence of arguments. |
tuple |
Construct a tuple value; equivalent to vector in query context. |
untuple |
Return a tuple value unchanged so it can be destructured by a binding. |
Examples:
;; Bind each vowel from a literal collection.
(d/q '[:find ?vowel
:where [(ground [:a :e :i :o :u]) [?vowel ...]]])
;; Build transaction data in a query.
(d/q '[:find [?tx-data ...]
:where [(ground :db/add) ?op]
[(vector ?op -1 :user/name "Alice") ?tx-data]])
;; Sum a tuple stored as a value.
(d/q '[:find ?e ?sum
:where [?e :nums ?nums]
[(apply + ?nums) ?sum]]
db)
5. String and Regex Functions
| Function | Purpose |
|---|---|
str |
Concatenate values as strings. |
pr-str |
Print values readably to a string. |
print-str |
Print values to a string using print semantics. |
println-str |
Print values with a trailing newline. |
prn-str |
Print values readably with a trailing newline. |
subs |
Return a substring. |
re-pattern |
Compile a regex pattern. |
re-find |
Find a regex match. |
re-matches |
Match an entire string against a regex. |
re-seq |
Return a sequence of regex matches. |
6. Database-Aware Functions
These functions take a Datalevin DB object, usually $, or interact with Datalevin indexes and runtime facilities.
| Function | Purpose |
|---|---|
get-else |
Return an entity attribute value or a non-nil default. |
get-some |
Return the first present attribute and value from a list of attributes. |
missing? |
True when an entity has no value for an attribute. |
q |
Run a nested Datalog query. Prefer joins, not-join, or rules when possible. |
fulltext |
Search full-text indexes and bind matching [e a v] tuples. |
vec-neighbors |
Search vector indexes with a vector query and bind matching tuples. |
embedding-neighbors |
Embed a text query and search embedding indexes. |
idoc-match |
Search indexed document attributes and bind matching tuples. |
idoc-get |
Extract a nested value from a bound idoc document by path. |
udf |
Invoke a registered runtime UDF descriptor in query context. |
6.1 Attribute Fallbacks
;; Bind either the user's height or a default.
(d/q '[:find ?e ?height
:where [?e :user/name]
[(get-else $ ?e :user/height 0) ?height]]
db)
;; Bind the first present contact attribute.
(d/q '[:find ?e ?attr ?value
:where [?e :user/name]
[(get-some $ ?e :user/email :user/phone) [?attr ?value]]]
db)
;; Filter entities that do not have an attribute.
(d/q '[:find ?e
:where [?e :user/name]
[(missing? $ ?e :user/deleted-at)]]
db)
get-else does not accept nil as its default value. Use a concrete sentinel or handle the absence with missing?.
6.2 Nested Queries
(d/q '[:find ?e ?age
:where [(q (quote [:find (min ?age)
:where [_ :user/age ?age]])
$) [[?age]]]
[?e :user/age ?age]]
db)
Nested q is available, but it can be expensive when executed per candidate tuple. Prefer expressing the same logic directly with joins, not-join, rules, or aggregates when possible.
6.3 Full-Text Search
;; Search all full-text domains.
(d/q '[:find ?e ?a ?v
:in $ ?query
:where [(fulltext $ ?query) [[?e ?a ?v]]]]
db "red fox")
;; Search one attribute-specific domain.
(d/q '[:find ?e ?a ?v
:in $ ?query
:where [(fulltext $ :article/body ?query) [[?e ?a ?v]]]]
db "red fox")
;; Search explicit full-text domains.
(d/q '[:find ?e ?a ?v
:in $ ?query
:where [(fulltext $ ?query {:domains ["articles"]})
[[?e ?a ?v]]]]
db "red fox")
By default, fulltext returns tuples that destructure as [e a v]. With {:display :refs+scores}, bind [e a v score]; with :texts, bind [e a v text]; with :offsets, bind [e a v offsets]; and with :texts+offsets, bind [e a v text offsets]. Attribute-specific search requires :db.fulltext/autoDomain true on the attribute. Phrase search and offset display require the relevant search domain to be configured with :index-position? true before indexing. Text display requires :include-text? true; full-text indexes store document references by default, not a duplicate raw-text copy.
6.4 Vector and Embedding Search
Vector and embedding search is always domain-scoped. Unlike fulltext and idoc-match, vec-neighbors and embedding-neighbors do not search all domains when no domain is supplied. Use an attribute-specific call or pass an options map with :domains.
;; Vector query against an attribute-specific vector domain.
(d/q '[:find ?e ?a ?v
:in $ ?query-vector
:where [(vec-neighbors $ :item/embedding ?query-vector)
[[?e ?a ?v]]]]
db query-vector)
;; Vector query against explicit vector domains.
(d/q '[:find ?e ?a ?v
:in $ ?query-vector
:where [(vec-neighbors $ ?query-vector {:domains ["items"]})
[[?e ?a ?v]]]]
db query-vector)
;; Text query against an attribute-specific embedding domain.
(d/q '[:find ?e ?a ?v
:in $ ?text
:where [(embedding-neighbors $ :article/body ?text)
[[?e ?a ?v]]]]
db "database internals")
With {:display :refs+dists}, vector and embedding searches can bind [e a v distance]. Attribute-specific embedding search requires :db.embedding/autoDomain true on the attribute. Explicit embedding-domain search uses the provider configured for each named domain.
6.5 Indexed Documents
;; Search idoc documents by query map.
(d/q '[:find ?e ?a ?doc
:where [(idoc-match $ {:status "active"}) [[?e ?a ?doc]]]]
db)
;; Extract a nested field from the matched document.
(d/q '[:find ?e ?email
:where [(idoc-match $ :person/profile {:status "active"})
[[?e ?a ?doc]]]
[(idoc-get ?doc :contact :email) ?email]]
db)
;; Search explicit idoc domains.
(d/q '[:find ?e ?a ?doc
:where [(idoc-match $ {:status "active"} {:domains ["profiles"]})
[[?e ?a ?doc]]]]
db)
Attribute-specific idoc-match requires an attribute with :db/valueType :db.type/idoc. idoc-get accepts path segments as separate arguments or a single vector path.
6.6 Runtime UDFs
(d/q '[:find ?normalized
:in $ ?email
:where [(udf :normalize-email ?email) ?normalized]]
db
"ALICE@EXAMPLE.COM")
The descriptor must be installed in the database or available from the runtime UDF registry, and its kind must be usable as a query function or predicate. Clojure, Java, Python, and JavaScript use the same Datalog udf form; only the registry helper names differ by host language.
In server mode, query resolution is server-safe: remote queries can call Datalevin built-ins and descriptor-backed UDFs registered on the server, but cannot resolve arbitrary host-language functions supplied by the client. Use udf for custom query logic that must run in a server process.
7. Aggregate Functions
Aggregate functions are used in :find, aggregate expressions, and :having.
| Function | Forms | Purpose |
|---|---|---|
sum |
(sum ?x) |
Sum numeric values. |
avg |
(avg ?x) |
Arithmetic mean. |
median |
(median ?x) |
Median value. |
variance |
(variance ?x) |
Population variance. |
stddev |
(stddev ?x) |
Population standard deviation. |
count |
(count ?x) |
Count values. |
count-distinct |
(count-distinct ?x) |
Count distinct values. |
distinct |
(distinct ?x) |
Return a set of distinct values. |
vec |
(vec ?x) |
Return a vector of grouped values. |
min |
(min ?x), (min n ?x) |
Smallest value, or vector of the n smallest values. |
max |
(max ?x), (max n ?x) |
Largest value, or vector of the n largest values. |
rand |
(rand ?x), (rand n ?x) |
Random value, or vector of n random draws. |
sample |
(sample n ?x) |
Vector of up to n sampled values. |
The table above lists built-in aggregates that are available without resolving host functions. A query can also use custom aggregates when the runtime permits them. The custom aggregate form (aggregate ?f ?x) receives the collector function as an input. Host-resolved aggregate symbols beyond the built-ins above depend on resolver mode and are not portable to server-safe query execution.
Aggregate expressions can combine aggregate results:
(d/q '[:find ?name (+ (sum ?debits) (sum ?credits))
:in [[?name ?debits ?credits]]]
rows)
Aggregate expressions are evaluated after grouping. The supported expression operators are +, -, *, /, mod, rem, and quot; arguments may be aggregate calls, constants, or nested aggregate expressions.
Custom aggregate functions are also supported with the special aggregate form:
(d/q '[:find ?group (aggregate ?agg ?x)
:in [[?group ?x]] ?agg]
rows
my-aggregate-fn)
8. Public Name Index
This index lists the public query names documented for application use. Internal resolver entries, such as implementation helper predicates with leading hyphens, are intentionally omitted.
Query functions and predicates:
!=, *, +, -, /, <, <=, =, ==, >, >=, and, apply, array-map, compare, complement, contains?, count, dec, embedding-neighbors, empty?, even?, false?, fulltext, get, get-else, get-some, ground, hash-map, identical?, identity, idoc-get, idoc-match, in, inc, keyword, like, list, max, meta, min, missing?, mod, name, namespace, neg?, nil?, not, not-empty, not-in, not-like, not=, odd?, or, pos?, pr-str, print-str, println-str, prn-str, q, quot, quote, rand, rand-int, range, re-find, re-matches, re-pattern, re-seq, rem, set, some?, str, subs, true?, tuple, type, udf, untuple, vec-neighbors, vector, zero?.
Find-only forms:
pull, aggregate, arithmetic aggregate expressions using +, -, *, /, mod, rem, and quot.
JVM method-call forms:
Symbols beginning with ., such as .toUpperCase.
Aggregate functions:
avg, count, count-distinct, distinct, max, median, min, rand, sample, stddev, sum, variance, vec.
Other host-resolved aggregate functions are allowed only when the resolver mode permits host function resolution, or when supplied through an explicit custom aggregate mechanism.
User Examples
Log in to create examplesNo examples for this chapter yet.
