forked from go-goe/goe
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinsert.go
More file actions
159 lines (131 loc) · 4.09 KB
/
Copy pathinsert.go
File metadata and controls
159 lines (131 loc) · 4.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package goe
import (
"context"
"errors"
"reflect"
"github.com/go-goe/goe/enum"
)
type stateInsert[T any] struct {
conn Connection
builder builder
ctx context.Context
err error
}
type create[T any] struct {
table *T
tx Transaction
insert *stateInsert[T]
}
// Create is a wrapper over [Insert] for simple insert one record
// and return the inserted record with the new id.
//
// Create uses [context.Background] internally;
// to specify the context, use [CreateContext].
//
// # Examples
//
// // create animal
// insertedAnimal, err = goe.Create(db.Animal).ByValue(Animal{})
func Create[T any](table *T) *create[T] {
return CreateContext(context.Background(), table)
}
func CreateContext[T any](ctx context.Context, table *T) *create[T] {
return &create[T]{table: table, insert: InsertContext(ctx, table)}
}
func (c *create[T]) OnTransaction(tx Transaction) *create[T] {
c.insert.OnTransaction(tx)
c.tx = tx
return c
}
func (c *create[T]) ByValue(value T) (*T, error) {
err := c.insert.One(&value)
if err != nil {
return nil, err
}
return Find(c.table).OnTransaction(c.tx).ById(value)
}
// Insert inserts a new record into the given table.
//
// Insert uses [context.Background] internally;
// to specify the context, use [InsertContext].
//
// # Examples
//
// // insert one record
// err = goe.Insert(db.Person).One(&Person{Name: "Jhon"})
// // insert a list of records
// persons := []Person{{Name: "Jhon"}, {Name: "Mary"}}
// err = goe.Insert(db.Person).All(persons)
func Insert[T any](table *T) *stateInsert[T] {
return InsertContext(context.Background(), table)
}
// InsertContext inserts a new record into the given table.
//
// See [Insert] for examples.
func InsertContext[T any](ctx context.Context, table *T) *stateInsert[T] {
var state *stateInsert[T] = createInsertState[T](ctx)
state.builder.fields, state.err = getArgsTable(addrMap.mapField, table)
return state
}
func (s *stateInsert[T]) OnTransaction(tx Transaction) *stateInsert[T] {
s.conn = tx
return s
}
func (s *stateInsert[T]) One(value *T) error {
if s.err != nil {
return s.err
}
if value == nil {
return errors.New("goe: invalid insert value. try sending a pointer to a struct as value")
}
v := reflect.ValueOf(value).Elem()
pkFieldId := s.builder.buildSqlInsert(v)
driver := s.builder.fields[0].getDb().driver
if s.conn == nil {
s.conn = driver.NewConnection()
}
if s.builder.query.ReturningId != nil {
return handlerValuesReturning(s.ctx, s.conn, s.builder.query, v, pkFieldId, driver.GetDatabaseConfig())
}
return handlerValues(s.ctx, s.conn, s.builder.query, driver.GetDatabaseConfig())
}
func (s *stateInsert[T]) All(value []T) error {
if len(value) == 0 {
return errors.New("goe: can't insert a empty batch value")
}
valueOf := reflect.ValueOf(value)
pkFieldId := s.builder.buildSqlInsertBatch(valueOf)
driver := s.builder.fields[0].getDb().driver
if s.conn == nil {
s.conn = driver.NewConnection()
}
return handlerValuesReturningBatch(s.ctx, s.conn, s.builder.query, valueOf, pkFieldId, driver.GetDatabaseConfig())
}
func createInsertState[T any](ctx context.Context) *stateInsert[T] {
return &stateInsert[T]{builder: createBuilder(enum.InsertQuery), ctx: ctx}
}
func getArgsTable[T any](addrMap map[uintptr]field, table *T) ([]field, error) {
if table == nil {
return nil, errors.New("goe: invalid argument. try sending a pointer to a database mapped struct as argument")
}
fields := make([]field, 0)
valueOf := reflect.ValueOf(table).Elem()
if valueOf.Kind() != reflect.Struct {
return nil, errors.New("goe: invalid argument. try sending a pointer to a database mapped struct as argument")
}
var fieldOf reflect.Value
for i := 0; i < valueOf.NumField(); i++ {
fieldOf = valueOf.Field(i)
if fieldOf.Kind() == reflect.Slice && fieldOf.Type().Elem().Kind() == reflect.Struct {
continue
}
addr := uintptr(fieldOf.Addr().UnsafePointer())
if addrMap[addr] != nil {
fields = append(fields, addrMap[addr])
}
}
if len(fields) == 0 {
return nil, errors.New("goe: invalid argument. try sending a pointer to a database mapped struct as argument")
}
return fields, nil
}