Giter Site home page Giter Site logo

qb's Introduction

alt text

qb - the database toolkit for go

Build Status Coverage Status License (LGPL version 2.1) Go Report Card GoDoc

This project is currently pre 1.

Currently, it's not feature complete. It can have potential bugs. There are no tests covering concurrency race conditions. It can crash especially in concurrency. Before 1.x releases, each major release could break backwards compatibility.

About qb

qb is a database toolkit for easier db queries in go. It is inspired from python's best orm, namely sqlalchemy. qb is an orm(sqlx) as well as a query builder. It is quite modular in case of using just expression api and query building stuff.

The documentation is hosted in readme.io which has great support for markdown docs. Currently, the docs are about 80% - 90% complete. The doc files will be added to this repo soon. Moreover, you can check the godoc from here. Contributions & Feedbacks in docs are welcome.

Features

  • Support for postgres(9.5.+), mysql & sqlite3
  • Powerful expression API for building queries & table ddls
  • Struct to table ddl mapper where initial table migrations can happen
  • Transactional session api that auto map structs to queries
  • Foreign key definitions
  • Single & Composite column indices
  • Relationships (soon.. probably in 0.3 milestone)

Installation

go get -u github.com/slicebit/qb

If you want to install test dependencies then;

go get -u -t github.com/slicebit/qb

Quick Start

package main

import (
	"fmt"
	"github.com/slicebit/qb"
	_ "github.com/mattn/go-sqlite3"
    _ "github.com/slicebit/qb/dialects/sqlite"
)

type User struct {
	ID       string `db:"id"`
	Email    string `db:"email"`
	FullName string `db:"full_name"`
	Oscars   int    `db:"oscars"`
}

func main() {

	users := qb.Table(
		"users",
		qb.Column("id", qb.Varchar().Size(40)),
		qb.Column("email", qb.Varchar()).NotNull().Unique(),
		qb.Column("full_name", qb.Varchar()).NotNull(),
		qb.Column("oscars", qb.Int()).NotNull().Default(0),
		qb.PrimaryKey("id"),
	)

	db, err := qb.New("sqlite3", "./qb_test.db")
	if err != nil {
		panic(err)
	}

	defer db.Close()

	metadata := qb.MetaData()

	// add table to metadata
	metadata.AddTable(users)

	// create all tables registered to metadata
	metadata.CreateAll(db)
	defer metadata.DropAll(db) // drops all tables

	ins := qb.Insert(users).Values(map[string]interface{}{
		"id":        "b6f8bfe3-a830-441a-a097-1777e6bfae95",
		"email":     "[email protected]",
		"full_name": "Jack Nicholson",
	})

	_, err = db.Exec(ins)
	if err != nil {
		panic(err)
	}

	// find user
	var user User

	sel := qb.Select(users.C("id"), users.C("email"), users.C("full_name")).
		From(users).
		Where(users.C("id").Eq("b6f8bfe3-a830-441a-a097-1777e6bfae95"))

	err = db.Get(sel, &user)
	fmt.Printf("%+v\n", user)
}

Credits

qb's People

Contributors

aacanakin avatar cdevienne avatar faide avatar gitter-badger avatar shawnps avatar

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

qb's Issues

Table based Expression API implementation

It is required to have an expression api that can be called from Table object. Table object can start a new query using builder. For instance,

table := NewTable() // make full initialization of table
values := map[string]interface{}{
    "id": 5,
    "fullName": "Aras Can Akin"
}
table.Insert(values)

More examples can be found here

comparator, aggregator, functions should use Escape()

The following builder functions should escape;

Avg(column string) string
Count(column string) string
Sum(column string) string
Min(column string) string
Max(column string) string
NotIn(key string, values ...interface{}) string
In(key string, values ...interface{}) string
NotEq(key string, value interface{}) string
Eq(key string, value interface{}) string
Gt(key string, value interface{}) string
Gte(key string, value interface{}) string
St(key string, value interface{}) string
Ste(key string, value interface{}) string

NewTable() key detection

NewTable() should detect primary & foreign keys and call AddPrimary() & AddRef() automatically

removing engine dependency from metadata

*Engine is only used in CreateAll() & DropAll() function calls. They should be CreateAll(engine *Engine), DropAll(engine *Engine). Session object should only keep the instance of *engine.

sqlx integration

Due to selective session function problems, it is way much easier to integrate sqlx. It has currently solid implementation especially StructScan() for select statements.

The integration should be the following;

  • Engine should have db parameters as *sqlx.DB
  • Table presumably won't have any changes
  • NamedExec() can be used for dialect to be more generic just like sqlalchemy does
  • The driver dependency of dialect will be removed.
  • Sessions selective queries are much more easier

Removing types

It seems that keeping all types is not required. All distinct types should be removed. Only type struct definition and NewType() function should be left.

Engine pointer becomes nil after initialization

In tests, a test case makes engine pointer nil after initialization.

var engine *Engine

func TestSetup(t *testing.T) {
    engine := NewEngine(...)
}

func TestEngine(t *testing.T) {
    engine.Exec(query) // here engine is nil
}

This may be deriving from go 1.6 update

The right use of dialect abstraction, removal of driver dependency from builder

The current use of dialect is not efficient. It is only the definition of functions in builder. There could be separate dialect implementations with a common dialect. Structural composition can be used here. For instance;

func NewBuilder(driver string) *Dialect {
    // returns a new dialect given driver
}

type CommonDialect struct {
    // consists of current methods of builder
}

type PostgresDialect struct {
    CommonDialect
    // and extra methods
}

type MysqlDialect struct {
    CommonDialect
    // and extra methods
}

Index support in mapper

The mapper should be able to understand index tag. The index tag could be in the following format;

type User struct {
    id int `qb:"index"`
    email string `qb:"index"`
    qb.CompositeIndex `qb:"index:id, email"`
}

should build index on id, email, and a composite index id,email

support for unsigned int mappings

Postgres doesn't support unsigned int mappings. It may not be needed but it could be useful to have it in mysql. This is also a potential bug when using uint types mapping into varchar(255)

potential race condition in session.Add()

Currently, if multiple goroutines calls session.Add(), it may cause to begin transactions without commiting and shows an error like transaction is already open. There should be a locking mechanism in Add() function that locks transaction opening

separation of adapters

Each adapter should have its own file like the following;

- default_adapter.go
- mysql_adapter.go
- postgres_adapter.go
- sqlite_adapter.go

adapter based auto increments

Currently, auto increment sql code is generated by mapper. It should be adapter based that should implement AutoIncrement() function.

Reorganization of all struct dependencies

Currently, it seems odd that structs have both driver string & dialect *Dialect dependency. The struct dependencies like this should be minimized as possible as it can be.

A possible solution to removing driver dependency from dialect

Currently, almost any structs, especially dialect depends on driver string. However, it seems it doesn't have to be that way.

Query struct would keep the placeholders in named statements. Only SQL() function should have driver dependency. Moreover, SQL() function should convert the named placeholders into native placeholders.

Composite foreign key generation doesn't generate accurate syntax

Composite foreign keys generate wrong syntax. For instance,

type User struct {
    id string `qb:"constraints:ref(profile.id)"`
    name string `qb:"constraints:ref(profile.name)"`
}

generates

CREATE TABLE user(
    id VARCHAR(255),
    name VARCHAR(255),
    FOREIGN KEY(id, `name`) REFERENCES profile(id, `name`)
)

All the key columns should be encapsulated by ``

Batch query support

The builder api should be able to build query templates, which means queries without bindings. This should be done like a Query() function call, namely Template(). Then engine functions should have something like BatchExec() which can take bindings as an array. There should also be an option to have transactions in batch exec. Maybe session api would do the trick.

Add support for entering inline table primary & foreign key constraints

Currently, generic struct mapping into table doesn't allow inline primary key, foreign key, unique & index constraints. The rule should be the following;

For primary key constraints;

  • if multiple definition of primary_key constraint tag is present, then the mapper should merge them into table level primary key constraint.

For foreign key constraint;

  • same with primary_key

For index and unique;

  • there should be a type called CompositeIndex & CompositeUnique which is defined in struct as the following;
type User struct {
    Email string `qbit:"constraints:index,unique"`
    Password string `qbit:"constraints:index"`
    CompositeIndex `qbit:"email,password"`
}

,the indices would be the following;

  • email index
  • email unique
  • password index
  • email,password index

remove table api's query builders

This makes confusing to choose whether use the builder api or table api. Table api doesn't require query builders. The builder does the job.

docs

An official docs page is required. All documentation would be there. it is qb.readme.io
Quick start should also have query building api

Improvements of Session

The Session should be improved. It is currently doing nothing. The session should be a container of queries and active transaction. More info could be found here

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.