forked from go-rel/rel
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cursor.go
110 lines (88 loc) · 1.74 KB
/
cursor.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
package rel
import (
"reflect"
)
// Cursor is interface to work with database result (used by adapter).
type Cursor interface {
Close() error
Fields() ([]string, error)
Next() bool
Scan(...any) error
NopScanner() any // TODO: conflict with manual scanners interface
}
func scanOne(cur Cursor, doc *Document) error {
defer cur.Close()
fields, err := cur.Fields()
if err != nil {
return err
}
if !cur.Next() {
return NotFoundError{}
}
var (
scanners = doc.Scanners(fields)
)
return cur.Scan(scanners...)
}
func scanAll(cur Cursor, col *Collection) error {
defer cur.Close()
fields, err := cur.Fields()
if err != nil {
return err
}
for cur.Next() {
var (
doc = col.Add()
scanners = doc.Scanners(fields)
)
if err := cur.Scan(scanners...); err != nil {
return err
}
}
return nil
}
func scanMulti(cur Cursor, keyField string, keyType reflect.Type, cols map[any][]slice) error {
defer cur.Close()
fields, err := cur.Fields()
if err != nil {
return err
}
keyFound := false
for _, field := range fields {
if keyField == field {
keyFound = true
}
}
if !keyFound && fields != nil {
panic("rel: primary key row does not exists")
}
var doc *Document
for k := range cols {
for _, col := range cols[k] {
doc = col.NewDocument()
break
}
break
}
// scan the result
for cur.Next() {
// scan key
if err := cur.Scan(doc.Scanners(fields)...); err != nil {
return err
}
key, found := doc.Value(keyField)
mustTrue(found, "rel: key field not found")
needCopy := false
for _, col := range cols[key] {
if needCopy {
col.Append(doc.Copy())
} else {
col.Append(doc)
needCopy = true
}
}
// create new doc for next scan
doc = doc.NewDocument()
}
return nil
}