diff --git a/oracle/oracle.go b/oracle/oracle.go index fa36955..ed70a86 100644 --- a/oracle/oracle.go +++ b/oracle/oracle.go @@ -102,6 +102,7 @@ func (d Dialector) Initialize(db *gorm.DB) (err error) { callback.Create().Replace("gorm:create", Create) callback.Delete().Replace("gorm:delete", Delete) callback.Update().Replace("gorm:update", Update) + callback.Query().Before("gorm:query").Register("oracle:before_query", BeforeQuery) maps.Copy(db.ClauseBuilders, OracleClauseBuilders()) diff --git a/oracle/query.go b/oracle/query.go new file mode 100644 index 0000000..902d375 --- /dev/null +++ b/oracle/query.go @@ -0,0 +1,68 @@ +/* +** Copyright (c) 2025 Oracle and/or its affiliates. +** +** The Universal Permissive License (UPL), Version 1.0 +** +** Subject to the condition set forth below, permission is hereby granted to any +** person obtaining a copy of this software, associated documentation and/or data +** (collectively the "Software"), free of charge and under any and all copyright +** rights in the Software, and any and all patent rights owned or freely +** licensable by each licensor hereunder covering either (i) the unmodified +** Software as contributed to or provided by such licensor, or (ii) the Larger +** Works (as defined below), to deal in both +** +** (a) the Software, and +** (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +** one is included with the Software (each a "Larger Work" to which the Software +** is contributed by such licensors), +** +** without restriction, including without limitation the rights to copy, create +** derivative works of, display, perform, and distribute the Software and make, +** use, sell, offer for sale, import, export, have made, and have sold the +** Software and the Larger Work(s), and to sublicense the foregoing rights on +** either these or other terms. +** +** This license is subject to the following condition: +** The above copyright notice and either this complete permission notice or at +** a minimum a reference to the UPL must be included in all copies or +** substantial portions of the Software. +** +** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +** SOFTWARE. + */ + +package oracle + +import ( + "gorm.io/gorm" + "regexp" + "strings" +) + +// Identifies the table name alias provided as +// "\"users\" \"u\"". Gorm already handles +// +// the other formats like "users u", "users AS u" etc. +var tableRegexp = regexp.MustCompile(`^"([^"]+)"\s+"([^"]+)"$`) + +func BeforeQuery(db *gorm.DB) { + if db == nil || db.Statement == nil || db.Statement.TableExpr == nil { + return + } + name := db.Statement.TableExpr.SQL + if strings.Contains(name, " ") || strings.Contains(name, "`") { + if results := tableRegexp.FindStringSubmatch(name); len(results) == 3 { + if results[2] != "" { + db.Statement.Table = results[2] + } else { + db.Statement.Table = results[1] + } + } + } + return +} diff --git a/tests/generics_test.go b/tests/generics_test.go index 3900eff..4ab97c1 100644 --- a/tests/generics_test.go +++ b/tests/generics_test.go @@ -151,7 +151,6 @@ func TestGenericsCreateInBatches(t *testing.T) { } func TestGenericsExecAndUpdate(t *testing.T) { - t.Skip() ctx := context.Background() name := "GenericsExec" @@ -159,7 +158,7 @@ func TestGenericsExecAndUpdate(t *testing.T) { t.Fatalf("Exec insert failed: %v", err) } - u, err := gorm.G[User](DB).Table("\"users\" u").Where("u.name = ?", name).First(ctx) + u, err := gorm.G[User](DB).Table("\"users\" \"u\"").Where("\"u\".\"name\" = ?", name).First(ctx) if err != nil { t.Fatalf("failed to find user, got error: %v", err) } else if u.Name != name || u.ID == 0 { diff --git a/tests/passed-tests.txt b/tests/passed-tests.txt index 89b4f74..c136c8f 100644 --- a/tests/passed-tests.txt +++ b/tests/passed-tests.txt @@ -106,7 +106,7 @@ TestSupportedDialectorWithErrDuplicatedKey TestSupportedDialectorWithErrForeignKeyViolated #TestGenericsCreate TestGenericsCreateInBatches -#TestGenericsExecAndUpdate +TestGenericsExecAndUpdate TestGenericsRow TestGenericsDelete TestGenericsFindInBatches @@ -222,7 +222,7 @@ TestPreloadManyToManyCallbacks TestPreloadWithAssociations TestNestedPreload TestNestedPreloadForSlice -#TestPreloadWithConds +TestPreloadWithConds TestNestedPreloadWithConds TestPreloadEmptyData TestPreloadGoroutine diff --git a/tests/preload_test.go b/tests/preload_test.go index 545c40b..40d2a30 100644 --- a/tests/preload_test.go +++ b/tests/preload_test.go @@ -148,7 +148,6 @@ func TestNestedPreloadForSlice(t *testing.T) { } func TestPreloadWithConds(t *testing.T) { - t.Skip() users := []User{ *GetUser("slice_nested_preload_1", Config{Account: true}), *GetUser("slice_nested_preload_2", Config{Account: false}), @@ -165,7 +164,7 @@ func TestPreloadWithConds(t *testing.T) { } var users2 []User - DB.Preload("Account", clause.Eq{Column: "account_number", Value: users[0].Account.AccountNumber}).Find(&users2, "id IN ?", userIDs) + DB.Preload("Account", clause.Eq{Column: "account_number", Value: users[0].Account.AccountNumber}).Find(&users2, "\"id\" IN ?", userIDs) sort.Slice(users2, func(i, j int) bool { return users2[i].ID < users2[j].ID }) @@ -180,8 +179,8 @@ func TestPreloadWithConds(t *testing.T) { var users3 []User if err := DB.Preload("Account", func(tx *gorm.DB) *gorm.DB { - return tx.Table("accounts a").Select("a.*") - }).Find(&users3, "id IN ?", userIDs).Error; err != nil { + return tx.Table("\"accounts\" \"a\"").Select("\"a\".*") + }).Find(&users3, "\"id\" IN ?", userIDs).Error; err != nil { t.Errorf("failed to query, got error %v", err) } sort.Slice(users3, func(i, j int) bool { @@ -195,13 +194,13 @@ func TestPreloadWithConds(t *testing.T) { var user4 User DB.Delete(&users3[0].Account) - if err := DB.Preload(clause.Associations).Take(&user4, "id = ?", users3[0].ID).Error; err != nil || user4.Account.ID != 0 { + if err := DB.Preload(clause.Associations).Take(&user4, "\"id\" = ?", users3[0].ID).Error; err != nil || user4.Account.ID != 0 { t.Errorf("failed to query, got error %v, account: %#v", err, user4.Account) } if err := DB.Preload(clause.Associations, func(tx *gorm.DB) *gorm.DB { return tx.Unscoped() - }).Take(&user4, "id = ?", users3[0].ID).Error; err != nil || user4.Account.ID == 0 { + }).Take(&user4, "\"id\" = ?", users3[0].ID).Error; err != nil || user4.Account.ID == 0 { t.Errorf("failed to query, got error %v, account: %#v", err, user4.Account) } }