Skip to content

Commit c8979e6

Browse files
feat: basic Go SQL driver implementation (#2)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent cb2f159 commit c8979e6

5 files changed

Lines changed: 86 additions & 8 deletions

File tree

driver.go

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Package airtablesql implements a Go SQL driver for Airtable
2+
// Import package github.com/sclgo/airtable-sql/register to register
3+
// a driver with default configuration automatically or use CreateDriver from this
4+
// package and register it explicitly with sql.Register.
5+
package airtablesql // import github.com/sclgo/airtable-sql
6+
7+
import (
8+
"net/url"
9+
10+
drivere "github.com/dolthub/go-mysql-server/driver"
11+
"github.com/dolthub/go-mysql-server/sql"
12+
"github.com/mehanizm/airtable"
13+
"github.com/sclgo/airtable-sql/internal/errhelp"
14+
"github.com/sclgo/airtable-sql/provider"
15+
16+
"database/sql/driver"
17+
)
18+
19+
func CreateDriver() interface {
20+
driver.Driver
21+
driver.DriverContext
22+
} {
23+
return drivere.New(factory{}, nil)
24+
}
25+
26+
type factory struct{}
27+
28+
// Resolve implements driver.Provider
29+
func (factory) Resolve(dsn string, _ *drivere.Options) (string, sql.DatabaseProvider, error) {
30+
dsnUri, err := url.Parse(dsn)
31+
if err != nil {
32+
return "", nil, errhelp.Errorf("could not parse DSN %s: %w", dsn, err)
33+
}
34+
key := dsnUri.Query().Get("key")
35+
if key == "" {
36+
return "", nil, errhelp.Errorf("could not find key in DSN %s", dsn)
37+
}
38+
return dsn, provider.New(airtable.NewClient(key)), nil
39+
}

driver_integ_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package airtablesql_test
2+
3+
import (
4+
"database/sql"
5+
"os"
6+
"testing"
7+
8+
airtablesql "github.com/sclgo/airtable-sql"
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
func TestCreateDriver(t *testing.T) {
13+
t.Run("happy", func(t *testing.T) {
14+
if os.Getenv("AIRTABLE_API_KEY") == "" {
15+
t.Skip("skipping integration test; AIRTABLE_API_KEY not set")
16+
}
17+
drv := airtablesql.CreateDriver()
18+
cnct, err := drv.OpenConnector("airtable:?key=" + os.Getenv("AIRTABLE_API_KEY"))
19+
require.NoError(t, err)
20+
db := sql.OpenDB(cnct)
21+
row := db.QueryRow("SELECT `Part Name` FROM `Order Assembly`.Parts")
22+
var part string
23+
require.NoError(t, row.Scan(&part))
24+
require.Equal(t, "Power Supply Unit", part)
25+
})
26+
}

provider/airdb.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@ import (
99
"github.com/mehanizm/airtable"
1010
)
1111

12-
var _ sql.Database = (*AirDB)(nil)
13-
var _ sql.Table = (*AirSqlTable)(nil)
12+
var (
13+
_ sql.Database = (*AirDB)(nil)
14+
)
1415

1516
type AirDB struct {
1617
client *airtable.Client
@@ -31,7 +32,7 @@ func (a *AirDB) GetTableInsensitive(ctx *sql.Context, tblName string) (sql.Table
3132
for _, tbl := range tbls.Tables {
3233
if strings.EqualFold(tblName, tbl.Name) {
3334
return AirSqlTable{
34-
tableClient: a.client.GetTable(a.dbId, tbl.Name),
35+
tableClient: a.client.GetTable(a.dbId, tbl.Name),
3536
airSchema: tbl,
3637
schema: toSqlSchema(tbl),
3738
}, true, nil

provider/airsqltable.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,12 @@ import (
99
"github.com/mehanizm/airtable"
1010
)
1111

12+
var (
13+
_ sql.RowIter = (*basicRowIter)(nil)
14+
_ sql.Disposable = (*basicRowIter)(nil)
15+
_ sql.Table = (*AirSqlTable)(nil)
16+
)
17+
1218
type AirSqlTable struct {
1319
tableClient *airtable.Table
1420
airSchema *airtable.TableSchema
@@ -100,8 +106,3 @@ func (b *basicRowIter) Close(*sql.Context) error {
100106
b.recs = nil
101107
return nil
102108
}
103-
104-
var (
105-
_ sql.RowIter = (*basicRowIter)(nil)
106-
_ sql.Disposable = (*basicRowIter)(nil)
107-
)

register/register.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package register
2+
3+
import (
4+
"database/sql"
5+
6+
airtablesql "github.com/sclgo/airtable-sql"
7+
)
8+
9+
func init() {
10+
sql.Register("airtable", airtablesql.CreateDriver())
11+
}

0 commit comments

Comments
 (0)