Skip to content

kd: the scripting language

kd is the scripting language of kinedb. A kd script runs in three places:

  • A file: kinedb --data-dir ./data -f script.kd runs the script in the process, with no server.
  • A stored function: CREATE FUNCTION ... LANGUAGE kd stores a function in the database, and CALL runs it on the server.
  • A ticker: CREATE TICKER ... CALL <function> runs a stored function on a schedule.

Every kd value is a JSON value: a number, a string, a boolean, null, an array or an object. Every example on this page ran on the current build with -f, in the order of this page, in one database. A // expect: comment shows a part of the output.

Run a script

sh
kinedb --data-dir ./data -f script.kd

print(...) writes its arguments on one line, with a space between them. After the last statement, kinedb prints the value of that statement: a string as it is, any other value as JSON, and nothing for null.

kd
// expect: hello kd 42
print("hello", "kd", 42);

Values

typeof gives the type of a value. A string takes double or single quotes, and the escapes \n, \t, \r, \\, \' and \".

kd
// expect: number string bool null array object
print(typeof(1), typeof("a"), typeof(true), typeof(null), typeof([1]), typeof({a: 1}));

Variables

let declares a variable. =, += and -= assign to it.

kd
// expect: 35
let x = 10;
x = 30;
x += 10;
x -= 5;
print(x);

Operators

The arithmetic operators are +, -, *, / and %. *, / and % bind stronger than + and -, and parentheses group.

kd
// expect: 17 2 1 2.5 25
print(2 + 3 * 5, 17 % 5, 7 - 6, 5 / 2, (2 + 3) * 5);

+ also joins strings and arrays:

kd
// expect: hello world [1,2,3,4]
print("hello" + " " + "world", [1, 2] + [3, 4]);

The comparison operators are ==, !=, <, <=, > and >=. The logical operators are &&, || and !.

kd
// expect: true true false true
print(1 == 1.0, "a" != "b", true && false, !false || false);

In a condition, null, false, 0 and "" are false. Every other value is true, empty arrays and empty objects too.

kd
// expect: no no no no yes yes
let out = "";
for v in [null, false, 0, "", [], {}] {
  if v { out = out + "yes "; } else { out = out + "no "; }
}
print(out);

Arrays and objects

An index reads an array element (from 0) or an object field. A dot also reads a field. An assignment to an index or a field changes the value.

kd
// expect: 2 Alice
let a = [1, 2, 3];
let p = {name: "Alice", age: 30};
print(a[1], p.name);
kd
// expect: [1,99,3] 31
let a = [1, 2, 3];
a[1] = 99;
let p = {name: "Alice", age: 30};
p.age = 31;
print(a, p["age"]);

Control flow

if, else if and else take a condition without parentheses and a block in braces.

kd
// expect: medium
let n = 15;
if n > 20 { print("large"); } else if n > 10 { print("medium"); } else { print("small"); }

for <name> in <value> walks the elements of an array, or the keys of an object. continue goes to the next element, and break leaves the loop.

kd
// expect: 7
let sum = 0;
for x in [1, 2, 3, 4, 5, 6] {
  if x == 3 { continue; }
  if x == 5 { break; }
  sum += x;
}
print(sum);
kd
// expect: a=1 b=2
let o = {a: 1, b: 2};
let s = "";
for k in o { s = s + k + "=" + to_string(o[k]) + " "; }
print(s);

Functions

fn defines a function. return gives its result; a function without return gives null. A function can call itself.

kd
// expect: 120
fn fact(n) {
  if n <= 1 { return 1; }
  return n * fact(n - 1);
}
print(fact(5));

Comments

kd
// expect: 3
// a line comment
/* a block
   comment */
print(1 + 2);

Built-in functions

FunctionWhat it gives
print(a, b, ...)Writes the values on one line. Gives null.
typeof(v)"number", "string", "bool", "null", "array" or "object".
length(v)The number of characters of a string, or of elements of an array or an object.
keys(o), values(o)The keys, or the values, of an object, as an array.
to_string(v)The value as a string.
to_number(s)The string as a number, or null when it is not a number.
to_int(n)The number without its fraction.
floor(n), ceil(n), round(n)The number rounded down, up, or to the nearest integer.
kd
// expect: 3 5 ["a","b"] [1,2]
print(length([1, 2, 3]), length("hello"), keys({a: 1, b: 2}), values({a: 1, b: 2}));
kd
// expect: 42 42 3 3 -4 4 4
print(to_number("42"), to_string(42), to_int(3.7), floor(3.9), floor(-3.2), ceil(3.1), round(3.5));

The database

A script reads and writes the database with these functions. The same functions work in a file (-f) and in a stored function.

FunctionWhat it does
query(sql)Runs the SQL. A SELECT gives an array of objects, one per row.
find(name), find(name, where)SELECT * FROM <name>, with an optional WHERE <where>.
insert(name, object)INSERT INTO <name>, with the keys of the object as the columns.
update(name, object, where)UPDATE <name> SET <key> = <value>, ... WHERE <where>.
delete(name, where), remove(name, where)DELETE FROM <name>, with an optional WHERE <where>.
log(a, b, ...)Writes the values to the log output.

The examples use this table:

sql
CREATE TABLE players (id INT, name TEXT, score INT, PRIMARY KEY (id));
INSERT INTO players (id, name, score) VALUES (1, 'ann', 10), (2, 'bob', 20);
kd
// expect: 2 ann 20
let rows = query("SELECT name, score FROM players ORDER BY id");
print(length(rows), rows[0].name, rows[1].score);
kd
// expect: [{"id":2,"name":"bob","score":20},{"id":3,"name":"cid","score":30}]
insert("players", {id: 3, name: "cid", score: 30});
print(find("players", "score > 15"));
kd
// expect: 99 2
update("players", {score: 99}, "id = 1");
delete("players", "id = 2");
print(query("SELECT score FROM players WHERE id = 1")[0].score, length(find("players")));

The last statement of this script is a value, so kinedb prints it:

kd
// expect: 129
let total = 0;
for r in find("players") { total += r.score; }
total

Stored functions and tickers

CREATE FUNCTION <name>(<parameters>) [RETURNS VALUE | TABLE] LANGUAGE kd AS $$ <body> $$ stores a function, and CALL <name>(<arguments>) runs it. The arguments bind to the parameter names in order, and a parameter without an argument is null. The array args also holds all the arguments. The body uses the built-in functions and the database functions above. Stored functions, CALL and tickers need a server connection.

sql
CREATE FUNCTION add_points(player, points) RETURNS VALUE LANGUAGE kd AS $$ update("players", {score: points}, "id = " + to_string(player)); return points; $$;
CALL add_points(1, 50);
CREATE FUNCTION decay() RETURNS VALUE LANGUAGE kd AS $$ query("UPDATE players SET score = score - 1"); return null; $$;
CREATE TICKER decay_every_minute EVERY 60s CALL decay OVERLAP SKIP;

See the SQL reference for SHOW FUNCTIONS, DROP FUNCTION and the ticker statements.