Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 0 additions & 4 deletions database/db/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ import (
)

var NameMapper = func(s string) string {
if s == "ID" {
return "id"
}

return str.Of(s).Snake().String()
}

Expand Down
15 changes: 11 additions & 4 deletions database/db/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -1008,16 +1008,23 @@ func (r *Query) buildInsert(data []map[string]any) (sql string, args []any, err
builder = builder.PlaceholderFormat(placeholderFormat)
}

first := data[0]
cols := make([]string, 0, len(first))
for col := range first {
// Collect all unique columns from all maps to avoid missing columns
colSet := make(map[string]bool)
for _, row := range data {
for col := range row {
colSet[col] = true
}
}

cols := make([]string, 0, len(colSet))
for col := range colSet {
cols = append(cols, col)
}
sort.Strings(cols)
builder = builder.Columns(cols...)

for _, row := range data {
vals := make([]any, 0, len(first))
vals := make([]any, 0, len(cols))
for _, col := range cols {
vals = append(vals, row[col])
}
Expand Down
129 changes: 126 additions & 3 deletions database/db/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"gorm.io/gorm"

"github.com/goravel/framework/support/carbon"
"github.com/goravel/framework/support/convert"
)

type Body struct {
Expand All @@ -20,11 +21,25 @@ type Body struct {
leg int `db:"leg"`
}

type House struct {
Address string `db:"address"`
Size *int `db:"size"`
}

type Job struct {
Title string `db:"title"`
Salary *float64 `db:"salary"`
}

type User struct {
ID int `db:"id"`
Name string `db:"-"`
Email string
ID int `db:"id"`
Name string `db:"-"`
Email string
Avatar *string
Alias *int
Body
House *House
Job Job
TestSoftDeletes
TestTimestamps
}
Expand Down Expand Up @@ -124,6 +139,114 @@ func TestConvertToSliceMap(t *testing.T) {
},
want: []map[string]any{{"weight": "100kg", "Age": 25}, {"weight": "90kg", "Age": 20}},
},
{
name: "user with nested struct pointer",
data: User{
ID: 1,
Name: "John",
Email: "john@example.com",
Body: Body{Weight: "100kg", Head: &head, DateTime: *dateTime},
House: &House{Address: "123 Main St", Size: nil},
Job: Job{Title: "Engineer", Salary: nil},
TestSoftDeletes: TestSoftDeletes{DeletedAt: deletedAt},
TestTimestamps: TestTimestamps{CreatedAt: dateTime, UpdatedAt: dateTime},
},
want: []map[string]any{
{
"id": 1, "email": "john@example.com", "weight": "100kg", "head": &head, "date_time": *dateTime,
"house": &House{Address: "123 Main St", Size: nil},
"job": Job{Title: "Engineer", Salary: nil},
"created_at": dateTime, "updated_at": dateTime, "deleted_at": deletedAt,
},
},
},
{
name: "user with nil nested struct pointer",
data: User{
ID: 1,
Email: "john@example.com",
Body: Body{Weight: "100kg", DateTime: *dateTime},
House: nil,
Job: Job{Title: "Engineer"},
TestTimestamps: TestTimestamps{CreatedAt: dateTime, UpdatedAt: dateTime},
},
want: []map[string]any{
{
"id": 1, "email": "john@example.com", "weight": "100kg", "date_time": *dateTime,
"job": Job{Title: "Engineer"},
"created_at": dateTime, "updated_at": dateTime,
},
},
},
{
name: "user with pointer fields",
data: func() User {
avatar := "avatar.jpg"
alias := 42
size := 100
salary := 50000.0
return User{
ID: 1,
Email: "john@example.com",
Avatar: &avatar,
Alias: &alias,
Body: Body{Weight: "100kg", Head: &head, DateTime: *dateTime},
House: &House{Address: "123 Main St", Size: &size},
Job: Job{Title: "Engineer", Salary: &salary},
TestTimestamps: TestTimestamps{CreatedAt: dateTime, UpdatedAt: dateTime},
}
}(),
want: []map[string]any{
{
"id": 1, "email": "john@example.com", "avatar": convert.Pointer("avatar.jpg"),
"alias": convert.Pointer(42), "weight": "100kg", "head": &head, "date_time": *dateTime,
"house": &House{Address: "123 Main St", Size: convert.Pointer(100)},
"job": Job{Title: "Engineer", Salary: convert.Pointer(50000.0)},
"created_at": dateTime, "updated_at": dateTime,
},
},
},
{
name: "user slice with mixed nested structs",
data: []User{
{
ID: 1,
Email: "john@example.com",
Body: Body{Length: 10, Weight: "100kg", Head: &head, DateTime: *dateTime},
House: &House{Address: "123 Main St"},
Job: Job{Title: "Engineer"},
TestTimestamps: TestTimestamps{CreatedAt: dateTime, UpdatedAt: dateTime},
},
{
ID: 2,
Email: "jane@example.com",
Body: Body{Weight: "90kg", DateTime: *dateTime},
House: nil,
Job: Job{Title: "Designer"},
TestTimestamps: TestTimestamps{CreatedAt: dateTime, UpdatedAt: dateTime},
},
},
want: []map[string]any{
{
"id": 1, "email": "john@example.com", "length": 10, "weight": "100kg", "head": &head, "date_time": *dateTime,
"house": &House{Address: "123 Main St"},
"job": Job{Title: "Engineer"},
"created_at": dateTime, "updated_at": dateTime,
},
{
"id": 2, "email": "jane@example.com", "weight": "90kg", "date_time": *dateTime,
"job": Job{Title: "Designer"},
"created_at": dateTime, "updated_at": dateTime,
},
},
},
{
name: "user with all zero values",
data: User{},
want: []map[string]any{
{},
},
},
}

for _, tt := range tests {
Expand Down
1 change: 1 addition & 0 deletions support/str/str_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,7 @@ func (s *StringTestSuite) TestSnake() {
s.Equal("a", Of("A").Snake().String())
s.Equal("foo123_bar", Of("foo123Bar").Snake().String())
s.Equal("123foo", Of("123foo").Snake().String())
s.Equal("id", Of("ID").Snake().String())
}

func (s *StringTestSuite) TestSplit() {
Expand Down
10 changes: 9 additions & 1 deletion tests/db_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -480,7 +480,8 @@ func (s *DBTestSuite) TestInsert_First_Get() {
},
},
{
Name: "multiple structs2",
Name: "multiple structs2",
Weight: convert.Pointer(1),
},
})
s.NoError(err)
Expand All @@ -490,8 +491,15 @@ func (s *DBTestSuite) TestInsert_First_Get() {
err = query.DB().Table("products").Where("name", []string{"multiple structs1", "multiple structs2"}).Where("deleted_at", nil).Get(&products)
s.NoError(err)
s.Equal(2, len(products))
s.True(products[0].ID > 0)
s.Equal("multiple structs1", products[0].Name)
s.NotEmpty(products[0].CreatedAt)
s.NotEmpty(products[0].UpdatedAt)
s.True(products[1].ID > 0)
s.Equal("multiple structs2", products[1].Name)
s.Equal(1, *products[1].Weight)
s.Empty(products[1].CreatedAt)
s.Empty(products[1].UpdatedAt)
})

s.Run("single map", func() {
Expand Down