diff --git a/cache_store.go b/cache_store.go index 57fe3cde..a77d3903 100644 --- a/cache_store.go +++ b/cache_store.go @@ -13,6 +13,7 @@ import ( type cacheItem struct { dataMutex sync.RWMutex data interface{} + err error created int64 accessMutex sync.RWMutex accessCount int64 @@ -97,7 +98,7 @@ func (c cache) Empty() { } } -func (c cache) GetItem(key string, offset int64) interface{} { +func (c cache) GetItem(key string, offset int64) (interface{}, error) { fmt.Print("Getting item " + key + " ... ") c.mutex.RLock() @@ -112,7 +113,7 @@ func (c cache) GetItem(key string, offset int64) interface{} { if (item.created+offset > time.Now().Unix()) || offset == -1 { fmt.Print("Found \n") c.mutex.RUnlock() - return item.data + return item.data, item.err } fmt.Print("Expired \n") @@ -121,7 +122,7 @@ func (c cache) GetItem(key string, offset int64) interface{} { } c.mutex.RUnlock() - return nil + return nil, nil } type modelId struct { @@ -129,7 +130,7 @@ type modelId struct { id string } -func (c *cache) StoreItem(key string, data interface{}) { +func (c *cache) StoreItem(key string, data interface{}, errors error) { fmt.Println("Storing item " + key) // Affected IDs @@ -158,12 +159,14 @@ func (c *cache) StoreItem(key string, data interface{}) { created: time.Now().UnixNano(), accessCount: 1, data: data, + err: errors, } c.mutex.Unlock() } else { c.mutex.RLock() c.database[key].dataMutex.Lock() c.database[key].data = data + c.database[key].err = errors c.database[key].created = time.Now().UnixNano() c.database[key].dataMutex.Unlock() c.mutex.RUnlock() diff --git a/callback_query.go b/callback_query.go index 82d85e30..9da29ed4 100644 --- a/callback_query.go +++ b/callback_query.go @@ -75,17 +75,19 @@ func queryCallback(scope *Scope) { if cacheOperation != nil { // If the time is > 0, simply provide the cached results if *cacheOperation > 0 || *cacheOperation == -1 { - cacheResults := scope.CacheStore().GetItem(key, *cacheOperation) + cacheResults, err := scope.CacheStore().GetItem(key, *cacheOperation) if cacheResults != nil { + scope.Err(err) // Add any error if exists results.Set(reflect.ValueOf(cacheResults)) fmt.Println("Cache HIT") readFromDB = false } else { readFromDB = true - fmt.Println() + fmt.Println("Cache MISS") writeToCache = true } } else { + fmt.Println("Cache REFRESH") readFromDB = true writeToCache = true } @@ -128,7 +130,7 @@ func queryCallback(scope *Scope) { } if writeToCache { - scope.CacheStore().StoreItem(key, results.Interface()) + scope.CacheStore().StoreItem(key, results.Interface(), scope.db.Error) } } } diff --git a/dialect.go b/dialect.go index 831c0a8e..9fee14b1 100644 --- a/dialect.go +++ b/dialect.go @@ -36,6 +36,8 @@ type Dialect interface { // ModifyColumn modify column's type ModifyColumn(tableName string, columnName string, typ string) error + HasTop(limit interface{}) string + // LimitAndOffsetSQL return generated SQL with Limit and Offset, as mssql has special case LimitAndOffsetSQL(limit, offset interface{}) string // SelectFromDummyTable return select values, for most dbs, `SELECT values` just works, mysql needs `SELECT value FROM DUAL` @@ -81,6 +83,10 @@ func GetDialect(name string) (dialect Dialect, ok bool) { return } +func HasTop(limit interface{}) string { + return "" +} + // ParseFieldStructForDialect get field's sql data type var ParseFieldStructForDialect = func(field *StructField, dialect Dialect) (fieldValue reflect.Value, sqlType string, size int, additionalType string) { // Get redirected field type diff --git a/dialect_common.go b/dialect_common.go index e3a5b702..fdfd5022 100644 --- a/dialect_common.go +++ b/dialect_common.go @@ -40,6 +40,10 @@ func (commonDialect) Quote(key string) string { return fmt.Sprintf(`"%s"`, key) } +func (commonDialect) HasTop(limit interface{}) string { + return "" +} + func (s *commonDialect) fieldCanAutoIncrement(field *StructField) bool { if value, ok := field.TagSettingsGet("AUTO_INCREMENT"); ok { return strings.ToLower(value) != "false" diff --git a/dialect_mysql.go b/dialect_mysql.go index 5a1ad708..97144100 100644 --- a/dialect_mysql.go +++ b/dialect_mysql.go @@ -25,6 +25,10 @@ func (mysql) GetName() string { return "mysql" } +func (mysql) HasTop(limit interface{}) string { + return "" +} + func (mysql) Quote(key string) string { return fmt.Sprintf("`%s`", key) } diff --git a/dialect_postgres.go b/dialect_postgres.go index 53d31388..01d67e09 100644 --- a/dialect_postgres.go +++ b/dialect_postgres.go @@ -21,6 +21,10 @@ func (postgres) GetName() string { return "postgres" } +func (postgres) HasTop(limit interface{}) string { + return "" +} + func (postgres) BindVar(i int) string { return fmt.Sprintf("$%v", i) } diff --git a/dialects/mssql/mssql.go b/dialects/mssql/mssql.go index 88a084cb..8e7c8283 100644 --- a/dialects/mssql/mssql.go +++ b/dialects/mssql/mssql.go @@ -168,21 +168,31 @@ func (s mssql) CurrentDatabase() (name string) { return } -func (mssql) LimitAndOffsetSQL(limit, offset interface{}) (sql string) { - if offset != nil { - if parsedOffset, err := strconv.ParseInt(fmt.Sprint(offset), 0, 0); err == nil && parsedOffset >= 0 { - sql += fmt.Sprintf(" OFFSET %d ROWS", parsedOffset) - } - } +func (mssql) HasTop(limit interface{}) (sql string) { if limit != nil { if parsedLimit, err := strconv.ParseInt(fmt.Sprint(limit), 0, 0); err == nil && parsedLimit >= 0 { - if sql == "" { - // add default zero offset - sql += " OFFSET 0 ROWS" - } - sql += fmt.Sprintf(" FETCH NEXT %d ROWS ONLY", parsedLimit) + sql += fmt.Sprintf(" TOP(%d)", parsedLimit) } } + + return +} + +func (mssql) LimitAndOffsetSQL(limit, offset interface{}) (sql string) { + if offset != nil { + //if parsedOffset, err := strconv.ParseInt(fmt.Sprint(offset), 0, 0); err == nil && parsedOffset >= 0 { + // sql += fmt.Sprintf(" OFFSET %d ROWS", parsedOffset) + //} + } + if limit != nil { + //if parsedLimit, err := strconv.ParseInt(fmt.Sprint(limit), 0, 0); err == nil && parsedLimit >= 0 { + // if sql == "" { + // // add default zero offset + // sql += " OFFSET 0 ROWS" + // } + // sql += fmt.Sprintf(" FETCH NEXT %d ROWS ONLY", parsedLimit) + //} + } return } diff --git a/scope.go b/scope.go index cb2e5d46..f26e223c 100644 --- a/scope.go +++ b/scope.go @@ -905,11 +905,15 @@ func (scope *Scope) tableSQL() string { } } +func (scope *Scope) needTop() string { + return scope.Dialect().HasTop(scope.Search.limit) +} + func (scope *Scope) prepareQuerySQL() { if scope.Search.raw { scope.Raw(scope.CombinedConditionSql()) } else { - scope.Raw(fmt.Sprintf("SELECT %v FROM %v %v", scope.selectSQL(), scope.tableSQL(), scope.CombinedConditionSql())) + scope.Raw(fmt.Sprintf("SELECT %v %v FROM %v %v", scope.needTop(), scope.selectSQL(), scope.tableSQL(), scope.CombinedConditionSql())) } return }