7.5 KiB
Introduction
ZipponDB is a relational database written entirely in Zig from stractch with 0 dependency.
ZipponDB goal is to be ACID, light, simple and high performance. It is aim for small to medium application that don't need fancy features but a simple and reliable database.
Why Zippon ?
- Open-source and written 100% in Zig with 0 dependency
- Relational database
- Simple and minimal query language
- Small, light, fast and implementable everywhere
Declare a schema
ZipponDB need a schema to work. A schema is a way to define how your data will be store.
Compared to SQL, you can see it as a file where you declare all table name, columns name, data type and relationship.
But here you declare struct. A struct have a name and members. A member is one data or link and have a type associated. Here a simple example for a user:
User (
name: str,
email: str,
best_friend: User,
)
Note that the best friend is a link to another User.
Here a more advance example with multiple struct:
User {
name: str,
email: str,
friends: []User,
posts: []Post,
liked_posts: []Post,
comments: []Comment,
liked_coms: []Comment,
}
Post {
title: str,
image: str,
at: date,
from: User,
like_by: []User,
comments: []Comment,
}
Comment {
content: str,
at: date,
from: User,
like_by: []User,
of: Post,
}
Can be simplify to take less space but can require more complexe query:
User {
name: str,
email: str,
friends: []User,
posts: []Post,
comments: []Comment,
}
Post {
title: str,
image: str,
at: date,
like_by: []User,
comments: []Comment,
}
Comment {
content: str,
at: date,
like_by: []User,
}
Note: [] are list of value.
ZipponQL
ZipponDB use it's own query language, ZipponQL or ZiQL for short. Here the keys point to remember:
- 4 actions available:
GRAB
ADD
UPDATE
DELETE
- All query start with an action then a struct name
- {} Are filters
- [] Are how much; what data
- () Are new or updated data (Not already in file)
- || Are additional options
- By default all member that are not link are return
- To return link or just some member, specify them between []
GRAB
The main action is GRAB
, this will parse files and return data. Here how it's work:
GRAB StructName [number_of_entity_max; member_name1, member_name2] { member_name1 = value1}
Note that []
and {}
are both optional.
So this will work and return all User without any filtering:
GRAB User
Here a simple example where to get all User above 18 years old:
GRAB User {age > 18}
To just return the name of User:
GRAB User [name] {age > 18}
To return the 10 first User:
GRAB User [10] {age > 18}
You can use both:
GRAB User [10; name] {age > 18}
To order it using the name:
GRAB User [10; name] {age > 10} |ASC name|
ADD
The ADD
action will add one entity into the database.
The synthax is similare but use ()
, this mean that the data is not yet in the database if between ()
.
Here an example:
ADD User (name = 'Bob', age = 30, email = 'bob@email.com', scores = [1 100 44 82])
You need to specify all member when adding an entity (default value are comming).
Not implemented
And you can also add them in batch
ADD User (name = 'Bob', age = 30, email = 'bob@email.com', scores = [1 100 44 82]) (name = 'Bob2', age = 33, email = 'bob2@email.com', scores = [])
You don't need to specify the member in the second entity as long as the order is respected
ADD User (name = 'Bob', age = 30, email = 'bob@email.com', scores = [1 100 44 82]) ('Bob2', 33, 'bob2@email.com', [])
DELETE
Similare to GRAB
but delete all entity found using the filter and return the list of UUID deleted.
DELETE User {name = 'Bob'}
UPDATE
A mix of GRAB
and ADD
. This take a filter first, then the new data.
Here we update the 5 first User named adrien
to add a capital and become Adrien
.
UPDATE User [5] {name='adrien'} => (name = 'Adrien')
Note that compared to ADD
, you don't need to specify all member between ()
. Only the one specify will be updated.
Examples list
Command | Description |
---|---|
GRAB User | Get all users |
GRAB User { name = 'Adrien' } | Get all users named Adrien |
GRAB User [1; email] | Get one user's email |
GRAB User | ASC name | | Get all users ordered by name |
GRAB User [name] { age > 10 AND name != 'Adrien' } | Get users' name if more than 10 years old and not named Adrien |
GRAB User { age > 10 AND (name = 'Adrien' OR name = 'Bob'} | Use multiple condition |
UPDATE User [1] { name = 'Adrien' } => ( email = 'new@email.com' ) | Update a user's email |
REMOVE User { id = '000-000' } | Remove a user by ID |
ADD User ( name = 'Adrien', email = 'email', age = 40 ) | Add a new user |
Not yet implemented
Command | Description |
---|---|
GRAB User { age > 10 AND name IN ['Adrien' 'Bob']} | In comparison |
GRAB User [1] { bestfriend IN { name = 'Adrien' } } | Get one user that has a best friend named Adrien |
GRAB User [10; friends [1]] { age > 10 } | Get one friend of the 10th user above 10 years old |
GRAB Message [100; comments [ date ] ] { writter IN { name = 'Adrien' }.bestfriend } | Get the date of 100 comments written by the best friend of a user named Adrien |
GRAB User { IN Message { date > '12-01-2014' }.writter } | Get all users that sent a message after the 12th January 2014 |
GRAB User { !IN Comment { }.writter } | Get all users that didn't write a comment |
GRAB User { IN User { name = 'Adrien' }.friends } | Get all users that are friends with an Adrien |
Data types
Their is 5 data type for the moment:
int
: 64 bit integerfloat
: 64 bit float. Need to have a dot,1.
is a float1
is an integer.bool
: Boolean, can betrue
orfalse
string
: Character array between''
uuid
: Id in the UUID format, used for relationship, ect. All struct have an id member.
Comming soon:
date
: A date in yyyy/mm/dddatetime
: A date time in yyyy/mm/dd/hh/mm/sstime
: A time in hh/mm/ss
All data type can be an array of those type using [] in front of it. So []int is an array of integer.
All data type can also be null
. Expect array that can only be empty.
Lexique
- Struct: A struct of how to store data. E.g.
User
- Entity: An entity is one instance of a struct.
- Member: A member is one data saved in a struct. E.g.
name
inUser
How does it work ?
TODO: Create a tech doc of what is happening inside.
Roadmap
v0.1 - Base
- UUID
- CLI
- Tokenizers
- ZiQL parser
- Schema engine
- File engine
v0.2 - Usable
- B-Tree
- Relationships
- Date
- Docker
v0.3 - QoL
- Schema migration
- Dump/Bump data
- Recovery
- Better CLI
v0.4 - Usability
- Server
- Python interface
- Go interface
v0.5 - In memory
- In memory option
- Cache
v0.6 - Performance
- Transaction
- Multi threading
- Lock manager
v0.7 - Safety
- Auth
- Metrics
- Durability
v0.8 - Advanced
- Query optimizer
v0.9 - Docs
- ZiQL tuto
- Deployment tuto
- Code docs
- CLI help
v1.0 - Web interface
- Query builder
- Tables
- Schema visualization
- Dashboard metrics
Let's see where it (or my brain) start explode ;)