orange

package module
v0.0.0-...-77f95b2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 8, 2016 License: MIT Imports: 10 Imported by: 0

README

Orange GoDocCoverage Status

Build Status

Orange is a lightweight, simple Object relational Mapper for Golang. Orange offers a simple API for building meaningful database queries, and good abstractions on top of standard database/sq

Orange is inspired by gorm

Features

  • Simple API
  • Fast
  • Auto migrations
  • Multiple database support( currently only postgresql but mysql and sqlite are work in progress)
  • Zero dependency( only the standard library)
  • Simple SQL query building API

Motivation

This is my understanding of Object Relational Mapping with Golang. Instead of writing a blog post, I took the liberty to implement orange. It has almost all the things you might need to interact with databases with Golang.

The source code is geared toward people who want to harness the power of Go. There is a lot of myths around reflections in Go, I have almost used all the techniques you will need to master reflections.

THIS IS NOT FOR PRODUCTION USE, unless you know what you are doing in which case your contribution is welcome.

Installation

go get github.com/gernest/orange

Usage

The following is a simple example to showcase the power of orange, for comprehensive API please check The Orange Documentation

package orange_test

import (
	"fmt"

	"github.com/gernest/orange"

	// Include the driver for your database
	_ "github.com/lib/pq"
)

type golangster struct {
	ID   int64
	Name string
}

func Example() {

	// Open a database connection
	connectionSTring := "user=postgres dbname=orange_test sslmode=disable"
	db, err := orange.Open("postgres", connectionSTring)
	if err != nil {
		panic(err)
	}

	// Register the structs that you want to map to
	err := db.Register(&golangster{})
	if err != nil {
		panic(err)
	}

	// Do database migrations( tables will be created if they dont exist
	err = db.Automigrate()
	if err != nil {
		panic(err)
	}

	// Make sure we are connected to the database we want
	name := db.CurrentDatabase()
	fmt.Println(name) // on my case it is orange_test

	// Insert a new record into the database
	err = db.Create(&golangster{Name: "hello"})
	if err != nil {
		panic(err)
	}

	// count the number of records
	var count int
	db.Count("*").Bind(&count)
	fmt.Println(count) // in my case 1

	// Retrieve a a record with name hello
	result := golangster{}
	db.Find(&result, &golangster{Name: "hello"})
	fmt.Println(result) // on my case { 1, "hello"}

}

TODO list

These are some of the things I will hope to add when I get time

  • Delete record
  • Support mysql
  • support sqlite
  • more comprehensive tests
  • improve perfomace
  • talk about orange

Contributing

Contributions of all kinds are welcome

Author

Geofrey Ernest twitter @gernesti

Licence

MIT see LICENCE

Documentation

Overview

Package orange is a lightwight object relation mapper for Go. Orange offers a simple API for building meaningful database queries, and good abstractions on top of standard database/sql.

This is intendend for educational purpose only. It is not feature complete, and lacks edge case testing. There is a lot of work still to be done to make this package stable .

Use this as a way to dive into Golang, a quick easy way to interact with your database.Enjoy.

Example
package main

import (
	"fmt"

	"github.com/gernest/orange"

	// Include the driver for your database
	_ "github.com/lib/pq"
)

type golangster struct {
	ID   int64
	Name string
}

func main() {

	// Open a database connection
	connectionSTring := "user=postgres dbname=orange_test sslmode=disable"
	db, err := orange.Open("postgres", connectionSTring)
	if err != nil {
		panic(err)
	}

	// Register the structs that you want to map to
	err = db.Register(&golangster{})
	if err != nil {
		panic(err)
	}

	// Do database migrations( tables will be created if they dont exist
	err = db.Automigrate()
	if err != nil {
		panic(err)
	}

	// Make sure we are connected to the database we want
	name := db.CurrentDatabase()
	fmt.Println(name) // on my case it is orange_test

	// Insert a new record into the database
	err = db.Create(&golangster{Name: "hello"})
	if err != nil {
		panic(err)
	}

	// count the number of records
	var count int
	err = db.Count("*").Bind(&count)
	if err != nil {
		panic(err)
	}
	fmt.Println(count) // in my case 1

	// Retrieve a a record with name hello
	result := golangster{}
	err = db.Find(&result, &golangster{Name: "hello"})
	if err != nil {
		panic(err)
	}
	fmt.Println(result) // on my case { 1, "hello"}

}
Output:

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	//ErrNoField is returned when the field is not found
	ErrNoField = errors.New("no field found")

	//ErrNoFlag is returned when the flag is not found
	ErrNoFlag = errors.New("no flag found")
)

Functions

func Values

func Values(t Table, v interface{}) (cols []string, vals []interface{}, err error)

Values returns the fields that are present in the table t which have values set in model v. THis tries to breakdown the mapping of table collum names with their corresponding values.

For instance if you have a model defined as

type foo  struct{
	ID int
}

After loading a table representation of foo, you can get the column names that have been assigned values like this

cols,vals,err:=Values(fooTable,&foo{ID: 1})
// cols will be []string{"ID"}
// vals will be []interface{}{1}

Types

type Adopter

type Adopter interface {

	//Create returns sql for creating the table
	Create(Table) (string, error)

	//Field is returns sql representation of the field in the database. The
	//returned string is used for the creation of the tables.
	Field(Field) (string, error)

	//Drop returns sql query for droping the table
	Drop(Table) (string, error)

	// Quote returns  guoted  string for use in the sql queries. This offers a
	// character for positional arguments.
	//
	//	for mysql ? is used e.g name=?
	//	for postgres $ is used e.g name=$1
	// The argument is the position of the parameter.
	Quote(int) string

	//HasPrepare returns true if the adopter support prepared statements
	HasPrepare() bool

	//Name returns the name of the adopter
	Name() string

	//Database returns the current Database
	Database(*SQL) string
}

Adopter is an interface for database centric sql.

type Field

type Field interface {
	Name() string
	Type() reflect.Type
	Flags() ([]Flag, error)

	//ColumnName is the name that this field is represented in the database table
	ColumnName() string
}

Field is an interface for a table field.

type Flag

type Flag interface {
	Name() string
	Key() string
	Value() string
}

Flag is an interface for tagging objects. This can hold additional information about fields or tables.

type LoadFunc

type LoadFunc func(model interface{}) (Table, error)

LoadFunc is an interface for loading tables from models. Models are structs that maps to database tables.

type SQL

type SQL struct {
	// contains filtered or unexported fields
}

SQL provides methods for interacting with Relational databases

func Open

func Open(dbAdopter, dbConnection string) (*SQL, error)

Open opens a new database connection for the given adopter

There is only postgres support right now, mysql will come out soon.

database	| adopter name
----------------------------
postgresql	| postgres

func (*SQL) Automigrate

func (s *SQL) Automigrate() error

Automigrate creates the database tables if they don't exist

func (*SQL) Bind

func (s *SQL) Bind(value interface{}, args ...interface{}) error

Bind executes the query and scans results into value. If there is any error it will be returned.

values is a pointer to the golang type into which the resulting query results will be assigned. For structs, make sure the strucrs have been registered with the Register method.

If you want to assign values from the resulting query you can pass them ass a comma separated list of argumens.

eg db.Bind(&col1,&col2,&col3)
will assign results from executing the query(only first row) to
col1,col2,and col3 respectively

value can be a slice of struct , in which case the stuct should be a model which has previously been registered with Register method.

When value is a slice of truct the restult of multiple rows will be assigned to the struct and appeded to the slice. So if the result of the query has 10 rows, the legth of the slice will be 10 and each slice item will be a struct containing the row results.

TODO(gernest) Add support for a slice of map[string]interface{}

func (*SQL) BuildQuery

func (s *SQL) BuildQuery() (string, []interface{}, error)

BuildQuery returns the sql query that will be executed

func (*SQL) Copy

func (s *SQL) Copy() *SQL

Copy returns a new copy of s. It is used for effective method chaining to avoid messing up the scope.

func (*SQL) CopyQuery

func (s *SQL) CopyQuery() *SQL

CopyQuery returns a copy of *SQL when the composed query has already been executed.

func (*SQL) Count

func (s *SQL) Count(column string) *SQL

Count adds COUNT statement, colum is the column name that you want to count. It is up to the caller to provide a single value to bind to( in which the tal count will be written to.

var total int64
db.Select(&user{}).Count"id").Bind(&total)

func (*SQL) Create

func (s *SQL) Create(model interface{}) error

Create creates a new record into the database

func (*SQL) CurrentDatabase

func (s *SQL) CurrentDatabase() string

CurrentDatabase returns the name of the database in which the queries are executed.

func (*SQL) DB

func (s *SQL) DB() *sql.DB

DB returns the underlying Database connection.

func (*SQL) DropTable

func (s *SQL) DropTable(model interface{}) error

DropTable drops the Database table for the model.

func (*SQL) Exec

func (s *SQL) Exec(query string, args ...interface{}) (sql.Result, error)

Exec executes the query.

func (*SQL) Find

func (s *SQL) Find(model interface{}, where ...interface{}) error

Find executes the composed query and retunrs a single value if model is not a slice, or a slice of models when the model is slice.

func (*SQL) Limit

func (s *SQL) Limit(condition int) *SQL

Limit sets up LIMIT clause, condition is the value for limit. Calling this with condition, will set a barrier to the actual number of rows that are returned after executing the query.

If you set limit to 10, only the first 10 records will be returned and if the query result returns less than the 10 rows thn they will be used instead.

func (*SQL) LoadFunc

func (s *SQL) LoadFunc(f LoadFunc) *SQL

LoadFunc sets f as the table loading function. To get Table from models the function f will be used. It is up to the user to make sense out of the Table implementation when this method is used.

func (*SQL) Offset

func (s *SQL) Offset(condition int) *SQL

Offset adds OFFSET clause with the offset value set to condition.This allows you to pick just a part of the result of executing the whole query, all the rows before condition will be skipped.

For instance if condition is set to 5, then the results will contain rows from number 6

func (*SQL) Query

func (s *SQL) Query(query string, args ...interface{}) (*sql.Rows, error)

Query retriews matching rows . This wraps the sql.Query and no further no further processing is done.

func (*SQL) QueryRow

func (s *SQL) QueryRow(query string, args ...interface{}) *sql.Row

QueryRow QueryRow returnes a single matched row. This wraps sql.QueryRow no further processing is done.

func (*SQL) Register

func (s *SQL) Register(models ...interface{}) error

Register registers model. All models should be registered before calling any method from this struct. It is safe to call this method in multiple goroutines.

func (*SQL) Select

func (s *SQL) Select(query interface{}, args ...interface{}) *SQL

Select adds SELECT clause. No query is executed by this method, only the call for *SQL.Bind will excute the built query( with exceptions of the wrappers for database/sql package)

query can be a model or a string. Only when query is a string will the args be used.

func (*SQL) Update

func (s *SQL) Update(model interface{}) error

Update updates a model values into the database

func (*SQL) Where

func (s *SQL) Where(value interface{}, args ...interface{}) *SQL

Where adds a where query, value can be a query string, a model or a map

type Table

type Table interface {

	//Name returns the name of the table.
	Name() string

	//Fields returns a collection of fields of the table. They are like an abstract
	//representation of database table colums although in some case they might
	//not. This means what they are will depend on the implementation details.
	Fields() ([]Field, error)

	//Size  returns the number of fields present in the table
	Size() int

	//Flags is a collection additional information that is tied to the table. They can be
	//anything within the scope of your wild imagination.
	Flags() ([]Flag, error)
}

Table is an interface for an object that can be mapped to a database table. This has no one one one correspondance with the actual database table. There is no limitation of the implementation of this interface.

Just be aware that, In case you want to use custom implementation make sure the loading function is set correctly to your custom table loading function. see *SQL.LoadFunc for more details on custom table loading functoons.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL