-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhandle.go
143 lines (124 loc) · 4.69 KB
/
handle.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
package cfd1
import (
"context"
"sync"
)
// Handle represents a psuedo-connection to a single D1 database, similar to a
// connection with other database engines. The D1 API does not provide for
// persistent connections, however Handle is still a useful abstraction for
// accessing a single database for multiple operations. To get a database
// handle, use [Client.GetHandle].
type Handle struct {
client *Client
dbID string
rowsRead int
rowsWritten int
lastRowID int
lastMeta QueryMeta
mux sync.RWMutex
}
// Ping sends a ping request to the database to check if it is reachable.
func (h *Handle) Ping(ctx context.Context) error {
_, err := h.Query(ctx, "SELECT 1")
return err
}
// Query executes a SQL query on this database and returns the results. The
// query can contain multiple semicolon-separated statements, which will be
// executed as a batch, and be up to 100KB. A maximum of 100 placeholder
// parameters can be used.
func (h *Handle) Query(ctx context.Context, sql string, params ...any) ([]map[string]any, error) {
result, err := h.client.Query(ctx, h.dbID, sql, params...)
if err != nil {
return nil, err
}
h.mux.Lock()
defer h.mux.Unlock()
h.rowsRead += result.Meta.RowsRead
h.rowsWritten += result.Meta.RowsWritten
h.lastRowID = result.Meta.LastRowID
h.lastMeta = result.Meta
return result.Results, nil
}
// Execute executes a SQL query on this database that has no results. The query
// can contain multiple semicolon-separated statements, which will be executed
// as a batch, and be up to 100KB. A maximum of 100 placeholder parameters can
// be used.
func (h *Handle) Execute(ctx context.Context, sql string, params ...any) error {
_, err := h.Query(ctx, sql, params...)
return err
}
// QueryRow executes a SQL query on this database and returns a single row of
// results as a Row object, suitable for calling Scan. If the query returns
// multiple rows, only the first row is reachable.
func (h *Handle) QueryRow(ctx context.Context, sql string, params ...any) *Row {
result, err := h.client.RawQuery(ctx, h.dbID, sql, params...)
return newRow(&result[0], err)
}
// QueryRows executes a SQL query on this database and returns a Rows object
// that can iterate the resultsets and rows.
func (h *Handle) QueryRows(ctx context.Context, sql string, params ...any) *Rows {
result, err := h.client.RawQuery(ctx, h.dbID, sql, params...)
return newRows(result, err)
}
// Export initiates an export (SQL dump) on this database. It accepts an
// optional [ExportOptions] to limit the scope of the export; passing nil for
// this parameter will export the data and schema of all tables. The method
// waits until the export is complete, and returns the download URL for the
// completed SQL dump as a string. The database will be unavailable for other
// queries for the duration of the export.
func (h *Handle) Export(ctx context.Context, opts *ExportOptions) (string, error) {
return h.client.Export(ctx, h.dbID, opts)
}
// Import initiates an import of an SQL dump into this database. The method
// accepts the SQL dump as filename, reads it from disk, and waits until the
// import is complete. The database will be unavailable for other queries for
// the duration of the import.
func (h *Handle) Import(ctx context.Context, sqlFilePath string) (*ImportResult, error) {
result, err := h.client.Import(ctx, h.dbID, sqlFilePath)
if err != nil {
return nil, err
}
h.mux.Lock()
defer h.mux.Unlock()
h.rowsRead += result.RowsRead
h.rowsWritten += result.RowsWritten
return result, nil
}
// UUID returns the unique identifier for the database represented by this
// handle. This is a 36-character hex string of the form
// "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee".
func (h *Handle) UUID() string {
return h.dbID
}
// LastRowID returns the last row ID that was inserted into the database by this
// handle.
func (h *Handle) LastRowID() int {
h.mux.RLock()
defer h.mux.RUnlock()
return h.lastRowID
}
// LastMeta returns the [QueryMeta] for the last query executed by this handle.
func (h *Handle) LastMeta() QueryMeta {
h.mux.RLock()
defer h.mux.RUnlock()
return h.lastMeta
}
// GetDetails returns the current DatabaseDetails describing this database,
// including the number of tables and size on disk.
func (h *Handle) GetDetails(ctx context.Context) (*DatabaseDetails, error) {
return h.client.GetDatabase(ctx, h.dbID)
}
// RowsRead returns the total number of rows read during the lifetime of this
// handle.
func (h *Handle) RowsRead() int {
h.mux.RLock()
defer h.mux.Unlock()
return h.rowsRead
}
// RowsWritten returns the total number of rows written during the lifetime of
// this handle.
func (h *Handle) RowsWritten() int {
h.mux.RLock()
defer h.mux.Unlock()
return h.rowsWritten
}