database/sqlのsqlドライバーを使ってSalesforceのSOQLを動かしてみましたー
ということで使い方とdatabase/sqlのドライバーの作り方を備忘として残しておきます。
使い方
$ go get github.com/tzmfreedom/go-soql-driver
して、以下のようにして使います
package main
import (
"database/sql"
"fmt"
"net/url"
"os"
soqlDriver "github.com/tzmfreedom/go-soql-driver"
)
func main() {
username := os.Getenv("SFDC_USERNAME")
password := os.Getenv("SFDC_PASSWORD")
dsn := soqlDriver.CreateDsn(url.QueryEscape(username), url.QueryEscape(password), "login.salesforce.com")
db, err := sql.Open("soql", dsn)
if err != nil {
panic(err)
}
rows, err := db.Query("SELECT Id, Name FROM Account")
if err != nil {
panic(err)
}
for rows.Next() {
var id, name string
rows.Scan(&id, &name)
fmt.Println(id, name)
}
}
func insert(db *sql.DB) {
r, err := db.Exec("INSERT INTO Account(Name) VALUES ('Created By sql driver')")
if err != nil {
panic(err)
}
fmt.Println(r.RowsAffected())
}
func update(db *sql.DB) {
r, err := db.Exec("UPDATE Account SET Name = 'Updated By sql driver' WHERE Name = 'Created By sql driver'")
if err != nil {
panic(err)
}
fmt.Println(r.RowsAffected())
}
func delete(db *sql.DB) {
r, err := db.Exec("DELETE FROM Account WHERE Name = 'Updated By sql driver'")
if err != nil {
panic(err)
}
fmt.Println(r.RowsAffected())
}
SOQLにはINSERT, UPDATE, DELETE構文はありませんが、よしなに変換してDMLを発行しています。
Execに引数をバインドするのは未対応なのでこれからって感じっす
database/sqlのdriverの作り方
まずはDriverをRegisterします。importしたときにRegisterしたい場合はinitで実行します。
func init() {
sql.Register("soql", &SOQLDriver{})
}
DriverのインターフェースとしてOpen関数を実装する必要があります。
type Driver interface {
Open(name string) (Conn, error)
}
SOQLDriverの場合は、dsnに応じてSalesforceにログインする処理をしています。 戻り値はdriver.Connインターフェースになります。
driver.Connインターフェースは以下の定義になります。
type Conn interface {
Prepare(query string) (Stmt, error)
Close() error
Begin() (Tx, error)
}
SOQLDriverの場合はトランザクション無し、CloseもなしなのでPrepareのみ実装しています。 Prepareはクエリ文字列を引数に受け取り、driver.Stmtインターフェースを返します。
driver.Stmtインターフェースは以下の定義になります。
type Stmt interface {
Close() error
NumInput() int
Exec(args []Value) (Result, error)
Query(args []Value) (Rows, error)
}
QueryはSELECT実行、ExecはSELECT以外のDMLの実行をする関数です。
driver.Rowsインターフェースは以下の定義になります。
type Rows interface {
Columns() []string
Close() error
Next(dest []Value) error
}
Columnsは現在のカーソルの値を返す関数、Nextは次のレコードが存在するかを判定する関数です。
driver.Resultインターフェースは以下のような定義です。
type Result interface {
LastInsertId() (int64, error)
RowsAffected() (int64, error)
}
SOQLDriverの場合、IDは文字列型でLastInsertIdはアンマッチだったので使っていません。