3
0

Fix DATE type parsing in SQLite

This commit is contained in:
Denis Arh
2022-10-07 10:49:22 +02:00
committed by Tomaž Jerman
parent fbf4410335
commit 2927826ecd
3 changed files with 75 additions and 8 deletions

View File

@@ -31,7 +31,7 @@ const (
var (
// make a custom driver with REGEX support
driver = &sqlite3.SQLiteDriver{
customDriver = &sqlite3.SQLiteDriver{
ConnectHook: func(conn *sqlite3.SQLiteConn) (err error) {
// register regexp function and use Go's regexp fn
if err = conn.RegisterFunc("regexp", regexp.MatchString, true); err != nil {
@@ -45,9 +45,9 @@ var (
func init() {
// register alter driver
sql.Register(altSchema, driver)
sql.Register(altSchema, customDriver)
// register drbug driver
sql.Register(debugSchema, sqlmw.Driver(driver, instrumentation.Debug()))
sql.Register(debugSchema, sqlmw.Driver(customDriver, instrumentation.Debug()))
store.Register(Connect, SCHEMA, altSchema, debugSchema)
}

View File

@@ -52,14 +52,41 @@ func (d sqliteDialect) TableCodec(m *dal.Model) drivers.TableCodec {
return drivers.NewTableCodec(m, d)
}
func (d sqliteDialect) TypeWrap(t dal.Type) drivers.Type {
func (d sqliteDialect) TypeWrap(dt dal.Type) drivers.Type {
// Any exception to general type-wrap implementation in the drivers package
// should be placed here
return drivers.TypeWrap(t)
// Any exception to general type-wrap implementation in the drivers package
// should be placed here
switch c := dt.(type) {
case *dal.TypeDate:
return &TypeDate{c}
}
return drivers.TypeWrap(dt)
}
func (sqliteDialect) AttributeCast(attr *dal.Attribute, val exp.LiteralExpression) (exp.LiteralExpression, error) {
return drivers.AttributeCast(attr, val)
var (
c exp.CastExpression
)
switch attr.Type.(type) {
case *dal.TypeDate:
ce := exp.NewCaseExpression().
When(val.RegexpLike(drivers.CheckDateISO8061), val).
Else(drivers.LiteralNULL)
// if we cast to DATE result value is treated like number (int64) and
// we only get the year part. So we need to cast to TEXT first
// and the the full-date is parsed into time.Time
c = exp.NewCastExpression(ce, "TEXT")
default:
return drivers.AttributeCast(attr, val)
}
return exp.NewLiteralExpression("?", c), nil
}
func (sqliteDialect) AttributeToColumn(attr *dal.Attribute) (col *ddl.Column, err error) {
@@ -84,12 +111,12 @@ func (sqliteDialect) AttributeToColumn(attr *dal.Attribute) (col *ddl.Column, er
col.Default = ddl.DefaultValueCurrentTimestamp(t.DefaultCurrentTimestamp)
case *dal.TypeDate:
col.Type.Name = "DATE"
col.Type.Name = "TEXT"
col.Default = ddl.DefaultValueCurrentTimestamp(t.DefaultCurrentTimestamp)
case *dal.TypeNumber:
col.Type.Name = "NUMERIC"
// @todo precision, scale?
// @todo precision, scale? x
col.Default = ddl.DefaultNumber(t.HasDefault, t.Precision, t.DefaultValue)
case *dal.TypeText:

View File

@@ -0,0 +1,40 @@
package sqlite
import (
"database/sql"
"database/sql/driver"
"fmt"
"github.com/spf13/cast"
"time"
"github.com/cortezaproject/corteza-server/pkg/dal"
"github.com/cortezaproject/corteza-server/store/adapters/rdbms/drivers"
)
type (
TypeDate struct{ *dal.TypeDate }
)
func (*TypeDate) MakeScanBuffer() any { return new(sql.NullString) }
func (t *TypeDate) Decode(raw any) (any, bool, error) {
dec, is := raw.(*sql.NullString)
if !is {
return nil, false, fmt.Errorf("unexpected raw type %T for Time", raw)
}
if !dec.Valid {
return time.Time{}, false, nil
}
parsed, err := cast.StringToDate(dec.String)
if err != nil {
return time.Time{}, false, err
}
return parsed.Format(drivers.DateLayout), true, nil
}
func (t *TypeDate) Encode(val any) (driver.Value, error) {
return val, nil
}