Update README and doc
This commit is contained in:
parent
154a146678
commit
a16c9b29c1
42
README.md
42
README.md
@ -1,16 +1,18 @@
|
||||

|
||||
|
||||
# Introduction
|
||||
|
||||
ZipponDB is a relational database written entirely in Zig from scratch with 0 dependencies.
|
||||
|
||||
ZipponDB's goal is to be ACID, light, simple, and high-performance. It aims at small to medium applications that don't need fancy features but a simple and reliable database.
|
||||
|
||||
### Why Zippon ?
|
||||
Key Features:
|
||||
|
||||
- Relational database
|
||||
- Simple and minimal query language
|
||||
- Small, light, fast, and implementable everywhere
|
||||
* **Small:** Binary is small, around 2-3Mb.
|
||||
* **Fast:** Parse millions of entities in milliseconds.
|
||||
* **Relationship:** Build with focus on easy relationship.
|
||||
* **Query Language:** Use it's own simple query language.
|
||||
* **No dependencies:** Depend on nothing, every line of code running is in the codebase.
|
||||
* **Open-source:** Open-source under MIT licence.
|
||||
* **Portable:** Easily compiled and deployed across various platforms.
|
||||
|
||||
For more informations visit the docs: https://mrbounty.github.io/ZipponDB/
|
||||
|
||||
@ -20,18 +22,32 @@ For more informations visit the docs: https://mrbounty.github.io/ZipponDB/
|
||||
|
||||
In ZipponDB, you use structures, or structs for short, and not tables to organize how your data is stored and manipulated. A struct has a name like `User` and members like `name` and `age`.
|
||||
|
||||
Create a file that contains a schema that describes all structs. Compared to SQL, you can see it as a file where you declare all table names, column names, data types, and relationships. All structs have an id of the type UUID by default.
|
||||
Create a file that contains a schema that describes all structs. Compared to SQL, you can see it as a file where you declare all table names, column names, data types, and relationships.
|
||||
All structs have an id of the type UUID by default.
|
||||
|
||||
Here an example of a file:
|
||||
```lua
|
||||
User (
|
||||
name: str,
|
||||
age: int,
|
||||
email: str,
|
||||
best_friend: User,
|
||||
Parent: User,
|
||||
childrens: []User,
|
||||
orders: []Order,
|
||||
)
|
||||
|
||||
Order (
|
||||
at: datetime,
|
||||
items: []Item,
|
||||
)
|
||||
|
||||
Item (
|
||||
name: str,
|
||||
category: str,
|
||||
)
|
||||
```
|
||||
|
||||
Note that the best friend is a link to another `User`. You can find more examples [here](https://github.com/MrBounty/ZipponDB/tree/main/schema).
|
||||
Note that parent is a link to another `User` and can be `none`, `[]` mean an array. You can find more examples [here](https://github.com/MrBounty/ZipponDB/tree/main/schema).
|
||||
|
||||
# ZipponQL
|
||||
|
||||
@ -44,12 +60,12 @@ ZipponDB uses its own query language, ZipponQL or ZiQL for short. Here are the k
|
||||
|
||||
## GRAB
|
||||
|
||||
The main action is `GRAB`, this will parse files and return data.
|
||||
The main action is `GRAB`, it parse files and return data.
|
||||
```js
|
||||
GRAB User {name = 'Bob' AND (age > 30 OR age < 10)}
|
||||
```
|
||||
|
||||
Can use [] before the filter to tell what to return.
|
||||
Using `[]` before the filter tell what to return.
|
||||
```js
|
||||
GRAB User [id, email] {name = 'Bob'}
|
||||
```
|
||||
@ -59,7 +75,7 @@ Relationship use filter within filter.
|
||||
GRAB User {best_friend IN {name = 'Bob'}}
|
||||
```
|
||||
|
||||
GRAB queries return a list of JSON objects with the data inside, e.g:
|
||||
GRAB queries return a list of JSON objects, e.g:
|
||||
```
|
||||
[{id:"1e170a80-84c9-429a-be25-ab4657894653", name: "Gwendolyn Ray", age: 70, email: "austin92@example.org", scores: [ 77 ], friends: [], }, ]
|
||||
```
|
||||
@ -68,7 +84,7 @@ GRAB queries return a list of JSON objects with the data inside, e.g:
|
||||
|
||||
The `ADD` action adds one entity to the database. The syntax is similar to `GRAB`, but uses `()`. This signifies that the data is not yet in the database.
|
||||
```js
|
||||
ADD User (name = 'Bob', age = 30, email = 'bob@email.com', scores = [1 100 44 82])
|
||||
ADD User (name = 'Bob', age = 30)
|
||||
```
|
||||
|
||||
## DELETE
|
||||
|
@ -25,7 +25,7 @@ Alternatively, set the `ZIPPONDB_PATH` environment variable.
|
||||
Define a [schema](/ZipponDB/Schema) and attach it to the database by running:
|
||||
|
||||
```bash
|
||||
schema init path/to/schema.txt
|
||||
schema use path/to/schema.txt
|
||||
```
|
||||
|
||||
This will create the necessary directories and empty files for data storage. Test the current database schema by running:
|
||||
|
@ -13,7 +13,7 @@ User (
|
||||
)
|
||||
```
|
||||
|
||||
In this example, the `best_friend` member is a reference to another `User` struct, demonstrating how relationships between structs can be established.
|
||||
In this example, the `best_friend` member is a reference to another `User`.
|
||||
|
||||
Here's a more complex example featuring multiple structs:
|
||||
```lua
|
||||
@ -48,7 +48,7 @@ In future releases, ZipponDB will support schema updates, allowing you to modify
|
||||
|
||||
I will add commands or query to add, delete and update struct in the schema. Maybe the schema will be a Struct itself with a schema like that:
|
||||
|
||||
```
|
||||
```lua
|
||||
Struct (
|
||||
name: str,
|
||||
members: []Member,
|
||||
@ -60,7 +60,7 @@ Member (
|
||||
)
|
||||
```
|
||||
|
||||
Like that can just do ZiQL qquery directly on it.
|
||||
Like that can just do ZiQL query directly on it.
|
||||
|
||||
### Planned Migration Features
|
||||
|
||||
|
@ -28,14 +28,14 @@ medium applications that want a quick and simple database.
|
||||
* **Small:** ZipponDB binary is small, around 2-3Mb.
|
||||
* **Fast:** ZipponDB can parse millions of entities in milliseconds.
|
||||
* **Relationship:** ZipponDB is build with focus on easy relationship.
|
||||
* **Query Language:** ZipponDB use it's own simple query language named ZipponQL.
|
||||
* **No dependencies:** ZipponDB depend on nothing, every line of code is in the codebase.
|
||||
* **Query Language:** ZipponDB use it's own simple query language.
|
||||
* **No dependencies:** ZipponDB depend on nothing, every line of code running is in the codebase.
|
||||
* **Open-source:** ZipponDB is open-source under MIT licence.
|
||||
* **Portable:** ZipponDB can be easily compiled and deployed across various platforms.*
|
||||
|
||||
<small>* Plan for more platforms like arm, 32 bit system.</small>
|
||||
|
||||
### To come
|
||||
### After
|
||||
|
||||
* **Auth:** Be able to auth users, maybe third-party OAuth.
|
||||
* **HTTP server:** Be able to start a simple HTTP server and send json.
|
||||
|
@ -27,3 +27,9 @@ ADD User
|
||||
('Bob2', 33, 'bob2@email.com', [])
|
||||
```
|
||||
|
||||
## Soon
|
||||
|
||||
* Default value
|
||||
* Array default is empty
|
||||
* Link default is none
|
||||
|
||||
|
@ -2,30 +2,30 @@
|
||||
|
||||
The main action is `GRAB`, this will parse files and return data.
|
||||
|
||||
#### Basic
|
||||
## Basic
|
||||
|
||||
Here's how to return all `User` entities without any filtering:
|
||||
Here's how to return all `User` without any filtering:
|
||||
```
|
||||
GRAB User
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
To get all `User` entities above 30 years old:
|
||||
To get all `User` above 30 years old:
|
||||
```
|
||||
GRAB User {age > 30}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
To return only the `name` member of `User` entities:
|
||||
To return only the member `name` of `User`:
|
||||
```
|
||||
GRAB User [name] {age > 30}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
To return the 10 first `User` entities:
|
||||
To return the 10 first `User`:
|
||||
```
|
||||
GRAB User [10] {age > 30}
|
||||
```
|
||||
@ -53,14 +53,14 @@ GRAB queries return a list of JSON objects with the data inside, e.g:
|
||||
|
||||
---
|
||||
|
||||
#### Ordering - Not yet implemented
|
||||
## Ordering - Not yet implemented
|
||||
|
||||
To order the results by `name`:
|
||||
```js
|
||||
GRAB User [10; name] {age > 10} |ASC name|
|
||||
```
|
||||
|
||||
#### Array
|
||||
## Array
|
||||
You can use the `IN` operator to check if something is in an array:
|
||||
```js
|
||||
GRAB User { age > 10 AND name IN ['Adrien' 'Bob']}
|
||||
@ -68,7 +68,7 @@ GRAB User { age > 10 AND name IN ['Adrien' 'Bob']}
|
||||
|
||||
---
|
||||
|
||||
#### Relationship
|
||||
## Relationship
|
||||
|
||||
2 main things to remember with relationship:
|
||||
|
||||
@ -81,7 +81,7 @@ GRAB User { bestfriend IN { name = 'Adrien' } }
|
||||
```
|
||||
---
|
||||
|
||||
You can specify how much data to return and which members to include, even for links inside entity. In this example, I get 1 friend's name for 10 `User`:
|
||||
You can specify how much data to return and which members to include, even for links. In this example, I get 1 friend's name for 10 `User`:
|
||||
```js
|
||||
GRAB User [10; friends [1; name]]
|
||||
```
|
||||
@ -94,7 +94,7 @@ GRAB User { friends IN { name = 'Adrien' } }
|
||||
```
|
||||
---
|
||||
|
||||
To get `User` entities with all friends named Adrien:
|
||||
To get `User` with all friends named Adrien:
|
||||
```js
|
||||
GRAB User { friends ALLIN { name = 'Adrien' } }
|
||||
```
|
||||
@ -106,7 +106,7 @@ GRAB User { friends !IN { name = 'Adrien' } }
|
||||
```
|
||||
---
|
||||
|
||||
#### Dot - Not yet implemented
|
||||
## Dot - Not yet implemented
|
||||
|
||||
You can use `.` if you just want to do one comparison. Here I get all `User` that ordered at least one book:
|
||||
```js
|
||||
@ -118,3 +118,13 @@ Same as:
|
||||
GRAB User {orders IN { products IN { category IN { name = 'Book'} } } }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
You can also use the dot like that:
|
||||
|
||||
```js
|
||||
GRAB User.orders {name = 'Bob'}
|
||||
```
|
||||
|
||||
The filter is done on User but it return Order.
|
||||
It return all Order from User named 'Bob'.
|
||||
|
@ -16,6 +16,8 @@ Here are the key points to remember:
|
||||
|
||||
***Disclaimer: The language may change a bit over time.***
|
||||
|
||||
---
|
||||
|
||||
## Making errors
|
||||
|
||||
When you make an error writing ZiQL, you should see something like this to help you understand where you made a mistake:
|
||||
@ -31,9 +33,11 @@ GRAB User {name = 'Bob' AND {age > 10}}
|
||||
^
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## To return
|
||||
|
||||
What is between `[]` are what data to return. You can see it as the column name after `SELECT` in SQL.
|
||||
What is between `[]` are what data to return. You can see it as the column name after `SELECT` in SQL and number after `LIMIT`.
|
||||
|
||||
Here I return just the name of all users:
|
||||
```
|
||||
@ -51,8 +55,6 @@ Here the name of the 100 first users:
|
||||
GRAB User [100; name]
|
||||
```
|
||||
|
||||
### For relationship
|
||||
|
||||
You can also specify what data to return for each relationship returned. By default, query do not return any relationship.
|
||||
|
||||
This will return the name and best friend of all users:
|
||||
@ -66,6 +68,8 @@ You can also specify what the best friend return:
|
||||
GRAB User [name, best_friend [name, age]] {}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Filters
|
||||
|
||||
What is between `{}` are filters, basically as a list of condition. This filter is use when parsing files and evaluate entities. You can see it as `WHERE` in SQL.
|
||||
@ -78,7 +82,9 @@ Here an example in a query:
|
||||
GRAB User {name = 'Bob' AND age > 44}
|
||||
```
|
||||
|
||||
### For relationship
|
||||
---
|
||||
|
||||
## Relationship
|
||||
|
||||
Filter can be use inside filter. This allow simple yet powerfull relationship.
|
||||
|
||||
@ -110,6 +116,8 @@ GRAB User {orders IN { products.category.name = 'Book' AND date > 2024/01/01} }
|
||||
|
||||
1. Dot not yet implemented
|
||||
|
||||
---
|
||||
|
||||
|
||||
## Link query - Not yet implemented
|
||||
|
||||
@ -136,9 +144,68 @@ Which is the same as:
|
||||
GRAB User {name != 'Bob' AND age > 18}
|
||||
```
|
||||
|
||||
<small>Note that the query are completly isolated, so files will be parse 3 times.</small>
|
||||
|
||||
Another example:
|
||||
```
|
||||
GRAB Product [1] {category.name = 'Book'} => book =>
|
||||
GRAB Order {date > 2024/01/01 AND products IN book} => book_orders =>
|
||||
GRAB User [100] {orders IN book_orders}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Actions
|
||||
|
||||
### [GRAB](/ZipponDB/ziql/grab)
|
||||
|
||||
The main action is `GRAB`, it parse files and return data.
|
||||
```js
|
||||
GRAB User {name = 'Bob' AND (age > 30 OR age < 10)}
|
||||
```
|
||||
|
||||
Using `[]` before the filter tell what to return.
|
||||
```js
|
||||
GRAB User [id, email] {name = 'Bob'}
|
||||
```
|
||||
|
||||
Relationship use filter within filter.
|
||||
```js
|
||||
GRAB User {best_friend IN {name = 'Bob'}}
|
||||
```
|
||||
|
||||
GRAB queries return a list of JSON objects, e.g:
|
||||
```
|
||||
[{id:"1e170a80-84c9-429a-be25-ab4657894653", name: "Gwendolyn Ray", age: 70, email: "austin92@example.org", scores: [ 77 ], friends: [], }, ]
|
||||
```
|
||||
|
||||
[More info.](/ZipponDB/ziql/grab)
|
||||
|
||||
### [ADD](/ZipponDB/ziql/add)
|
||||
|
||||
The `ADD` action adds one entity to the database. The syntax is similar to `GRAB`, but uses `()`. This signifies that the data is not yet in the database.
|
||||
```js
|
||||
ADD User (name = 'Bob', age = 30)
|
||||
```
|
||||
|
||||
[More info.](/ZipponDB/ziql/add)
|
||||
|
||||
### [DELETE](/ZipponDB/ziql/delete)
|
||||
|
||||
Similar to `GRAB` but deletes all entities found using the filter and returns a list of deleted UUIDs.
|
||||
```js
|
||||
DELETE User {name = 'Bob'}
|
||||
```
|
||||
|
||||
[More info.](/ZipponDB/ziql/delete)
|
||||
|
||||
### [UPDATE](/ZipponDB/ziql/update)
|
||||
|
||||
A mix of `GRAB` and `ADD`. It takes a filter first, then the new data.
|
||||
Here, we update the first 5 `User` entities named 'bob' to capitalize the name and become 'Bob':
|
||||
```js
|
||||
UPDATE User [5] {name='bob'} TO (name = 'Bob')
|
||||
```
|
||||
|
||||
[More info.](/ZipponDB/ziql/update)
|
||||
|
||||
|
@ -20,6 +20,8 @@ You can use operations on values themselves when updating:
|
||||
UPDATE User {name = 'Bob'} TO (age += 1)
|
||||
```
|
||||
|
||||
## Array - Not yet implemented
|
||||
|
||||
You can also manipulate arrays, like adding or removing values:
|
||||
```js
|
||||
UPDATE User {name='Bob'} TO (scores APPEND 45)
|
||||
@ -30,7 +32,7 @@ UPDATE User {name='Bob'} TO (scores REMOVEAT [0 1 2])
|
||||
Currently, there will be four keywords for manipulating lists:
|
||||
|
||||
- `APPEND`: Adds a value to the end of the list.
|
||||
- `REMOVE`: Checks the list, and if the same value is found, deletes it.
|
||||
- `REMOVE`: Checks the list, and if the value is found, deletes it.
|
||||
- `REMOVEAT`: Deletes the value at a specific index.
|
||||
- `CLEAR`: Removes all values from the array.
|
||||
|
||||
|
@ -9,11 +9,11 @@ SELECT * FROM User
|
||||
```
|
||||
|
||||
```
|
||||
GRAB User
|
||||
or
|
||||
GRAB User {}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Selection on condition
|
||||
|
||||
```
|
||||
@ -27,6 +27,8 @@ AND (age > 30 OR age < 10);
|
||||
GRAB User {name = 'Bob' AND (age > 30 OR age < 10)}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Select something
|
||||
|
||||
```
|
||||
@ -39,9 +41,10 @@ LIMIT 100
|
||||
GRAB User [100; name, age] {}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Relationship
|
||||
|
||||
### List of other entity
|
||||
|
||||
```
|
||||
SELECT u1.name AS user_name, GROUP_CONCAT(u2.name || ' (' || u2.age || ')') AS friends_list
|
||||
@ -55,15 +58,13 @@ GROUP BY u1.name;
|
||||
GRAB User [name, friends [name, age]] {age > 30}
|
||||
```
|
||||
|
||||
### Join
|
||||
|
||||
#### Simple one
|
||||
---
|
||||
|
||||
SQL:
|
||||
```
|
||||
SELECT Users.name, Orders.orderID, Orders.orderDate
|
||||
FROM Users
|
||||
INNER JOIN Orders ON Users.UsersID = Orders.CustomerID;
|
||||
INNER JOIN Orders ON Users.UserID = Orders.UserID;
|
||||
```
|
||||
|
||||
ZiQL:
|
||||
@ -71,7 +72,7 @@ ZiQL:
|
||||
GRAB User [name, order [id, date]] {}
|
||||
```
|
||||
|
||||
#### More complexe one
|
||||
---
|
||||
|
||||
SQL:
|
||||
```
|
||||
@ -95,12 +96,41 @@ ORDER BY
|
||||
O.orderDate DESC;
|
||||
```
|
||||
|
||||
ZiQL
|
||||
ZiQL:
|
||||
```go
|
||||
GRAB User
|
||||
[ name, orders [id, date, details [quantity]], product [name], category [name] ]
|
||||
{ orders IN {date >= 2023/01/01} AND category IN {name != 'Accessories'} }
|
||||
| orders.date DESC | // (1)!
|
||||
[ name, orders [id, date, details [quantity, products [name, category [name]]]]]
|
||||
{ orders IN {date >= 2023/01/01 AND details.products.category.name != 'Accessories' } } // (1)!
|
||||
| orders.date DESC | // (2)!
|
||||
```
|
||||
|
||||
1. Ordering not yet implemented
|
||||
1. Dot not yet implemented. But you can do it with:
|
||||
```
|
||||
details IN { products IN {category IN {name != 'Accessories'}}}
|
||||
```
|
||||
2. Ordering not yet implemented
|
||||
|
||||
---
|
||||
|
||||
SQL:
|
||||
```
|
||||
UPDATE orders o
|
||||
JOIN customers c ON o.customer_id = c.customer_id
|
||||
SET o.status = 'Priority'
|
||||
WHERE c.membership_level = 'Premium' AND o.order_date > '2023-01-01';
|
||||
```
|
||||
|
||||
ZiQL:
|
||||
```go
|
||||
GRAB User.orders { membership_level = 'Premium' } // (1)!
|
||||
=> premium_order => // (2)!
|
||||
UPDATE Order {id IN premium_order AND date > 2023/01/01}
|
||||
TO (status = 'Priority')
|
||||
```
|
||||
|
||||
1. Not yet implemented. Can't do it now.
|
||||
Here that mean filter are done on User but it return Order.
|
||||
It return all order of User with a premium membership.
|
||||
|
||||
2. Linked query not implemented
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user