From 6642597fbce56a232f696536e043529c74c4259c Mon Sep 17 00:00:00 2001 From: Ben Krieger Date: Wed, 30 Oct 2024 15:37:27 -0400 Subject: [PATCH] Support []byte arguments to D1 Query/Exec --- cloudflare/d1/rows.go | 13 ++++++++++--- cloudflare/d1/stmt.go | 22 +++++++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/cloudflare/d1/rows.go b/cloudflare/d1/rows.go index 76c3f81..ee97465 100644 --- a/cloudflare/d1/rows.go +++ b/cloudflare/d1/rows.go @@ -7,6 +7,8 @@ import ( "math" "sync" "syscall/js" + + "github.com/syumai/workers/internal/jsutil" ) type rows struct { @@ -61,9 +63,14 @@ func convertRowColumnValueToAny(v js.Value) (driver.Value, error) { case js.TypeString: return v.String(), nil case js.TypeObject: - // TODO: handle BLOB type (ArrayBuffer). - // see: https://developers.cloudflare.com/d1/platform/client-api/#type-conversion - return nil, errors.New("d1: row column value type object is not currently supported") + // handle BLOB type (ArrayBuffer). + src := jsutil.Uint8ArrayClass.New(v) + dst := make([]byte, src.Length()) + n := js.CopyBytesToGo(dst, src) + if n != len(dst) { + return nil, errors.New("incomplete copy from Uint8Array") + } + return dst[:n], nil } return nil, errors.New("d1: unexpected row column value type") } diff --git a/cloudflare/d1/stmt.go b/cloudflare/d1/stmt.go index fe2cc1b..55593cc 100644 --- a/cloudflare/d1/stmt.go +++ b/cloudflare/d1/stmt.go @@ -34,11 +34,19 @@ func (s *stmt) Exec([]driver.Value) (driver.Result, error) { } // ExecContext executes prepared statement. -// Given []drier.NamedValue's `Name` field will be ignored because Cloudflare D1 client doesn't support it. +// Given []driver.NamedValue's `Name` field will be ignored because Cloudflare D1 client doesn't support it. func (s *stmt) ExecContext(_ context.Context, args []driver.NamedValue) (driver.Result, error) { argValues := make([]any, len(args)) for i, arg := range args { - argValues[i] = arg.Value + if src, ok := arg.Value.([]byte); ok { + dst := jsutil.Uint8ArrayClass.New(len(src)) + if n := js.CopyBytesToJS(dst, src); n != len(src) { + return nil, errors.New("incomplete copy into Uint8Array") + } + argValues[i] = dst + } else { + argValues[i] = arg.Value + } } resultPromise := s.stmtObj.Call("bind", argValues...).Call("run") resultObj, err := jsutil.AwaitPromise(resultPromise) @@ -57,7 +65,15 @@ func (s *stmt) Query([]driver.Value) (driver.Rows, error) { func (s *stmt) QueryContext(_ context.Context, args []driver.NamedValue) (driver.Rows, error) { argValues := make([]any, len(args)) for i, arg := range args { - argValues[i] = arg.Value + if src, ok := arg.Value.([]byte); ok { + dst := jsutil.Uint8ArrayClass.New(len(src)) + if n := js.CopyBytesToJS(dst, src); n != len(src) { + return nil, errors.New("incomplete copy into Uint8Array") + } + argValues[i] = dst + } else { + argValues[i] = arg.Value + } } resultPromise := s.stmtObj.Call("bind", argValues...).Call("raw", map[string]any{"columnNames": true}) rowsArray, err := jsutil.AwaitPromise(resultPromise)