Skip to content

Commit c4ff3ad

Browse files
committed
Add a Map and MapInto
Turn a row into a map[string]any
1 parent 0193694 commit c4ff3ad

File tree

3 files changed

+98
-3
lines changed

3 files changed

+98
-3
lines changed

row.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,28 @@ type Row struct {
55
err error
66
}
77

8+
func (r Row) Map() (map[string]any, error) {
9+
m := make(map[string]any, r.Stmt.columnCount)
10+
err := r.MapInto(m)
11+
return m, err
12+
}
13+
14+
func (r Row) MapInto(m map[string]any) error {
15+
stmt := r.Stmt
16+
defer stmt.Close()
17+
18+
hasRow, err := stmt.Step()
19+
if err != nil {
20+
return err
21+
}
22+
23+
if !hasRow {
24+
return ErrNoRows
25+
}
26+
27+
return stmt.MapInto(m)
28+
}
29+
830
func (r Row) Scan(dst ...interface{}) error {
931
if err := r.err; err != nil {
1032
return err

sqlite3_test.go

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ func Test_Conn_ExecAndScan(t *testing.T) {
3737

3838
now := time.Now()
3939
mustExec(db, `
40-
insert into test (cint, creal, ctext, cblob, time)
40+
insert into test (cint, creal, ctext, cblob, ctime)
4141
values (?1, ?2, ?3, ?4, ?5)
4242
`, 1, 2.2, "three", []byte("four"), now)
4343
assert.Equal(t, db.Changes(), 1)
@@ -289,6 +289,34 @@ func Test_Rows_ScanError(t *testing.T) {
289289
assert.Equal(t, rows.Error().Error(), "sqlite: cannot scan into *os.File (index: 0) (code: 21)")
290290
}
291291

292+
func Test_Row_Map(t *testing.T) {
293+
db := testDB()
294+
defer db.Close()
295+
296+
now := time.Now()
297+
298+
mustExec(db, `
299+
insert into test (id, cint, creal, ctext, cblob, ctime)
300+
values (?1, ?2, ?3, ?4, ?5, ?6)
301+
`, 99, 2, 3.3, "four", []byte("five"), now)
302+
303+
m, err := db.Row("select * from test").Map()
304+
assert.Nil(t, err)
305+
assert.Equal(t, len(m), 11)
306+
307+
assert.Equal(t, m["id"].(int), 99)
308+
assert.Equal(t, m["cint"].(int), 2)
309+
assert.Nil(t, m["cintn"])
310+
assert.Equal(t, m["creal"].(float64), 3.3)
311+
assert.Nil(t, m["crealn"])
312+
assert.Equal(t, m["ctext"].(string), "four")
313+
assert.Nil(t, m["ctextn"])
314+
assert.Equal(t, string(m["cblob"].([]byte)), "five")
315+
assert.Nil(t, m["cblobn"])
316+
assert.Equal(t, m["ctime"].(int), int(now.Unix()))
317+
assert.Nil(t, m["ctimen"])
318+
}
319+
292320
func testDB() sqlite.Conn {
293321
db, err := sqlite.Open(":memory:", true)
294322
if err != nil {
@@ -305,8 +333,8 @@ func testDB() sqlite.Conn {
305333
ctextn text null,
306334
cblob blob not null default(''),
307335
cblobn blob null,
308-
time int not null default(0),
309-
timen int null
336+
ctime int not null default(0),
337+
ctimen int null
310338
)
311339
`)
312340
return db

stmt.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ type Stmt struct {
3939
columnTypes []byte
4040
cColumnTypes *C.uchar
4141
cColumnCount C.int
42+
columnNames []string
4243
}
4344

4445
func (s *Stmt) Close() error {
@@ -50,12 +51,17 @@ func (s *Stmt) Close() error {
5051
}
5152

5253
func (s *Stmt) ColumnNames() []string {
54+
if names := s.columnNames; names != nil {
55+
return names
56+
}
57+
5358
stmt := s.stmt
5459
count := s.columnCount
5560
names := make([]string, count)
5661
for i := 0; i < count; i++ {
5762
names[i] = C.GoString(C.sqlite3_column_name(stmt, C.int(i)))
5863
}
64+
s.columnNames = names
5965
return names
6066
}
6167

@@ -134,6 +140,45 @@ func (s *Stmt) Bind(args ...interface{}) error {
134140
return nil
135141
}
136142

143+
func (s *Stmt) Map() (map[string]any, error) {
144+
m := make(map[string]any, s.columnCount)
145+
err := s.MapInto(m)
146+
return m, err
147+
}
148+
149+
func (s *Stmt) MapInto(m map[string]any) error {
150+
names := s.ColumnNames()
151+
for i, tpe := range s.columnTypes {
152+
name := names[i]
153+
switch tpe {
154+
case C.SQLITE_NULL:
155+
m[name] = nil
156+
break
157+
case C.SQLITE_INTEGER:
158+
m[name] = s.ColumnInt(i)
159+
break
160+
case C.SQLITE_TEXT:
161+
var err error
162+
m[name], err = s.ColumnText(i)
163+
if err != nil {
164+
return err
165+
}
166+
break
167+
case C.SQLITE_FLOAT:
168+
m[name] = s.ColumnDouble(i)
169+
break
170+
case C.SQLITE_BLOB:
171+
var err error
172+
m[name], err = s.ColumnBytes(i)
173+
if err != nil {
174+
return err
175+
}
176+
break
177+
}
178+
}
179+
return nil
180+
}
181+
137182
func (s *Stmt) Scan(dst ...interface{}) error {
138183
for i, v := range dst {
139184
if err := s.scan(i, v); err != nil {

0 commit comments

Comments
 (0)