/model.go
Go | 360 lines | 246 code | 79 blank | 35 comment | 58 complexity | 2ab78d1340e9402399e891486c84b61e MD5 | raw file
- package cqlorm
- import (
- "encoding/json"
- "errors"
- "fmt"
- "reflect"
- "strconv"
- "strings"
- "time"
- "bitbucket.org/matchmove/go-resource/param"
- "bitbucket.org/matchmove/go-tools/secure"
- valid "bitbucket.org/matchmove/go-valid"
- "github.com/gocql/gocql"
- "gopkg.in/validator.v2"
- )
- const (
- // ISO8601Date ISO 8601 format with just the date
- ISO8601Date = "2006-01-02"
- // SQLDatetime YYYY-MM-DD HH:II:SS format with the date and time
- SQLDatetime = "2006-01-02 15:04:05"
- // TimestampFormat Timestamp Format
- TimestampFormat = "20060102150405"
- // MaxLimit ...
- MaxLimit = 50
- // MinOffset ...
- MinOffset = 0
- // SQLNullDate default null date
- SQLNullDate = "0000-00-00 00:00:00"
- // SQLNoDatabaseConnection No database connection
- SQLNoDatabaseConnection = "No database connection"
- // SQLInvalidOperator Invalid sql operator
- SQLInvalidOperator = "Invalid sql operator"
- //LimitRangeErrorCode limit must be a value 1 to 50
- LimitRangeErrorCode = "limit must be a value 1 to 50"
- //OffsetRangeErrorCode offset must be >= 0
- OffsetRangeErrorCode = "offset must be >= 0"
- // SQLNoRowsErrorCode sql: no rows in result set
- SQLNoRowsErrorCode = "sql: no rows in result set"
- // JSONTag ...
- JSONTag = "json"
- //FieldPlaceholder ...
- FieldPlaceholder = "?"
- //DatabaseTag ...
- DatabaseTag = "db"
- // EmptyUUID ...
- EmptyUUID = "00000000-0000-0000-0000-000000000000"
- )
- // OrderByIDDesc desc
- var OrderByIDDesc = []string{"-id"}
- // Model represents the core model
- type Model struct {
- Session *gocql.Session
- Table string `json:"-"`
- Conditions Conditions `json:"-"`
- L int `json:"-"`
- LastID string `json:"-"`
- SortOrder []string `json:"-"`
- Consistency gocql.Consistency
- }
- // Record ...
- type Record map[string]interface{}
- // Records ...
- type Records []Record
- // UnixTimestamp return utc timestamp
- func UnixTimestamp() string {
- return fmt.Sprintf("%d", time.Now().Unix())
- }
- // UnixToMysqlTime return utc timestamp
- func UnixToMysqlTime(sec string, nsec string) string {
- iSec, _ := strconv.ParseInt(sec, 10, 64)
- iNsec, _ := strconv.ParseInt(nsec, 10, 64)
- return time.Unix(iSec, iNsec).Format(SQLDatetime)
- }
- func init() {
- InitValidators()
- }
- // InitValidators Initializes the validations using github.com/go-validator/validator
- func InitValidators() {
- validator.SetValidationFunc("pattern", valid.Pattern)
- validator.SetValidationFunc("sqlvalue", valid.SQLValue)
- validator.SetValidationFunc("required", valid.Required)
- validator.SetValidationFunc("greater", valid.GreaterThan)
- validator.SetValidationFunc("gender", valid.Gender)
- validator.SetValidationFunc("url", valid.URL)
- }
- // FindFirst find first instance of record
- func (me *Model) FindFirst(dst interface{}) (record Record, err error) {
- var (
- args []interface{}
- query string
- )
- me.Limit(1)
- record = make(Record)
- if query, args, err = me.SelectCQL(dst); err != nil {
- return
- }
- if err = me.Session.Query(query, args...).Consistency(me.Consistency).MapScan(record); err != nil {
- return
- }
- return
- }
- // Find find all match
- func (me *Model) Find(dst interface{}) (iterations *gocql.Iter, err error) {
- var (
- args []interface{}
- query string
- )
- if me.L == 0 {
- me.Limit(MaxLimit)
- }
- if query, args, err = me.SelectCQL(dst); err != nil {
- return
- }
- iterations = me.Session.Query(query, args...).Consistency(me.Consistency).Iter()
- return
- }
- // SQL ...
- func (me *Model) SQL(s string) string {
- return fmt.Sprintf(s, me.Table)
- }
- // DeleteCQL creates an sql delete statement
- func (me *Model) DeleteCQL(dst interface{}) (query string, args []interface{}, err error) {
- if query, args, err = me.PrepareStatement(dst); err != nil {
- return
- }
- query = me.SQL(`DELETE FROM %s ` + query)
- return
- }
- // SelectCQL creates an sql select statement
- func (me *Model) SelectCQL(dst interface{}) (query string, args []interface{}, err error) {
- if query, args, err = me.PrepareStatement(dst); err != nil {
- return
- }
- query = me.SQL(`SELECT * FROM %s ` + query)
- return
- }
- // UpdateCQL creates an sql update statement
- func (me *Model) UpdateCQL(dst interface{}) (query string) {
- var (
- set string
- )
- t := reflect.ValueOf(dst).Elem()
- for i := 0; i < t.NumField(); i++ {
- f := t.Type().Field(i)
- items := strings.Split(f.Tag.Get("db"), ",")
- if len(items) == 0 {
- continue
- }
- tag := items[0]
- if "" == tag || "-" == tag || tag == "id" || tag == "created_at" {
- continue
- }
- if len(set) == 0 {
- set = set + tag + " = ? "
- } else {
- set = set + "," + tag + " = ? "
- }
- }
- query = me.SQL(`UPDATE %s SET ` + set + "WHERE id = " + FieldPlaceholder)
- return
- }
- // InsertCQL creates an sql insert statement
- func (me *Model) InsertCQL(dst interface{}) (query string) {
- set := ""
- values := ""
- t := reflect.ValueOf(dst).Elem()
- for i := 0; i < t.NumField(); i++ {
- f := t.Type().Field(i)
- items := strings.Split(f.Tag.Get(DatabaseTag), ",")
- if len(items) == 0 {
- continue
- }
- tag := items[0]
- if "" == tag || "-" == tag {
- continue
- }
- set = set + tag
- values = values + FieldPlaceholder
- if i < t.NumField()-1 {
- set = set + ", "
- values = values + ", "
- } else {
- set = set + " "
- values = values + " "
- }
- }
- query = me.SQL(`INSERT INTO %s (` + set + `) VALUES (` + values + `)`)
- return
- }
- // Limit set the limit for the query
- func (me *Model) Limit(limit int) error {
- if limit < 1 || limit > 50 {
- return errors.New(LimitRangeErrorCode)
- }
- me.L = limit
- return nil
- }
- // Where set the conditions for the query
- func (me *Model) Where(field string, operator string, value interface{}) (err error) {
- me.Conditions = append(me.Conditions, Condition{
- Field: field,
- Operator: operator,
- Value: value,
- })
- if _, _, err = me.Filters(me.Conditions); err != nil {
- return
- }
- return
- }
- // Filters ...
- func (me *Model) Filters(filters Conditions) (filter []string, args []interface{}, err error) {
- var (
- f, v string
- )
- for _, cond := range filters {
- if err = cond.Validate(); err != nil {
- return
- }
- v = fmt.Sprint(cond.Value)
- if OperatorLike == cond.Operator {
- if v, err = param.ParseFilter(v, param.FilterRegexMatchAll); nil != err {
- return
- }
- }
- f = fmt.Sprintf("%s %s %s", cond.Field, cond.Operator, FieldPlaceholder)
- args = append(args, v)
- filter = append(filter, f)
- }
- return
- }
- // PrepareStatement initialize the query
- func (me *Model) PrepareStatement(model interface{}) (query string, args []interface{}, err error) {
- var (
- filters []string
- order, filter, limit string
- )
- if len(me.SortOrder) > 0 {
- order = "ORDER BY " + strings.Join(me.SortOrder, ", ")
- }
- if len(me.Conditions) > 0 {
- if filters, args, err = me.Filters(me.Conditions); err != nil {
- return
- }
- filter = "WHERE " + strings.Join(filters, " AND ")
- }
- if me.L != 0 {
- limit = fmt.Sprintf(`LIMIT %d`, me.L)
- }
- query = filter + ` ` + order + ` ` + limit
- return
- }
- // JSON ...
- func (me *Model) JSON(model interface{}) string {
- body, _ := json.Marshal(model)
- return string(body)
- }
- // GenerateERN ...
- func (me Model) GenerateERN(service string, resource string, args ...string) (ern string, err error) {
- var (
- prefix string
- )
- if len(service) != 3 {
- err = errors.New("Service must be 3 in lenght")
- }
- if len(resource) > 6 {
- err = errors.New("Resource must less than 6 in lenght")
- }
- if len(args) > 0 {
- programCode := args[0]
- if len(programCode) > 8 {
- err = errors.New("ProgramCode must less than 8 in lenght")
- }
- prefix = fmt.Sprintf("%s:%s:%s", service, resource, programCode)
- } else {
- prefix = fmt.Sprintf("%s:%s", service, resource)
- }
- hashLength := (31 - len(prefix))
- hash := fmt.Sprintf("%s%s", UnixTimestamp(), secure.RandomString(hashLength-len(UnixTimestamp()), []rune(secure.RuneAlNumCS)))
- ern = strings.ToUpper(fmt.Sprintf("%s:%s", prefix, hash))
- return
- }