Skip to content
NarDBv0.2.0-dev

create_schema

Fields, types, lengths, character encodings and indexes.

A schema defines a table: its fields, types, rules and indexes.

NarQL
create_schema('members')
    .fields({
        'id':       {type: string, max_length: 32, guid: true, primary_key: true},
        'name':     {type: string, max_length: 50},
        'surname':  {type: string, max_length: 50, encoding: latin5},
        'nickname': {type: string, max_length: 20, default: '🍉'},
        'email':    {type: string, max_length: 100, index: {unique: true, name: 'idx_email'}},
        'age':      {type: int8},
        'seq':      {type: int64, autoincrement: true},
        'birth':    {type: date, format: 'dd.mm.yyyy'},
        'balance':  {type: decimal, precision: 12, scale: 2, default: 0}
    })
    .commit();
  • Without .commit() the schema is only validated. Errors come with a line and a column.
  • Field order is kept; fields('*') returns fields in this order.
  • Every field gets an id that is never reused. Dropping a field and adding a new one cannot mix up old records.
  • Names are lowercase snake_case, at most 63 characters. The name privileges and names starting with nar_ are reserved.

To drop a schema:

NarQL
drop_schema('members').commit();

Dropping releases all of the table's pages.

Types#

GroupTypes
Integerint8 int16 int32 int64 · uint8 uint16 uint32 uint64
Floating pointfloat32 float64 · decimal (with precision, scale)
Textstring (default max_length: 255) · text (unbounded)
Booleanbool
Timedate datetime time timestamp
Identifierguid
Binarybinary blob

A bare int is not accepted; the size has to be written. int8 only holds up to 127, so choosing it by accident makes values overflow.

NarQL
# error: 'int' is ambiguous: write the size, e.g. int8 (−128..127), int32 or int64
create_schema('x').fields({'age': {type: int}});

Field options#

OptionWhat it does
max_lengthUpper limit for string and binary. Counts characters, not bytes.
encodingutf8 (default), ascii, latin1, latin5. See below.
precision, scaleTotal and fractional digits for decimal.
formatInput and display format of date fields, e.g. 'dd.mm.yyyy'.
nullableDefault true. Defaults to false for the primary key and for autoincrement and guid fields.
defaultA value, now(), guid() or null.
primary_keyAt most one field. Without one, a hidden row id is used.
autoincrementFor integer fields. Cannot be combined with guid.
guidGenerates ids for string (max_length ≥ 32) or the guid type.
indextrue or {name, unique}. Only btree for now.
checkValidation rules; see Validation.

Character encodings and emoji#

Text is always handled as UTF-8. encoding decides which characters a field accepts:

EncodingAccepts
utf8All of Unicode, emoji included: 🍉 👩‍💻 🇹🇷
ascii7-bit characters only (codes, slugs, country codes)
latin1Characters that ISO-8859-1 can represent
latin5Characters that ISO-8859-9 can represent, including Turkish ğ ı ş İ Ğ Ş
NarQL
create_schema('tags')
    .fields({
        'slug': {type: string, max_length: 40, encoding: ascii, primary_key: true},
        'name': {type: string, max_length: 40}
    })
    .commit();

from('tags').insert_one({slug: 'pomegranate-juice', name: 'Pomegranate juice 🍹'});
NarQL
# error: character 'ç' is not allowed in ascii
from('tags').insert_one({slug: 'çay', name: 'Tea'});

max_length counts Unicode code points. 🍉 is one character; 👩‍💻 is three (two emoji and the joiner between them).

Date formats#

The schema's format and the FORMAT and TO_DATE functions use the same tokens:

TokenMeaningTokenMeaning
yyyyyear (2026)hhhour (00–23)
yyyear (26)iiminute
mmmonthsssecond
ddday

MM and HH mean the same as mm and hh. Separators are - / . : , T and space. Without a format, ISO 8601 is used. A date field cannot have time tokens.

Indexes#

The primary key is indexed automatically (pk_<schema>). For other fields:

NarQL
create_schema('orders')
    .fields({
        'no':        {type: int64, autoincrement: true, primary_key: true},
        'member_id': {type: string, max_length: 32, index: true},
        'code':      {type: string, max_length: 20, index: {unique: true, name: 'idx_order_code'}}
    })
    .commit();

When where searches the primary key or an indexed field with equality, the table is not scanned; rows are read straight from the index. In a unique index null values do not count as equal, so many rows can be null.