Validation
check rules, nullable, default and password fields.
Rules are applied on every insert and update. A value that breaks a rule is not written, and the error says which field was rejected and why.
check#
create_schema('people')
.fields({
'email': {type: string, max_length: 100, index: {unique: true},
check: regex('^[\w.-]+@([\w-]+\.)+[\w-]{2,4}$')},
'age': {type: int8, check: {min: 0, max: 120}},
'gender': {type: int8, check: enum({0: 'male', 1: 'female'})},
'joined': {type: date, check: {min: '2020-01-01'}}
})
.commit();| Rule | Applies to |
|---|---|
{min: …, max: …} | numbers, decimal, dates |
regex('…') | string, text (RE2 syntax: no lookaround, no backreferences) |
enum({value: 'label'}) | integers and text |
password_hash() | string (max_length ≥ 128), text |
Several rules go in a list: check: [regex('^[a-z]+$'), enum({'a': 'A', 'b': 'B'})].
# error: age: 125 is above max 120
from('people').insert_one({email: 'a@b.co', age: 125});int8 holds at most 127. With 130 the error would be "does not fit int8": the type's range is checked before the rules.
# error: gender: 7 is not one of 0 (male), 1 (female)
from('people').insert_one({email: 'a@b.co', gender: 7});nullable and default#
create_schema('notes')
.fields({
'no': {type: int64, autoincrement: true, primary_key: true},
'title': {type: string, max_length: 80, nullable: false},
'status': {type: string, max_length: 10, default: 'draft'},
'created': {type: timestamp, default: now()}
})
.commit();
from('notes').insert_one({title: 'First note'});# error: title is required (not nullable)
from('notes').insert_one({status: 'published'});A default must satisfy the field's own rules; a schema with a default that breaks them is rejected when it is created.
Password fields#
create_schema('accounts')
.fields({
'username': {type: string, max_length: 40, primary_key: true},
'password': {type: string, check: password_hash()}
})
.commit();
from('accounts').insert_one({username: 'osman', password: 'secret-password'});
from('accounts').fields('*').get();- The value is hashed with Argon2id before it is written; the plain password never reaches the disk.
- Password fields appear as
••••••in query results. - A value that is already an Argon2id hash (imported from another system) is not hashed again.
password_hashcan only be set when the field is created. Adding it to an existing field would leave the existing values unhashed.
Uniqueness#
A unique index stops the same value from being written twice:
from('people').insert_one({email: 'osman@example.com'});# error: email: value osman@example.com already exists (unique index idx_email)
from('people').insert_one({email: 'osman@example.com'});