Skip to content

MrBounty/ZipponDB

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

56 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

alt text

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 ?

  • Relational database (Soon)
  • Simple and minimal query language
  • Small, light, fast, and implementable everywhere

Note: ZipponDB is still in Alpha v0.1 and is missing a lot of features, see roadmap at the end of this README.

Quickstart

  1. Get a binary: You can build the binary directly from the source code for any architecture (tutorial is coming), or using the binary in the release (coming too).
  2. Create a database: You can then run the binary, this will start a Command Line Interface. The first thing to do is to create a new database. For that, run the command db new path/to/directory, it will create a ZipponDB directory. Then db metrics to see if it worked.
  3. Select a database: You can select a database by using db use path/to/ZipponDB. You can also set the environment variable ZIPPONDB_PATH, and it will use this path, this needs to be the path to a directory with proper DATA, BACKUP, and LOG directories.
  4. Attach a schema: Once the database is created, you need to attach a schema to it (see next section for how to define a schema). For that, you can run schema init path/to/schema.txt. This will create new directories and empty files used to store data. You can test the current db schema by running schema describe.
  5. Use the database: ou can now start using the database by sending queries like that: run "ADD User (name = 'Bob')".

Note: For the moment, ZipponDB uses the current working directory as the main directory, so all paths are sub-paths of it.

Declare a schema

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.

Here an example of a file:

User (
    name: str,
    email: str,
    best_friend: User,
)

Note that the best friend is a link to another User.

Here is a more advanced example with multiple structs:

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: [] before the type means a list/array of this type.

Migration to a new schema - Not yet implemented

In the future, you will be able to update the schema, such as adding a new member to a struct, and update the database. For the moment, you can't change the schema once it's initialized.

ZipponQL

ZipponDB uses its own query language, ZipponQL or ZiQL for short. Here are the key points to remember:

  • 4 actions available: GRAB, ADD, UPDATE, DELETE
  • All queries start with an action followed by a struct name
  • {} are filters
  • [] specify how much and what data
  • () contain new or updated data (not already in the file)
  • || are additional options

Disclaimer: Lot of stuff are still missing and the language may change over time.

ZiQL Quickstart

For more information see ZiQL Introduction

GRAB

The main action is GRAB, this will parse files and return data.

GRAB User {name = 'Bob' AND (age > 30 OR age < 10)}

GRAB queries return a list of JSON objects with the data inside, e.g:

[{id:"1e170a80-84c9-429a-be25-ab4657894653", name: "Gwendolyn Ray", age: 70, email: "austin92@example.org", scores: [ 77 ], friends: [], }, ]

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.

ADD User (name = 'Bob', age = 30, email = 'bob@email.com', scores = [1 100 44 82])

DELETE

Similar to GRAB but deletes all entities found using the filter and returns a list of deleted UUIDs.

DELETE User {name = 'Bob'}

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':

UPDATE User [5] {name='bob'} TO (name = 'Bob')

Not yet implemented

A lot of things are not yet implemented, you can find examples in the ZiQL Introduction.

This include:

  • Relationship
  • Ordering
  • Batch
  • Array manipulation
  • And more...

Link query - Not yet implemented

You can also link query. Each query returns a list of UUID of a specific struct. You can use it in the next query. Here an example where I create a new Comment that I then append to the list of comment of one specific User.

ADD Comment (content='Hello world', at=NOW, like_by=[]) => added_comment => UPDATE User {id = '000'} TO (comments APPEND added_comment)

The name between => is the variable name of the list of UUID used for the next queries, you can have multiple one if the link has more than 2 queries. You can also just use one => but the list of UUID is discarded in that case.

Data types

There is 5 data types for the moment:

  • int: 64 bit integer
  • float: 64 bit float. Need to have a dot, 1. is a float 1 is an integer.
  • bool: Boolean, can be true or false
  • 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/dd
  • datetime: A date time in yyyy/mm/dd/hh/mm/ss
  • time: A time in hh/mm/ss

All data types can be an array of those types using [] in front of it. So []int is an array of integer.

All data types can also be null. Except arrays that can only be empty.

Why I created it ?

Well, the first reason is to learn both Zig and databases.

The second is to use it in my apps. I like to deploy Golang + HTMX apps on Fly.io, but I often find myself struggling to get a simple database. I can either host it myself, but then I need to link my app and the database securely. Or I can use a cloud database service, but that means my database is far from my app. All I want is to give a Fly machine 10GB of storage, do some backups on it, and call it a day. But for that, I need to include it in the Dockerfile of my app. What easier way than just a binary?

So that's my long-term goal: to use it in my apps as a simple database that lives with the app, sharing CPU and memory.

How does it work ?

TODO: Create a tech doc of what is happening inside.

Roadmap

Note: This will probably evolve over time.

Alpha

v0.1 - Base

  • UUID
  • CLI
  • Tokenizers
  • ZiQL parser
  • Schema engine
  • File engine

v0.2 - Usable

  • B+Tree
  • Relationships
  • Date
  • Linked query
  • Docker

v0.3 - QoL

  • Schema migration
  • Dump/Bump data
  • Recovery
  • Better CLI
  • Logs

Beta

v0.4 - Usability

  • Server
  • Config file
  • Python interface
  • Go interface

v0.5 - In memory

  • In memory option
  • Cache

v0.6 - Performance

  • Transaction
  • Multi threading
  • Lock manager
  • Optimized data file

v0.7 - Safety

  • Auth
  • Metrics
  • Durability

Gold

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 ;)

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages