Skip to content

Commit

Permalink
Merge pull request #23 from syumai/d1-treat-integral-float64-as-int64
Browse files Browse the repository at this point in the history
treat D1 driver row's integral float64 value as int64
  • Loading branch information
syumai committed Feb 26, 2023
2 parents 4e34fba + a496d2d commit efa79d9
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 14 deletions.
18 changes: 16 additions & 2 deletions cloudflare/d1/rows.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"database/sql/driver"
"errors"
"io"
"math"
"sync"
"syscall/js"

Expand Down Expand Up @@ -50,6 +51,15 @@ func (r *rows) Close() error {
return nil
}

// isIntegralNumber returns if given float64 value is integral value or not.
func isIntegralNumber(f float64) bool {
// If the value is NaN or Inf, returns the value to avoid being mistakenly treated as an integral value.
if math.IsNaN(f) || math.IsInf(f, 0) {
return false
}
return f == math.Trunc(f)
}

// convertRowColumnValueToDriverValue converts row column's value in JS to Go's driver.Value.
// row column value is `null | Number | String | ArrayBuffer`.
// see: https://developers.cloudflare.com/d1/platform/client-api/#type-conversion
Expand All @@ -58,8 +68,12 @@ func convertRowColumnValueToAny(v js.Value) (driver.Value, error) {
case js.TypeNull:
return nil, nil
case js.TypeNumber:
// TODO: handle INTEGER type.
return v.Float(), nil
fv := v.Float()
// if the value can be treated as integral value, return as int64.
if isIntegralNumber(fv) {
return int64(fv), nil
}
return fv, nil
case js.TypeString:
return v.String(), nil
case js.TypeObject:
Expand Down
44 changes: 44 additions & 0 deletions cloudflare/d1/rows_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package d1

import (
"math"
"testing"
)

func Test_isIntegralNumber(t *testing.T) {
tests := map[string]struct {
f float64
want bool
}{
"valid integral value": {
f: 1,
want: true,
},
"invalid float value": {
f: 1.1,
want: false,
},
"invalid NaN": {
f: math.NaN(),
want: false,
},
"invalid +Inf": {
f: math.Inf(+1),
want: false,
},
"invalid -Inf": {
f: math.Inf(-1),
want: false,
},
}
for name, tc := range tests {
name := name
tc := tc
t.Run(name, func(t *testing.T) {
t.Parallel()
if got := isIntegralNumber(tc.f); got != tc.want {
t.Errorf("isIntegralNumber() = %v, want %v", got, tc.want)
}
})
}
}
19 changes: 7 additions & 12 deletions examples/d1-blog-server/app/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,20 +108,15 @@ ORDER BY created_at DESC;

articles := []model.Article{}
for rows.Next() {
var (
title, body string
id, createdAt float64 // number value is always retrieved as float64.
)
err = rows.Scan(&id, &title, &body, &createdAt)
var a model.Article
err = rows.Scan(&a.ID, &a.Title, &a.Body, &a.CreatedAt)
if err != nil {
break
log.Println(err)
h.handleErr(w, http.StatusInternalServerError,
"failed to scan article")
return
}
articles = append(articles, model.Article{
ID: uint64(id),
Title: title,
Body: body,
CreatedAt: uint64(createdAt),
})
articles = append(articles, a)
}
res := model.ListArticlesResponse{
Articles: articles,
Expand Down

0 comments on commit efa79d9

Please sign in to comment.