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 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
|
package internal
import (
"crypto/md5"
"fmt"
"math/rand"
"time"
)
// RS is a result set.
type RS struct {
rs int
pos int
cols []string
vals [][][]any
}
// New creates a new result set
func New(cols []string, vals ...[][]any) *RS {
return &RS{
cols: cols,
vals: vals,
}
}
// Multi creates a result set with multiple result sets.
func Multi() *RS {
s, t := rset(14), rset(38)
r := &RS{
cols: []string{"author_id", "name", "z"},
vals: [][][]any{
s[:2], s[2:], t,
},
}
return r
}
// Big creates a random, big result set using the provided seed.
func Big(seed int64) *RS {
src := rand.New(rand.NewSource(seed))
count := src.Intn(1000)
// generate rows
vals := make([][]any, count)
for i := range count {
p := newRrow(src)
vals[i] = []any{i + 1, p.name, p.dob, p.f, p.hash, p.char, p.z}
}
return &RS{
cols: []string{"id", "name", "dob", "float", "hash", "", "z"},
vals: [][][]any{vals},
}
}
// Tiny creates a tiny result set.
func Tiny() *RS {
return &RS{
cols: []string{"z"},
vals: [][][]any{
{
{"x"},
},
},
}
}
// Wide creates a wide result set.
func Wide() *RS {
return &RS{
cols: []string{
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
"cccccccccccccccccccccccccccccc",
"dddddddddddddddddddddddddddddd",
"eeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
"ffffffffffffffffffffffffffffff",
"gggggggggggggggggggggggggggggg",
"hhhhhhhhhhhhhhhhhhhhhhhhhhhhhh",
"iiiiiiiiiiiiiiiiiiiiiiiiiiiiii",
"jjjjjjjjjjjjjjjjjjjjjjjjjjjjjj",
},
vals: [][][]any{
{
{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"},
},
},
}
}
// Err satisfies the ResultSet interface.
func (*RS) Err() error {
return nil
}
// Err satisfies the ResultSet interface.
func (*RS) Close() error {
return nil
}
// Err satisfies the ResultSet interface.
func (r *RS) Columns() ([]string, error) {
return r.cols, nil
}
// Err satisfies the ResultSet interface.
func (r *RS) Next() bool {
return r.pos < len(r.vals[r.rs])
}
// Err satisfies the ResultSet interface.
func (r *RS) Scan(vals ...any) error {
for i := range vals {
x, ok := vals[i].(*any)
if !ok {
return fmt.Errorf("scan for col %d expected *interface{}, got: %T", i, vals[i])
}
*x = r.vals[r.rs][r.pos][i]
}
r.pos++
return nil
}
// Err satisfies the ResultSet interface.
func (r *RS) NextResultSet() bool {
r.rs, r.pos = r.rs+1, 0
return r.rs < len(r.vals)
}
// Reset resets the rset so that it can be used repeatedly.
func (r *RS) Reset() {
r.pos, r.rs = 0, 0
}
// rrow is a random row.
type rrow struct {
name string
dob time.Time
f float64
hash []byte
char []byte
z any
}
// newRrow creates a new random row using the rand source.
func newRrow(src *rand.Rand) rrow {
hash := md5.Sum([]byte(rstr(src)))
var char []byte
if src.Intn(2) == 1 {
char = []byte{byte(int('a') + src.Intn(26))}
}
var z any
switch src.Intn(4) {
case 0, 1:
case 2:
c := 1 + src.Intn(5)
m := make(map[string]any, c)
for range c {
r := []rune(rstr(src))
m[string(r[0:3])] = string(r[3:])
}
z = m
case 3:
y := make([]any, 1+src.Intn(5))
for i := range y {
r := []rune(rstr(src))
y[i] = string(r[0 : 1+src.Intn(6)])
}
z = y
}
return rrow{
name: rstr(src),
dob: rtime(src),
f: src.Float64(),
hash: fmt.Appendf(nil, "%x", hash[:]),
char: char,
z: z,
}
}
var glyphs = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 _'\"\t\b\n\rゼ一二三四五六七八九十〇")
// rstr creates a random string using the rand source.
func rstr(src *rand.Rand) string {
l := 6 + src.Intn(32)
r := make([]rune, l)
for i := range l {
r[i] = glyphs[src.Intn(len(glyphs))]
}
return string(r)
}
// rtime creates a random time using the rand source.
func rtime(src *rand.Rand) time.Time {
min := time.Date(1970, 1, 0, 0, 0, 0, 0, time.UTC).Unix()
max := time.Date(2070, 1, 0, 0, 0, 0, 0, time.UTC).Unix()
delta := max - min
return time.Unix(src.Int63n(delta)+min, 0).UTC()
}
// rset returns predefined record set values.
func rset(i int) [][]any {
return [][]any{
{float64(i), "a\tb\tc\td", "x"},
{float64(i + 1), "aoeu\ntest\n", nil},
{float64(i + 2), "foo\bbar", nil},
{float64(i + 3), "袈\t袈\t\t袈", nil},
{float64(i + 4), "a\tb\t\r\n\ta", "a\n"},
{float64(i + 5), "袈\t袈\t\t袈\n", nil},
{float64(i + 6), "javascript", map[string]any{
fmt.Sprintf("test%d", i+7): "a value",
fmt.Sprintf("test%d", i+8): "foo\bbar",
}},
{float64(i + 9), "slice", []string{"a", "b"}},
}
}
const Divider = "==============================================="
|