@ -1,44 +0,0 @@ | |||
package xql | |||
import ( | |||
"database/sql" | |||
) | |||
type StatementBuilder interface { | |||
Create(*Table, ...interface{}) (string, []interface{}, error) | |||
Select(*Table, []QueryColumn, []QueryFilter, []QueryOrder, int64, int64) (string, []interface{}, error) | |||
Insert(*Table, interface{}, ...string) (string, []interface{}, error) | |||
Update(*Table, []QueryFilter, ...UpdateColumn) (string, []interface{}, error) | |||
Delete(*Table, []QueryFilter) (string, []interface{}, error) | |||
} | |||
var _statement_builders map[string]StatementBuilder | |||
func init() { | |||
_statement_builders = make(map[string]StatementBuilder) | |||
} | |||
func RegisterBuilder(name string, d StatementBuilder) { | |||
_statement_builders[name] = d | |||
} | |||
type Engine struct { | |||
db *sql.DB | |||
driverName string | |||
} | |||
func CreateEngine(name string, dataSource string) (*Engine, error) { | |||
db, err := sql.Open(name, dataSource) | |||
if nil != err { | |||
return nil, err | |||
} | |||
return &Engine{db:db, driverName:name}, nil | |||
} | |||
func (engine *Engine) MakeSession() *Session { | |||
return &Session{ | |||
db: engine.db, | |||
driverName: engine.driverName, | |||
} | |||
} |
@ -1 +0,0 @@ | |||
package mysql |
@ -1,187 +0,0 @@ | |||
package postgres | |||
import ( | |||
"bitbucket.org/cygnux/kepler/xql" | |||
"fmt" | |||
"reflect" | |||
"strings" | |||
) | |||
type PostgresBuilder struct { | |||
} | |||
func (pb PostgresBuilder) Create(t *xql.Table, options ...interface{}) (s string, args []interface{}, err error) { | |||
return | |||
} | |||
func (pb PostgresBuilder) Select(t *xql.Table, cols []xql.QueryColumn, filters []xql.QueryFilter, orders []xql.QueryOrder, offset int64, limit int64) (s string, args []interface{}, err error) { | |||
var colnames []string | |||
for _,x := range cols { | |||
colnames = append(colnames, x.String()) | |||
} | |||
s = fmt.Sprintf("SELECT %s FROM ", strings.Join(colnames,",")) | |||
if t.Schema != "" { | |||
s += t.Schema+"." | |||
} | |||
s += t.TableName | |||
var n int | |||
for i, f := range filters { | |||
var cause string | |||
switch f.Condition { | |||
case xql.CONDITION_AND: | |||
cause = "AND" | |||
case xql.CONDITION_OR: | |||
cause = "OR" | |||
} | |||
if i == 0 { | |||
cause = "WHERE" | |||
} | |||
if f.Operator == "" { | |||
s = fmt.Sprintf(`%s %s %s`, s, cause, f.Field) | |||
} else if f.Reversed { | |||
n += 1 | |||
s = fmt.Sprintf(`%s %s $%d %s %s`, s, cause, n, f.Operator, f.Field) | |||
args = append(args, f.Value) | |||
} else { | |||
n += 1 | |||
s = fmt.Sprintf(`%s %s %s %s $%d`, s, cause, f.Field, f.Operator, n) | |||
args = append(args, f.Value) | |||
} | |||
} | |||
var s_orders []string | |||
for _, o := range orders { | |||
switch o.Type { | |||
case xql.ORDER_ASC: | |||
s_orders = append(s_orders, fmt.Sprintf(`%s ASC`, o.Field)) | |||
case xql.ORDER_DESC: | |||
s_orders = append(s_orders, fmt.Sprintf(`%s DESC`, o.Field)) | |||
} | |||
} | |||
if len(s_orders) > 0 { | |||
s = fmt.Sprintf(`%s ORDER BY %s`, s, strings.Join(s_orders, ",")) | |||
} | |||
if offset >= 0 && limit >= 0 { | |||
s = fmt.Sprintf(`%s OFFSET %d LIMIT %d`, s, offset, limit) | |||
} | |||
return | |||
} | |||
func (pb PostgresBuilder) Insert(t *xql.Table, obj interface{}, col...string) (s string, args []interface{}, err error) { | |||
s = "INSERT INTO " | |||
if t.Schema != "" { | |||
s += t.Schema+"." | |||
} | |||
s += t.TableName | |||
var cols []string | |||
var vals []string | |||
i := 0 | |||
r := reflect.ValueOf(obj) | |||
if len(col) > 0 { | |||
for _, n := range col { | |||
v, ok := t.Columns[n] | |||
if ! ok { | |||
continue | |||
} | |||
i += 1 | |||
cols = append(cols, n) | |||
vals = append(vals, fmt.Sprintf("$%d", i)) | |||
fv := reflect.Indirect(r).FieldByName(v.PropertyName).Interface() | |||
args = append(args, fv) | |||
} | |||
}else{ | |||
for k, v := range t.Columns { | |||
i += 1 | |||
cols = append(cols, k) | |||
vals = append(vals, fmt.Sprintf("$%d", i)) | |||
fv := reflect.Indirect(r).FieldByName(v.PropertyName).Interface() | |||
args = append(args, fv) | |||
} | |||
} | |||
s = fmt.Sprintf("%s (%s) VALUES(%s)", s, strings.Join(cols,","), strings.Join(vals,",")) | |||
return | |||
} | |||
func (pb PostgresBuilder) Update(t *xql.Table, filters []xql.QueryFilter, cols ...xql.UpdateColumn) (s string, args []interface{}, err error) { | |||
s = "UPDATE " | |||
if t.Schema != "" { | |||
s += t.Schema+"." | |||
} | |||
s += t.TableName | |||
if len(cols) < 1 { | |||
panic("Empty Update Columns!!!") | |||
} | |||
var n int | |||
for i, uc := range cols { | |||
if i == 0 { | |||
s = s + " SET " | |||
} | |||
n += 1 | |||
s = fmt.Sprintf(`%s "%s"=$%d`,s, uc.Field, n) | |||
args = append(args, uc.Value) | |||
} | |||
for i, f := range filters { | |||
var cause string | |||
switch f.Condition { | |||
case xql.CONDITION_AND: | |||
cause = "AND" | |||
case xql.CONDITION_OR: | |||
cause = "OR" | |||
} | |||
if i == 0 { | |||
cause = "WHERE" | |||
} | |||
if f.Operator == "" { | |||
s = fmt.Sprintf("%s %s %s", s, cause, f.Field) | |||
} else if f.Reversed { | |||
n += 1 | |||
s = fmt.Sprintf("%s %s $%d %s %s", s, cause, n, f.Operator, f.Field) | |||
args = append(args, f.Value) | |||
} else { | |||
n += 1 | |||
s = fmt.Sprintf("%s %s %s %s $%d", s, cause, f.Field, f.Operator, n) | |||
args = append(args, f.Value) | |||
} | |||
} | |||
return | |||
} | |||
func (pb PostgresBuilder) Delete(t *xql.Table, filters []xql.QueryFilter) (s string, args []interface{}, err error) { | |||
s = "DELETE FROM " | |||
if t.Schema != "" { | |||
s += t.Schema+"." | |||
} | |||
s += t.TableName | |||
var n int | |||
for i, f := range filters { | |||
var cause string | |||
switch f.Condition { | |||
case xql.CONDITION_AND: | |||
cause = "AND" | |||
case xql.CONDITION_OR: | |||
cause = "OR" | |||
} | |||
if i == 0 { | |||
cause = "WHERE" | |||
} | |||
if f.Operator == "" { | |||
s = fmt.Sprintf("%s %s %s", s, cause, f.Field) | |||
} else if f.Reversed { | |||
n += 1 | |||
s = fmt.Sprintf("%s %s $%d %s %s", s, cause, n, f.Operator, f.Field) | |||
args = append(args, f.Value) | |||
} else { | |||
n += 1 | |||
s = fmt.Sprintf("%s %s %s %s $%d", s, cause, f.Field, f.Operator, n) | |||
args = append(args, f.Value) | |||
} | |||
} | |||
return | |||
} | |||
func init() { | |||
xql.RegisterBuilder("postgres", &PostgresBuilder{}) | |||
} |
@ -1,252 +0,0 @@ | |||
package xql | |||
import ( | |||
"errors" | |||
"strings" | |||
"fmt" | |||
"regexp" | |||
"database/sql" | |||
"database/sql/driver" | |||
"encoding/json" | |||
) | |||
type JSONDictionary map[string]interface{} | |||
type JSONDictionaryArray []JSONDictionary | |||
type HSTOREDictionary map[string]interface{} | |||
type StringArray []string | |||
type IntegerArray []int | |||
type SmallIntegerArray []int16 | |||
type BoolArray []bool | |||
func (p *JSONDictionary) Scan(src interface{}) error { | |||
if nil == src { | |||
*p = nil | |||
return nil | |||
} | |||
source, ok := src.([]byte) | |||
if !ok { | |||
return errors.New("Type assertion .([]byte) failed.") | |||
} | |||
var i JSONDictionary | |||
err := json.Unmarshal(source, &i) | |||
if err != nil { | |||
return err | |||
} | |||
*p = i | |||
return nil | |||
} | |||
func (p JSONDictionary) Value() (driver.Value, error) { | |||
j, err := json.Marshal(p) | |||
return j, err | |||
} | |||
func (p *JSONDictionaryArray) Scan(src interface{}) error { | |||
source, ok := src.([]byte) | |||
if !ok { | |||
return errors.New("Type assertion .([]byte) failed.") | |||
} | |||
var i JSONDictionaryArray | |||
err := json.Unmarshal(source, &i) | |||
if err != nil { | |||
return err | |||
} | |||
*p = i | |||
return nil | |||
} | |||
func (p JSONDictionaryArray) Value() (driver.Value, error) { | |||
j, err := json.Marshal(p) | |||
return j, err | |||
} | |||
// PARSING ARRAYS | |||
// SEE http://www.postgresql.org/docs/9.1/static/arrays.html#ARRAYS-IO | |||
// Arrays are output within {} and a delimiter, which is a comma for most | |||
// postgres types (; for box) | |||
// | |||
// Individual values are surrounded by quotes: | |||
// The array output routine will put double quotes around element values if | |||
// they are empty strings, contain curly braces, delimiter characters, | |||
// double quotes, backslashes, or white space, or match the word NULL. | |||
// Double quotes and backslashes embedded in element values will be | |||
// backslash-escaped. For numeric data types it is safe to assume that double | |||
// quotes will never appear, but for textual data types one should be prepared | |||
// to cope with either the presence or absence of quotes. | |||
// construct a regexp to extract values: | |||
var ( | |||
// unquoted array values must not contain: (" , \ { } whitespace NULL) | |||
// and must be at least one char | |||
unquotedChar = `[^",\\{}\s(NULL)]` | |||
unquotedValue = fmt.Sprintf("(%s)+", unquotedChar) | |||
// quoted array values are surrounded by double quotes, can be any | |||
// character except " or \, which must be backslash escaped: | |||
quotedChar = `[^"\\]|\\"|\\\\` | |||
quotedValue = fmt.Sprintf("\"(%s)*\"", quotedChar) | |||
// an array value may be either quoted or unquoted: | |||
arrayValue = fmt.Sprintf("(?P<value>(%s|%s))", unquotedValue, quotedValue) | |||
// Array values are separated with a comma IF there is more than one value: | |||
arrayExp = regexp.MustCompile(fmt.Sprintf("((%s)(,)?)", arrayValue)) | |||
valueIndex int | |||
) | |||
// Find the index of the 'value' named expression | |||
func init() { | |||
for i, subexp := range arrayExp.SubexpNames() { | |||
if subexp == "value" { | |||
valueIndex = i | |||
break | |||
} | |||
} | |||
} | |||
// Parse the output string from the array type. | |||
// Regex used: (((?P<value>(([^",\\{}\s(NULL)])+|"([^"\\]|\\"|\\\\)*")))(,)?) | |||
func parseArray(array string) []string { | |||
results := make([]string, 0) | |||
matches := arrayExp.FindAllStringSubmatch(array, -1) | |||
for _, match := range matches { | |||
s := match[valueIndex] | |||
// the string _might_ be wrapped in quotes, so trim them: | |||
s = strings.Trim(s, "\"") | |||
results = append(results, s) | |||
} | |||
return results | |||
} | |||
func (p *StringArray) Scan(src interface{}) error { | |||
asBytes, ok := src.([]byte) | |||
if !ok { | |||
return error(errors.New("Scan source was not []bytes")) | |||
} | |||
asString := string(asBytes) | |||
parsed := parseArray(asString) | |||
(*p) = StringArray(parsed) | |||
return nil | |||
} | |||
func (p StringArray) Value() (driver.Value, error) { | |||
j, err := json.Marshal(p) | |||
return j, err | |||
} | |||
// escapes and quotes hstore keys/values | |||
// s should be a sql.NullString or string | |||
func hQuote(s interface{}) string { | |||
var str string | |||
switch v := s.(type) { | |||
case sql.NullString: | |||
if !v.Valid { | |||
return "NULL" | |||
} | |||
str = v.String | |||
case string: | |||
str = v | |||
default: | |||
panic("not a string or sql.NullString") | |||
} | |||
str = strings.Replace(str, "\\", "\\\\", -1) | |||
return `"` + strings.Replace(str, "\"", "\\\"", -1) + `"` | |||
} | |||
// Scan implements the Scanner interface. | |||
// | |||
// Note h.Map is reallocated before the scan to clear existing values. If the | |||
// hstore column's database value is NULL, then h.Map is set to nil instead. | |||
func (h *HSTOREDictionary) Scan(value interface{}) error { | |||
if value == nil { | |||
*h = nil | |||
return nil | |||
} | |||
m := make(map[string]interface{}) | |||
var b byte | |||
pair := [][]byte{{}, {}} | |||
pi := 0 | |||
inQuote := false | |||
didQuote := false | |||
sawSlash := false | |||
bindex := 0 | |||
for bindex, b = range value.([]byte) { | |||
if sawSlash { | |||
pair[pi] = append(pair[pi], b) | |||
sawSlash = false | |||
continue | |||
} | |||
switch b { | |||
case '\\': | |||
sawSlash = true | |||
continue | |||
case '"': | |||
inQuote = !inQuote | |||
if !didQuote { | |||
didQuote = true | |||
} | |||
continue | |||
default: | |||
if !inQuote { | |||
switch b { | |||
case ' ', '\t', '\n', '\r': | |||
continue | |||
case '=': | |||
continue | |||
case '>': | |||
pi = 1 | |||
didQuote = false | |||
continue | |||
case ',': | |||
s := string(pair[1]) | |||
if !didQuote && len(s) == 4 && strings.ToLower(s) == "null" { | |||
m[string(pair[0])] = nil // sql.NullString{String: "", Valid: false} | |||
} else { | |||
m[string(pair[0])] = string(pair[1]) // sql.NullString{String: string(pair[1]), Valid: true} | |||
} | |||
pair[0] = []byte{} | |||
pair[1] = []byte{} | |||
pi = 0 | |||
continue | |||
} | |||
} | |||
} | |||
pair[pi] = append(pair[pi], b) | |||
} | |||
if bindex > 0 { | |||
s := string(pair[1]) | |||
if !didQuote && len(s) == 4 && strings.ToLower(s) == "null" { | |||
m[string(pair[0])] = nil // sql.NullString{String: "", Valid: false} | |||
} else { | |||
m[string(pair[0])] = string(pair[1]) // sql.NullString{String: string(pair[1]), Valid: true} | |||
} | |||
} | |||
*h = m | |||
return nil | |||
} | |||
// Value implements the driver Valuer interface. Note if h.Map is nil, the | |||
// database column value will be set to NULL. | |||
func (h HSTOREDictionary) Value() (driver.Value, error) { | |||
if h == nil { | |||
return nil, nil | |||
} | |||
parts := []string{} | |||
for key, val := range h { | |||
thispart := hQuote(key) + "=>" + hQuote(val) | |||
parts = append(parts, thispart) | |||
} | |||
return []byte(strings.Join(parts, ",")), nil | |||
} | |||
@ -1,40 +0,0 @@ | |||
package xql | |||
type ConditionType uint | |||
const ( | |||
CONDITION_AND ConditionType = iota | |||
CONDITION_OR | |||
) | |||
type OrderType uint | |||
const ( | |||
ORDER_ASC OrderType = iota | |||
ORDER_DESC | |||
) | |||
type QueryFilter struct { | |||
Condition ConditionType // AND , OR | |||
Reversed bool // Reversed Field and Value if it is true | |||
Field string | |||
Operator string // Value will not used if empty. | |||
Value interface{} | |||
} | |||
type QueryOrder struct { | |||
Type OrderType | |||
Field string | |||
} | |||
type QueryColumn struct { | |||
FieldName string | |||
Function string | |||
Alias string | |||
} | |||
type UpdateColumn struct { | |||
Field string | |||
Operator string | |||
Value interface{} | |||
} |
@ -1,285 +0,0 @@ | |||
package xql | |||
import ( | |||
"errors" | |||
log "github.com/Sirupsen/logrus" | |||
"reflect" | |||
"database/sql" | |||
) | |||
func (qc QueryColumn) String(as...bool) string { | |||
s := "" | |||
if qc.Function != "" { | |||
s = qc.Function+"("+qc.FieldName+")" | |||
}else{ | |||
s = qc.FieldName | |||
} | |||
if qc.Alias != "" && len(as)>0 && as[0] { | |||
s = s + " AS " + qc.Alias | |||
} | |||
return s | |||
} | |||
type QuerySet struct { | |||
session *Session | |||
table *Table | |||
queries []QueryColumn | |||
filters []QueryFilter | |||
orders []QueryOrder | |||
offset int64 | |||
limit int64 | |||
} | |||
type XRow struct { | |||
row *sql.Row | |||
qs *QuerySet | |||
} | |||
func (self *XRow) Scan(dest ...interface{}) error { | |||
if nil == self.row { | |||
return errors.New("Nil row.") | |||
} | |||
if len(dest) < 1 { | |||
panic("Empty output!") | |||
} | |||
if len(dest) == 1 { | |||
d := dest[0] | |||
if reflect.TypeOf(d) == reflect.TypeOf(self.qs.table.Entity) { | |||
var outputs []interface{} | |||
r := reflect.ValueOf(d) | |||
for _, qc := range self.qs.queries { | |||
c, _ := self.qs.table.Columns[qc.FieldName] | |||
vp := r.Elem().FieldByName(c.PropertyName).Addr().Interface() | |||
outputs = append(outputs, vp) | |||
} | |||
return self.row.Scan(outputs...) | |||
} | |||
} | |||
return self.row.Scan(dest...) | |||
} | |||
type XRows struct { | |||
rows *sql.Rows | |||
qs *QuerySet | |||
} | |||
func (self *XRows) Scan(dest ...interface{}) error { | |||
if nil == self.rows { | |||
return errors.New("No rows.") | |||
} | |||
if len(dest) < 1 { | |||
panic("Empty output!") | |||
} | |||
if len(dest) == 1 { | |||
d := dest[0] | |||
if reflect.TypeOf(d) == reflect.TypeOf(self.qs.table.Entity) { | |||
var outputs []interface{} | |||
r := reflect.ValueOf(d) | |||
for _, qc := range self.qs.queries { | |||
c, _ := self.qs.table.Columns[qc.FieldName] | |||
vp := r.Elem().FieldByName(c.PropertyName).Addr().Interface() | |||
outputs = append(outputs, vp) | |||
} | |||
return self.rows.Scan(outputs...) | |||
} | |||
} | |||
return self.rows.Scan(dest...) | |||
} | |||
func (self *XRows) Next() bool { | |||
if nil == self.rows { | |||
return false | |||
} | |||
return self.rows.Next() | |||
} | |||
func (self *XRows) Close() { | |||
self.rows.Close() | |||
self.rows = nil | |||
} | |||
func makeQueryOrder(table *Table, s string) QueryOrder { | |||
qo := QueryOrder{} | |||
if s[:1] == "-" { | |||
qo.Type = ORDER_DESC | |||
qo.Field = s[1:] | |||
} else { | |||
qo.Type = ORDER_ASC | |||
qo.Field = s | |||
} | |||
return qo | |||
} | |||
func (self *QuerySet) Filter(cons ...interface{}) *QuerySet { | |||
for _, con := range cons { | |||
if vs, ok := con.(string); ok { | |||
self.filters = append(self.filters, QueryFilter{ | |||
Field: vs, | |||
}) | |||
}else if vm, ok := con.(map[string]interface{}); ok { | |||
for k, v := range vm { | |||
self.filters = append(self.filters, QueryFilter{ | |||
Field:k, | |||
Value:v, | |||
Operator: "=", | |||
}) | |||
} | |||
}else if vf, ok := con.(QueryFilter); ok { | |||
self.filters = append(self.filters, vf) | |||
} | |||
} | |||
return self | |||
} | |||
func (self *QuerySet) OrderBy(orders ...interface{}) *QuerySet { | |||
for _, x := range orders { | |||
switch x.(type) { | |||
case string: | |||
qo := makeQueryOrder(self.table, x.(string)) | |||
self.orders = append(self.orders, qo) | |||
case QueryOrder: | |||
self.orders = append(self.orders, x.(QueryOrder)) | |||
default: | |||
panic("Not supported parameter type.") | |||
} | |||
} | |||
return self | |||
} | |||
func (self *QuerySet) Offset(offset int64) *QuerySet { | |||
self.offset = offset | |||
return self | |||
} | |||
func (self *QuerySet) Limit(limit int64) *QuerySet { | |||
self.limit = limit | |||
return self | |||
} | |||
func (self *QuerySet) Count(cols...string) (int64,error) { | |||
s, args, err := self.session.getStatementBuilder().Select(self.table, | |||
[]QueryColumn{{Function:"COUNT", FieldName:"*"}}, | |||
self.filters, nil, -1, -1) | |||
if nil != err { | |||
return 0, err | |||
} | |||
row := self.session.doQueryRow(s, args...) | |||
var n int64 | |||
if e := row.Scan(&n); nil != e { | |||
return 0, e | |||
} | |||
return n, nil | |||
} | |||
func (self *QuerySet) All() (*XRows, error) { | |||
s, args, err := self.session.getStatementBuilder().Select(self.table, self.queries, | |||
self.filters, self.orders, self.offset, self.limit) | |||
if nil != err { | |||
return nil, err | |||
} | |||
rows, err := self.session.doQuery(s, args...) | |||
if nil != err { | |||
return nil, err | |||
} | |||
xrows := &XRows{rows:rows, qs:self} | |||
return xrows, nil | |||
} | |||
func (self *QuerySet) One() *XRow { | |||
s, args, err := self.session.getStatementBuilder().Select(self.table, self.queries, | |||
self.filters, self.orders, self.offset, 1) | |||
if nil != err { | |||
return nil | |||
} | |||
row := self.session.doQueryRow(s, args...) | |||
xrow := &XRow{row:row, qs:self} | |||
return xrow | |||
} | |||
func (self *QuerySet) Update(vals interface{}) (int64, error) { | |||
cols := []UpdateColumn{} | |||
if cm, ok := vals.(map[string]interface{}); ok { | |||
for k, v := range cm { | |||
uc := UpdateColumn{Field:k, Value:v, Operator:"="} | |||
cols = append(cols, uc) | |||
} | |||
}else if cx, ok := vals.([]UpdateColumn); ok { | |||
cols = cx | |||
} | |||
s, args, err := self.session.getStatementBuilder().Update(self.table, self.filters, cols...) | |||
if nil != err { | |||
return 0, err | |||
} | |||
var ret sql.Result | |||
ret, err = self.session.doExec(s, args...) | |||
if nil != err { | |||
return 0, err | |||
}else{ | |||
rows, e := ret.RowsAffected() | |||
return rows, e | |||
} | |||
return 0, nil | |||
} | |||
func (self *QuerySet) Delete() (int64, error) { | |||
s, args, err := self.session.getStatementBuilder().Delete(self.table, self.filters) | |||
if nil != err { | |||
return 0, err | |||
} | |||
var ret sql.Result | |||
ret, err = self.session.doExec(s, args...) | |||
if nil != err { | |||
return 0, err | |||
}else{ | |||
rows, e := ret.RowsAffected() | |||
return rows, e | |||
} | |||
return 0, nil | |||
} | |||
func (self *QuerySet) Insert(objs ...interface{}) (int64, error) { | |||
//log.Debugln("Insert:> ", objs) | |||
//log.Debugln("Table:> ", self.table) | |||
//var ret sql.Result | |||
var rows int64 = 0 | |||
var cols []string | |||
if len(self.queries) > 0 { | |||
for _,x := range self.queries { | |||
cols = append(cols, x.FieldName) | |||
} | |||
} | |||
for _, obj := range objs { | |||
log.Debugln("reflect.TypeOf(obj)>", reflect.TypeOf(obj)) | |||
log.Debugln("reflect.TypeOf(self.table.Entity)>", reflect.TypeOf(self.table.Entity)) | |||
if reflect.TypeOf(obj) != reflect.TypeOf(self.table.Entity) { | |||
return 0, errors.New("Invalid data type.") | |||
} | |||
s, args, err := self.session.getStatementBuilder().Insert(self.table, obj, cols...) | |||
if nil != err { | |||
return 0, err | |||
} | |||
_, err = self.session.doExec(s, args...) | |||
if nil != err { | |||
return 0, err | |||
}else{ | |||
//if nil != ret { | |||
// n, e := ret.LastInsertId() | |||
// if nil == e { | |||
// rows += n | |||
// }else{ | |||
// rows += 1 | |||
// } | |||
// //log.Debugln("Insert:> ", n) | |||
//}else{ | |||
// rows += 1 | |||
//} | |||
rows += 1 | |||
} | |||
} | |||
return rows, nil | |||
} |
@ -1,113 +0,0 @@ | |||
package xql | |||
import ( | |||
"errors" | |||
"database/sql" | |||
"fmt" | |||
log "github.com/Sirupsen/logrus" | |||
) | |||
type Session struct { | |||
driverName string | |||
db *sql.DB | |||
tx *sql.Tx | |||
} | |||
func (self *Session) getStatementBuilder() StatementBuilder { | |||
if s, ok := _statement_builders[self.driverName]; ok { | |||
return s | |||
}else{ | |||
panic(fmt.Sprintf("Statement Builder '%s' not registered! ", self.driverName)) | |||
} | |||
return nil | |||
} | |||
func (self *Session) Query(table *Table, columns ...interface{}) *QuerySet { | |||
qs := &QuerySet{session:self, offset:-1, limit:-1} | |||
qs.table = table | |||
if len(columns) > 0 { | |||
for _, c := range columns { | |||
if qc, ok := c.(QueryColumn); ok { | |||
qs.queries = append(qs.queries, qc) | |||
}else if qcn, ok := c.(string); ok { | |||
if col, ok := qs.table.Columns[qcn]; !ok { | |||
panic("Invalid column name.") | |||
}else{ | |||
qs.queries = append(qs.queries, QueryColumn{FieldName:col.FieldName, Alias:col.FieldName}) | |||
} | |||
}else{ | |||
panic("Unsupported parameter type!") | |||
} | |||
} | |||
}else{ | |||
for _, col := range qs.table.Columns { | |||
qs.queries = append(qs.queries, QueryColumn{FieldName:col.FieldName, Alias:col.FieldName}) | |||
} | |||
} | |||
return qs | |||
} | |||
func (self *Session) Begin() error { | |||
if nil != self.tx { | |||
return errors.New("Already in Tx!") | |||
} | |||
tx, err := self.db.Begin() | |||
if nil == err { | |||
self.tx = tx | |||
} | |||
return err | |||
} | |||
func (self *Session) Commit() error { | |||
if nil == self.tx { | |||
return errors.New("Not open Tx!") | |||
} | |||
err := self.tx.Commit() | |||
if nil == err { | |||
self.tx = nil | |||
} | |||
return err | |||
} | |||
func (self *Session) Rollback() error { | |||
if nil == self.tx { | |||
return errors.New("Not open Tx!") | |||
} | |||
err := self.tx.Rollback() | |||
self.tx = nil | |||
return err | |||
} | |||
func (self *Session) doExec(query string, args ...interface{}) (sql.Result, error) { | |||
if self.tx != nil { | |||
log.Debugln("doExec in Tx: ", query, args) | |||
return self.tx.Exec(query, args...) | |||
}else{ | |||
log.Debugln("doExec in DB: ", query, args) | |||
return self.db.Exec(query, args...) | |||
} | |||
return nil, nil | |||
} | |||
func (self *Session) doQuery(query string, args ...interface{}) (*sql.Rows, error) { | |||
if self.tx != nil { | |||
log.Debugln("doQuery in Tx: ", query, args) | |||
return self.tx.Query(query, args...) | |||
}else{ | |||
log.Debugln("doQuery in DB: ", query, args) | |||
return self.db.Query(query, args...) | |||
} | |||
return nil, nil | |||
} | |||
func (self *Session) doQueryRow(query string, args ...interface{}) *sql.Row { | |||
if self.tx != nil { | |||
log.Debugln("doQueryRow in Tx: ", query, args) | |||
return self.tx.QueryRow(query, args...) | |||
}else{ | |||
log.Debugln("doQueryRow in Db: ", query, args) | |||
return self.db.QueryRow(query, args...) | |||
} | |||
return nil | |||
} |
@ -1,70 +0,0 @@ | |||
package xql | |||
import ( | |||
"reflect" | |||
"bitbucket.org/cygnux/kepler/utils" | |||
"strings" | |||
) | |||
type Table struct { | |||
TableName string | |||
Schema string | |||
Entity interface{} | |||
Columns map[string]Column | |||
PrimaryKey []string | |||
} | |||
type Column struct { | |||
FieldName string | |||
PropertyName string | |||
Type string | |||
Length uint16 | |||
Unique bool | |||
Nullable bool | |||
Indexed bool | |||
PrimaryKey bool | |||
} | |||
func DeclareTable(name string, entity interface{}, schema ...string) *Table { | |||
t := &Table{ | |||
TableName:name, | |||
Entity: entity, | |||
Columns: make(map[string]Column), | |||
} | |||
if len(schema) > 0 { | |||
t.Schema = schema[0] | |||
} | |||
if nil != entity { | |||
et := reflect.TypeOf(entity) | |||
for i:=0; i< et.Elem().NumField(); i++ { | |||
f := et.Elem().Field(i) | |||
//f.Name | |||
c := Column{PropertyName:f.Name} | |||
x_tags := strings.Split(f.Tag.Get("xql"),",") | |||
if len(x_tags) < 1 || x_tags[0]=="" { | |||
c.FieldName = utils.Camel2Underscore(f.Name) | |||
}else if x_tags[0] == "-" { | |||
continue | |||
}else{ | |||
c.FieldName = x_tags[0] | |||
for _, x := range x_tags[1:] { | |||
switch x { | |||
case "pk": | |||
c.PrimaryKey = true | |||
t.PrimaryKey = append(t.PrimaryKey, x) | |||
case "indexed": | |||
c.Indexed = true | |||
case "nullable": | |||
c.Nullable = true | |||
case "unique": | |||
c.Unique = true | |||
} | |||
} | |||
} | |||
t.Columns[c.FieldName] = c | |||
} | |||
} | |||
return t | |||
} |
@ -1,3 +0,0 @@ | |||
package xql | |||
@ -1,10 +0,0 @@ | |||
package xql | |||
import "database/sql" | |||
func MakeSession(db *sql.DB, driverName string) *Session { | |||
return &Session{db:db, driverName:driverName} | |||
} | |||
@ -1,68 +0,0 @@ | |||
package xql | |||
import ( | |||
"testing" | |||
"time" | |||
_ "github.com/lib/pq" | |||
"bitbucket.org/cygnux/kepler/models/metas" | |||
"github.com/archsh/go.uuid" | |||
_ "bitbucket.org/cygnux/kepler/xql/driver/postgres" | |||
) | |||
var MovieCrew = DeclareTable("metas_crews", &metas.Crew{}, "deneb") | |||
func TestCreateEngine(t *testing.T) { | |||
t1 := time.Now() | |||
engine, e := CreateEngine("postgres", | |||
"host=localhost port=5432 user=postgres password=postgres dbname=cygnuxdb sslmode=disable") | |||
if nil != e { | |||
t.Fatal("Connec DB failed:> ", e) | |||
} | |||
t.Log("MovieCrew:> ", MovieCrew) | |||
_ = engine.MakeSession() | |||
t.Log("Time spent:> ", time.Now().Sub(t1)) | |||
} | |||
func TestQuerySet_Insert(t *testing.T) { | |||
t1 := time.Now() | |||
engine, e := CreateEngine("postgres", | |||
"host=localhost port=5432 user=postgres password=postgres dbname=cygnuxdb sslmode=disable") | |||
if nil != e { | |||
t.Fatal("Connec DB failed:> ", e) | |||
} | |||
t.Log("MovieCrew:> ", MovieCrew) | |||
sess := engine.MakeSession() | |||
c1 := metas.Crew{Id:uuid.NewV4().String(), FullName:"Tom Cruse", Region:"US"} | |||
c2 := metas.Crew{Id:uuid.NewV4().String(), FullName:"Hue Jackman", Region:"US"} | |||
n, e := sess.Query(MovieCrew).Insert(&c1, &c2) | |||
if nil != e { | |||
t.Fatal("Insert failed:> ", e) | |||
} | |||
t.Log("Insert lines:>", n) | |||
t.Log("Time spent:> ", time.Now().Sub(t1)) | |||
} | |||
func TestQuerySet_Update(t *testing.T) { | |||
t1 := time.Now() | |||
t.Log("Time spent:> ", time.Now().Sub(t1)) | |||
} | |||
func TestQuerySet_Delete(t *testing.T) { | |||
t1 := time.Now() | |||
t.Log("Time spent:> ", time.Now().Sub(t1)) | |||
} | |||
func TestQuerySet_One(t *testing.T) { | |||
t1 := time.Now() | |||
t.Log("Time spent:> ", time.Now().Sub(t1)) | |||
} | |||
func TestQuerySet_Scan(t *testing.T) { | |||
t1 := time.Now() | |||
t.Log("Time spent:> ", time.Now().Sub(t1)) | |||
} |