0
# Go API Reference
1
2
The FoundationDB Go API provides an idiomatic Go interface to the database with context support, interface-based design patterns, and channel-friendly async operations. The API follows Go conventions and integrates well with modern Go applications.
3
4
## Installation
5
6
```bash
7
go get github.com/apple/foundationdb/bindings/go/src/fdb
8
```
9
10
## Core Imports
11
12
```go
13
import (
14
"github.com/apple/foundationdb/bindings/go/src/fdb"
15
"github.com/apple/foundationdb/bindings/go/src/fdb/tuple"
16
"github.com/apple/foundationdb/bindings/go/src/fdb/subspace"
17
"github.com/apple/foundationdb/bindings/go/src/fdb/directory"
18
)
19
```
20
21
## Capabilities
22
23
### Initialization and Database Connection
24
25
```go { .api }
26
// Set API version (must be called first)
27
func APIVersion(version int) error
28
29
// Open database from cluster file
30
func OpenDatabase(clusterFile string) (Database, error)
31
32
// Open database from connection string
33
func OpenDatabaseFromConnectionString(connectionString string) (Database, error)
34
35
// Network management
36
func StartNetwork() error
37
func StopNetwork() error
38
```
39
40
**Usage Example:**
41
42
```go
43
// Initialize FoundationDB
44
fdb.APIVersion(740)
45
46
// Start network
47
fdb.StartNetwork()
48
defer fdb.StopNetwork()
49
50
// Open database
51
db, err := fdb.OpenDatabase("") // Default cluster file
52
if err != nil {
53
log.Fatal(err)
54
}
55
```
56
57
### Core Interfaces
58
59
```go { .api }
60
type Database interface {
61
CreateTransaction() (Transaction, error)
62
Transact(func(Transaction) (interface{}, error)) (interface{}, error)
63
ReadTransact(func(ReadTransaction) (interface{}, error)) (interface{}, error)
64
OpenTenant(tenantName []byte) (Tenant, error)
65
}
66
67
type Transaction interface {
68
ReadTransaction
69
Set(key KeyConvertible, value []byte)
70
Clear(key KeyConvertible)
71
ClearRange(begin, end KeyConvertible)
72
Commit() Future
73
OnError(error) Future
74
SetReadVersion(version int64)
75
GetCommittedVersion() int64
76
GetVersionstamp() Future
77
}
78
79
type ReadTransaction interface {
80
Get(key KeyConvertible) Future
81
GetRange(r Range, options RangeOptions) RangeResult
82
GetReadVersion() Future
83
Snapshot() ReadTransaction
84
}
85
86
type Future interface {
87
Get() (interface{}, error)
88
GetWithError() (interface{}, error)
89
IsReady() bool
90
BlockUntilReady() error
91
}
92
93
type KeyConvertible interface {
94
FDBKey() Key
95
}
96
97
type Key []byte
98
type KeyValue struct {
99
Key Key
100
Value []byte
101
}
102
```
103
104
### Transaction Operations
105
106
```go { .api }
107
// Functional transaction pattern
108
result, err := db.Transact(func(tr fdb.Transaction) (interface{}, error) {
109
value, err := tr.Get(fdb.Key("my_key")).Get()
110
if err != nil {
111
return nil, err
112
}
113
114
if value == nil {
115
tr.Set(fdb.Key("my_key"), []byte("initial_value"))
116
return "created", nil
117
}
118
119
return string(value.([]byte)), nil
120
})
121
122
// Manual transaction handling
123
tr, err := db.CreateTransaction()
124
if err != nil {
125
return err
126
}
127
128
for {
129
value, err := tr.Get(fdb.Key("counter")).Get()
130
if err != nil {
131
onErrorFuture := tr.OnError(err)
132
err = onErrorFuture.BlockUntilReady()
133
if err != nil {
134
return err
135
}
136
continue
137
}
138
139
var newValue int64 = 1
140
if value != nil {
141
currentValue, _ := strconv.ParseInt(string(value.([]byte)), 10, 64)
142
newValue = currentValue + 1
143
}
144
145
tr.Set(fdb.Key("counter"), []byte(strconv.FormatInt(newValue, 10)))
146
147
err = tr.Commit().BlockUntilReady()
148
if err != nil {
149
onErrorFuture := tr.OnError(err)
150
err = onErrorFuture.BlockUntilReady()
151
if err != nil {
152
return err
153
}
154
continue
155
}
156
157
break
158
}
159
```
160
161
### Range Operations
162
163
```go { .api }
164
type Range struct {
165
Begin KeyConvertible
166
End KeyConvertible
167
}
168
169
type RangeOptions struct {
170
Limit int
171
Reverse bool
172
Mode StreamingMode
173
}
174
175
type RangeResult interface {
176
Iterator() *RangeIterator
177
GetSliceOrPanic() []KeyValue
178
GetSliceWithError() ([]KeyValue, error)
179
}
180
181
type RangeIterator struct {
182
// Iterator for traversing key-value pairs
183
}
184
185
func (ri *RangeIterator) Advance() bool
186
func (ri *RangeIterator) Get() (KeyValue, error)
187
```
188
189
### Key Selectors
190
191
```go { .api }
192
type KeySelector struct {
193
Key KeyConvertible
194
OrEqual bool
195
Offset int
196
}
197
198
func LastLessThan(key KeyConvertible) KeySelector
199
func LastLessOrEqual(key KeyConvertible) KeySelector
200
func FirstGreaterThan(key KeyConvertible) KeySelector
201
func FirstGreaterOrEqual(key KeyConvertible) KeySelector
202
```
203
204
### Tuple Encoding
205
206
```go { .api }
207
// Package: fdb/tuple
208
209
type Tuple []TupleElement
210
211
func (t Tuple) Pack() []byte
212
func Unpack(b []byte) Tuple
213
func (t Tuple) FDBKey() Key
214
func (t Tuple) FDBRangeKeys() (Key, Key)
215
216
// Create ranges for prefix queries
217
userRange := tuple.Tuple{"users", userID}.FDBRangeKeys()
218
```
219
220
### Subspace Operations
221
222
```go { .api }
223
// Package: fdb/subspace
224
225
type Subspace struct {
226
// Key prefix management
227
}
228
229
func Sub(prefix []byte) Subspace
230
func FromBytes(prefix []byte) Subspace
231
232
func (s Subspace) Pack(t tuple.Tuple) Key
233
func (s Subspace) Unpack(key Key) tuple.Tuple
234
func (s Subspace) FDBRangeKeys() (Key, Key)
235
func (s Subspace) Sub(t tuple.Tuple) Subspace
236
func (s Subspace) Contains(key Key) bool
237
```
238
239
### Directory Layer
240
241
```go { .api }
242
// Package: fdb/directory
243
244
type DirectoryLayer interface {
245
CreateOrOpen(tr fdb.ReadTransaction, path []string, layer []byte) (Directory, error)
246
Open(tr fdb.ReadTransaction, path []string, layer []byte) (Directory, error)
247
Create(tr fdb.Transaction, path []string, layer []byte) (Directory, error)
248
List(tr fdb.ReadTransaction, path []string) ([]string, error)
249
Remove(tr fdb.Transaction, path []string) (bool, error)
250
Move(tr fdb.Transaction, oldPath []string, newPath []string) (Directory, error)
251
Exists(tr fdb.ReadTransaction, path []string) (bool, error)
252
}
253
254
type Directory interface {
255
subspace.Subspace
256
GetLayer() []byte
257
GetPath() []string
258
}
259
260
var Root DirectoryLayer
261
```
262
263
## Error Handling
264
265
```go { .api }
266
type Error struct {
267
Code int
268
Description string
269
}
270
271
func (e Error) Error() string
272
273
// Error predicate functions
274
func (e Error) IsRetryable() bool
275
func (e Error) IsMaybeCommitted() bool
276
func (e Error) IsRetryableNotCommitted() bool
277
```
278
279
## Complete Usage Example
280
281
```go
282
package main
283
284
import (
285
"fmt"
286
"log"
287
"strconv"
288
289
"github.com/apple/foundationdb/bindings/go/src/fdb"
290
"github.com/apple/foundationdb/bindings/go/src/fdb/tuple"
291
"github.com/apple/foundationdb/bindings/go/src/fdb/subspace"
292
)
293
294
func main() {
295
// Initialize FoundationDB
296
fdb.APIVersion(740)
297
fdb.StartNetwork()
298
defer fdb.StopNetwork()
299
300
// Open database
301
db, err := fdb.OpenDatabase("")
302
if err != nil {
303
log.Fatal(err)
304
}
305
306
// Set up subspaces
307
userSpace := subspace.Sub(tuple.Tuple{"users"}.Pack())
308
309
// Create user
310
userID := "user123"
311
result, err := db.Transact(func(tr fdb.Transaction) (interface{}, error) {
312
user := userSpace.Sub(tuple.Tuple{userID})
313
314
tr.Set(user.Pack(tuple.Tuple{"email"}), []byte("alice@example.com"))
315
tr.Set(user.Pack(tuple.Tuple{"name"}), []byte("Alice Smith"))
316
317
return userID, nil
318
})
319
320
if err != nil {
321
log.Fatal(err)
322
}
323
324
fmt.Printf("Created user: %s\n", result)
325
326
// Read user profile
327
profile, err := db.ReadTransact(func(tr fdb.ReadTransaction) (interface{}, error) {
328
user := userSpace.Sub(tuple.Tuple{userID})
329
begin, end := user.FDBRangeKeys()
330
331
ri := tr.GetRange(fdb.Range{begin, end}, fdb.RangeOptions{}).Iterator()
332
333
userData := make(map[string]string)
334
for ri.Advance() {
335
kv, err := ri.Get()
336
if err != nil {
337
return nil, err
338
}
339
340
field := user.Unpack(kv.Key)[0].(string)
341
userData[field] = string(kv.Value)
342
}
343
344
return userData, nil
345
})
346
347
if err != nil {
348
log.Fatal(err)
349
}
350
351
fmt.Printf("User profile: %+v\n", profile)
352
}
353
```