Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
d47a623
refactor: replace references to jinzhu/gorm with Vernacular-ai/gorm
akshaydeshraj Aug 16, 2019
1575b6e
chore: update go.mod and go.sum
akshaydeshraj Aug 16, 2019
377d7b8
make oracle support optional
deep110 Sep 16, 2019
e504e91
refactor: Handle case where type is explicitly set as "uuid"
misterEggroll Nov 12, 2019
f6c2807
refactor: In case it is of type json.RawMessage, set type to json in …
misterEggroll Nov 12, 2019
0c82986
Merge pull request #1 from Vernacular-ai/feat-explicit-uuid-mysql
misterEggroll Nov 25, 2019
a8cc314
add: Fn to remove constraint from a table
misterEggroll Feb 12, 2020
a7b077f
Merge pull request #2 from Vernacular-ai/feat-remove-constraint
misterEggroll Feb 12, 2020
5a62a6c
add: Fn to determine dialect-specific byte insertion limit
misterEggroll Mar 21, 2020
e1b7e67
Merge pull request #3 from Vernacular-ai/feat-dialect-byte-insertion-…
misterEggroll Mar 21, 2020
c98d9d0
add: New model which works for oracle at scale
misterEggroll May 28, 2020
77d5427
refactor: Checking if primary field is of type `primary`
misterEggroll May 28, 2020
c091566
refactor: Converting to uint with 64bits as bitsize
misterEggroll May 28, 2020
c00078d
Merge pull request #4 from Vernacular-ai/fix-float64-oracle-overflow
misterEggroll May 28, 2020
3837c21
refactor: Export `Primary` struct outside gorm package
misterEggroll May 28, 2020
967c824
Merge pull request #5 from Vernacular-ai/feat-export-primary
misterEggroll May 28, 2020
3942b1f
refactor: Remove primary key and foreign key custom structs
misterEggroll May 29, 2020
0a053f4
Merge pull request #6 from Vernacular-ai/feat-remove-primary
misterEggroll May 29, 2020
57a80e6
refactor: Use primaryField.Field.Uint to get uint when resolving row ID
misterEggroll Jun 1, 2020
5672191
Merge pull request #7 from Vernacular-ai/feat-uint-primary-field
misterEggroll Jun 1, 2020
a2832f1
feat: add support for setting nullable
vabshere Jul 15, 2020
c9d8908
feat: constrained scope to only dropping nullable and add support for…
vabshere Jul 16, 2020
f914f12
Merge pull request #8 from vabshere/master
misterEggroll Jul 16, 2020
064fd17
fix: Resolve row Id when rows>=10^6
misterEggroll Jul 19, 2020
d76d425
Merge pull request #9 from Vernacular-ai/fix-rowid-resolution
misterEggroll Jul 19, 2020
0693ce5
feat: add ModifyColumn support in oci8 dialect
vabshere Aug 24, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@ The fantastic ORM library for Golang, aims to be developer friendly.

* GORM Guides [https://gorm.io](https://gorm.io)

## Oracle Support
Oracle support is made optional.

Since oracle drivers initialize at start, a build flag has been added to enable oracle sdk.
Example:
```shell
go build -tags oracle ./...
```
or running main during development
```shell
go run -tags oracle main.go
```

## Contributing

[You can help to deliver a better GORM, check out things you can do](https://gorm.io/contribute.html)
Expand Down
2 changes: 1 addition & 1 deletion association_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import (
"sort"
"testing"

"github.com/jinzhu/gorm"
"github.com/Vernacular-ai/gorm"
)

func TestBelongsTo(t *testing.T) {
Expand Down
5 changes: 2 additions & 3 deletions callback_create.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,10 +176,9 @@ func afterCreateCallback(scope *Scope) {
// Currently does not support composite primary keys
scope.Dialect().SetDB(scope.db.db)
primaryField := scope.PrimaryField()
val := primaryField.Field.Interface()
// Row ID cannot be 0. Obvious issue that has occurred upstream.
if arg, ok := val.(uint); ok && arg != 0{
scope.Err(primaryField.Set(scope.Dialect().ResolveRowID(scope.TableName(), arg)))
if val := primaryField.Field.Uint(); val != 0 {
scope.Err(primaryField.Set(scope.Dialect().ResolveRowID(scope.TableName(), uint(val))))
}
}
}
2 changes: 1 addition & 1 deletion callbacks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package gorm_test
import (
"errors"

"github.com/jinzhu/gorm"
"github.com/Vernacular-ai/gorm"

"reflect"
"testing"
Expand Down
2 changes: 1 addition & 1 deletion customize_column_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"testing"
"time"

"github.com/jinzhu/gorm"
"github.com/Vernacular-ai/gorm"
)

type CustomizeColumn struct {
Expand Down
8 changes: 8 additions & 0 deletions dialect.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,25 @@ type Dialect interface {
Quote(key string) string
// DataTypeOf return data's sql type
DataTypeOf(field *StructField) string
// SplitDataTypeOf returns data's sql type and it's additional type
SplitDataTypeOf(field *StructField) (string, string)

// HasIndex check has index or not
HasIndex(tableName string, indexName string) bool
// HasForeignKey check has foreign key or not
HasForeignKey(tableName string, foreignKeyName string) bool
// RemoveIndex remove index
RemoveIndex(tableName string, indexName string) error
// Remove constraint from a column in the DB
RemoveConstraint(tableName string, constraintName string) error
// HasTable check has table or not
HasTable(tableName string) bool
// HasColumn check has column or not
HasColumn(tableName string, columnName string) bool
// ModifyColumn modify column's type
ModifyColumn(tableName string, columnName string, typ string) error
// Nullable sets column's null constraint
DropNullable(tableName string, columnName string, colType string) error

// LimitAndOffsetSQL return generated SQL with Limit and Offset, as mssql has special case
LimitAndOffsetSQL(limit, offset interface{}) string
Expand Down Expand Up @@ -66,6 +72,8 @@ type Dialect interface {

// Determing the tag setting based on the dialect being used
GetTagSetting(field *StructField, key string) (string, bool)
// Determine the limit of byte size for a BLOB
GetByteLimit() int
}

var dialectsMap = map[string]Dialect{}
Expand Down
28 changes: 24 additions & 4 deletions dialect_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,15 @@ func (s *commonDialect) fieldCanAutoIncrement(field *StructField) bool {
}

func (s *commonDialect) DataTypeOf(field *StructField) string {
var sqlType, additionalType = s.SplitDataTypeOf(field)

if strings.TrimSpace(additionalType) == "" {
return sqlType
}
return fmt.Sprintf("%v %v", sqlType, additionalType)
}

func (s *commonDialect) SplitDataTypeOf(field *StructField) (string, string) {
var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, s)

if sqlType == "" {
Expand Down Expand Up @@ -93,10 +102,7 @@ func (s *commonDialect) DataTypeOf(field *StructField) string {
panic(fmt.Sprintf("invalid sql type %s (%s) for commonDialect", dataValue.Type().Name(), dataValue.Kind().String()))
}

if strings.TrimSpace(additionalType) == "" {
return sqlType
}
return fmt.Sprintf("%v %v", sqlType, additionalType)
return sqlType, additionalType
}

func (s commonDialect) HasIndex(tableName string, indexName string) bool {
Expand All @@ -111,6 +117,11 @@ func (s commonDialect) RemoveIndex(tableName string, indexName string) error {
return err
}

func (s commonDialect) RemoveConstraint(tableName string, constraintName string) error {
_, err := s.db.Exec(fmt.Sprintf("ALTER TABLE %v DROP CONSTRAINT %v", tableName, constraintName))
return err
}

func (s commonDialect) HasForeignKey(tableName string, foreignKeyName string) bool {
return false
}
Expand All @@ -134,6 +145,11 @@ func (s commonDialect) ModifyColumn(tableName string, columnName string, typ str
return err
}

func (s commonDialect) DropNullable(tableName string, columnName string, colType string) error {
_, err := s.db.Exec(fmt.Sprintf("ALTER TABLE %v MODIFY %v %v NULL", tableName, columnName, colType))
return err
}

func (s commonDialect) CurrentDatabase() (name string) {
s.db.QueryRow("SELECT DATABASE()").Scan(&name)
return
Expand Down Expand Up @@ -201,3 +217,7 @@ func (commonDialect) ColumnEquality(fieldDBName, columnName string) bool {
func (s commonDialect) GetTagSetting(field *StructField, key string) (val string, ok bool) {
return field.TagSettingsGet(key)
}

func (s commonDialect) GetByteLimit() int {
return -1
}
27 changes: 22 additions & 5 deletions dialect_mysql.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ func (mysql) Quote(key string) string {

// Get Data Type for MySQL Dialect
func (s *mysql) DataTypeOf(field *StructField) string {
var sqlType, additionalType = s.SplitDataTypeOf(field)

if strings.TrimSpace(additionalType) == "" {
return sqlType
}
return fmt.Sprintf("%v %v", sqlType, additionalType)
}

func (s *mysql) SplitDataTypeOf(field *StructField) (string, string) {
var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, s)

// MySQL allows only one auto increment column per table, and it must
Expand Down Expand Up @@ -110,30 +119,38 @@ func (s *mysql) DataTypeOf(field *StructField) string {
}
default:
if IsByteArrayOrSlice(dataValue) {
if size > 0 && size < 65532 {
if isJSON(dataValue) {
// Adding a constraint to see ensure that the value is a well formed JSON
sqlType = "json"
} else if size > 0 && size < 65532 {
sqlType = fmt.Sprintf("varbinary(%d)", size)
} else {
sqlType = "longblob"
}
}
}
} else if isUUID(dataValue) {
// In case the user has specified uuid as the type explicitly
sqlType = "varchar(36)"
}

if sqlType == "" {
panic(fmt.Sprintf("invalid sql type %s (%s) for mysql", dataValue.Type().Name(), dataValue.Kind().String()))
}

if strings.TrimSpace(additionalType) == "" {
return sqlType
}
return fmt.Sprintf("%v %v", sqlType, additionalType)
return sqlType, additionalType
}

func (s mysql) RemoveIndex(tableName string, indexName string) error {
_, err := s.db.Exec(fmt.Sprintf("DROP INDEX %v ON %v", indexName, s.Quote(tableName)))
return err
}

func (s mysql) RemoveConstraint(tableName string, constraintName string) error {
_, err := s.db.Exec(fmt.Sprintf("ALTER TABLE %v DROP INDEX %v", tableName, constraintName))
return err
}

func (s mysql) ModifyColumn(tableName string, columnName string, typ string) error {
_, err := s.db.Exec(fmt.Sprintf("ALTER TABLE %v MODIFY COLUMN %v %v", tableName, columnName, typ))
return err
Expand Down
55 changes: 38 additions & 17 deletions dialect_oci8.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// +build oracle

package gorm

import (
Expand Down Expand Up @@ -38,11 +40,20 @@ func (*oci8) BindVar(i int) string {
}

func (o *oci8) DataTypeOf(field *StructField) string {
var sqlType, additionalType = o.SplitDataTypeOf(field)

if len(strings.TrimSpace(additionalType)) == 0 {
return sqlType
}
return fmt.Sprintf("%v %v", sqlType, additionalType)
}

func (o *oci8) SplitDataTypeOf(field *StructField) (string, string) {
var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, o)

charset, _ := o.GetTagSetting(field,"CHARSET")
charset, _ := o.GetTagSetting(field, "CHARSET")
var strDataType string
if strings.EqualFold(charset,"utf-8"){
if strings.EqualFold(charset, "utf-8") {
strDataType = "NVARCHAR2"
} else {
strDataType = "VARCHAR2"
Expand Down Expand Up @@ -88,7 +99,7 @@ func (o *oci8) DataTypeOf(field *StructField) string {
}
}

} else if isUUID(dataValue){
} else if isUUID(dataValue) {
// In case the user has specified uuid as the type explicitly
sqlType = fmt.Sprintf("%s(36)", strDataType)
}
Expand All @@ -97,10 +108,7 @@ func (o *oci8) DataTypeOf(field *StructField) string {
panic(fmt.Sprintf("invalid sql type %s (%s) for oci8", dataValue.Type().Name(), dataValue.Kind().String()))
}

if len(strings.TrimSpace(additionalType)) == 0 {
return sqlType
}
return fmt.Sprintf("%v %v", sqlType, additionalType)
return sqlType, additionalType
}

func (o *oci8) HasIndex(tableName string, indexName string) bool {
Expand All @@ -127,6 +135,15 @@ func (o *oci8) HasColumn(tableName string, columnName string) bool {
return count > 0
}

func (o *oci8) ModifyColumn(tableName string, columnName string, typ string) error {
_, err := o.db.Exec(fmt.Sprintf("ALTER TABLE %v MODIFY %v %v", tableName, columnName, typ))
return err
}

func (s *oci8) DropNullable(tableName string, columnName string, colType string) error {
_, err := s.db.Exec(fmt.Sprintf("ALTER TABLE %v MODIFY %v %v NULL", tableName, columnName, colType))
return err
}

func (*oci8) buildSha(str string) string {
if utf8.RuneCountInString(str) <= 30 {
Expand All @@ -146,29 +163,29 @@ func (*oci8) buildSha(str string) string {

// Returns the primary key via the row ID
// Assumes that the primary key is the ID of the table
func (o *oci8) ResolveRowID(tableName string, rowID uint) uint{
func (o *oci8) ResolveRowID(tableName string, rowID uint) uint {
strRowID := ociDriver.GetLastInsertId(int64(rowID))
var id string
var id float64
query := fmt.Sprintf(`SELECT id FROM %s WHERE rowid = :2`, o.Quote(tableName))
var err error
if err = o.db.QueryRow(query, strRowID).Scan(&id); err == nil{
if res, err := strconv.ParseUint(id, 10, 32); err == nil{
resolvedId := uint(res)
return resolvedId
}
if err = o.db.QueryRow(query, strRowID).Scan(&id); err == nil {
return uint(id)
} else {
defaultLogger.Print(fmt.Sprintf("[warning][oci8] Unable to fetch ID for rowID %v: %v\n", strRowID, err))
}

return rowID
}

// Client statement separator used to terminate the statement
func (*oci8) ClientStatementSeparator() string{
func (*oci8) ClientStatementSeparator() string {
// In case of most DB's, it's a semicolon
return ""
}

func (*oci8) LimitAndOffsetSQL(limit, offset interface{}) (sql string) {
// In case both limit and offset are nil, simply return and empty string
if offset == nil && limit == nil{
if offset == nil && limit == nil {
return ""
}

Expand All @@ -191,7 +208,7 @@ func (*oci8) LimitAndOffsetSQL(limit, offset interface{}) (sql string) {
}

// Limit clause comes later
if errLimitParse == nil && parsedLimit >= 0 {
if errLimitParse == nil && parsedLimit >= 0 {
sql += fmt.Sprintf(" ROWS FETCH NEXT %d ROWS ONLY", parsedLimit)
}
return
Expand All @@ -208,3 +225,7 @@ func (*oci8) ColumnEquality(fieldDBName, columnName string) bool {
func (o *oci8) GetTagSetting(field *StructField, key string) (val string, ok bool) {
return field.TagSettingsGetFirst(strings.ToUpper(o.GetName())+" "+key, key)
}

func (o *oci8) GetByteLimit() int {
return 30000
}
19 changes: 15 additions & 4 deletions dialect_postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ func (postgres) BindVar(i int) string {
}

func (s *postgres) DataTypeOf(field *StructField) string {
var sqlType, additionalType = s.SplitDataTypeOf(field)

if strings.TrimSpace(additionalType) == "" {
return sqlType
}
return fmt.Sprintf("%v %v", sqlType, additionalType)
}

func (s *postgres) SplitDataTypeOf(field *StructField) (string, string) {
var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, s)

if sqlType == "" {
Expand Down Expand Up @@ -85,10 +94,7 @@ func (s *postgres) DataTypeOf(field *StructField) string {
panic(fmt.Sprintf("invalid sql type %s (%s) for postgres", dataValue.Type().Name(), dataValue.Kind().String()))
}

if strings.TrimSpace(additionalType) == "" {
return sqlType
}
return fmt.Sprintf("%v %v", sqlType, additionalType)
return sqlType, additionalType
}

func (s postgres) HasIndex(tableName string, indexName string) bool {
Expand All @@ -115,6 +121,11 @@ func (s postgres) HasColumn(tableName string, columnName string) bool {
return count > 0
}

func (s postgres) DropNullable(tableName string, columnName string, colType string) error {
_, err := s.db.Exec(fmt.Sprintf("ALTER TABLE %v ALTER COLUMN %v DROP NOT NULL", tableName, columnName))
return err
}

func (s postgres) CurrentDatabase() (name string) {
s.db.QueryRow("SELECT CURRENT_DATABASE()").Scan(&name)
return
Expand Down
Loading