-
Notifications
You must be signed in to change notification settings - Fork 0
/
delete.go
145 lines (133 loc) · 4.36 KB
/
delete.go
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
package nidhi
import (
"context"
"fmt"
sq "github.com/elgris/sqrl"
)
// OnDeleteHook is the function signature for the [Hooks.OnDelete] hook.
type OnDeleteHook func(*HookContext, string, *DeleteOptions)
// OnDeleteManyHook is the function signature for the [Hooks.OnDeleteMany] hook.
type OnDeleteManyHook func(*HookContext, Sqlizer, *DeleteManyOptions)
// DeleteOptions are options for the `Delete` operation
type DeleteOptions struct {
// Metadata is the metadata of the document.
// This will be merged with existing metadata.
//
// NOTE: This is a no op if `Permanent` is set.
Metadata Metadata
// Permanent if set will hard delete the document.
Permanent bool
}
// DeleteManyOptions are options for the `DeleteMany` operation
type DeleteManyOptions struct {
// Metadata is the metadata of the document.
// This will be merged with existing metadata.
//
// NOTE: This is a no op if `Permanent` is set.
Metadata Metadata
// Permanent if set will hard delete the document.
Permanent bool
}
// DeleteResult is the result of the delete call.
// It doesn't have any fields as of now.
//
// Having an explicit result type will not break future changes.
type DeleteResult struct{}
// DeleteManyResult is the result of the delete many call.
type DeleteManyResult struct {
// DeleteCount is the number of documents that were deleted.
DeleteCount int64
}
// Delete deletes a single record from the store using its id.
//
// By default all deletes are soft deletes. To hard delete, see `DeleteOptions`
func (s *Store[T]) Delete(ctx context.Context, id string, opts DeleteOptions) (*DeleteResult, error) {
hookCtx := NewHookContext(ctx, s)
for _, h := range s.hooks {
if h.OnDelete != nil {
h.OnDelete(hookCtx, id, &opts)
}
}
var (
sqlStr string
args []any
err error
)
if opts.Permanent {
sqlStr, args, err = sq.Delete(s.table).Where(sq.Eq{ColId: id}).PlaceholderFormat(sq.Dollar).ToSql()
if err != nil {
return nil, fmt.Errorf("nidhi: this seems to be a bug: failed to build hard delete statement: %w", err)
}
} else {
mdJSON, err := getJson(opts.Metadata)
if err != nil {
return nil, fmt.Errorf("nidhi: failed to marshal metadata of collection: %s, err: %w", s.table, err)
}
defer putJson(mdJSON)
st := sq.Update(s.table).
Where(sq.Eq{ColId: id}).
Where(notDeleted).
Set(ColDel, true).
Set(ColMeta, merge(ColMeta, mdJSON.Buffer()))
sqlStr, args, err = st.PlaceholderFormat(sq.Dollar).ToSql()
if err != nil {
return nil, fmt.Errorf("nidhi: this seems to be a bug: failed to build soft delete statement: %w", err)
}
}
if _, err := s.db.ExecContext(ctx, sqlStr, args...); err != nil {
return nil, fmt.Errorf("nidhi: failed to delete a document of collection: %s, err: %w", s.table, err)
}
return &DeleteResult{}, nil
}
func (s *Store[T]) DeleteMany(ctx context.Context, q Sqlizer, opts DeleteManyOptions) (*DeleteManyResult, error) {
hookCtx := NewHookContext(ctx, s)
for _, h := range s.hooks {
if h.OnDeleteMany != nil {
h.OnDeleteMany(hookCtx, q, &opts)
}
}
var (
sqlStr string
args []any
err error
)
if opts.Permanent {
st := sq.Delete(s.table)
if any(q) != nil {
st = st.Where(q)
}
sqlStr, args, err = st.PlaceholderFormat(sq.Dollar).ToSql()
if err != nil {
return nil, fmt.Errorf("nidhi: there seems to be a bug: failed to build delete statement: %w", err)
}
} else {
mdJSON, err := getJson(opts.Metadata)
if err != nil {
return nil, fmt.Errorf("nidhi: failed to marshal metadata of collection: %s, err: %w", s.table, err)
}
defer putJson(mdJSON)
st := sq.Update(s.table).Set(ColDel, true).Set(ColMeta, merge(ColMeta, mdJSON.Buffer()))
if q != nil {
st = st.Where(q)
}
st = st.Where(notDeleted)
sqlStr, args, err = st.PlaceholderFormat(sq.Dollar).ToSql()
if err != nil {
return nil, fmt.Errorf("nidhi: there seems to be a bug: failed to build delete statement: %w", err)
}
}
res, err := s.db.ExecContext(ctx, sqlStr, args...)
if err != nil {
return nil, fmt.Errorf("nidhi: failed to delete a document of collection: %s, err: %w", s.table, err)
}
deleteCount, err := res.RowsAffected()
if err != nil {
return nil, fmt.Errorf("nidhi: failed to get deleted document count for collection: %q, err: %w", s.table, err)
}
return &DeleteManyResult{
DeleteCount: deleteCount,
}, nil
}
func merge(column string, value []byte) sq.Sqlizer {
return sq.Expr(column+" || ? ", value)
}