Skip to main content

SmartFunctions

SmartFunctions are the engine for setting permissions in Fluree. This section lists all built-in predicates that can be added to a function, as well as information on how to write the actual function code.

To learn more about how to use smart functions, see the Smart Functions guide.

_fn#

PredicateTypeDescription
namestringFunction name
params(multi) stringList of parameters this function supports.
codestringActual ledger code. Can just be true or false.
docstringA docstring for this function.
languagestringProgramming language used (not yet implemented, currently only Clojure supported)
specJSON(not yet implemented) Optional spec for parameters. Spec should

be structured as a map, parameter names are keys and the respective spec is the value.

Universal Functions For _fn/code#

Clojure is the only language that is currently supported for writing smart functions. Only a subset of Clojure functions, as well as several custom functions, are allowed to be used in smart functions.

The below functions are available for any smart functions, regardless of where those smart functions are referenced. (i.e. _predicate/spec versus _rule/fns). In addition, true and false are valid keywords in your function code.

Note: Each function accrues a certain amount of fuel. Fuel is used to limit usage in the hosted version of Fluree.

FunctionArgumentsExampleDescriptionCost (in fuel)
incn optional(inc)Increment existing value by 1. Works on integer.10
decn optional(dec)Decrement existing value by 1. Works on integer.10
nownone(now)Insert current server time. Works on instant.10
==arg1 arg2 ...(== 1 1 1 1)Returns true if all items within the vector are equal. Works on integer, string, and boolean.9 + count of objects in ==
+arg1 arg2 ...(+ 1 2 3)Returns the sum of the provided values. Works on integer and float.9 + count of objects in +
-arg1 arg2 ...(- 10 9 3)Returns the difference of the numbers. The first, as the minuend, the rest as the subtrahends. Works on integer and float.9 + count of objects in -
*arg1 arg2 ...(* 90 10 2)Returns the product of the provided values. Works on integer and float.9 + count of objects in *
/arg1 arg2 ...(/ 36 3 4)If only one argument supplied, returns 1/first argument, else returns first argument divided by all of the other arguments. Works on integer and float.9 + count of objects in /
>arg1 arg2 ...(> 90 10 2)Returns true if values are in monotonically decreasing order.9 + count of objects in >
>=arg1 arg2 ...(>= 90 90 10 2)Returns true if values are in monotonically non-increasing order.9 + count of objects in >=
<arg1 arg2 ...(< 2 10 90)Returns true if values are in monotonically increasing order.9 + count of objects in <
<=arg1 arg2 ...(<= 2 10 90 90)Returns true if values are in monotonically non-decreasing order.9 + count of objects in <=
quotn d(quot 60 10)Returns the quotient of dividing the first argument by the second argument. Rounds the answer towards 0 to return the nearest integer. Works on integer and float.10
remn d(rem 64 10)Remainder of dividing the first argument by the second argument. Works on integer and float.10
modn d(mod 64 10)Modulus of the first argument divided by the second argument. The mod function takes the rem of the two arguments, and if the either the numerator or denominator are negative, it adds the denominator to the remainder, and returns that value. Works on integer and float.10
maxarg1 arg2 ...(max 1 2 3)Returns the max of the provided values. Works on integer, float.9 + count of objects in max
minarg1 arg2 ...(min 1 2 3)Returns the min of the provided values. Works on integer, float.9 + count of objects in min
max-pred-valpredicate-name(max-pred-val \"person/age\")Returns the max of the provided predicate. Works on integer, float.10 + cost of fuel to query max-pred-val
strarg1 arg2 ...(str \"flur.\" \"ee\")Concatenates all strings in the vector. Works on integer, string, float, and boolean.10
if-elsetest true false(if-else (== 1 1) \"John\" \"Jane\")Takes a test as a first argument. If the test succeeds, return the second argument, else return the third argument.10
andarg1 arg2 ...(and (== 1 1) (== 2 2) )Returns true if all objects within the vector are non-nil and non-false, else returns false.9 + count of objects in and
orarg1 arg2 ...(or (== 1 1) (== 2 3))Returns true if any of the objects within the vector are non-nil and non-false, else returns false.9 + count of objects in or
notarg1 arg2 ...(not (== 3 3))Returns true if value is falsey, returns false if value is truthy. (not (== 3 3)) would return false.10
booleanx(boolean 1)Coerces any non-nil and non-false value to true, else returns false.10
nil?x(nil? 2)If nil, returns true, else returns false.10
count[s] or string(count \"Appleseed\"), #(count [1 2 3])Returns the count of letters in a string or the number of items in a vector.9 + count of objects in count
getsubject predicate(get (?s) \"_id\" )Returns the value of an predicate within an object. In this example, we extract the _id of the subject using get.10
contains?subject value(contains? (get-all (?s) [\"person/user\"]) ?user)Checks whether an object or hash-set contains a specific key (for objects) or value (for hash-sets). Vectors check index and NOT value. To check values of vector, convert values to hash-set first. In this example, get-all checks whether the person user contains the current user.10
hash-setarg1 arg2 ...(hash-set \"orange\" \"pear\")Returns hash-set containing all the args9 + count of values in hash-set
upper-casestr.(upper-case \"pear\")Returns upper-case version of string.10
lower-casestr.(lower-case \"pear\")Returns lower-case version of string.10
nthcollection integer(nth [1 2 3] 0)Returns the nth element in a collection, for example (nth [1 2 3] 0) returns 1.9 + count of objects in the collection
get-allsubject [path](contains? (get-all ?s [\"chat/person\" \"person/user\"]) ?user)Returns nil or a set of all of a certain predicate (or predicate-path) from an subject.9 + length of path
valid-email?x(valid-email? (?o))Checks whether a value is a valid email using the following pattern, [a-z0-9!#$%&'*+/=?^_{\|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_{\|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?.10
re-findpattern string(re-find "^[a-zA-Z0-9_][a-zA-Z0-9\.\-_]{0,254}" \"apples1\")Checks whether a string follows a given regex pattern.10
dbnone(== (get db \"dbid\") 2)Returns a ledger object with the following keys: dbid, block, and permissions.10
queryquery-string(query \"{\\\"select\\\":[\\\"*\\\"],\\\"from\\\":\\\"person\\\"}\")Allows you to query the current ledger. You need to doubly-escape the quotation marks in the query string \"{\\\"select\\\":[\\\"*\\\"],\\\"from\\\":\\\"person\\\"}\".Fuel required for the query.
queryselect-string from-string where-string block-string limit-string(get (query \"[*]\" [\"book/editor\" \"Penguin\"] nil nil nil) \"book/year\")Allows you to query the current ledger. The select-string should be inputted without any commas. The select-string and can be inputted without any quotation marks, for example, "[* {person/user [*]}]", or you can optionally doubly-escape those strings "[\\\"*\\\" {\\\"person/user\\\" [\\\"*\\\"]}]".Fuel required for the query.
relationship?startSubject path endSubject(relationship? [\"_user/username\" \"anna\"] [\"_user/auth\" \"_auth/department\" \"company/_department\"] [\"company/name\" \"Fluree\"])Returns a true or false, depending on if there is a relationship between two subjects. Start and end subjects should resolve to either subject _ids or unique two-tuples. For example, (?sid) resolves to a subject _id, 87960930223080 and ["_user/username" "anna"] are all valid for start or end subjects. The path should be a single predicate or a vector of predicates that potentially connect the two subjects.10, plus fuel of query
randmax seed(rand 100)Returns a random integer from 0 to the max number you provided. A seed is optional.10
uuidnone(uuid)Returns a UUID. Can be used in predicates of type string or uuid10
cascompare-val new-val(cas "hi" "hi again")For use as transaction function, if current db value does not equal compare-val, the transaction will fail otherwise it will get updated with new-val20

ledger function can also be combined, for instance (inc (max 1.5 2 3)) will return 4.

When you write a smart function and add it to the _fn collection, you can use the name of that smart function in other smart functions.

For example, you can add a function called, addThree that adds 3 to any number, n.

[  {    "_id": "_fn",    "name": "addThree",    "params": ["n"],    "code": "(+ 3 n)"  }]

Once, addThree is in the ledger, you can create a new function called addTen, which uses addThree.

[  {    "_id": "_fn",    "name": "addTen",    "params": ["n"],    "code": "(+ 7 (addThree n))"  }]

Context-Dependent Functions#

Some available functions are only available in certain contexts. For example, ?o, which gets the object of a triple is relevant for a _predicate/spec, but not for a _collection/spec.

FnArgsExampleAvailable InUsageFuel
?sidNone(== (?auth_id) (?sid))_predicate/spec, _collection/spec,_rule/fnsThe _id of the subject that the spec is being applied to10
?pidNone(?pid)_predicate/spec, _predicate/txSpec, transaction_id of the predicate that the spec is being applied to10
?sstring*(== (get (?s) \"person/handle\") \"jdoe\")_predicate/spec, _collection/spec, _rule/fnsAllows you to access all the predicates of the subject that the spec is being applied to.10 plus cost of lookup
?pstring**(== (get (?p) \"_predicate/name") \"person/fullName\")_predicate/spec, _predicate/txSpec, transactionAllows you to access all the predicates of the predicate that the spec is being applied to.10 plus cost of fuel
?oNone(< 1000 (?o))_predicate/specThe proposed object of the predicate that the user is attempting to add or update.10
?pONone(< (?pO) (?o))_predicate/specThe object of the predicate that the user is attempting to add or update, as of the block before the proposed transaction10 plus cost of object-lookup
?auth_idNone(== (?auth_id) (?sid))_predicate/spec, _collection/spec, _rule/fns, transactionsThe _id of the auth that is querying or transacting10
?user_idNone(== (?user_id) (?sid))_predicate/spec, _collection/spec, _rule/fns, transactionsThe _id of the user, if any, that is querying or transacting10
flakesNone(flakes)_predicate/spec, _collection/spec, _predicate/txSpecReturns an array of all flakes in the current proposed transaction. For _predicate/spec and _collection/spec this is a single flake. For _predicate/txSpec this is all the flakes in a given transaction that pertain to the specified predicate.10
objTNone(objT)_predicate/spec, _collection/spec, _predicate/txSpecSum of the value of all flakes being added in the current spec.10
objFNone(objF)_predicate/spec, _collection/spec, _predicate/txSpecSum of the value of all flakes being retracted in the current spec.10

* Optional string of additional-select-parameters. By default, this function will query {"select": ["*"], from: [SUBJECT]}, however, if you would like to follow the subject's relationships further, you can optionally include an additional select string. You do not need to include the glob character, *, in your select string. You can either not include any quotes in the select string, or doubly-escape them, for example: "[{person/user [*]}]" or "[{\\\"person/user\\\" [\\\"*\\\"]}]". Your select string needs to be inside of a vector, [].

** Optional string of additional-select-parameters. By default, this function will query {"select": ["*"], from: p}, however, if you would like to follow the subject's relationships further, you can optionally include an additional select string. You do not need to include the glob character, *, in your select string. You can either not include any quotes in the select string, or doubly-escape them, for example: "[{person/user [*]}]" or "[{\\\"person/user\\\" [\\\"*\\\"]}]". Your select string needs to be inside of a vector, [].