GithubHelp home page GithubHelp logo

chai's Introduction

ChaiSQL

ChaiSQL is a modern embedded SQL database, focusing on flexibility and ease of use for developers.

Build Status go.dev reference Status

Key Features

  • PostgreSQL API: ChaiSQL SQL API is compatible with PostgreSQL
  • Optimized for Go: Native Go implementation with no CGO dependency.
  • Storage flexibility: Store data on-disk or in-memory.
  • Solid foundations: ChaiSQL is backed by Pebble for native Go toolchains, and RocksDB for non-Go or CGO builds (coming soon).

Roadmap

ChaiSQL is work in progress and is not ready yet for production.

Here is a high level list of features that we want to implement in the near future, in no particular order:

  • Stable storage format (90% completed)
  • Implement most of the SQL-92 standard (detailed roadmap coming soon)
  • Provide clients for other languages (JS/TS, Python, etc) and add support for RocksDB as the backend
  • Compatibility with PostgreSQL drivers and ORMs

Installation

Install the ChaiSQL database

go install github.com/chaisql/chai

Quickstart

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/chaisql/chai"
)

func main() {
    // Create a database instance, here we'll store everything on-disk
    db, err := chai.Open("mydb")
    if err != nil {
        log.Fatal(err)
    }
    defer db.Close()

    err = db.Exec(`
        CREATE TABLE user (
            id              INT         PRIMARY KEY,
            name            TEXT        NOT NULL UNIQUE,
            created_at      TIMESTAMP   NOT NULL
        )
    `)

    err = db.Exec(`INSERT INTO user (id, name, age) VALUES ($1, $2, $3)`, 20, "foo", 40)

    rows, err := db.Query("SELECT id, name, age, address FROM user WHERE age >= $1", 18)
    defer rows.Close()

    err = rows.Iterate(func(r *chai.Row) error {
        // scan each column
        var id, name, age
        err = r.Scan(&id, &name, &age)
        // or into a struct
        var u User
        err = r.StructScan(&u)
        // or even a map
        var m map[string]any
        err = r.MapScan(&m)
        return nil
    })
}

Checkout the Go doc and the usage example in the README to get started quickly.

In-memory database

For in-memory operations, simply use :memory::

db, err := chai.Open(":memory:")

Using database/sql

// import chai as a blank import
import _ "github.com/chaisql/chai/driver"

// Create a sql/database DB instance
db, err := sql.Open("chai", "mydb")
if err != nil {
    log.Fatal(err)
}
defer db.Close()

// Then use db as usual
res, err := db.ExecContext(...)
res, err := db.Query(...)
res, err := db.QueryRow(...)

// use the driver.Scanner to scan into a struct
var u User
err = res.Scan(driver.Scanner(&u))

chai shell

The chai command line provides an SQL shell for database management:

go install github.com/chaisql/chai/cmd/chai@latest

Usage example:

# For in-memory database:
chai

# For disk-based database:
chai dirName

Contributing

Contributions are welcome!

A big thanks to our contributors!

Made with contrib.rocks.

For any questions or discussions, open an issue.

chai's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

chai's Issues

Partial schema

Add support for specifying the type of certain fields

CREATE TABLE foo (a STRING, b INT8, c TEXT);
INSERT INTO foo (a, b, c, d) VALUES ('hello', -10, 'bye', 'i can add other non specified fields though')

Add Bitcask backend

KV Store: https://github.com/prologic/bitcask

Currently the master branch is (really) unstable as I'm basically breaking everything with a sledgehammer. The engine package though (the one that contains interfaces that need to be implemented) wasn't touch in the master branch so it should be good.

Also, I'd really like to avoid having too many dependencies with Genji (especially because of the store implementations) so I think it should be better if the Bitcask package had its own go.mod. In next release, every backends will have their own go.mod so users will be able to choose explicitly the store they want to use.
This also means that you'll have to base your work on the v0.1.0 tag, which is fine I suppose, as I said there aren't that many changes in the engine on the master branch.

Regarding tests, there is a engine/enginetest package that contains importable tests that make sure your backend is compatible, you can take a look at the other backends if you need examples.

Support transaction promotion

Transactions are currently either read-only or read/write. When not defined explicitly, transactions must default to read-only and be promoted to read-write as soon as any write statement is run.

Select query fails with nil pointer deference in btree:774

I'm performing a query with a limit=1:

type MyModel struct {
	ID         string `genji:"pk"`
	AccountID  string `genji:"index"`
	Name       string `genji:"index"`
	Field1     uint32
	Field2     uint32
	Field3     uint32
	Field4     uint32
	Field5     uint32
	Field6     bool
}

func (self MyDAO) FindOne(tx *genji.Tx, where query.Expr) query.Result {
	table, err := tx.GetTable("mytable")
	if err != nil {
		...
	}
	return query.Select().From(table).Limit(1).Run(tx)
}

...

_, err := tx.InitTable("mytable", new(MyModel))

mymodelFields := model.NewMyModelFields()
where := query.And(
	mymodelFields.AccountID.Eq("<id>"),
	mymodelFields.Name.Eq("<name>"),
)
res := myDAO.FindOne(where)

And getting this error:

.../vendor/github.com/google/btree.(*BTree).Ascend(...)
	/.../vendor/github.com/google/btree/btree.go:774
.../vendor/github.com/asdine/genji/query.(*indexResultTable).Iterate(0xc0003027e0, 0xc000302860, 0xc000174800, 0x19ba6d0)
	
/.../vendor/github.com/asdine/genji/query/matcher.go:455 +0x6a
.../vendor/github.com/asdine/genji/table.Stream.Iterate(0x1531ac0, 0xc0003027e0, 0x0, 0xc000302860, 0x1, 0xc000302860)
	/.../vendor/github.com/asdine/genji/table/stream.go:35 +0x149
.../vendor/github.com/asdine/genji/table.Stream.Iterate(0x1532e60, 0xc000302820, 0xc000312700, 0xc0003225b0, 0x1539fc0, 0xc0000a9820)
	/.../vendor/github.com/asdine/genji/table/stream.go:40 +0x94

Support for maps

Example:

// compile time map
type MyMap map[string]int
genji record -f mymap.go -t MyMap

Binlog

Is there the ability to implement binlog equivalent ?
This is for subscriptions use case .

This library is really nice to use. Great work

Execute SQL script

The command-line tool must support reading from stdin:

# bolt
genji my.db < script.sql

# memory
genji < script.sql

# badger
genji --badger data < script.sql

Support key-only iteration

It's unclear from the documentation whether key-only iteration is supported.

For example, in an Iterate(func(recordId []byte, r record.Record) error function call, does the r variable contain a facade that will lazy-load the value, or is the value already loaded?

In the underlying storage engines, key-only iteration is specifically called out as a first class use case (because it's so important, especially for Badger), so I think that makes sense to also document and support in a higher level library like this.

Scaling / HA using Raft / Multiraft

Do any of the dB drivers have any scaling aspects ?

I would like to use genji in the traditional embedded scenario on desktops but also in servers. So for server usage I need a way to make it use Raft.

I saw bitcask and bitraft references in the issues. Looks like a promising candidate but it's not integration into genji yet.
@prologic: happy to know the status.

I think that is a badger Multiraft implementation on GitHub.

Please let me know blockers so I can decide if we should help do contribution

Contribution & Communication

Hello @asdine

as someone who is using your awesome storm since 2016 I'm really interested in genji. I would like to know if you are searching for contributors and if there is any platform for genji-interested people to communicate (Slack, Discord, IRC) in order to avoid bloating the Issues ๐Ÿ˜„

Generated code doesn't compile when no indexes present

Given the model:

type MyModel struct {
	ID     string `genji:"pk"`
	Field1 string
	Field2 string
	Field3 uint32
	Field4 uint32
}

Compiling the generated code fails due to an unused import:

model/mymodel.genji.go:10:2: imported and not used: "github.com/.../vendor/github.com/asdine/genji/index"

Support Cursors in engines

AscendGreaterOrEqual and DescendLessOrEqual are callback based APIs that don't allow to control when and if we want to read the next item.
They also force us to run a goroutine if we want to interface them with the database/sql/driver#Rows type.

Instead of these methods, we'll ask engines to return cursors:

type Store interface {
  ...
  Cursor(reverse bool) (Cursor, error)
}

type Cursor interface {
  // Must be called before calling Pair
  // Returns false if there is an error or no more data
  Next() bool
  // Returns the current k-v pair.
  Pair() ([]byte, []byte, error)
  // Returns an error if Next failed
  Err() error
}

Support nested fields

> INSERT INTO foo (a, b, c) VALUES (1, {name: 'john', age: 18}, false);
> SELECT * FROM foo;
{
  "a": 1,
  "b": {
    "name": "john",
    "age": 18,
   }
  "c": false
}
> SELECT b.name FROM foo WHERE b.age = 18;
{
  "b.name": "john"
}
> INSERT INTO foo VALUES {a: 1, b: {name: 'john', age: 18}, friends: [1, 2, true]};

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.