Skip to content

Commit 6022ace

Browse files
bigmontzfbiville
authored andcommitted
Support temporal types in Testkit backend, inc. UTC DateTime
Signed-off-by: Florent Biville <[email protected]>
1 parent be34f02 commit 6022ace

File tree

3 files changed

+74
-15
lines changed

3 files changed

+74
-15
lines changed

testkit-backend/2cypher.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ package main
2121

2222
import (
2323
"fmt"
24+
"time"
2425

2526
"github.com/neo4j/neo4j-go-driver/v5/neo4j"
2627
)
@@ -39,6 +40,22 @@ func nativeToCypher(v interface{}) map[string]interface{} {
3940
return valueResponse("CypherBool", x)
4041
case float64:
4142
return valueResponse("CypherFloat", x)
43+
case time.Time:
44+
tzName, offset := x.Zone()
45+
values := map[string]any{
46+
"year": x.Year(),
47+
"month": x.Month(),
48+
"day": x.Day(),
49+
"hour": x.Hour(),
50+
"minute": x.Minute(),
51+
"second": x.Second(),
52+
"nanosecond": x.Nanosecond(),
53+
"utc_offset_s": offset,
54+
}
55+
if tzName != "Offset" {
56+
values["timezone_id"] = tzName
57+
}
58+
return valueResponse("CypherList", values)
4259
case []interface{}:
4360
values := make([]interface{}, len(x))
4461
for i, y := range x {

testkit-backend/2native.go

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,38 +21,67 @@ package main
2121

2222
import (
2323
"fmt"
24+
"time"
2425
)
2526

2627
// Converts received proxied "cypher" types to Go native types.
27-
func cypherToNative(c interface{}) interface{} {
28+
func cypherToNative(c interface{}) (any, error) {
2829
m := c.(map[string]interface{})
2930
d := m["data"].(map[string]interface{})
3031
n := m["name"]
3132
switch n {
33+
case "CypherDateTime":
34+
year := d["year"].(float64)
35+
month := d["month"].(float64)
36+
day := d["day"].(float64)
37+
hour := d["hour"].(float64)
38+
minute := d["minute"].(float64)
39+
second := d["second"].(float64)
40+
nanosecond := d["nanosecond"].(float64)
41+
offset := d["utc_offset_s"].(float64)
42+
var timezone *time.Location
43+
var err error
44+
if timezoneId, found := d["timezone_id"]; !found || timezoneId == nil {
45+
timezone = time.FixedZone("Offset", int(offset))
46+
} else {
47+
timezone, err = time.LoadLocation(timezoneId.(string))
48+
if err != nil {
49+
return nil, err
50+
}
51+
}
52+
// TODO: check whether the offset (possibly from the named time zone) matches
53+
// the offset sent by Testkit, if Testkit sends one along the tz name
54+
return time.Date(int(year), time.Month(month), int(day), int(hour), int(minute), int(second), int(nanosecond), timezone), nil
3255
case "CypherString":
33-
return d["value"].(string)
56+
return d["value"].(string), nil
3457
case "CypherInt":
35-
return int64(d["value"].(float64))
58+
return int64(d["value"].(float64)), nil
3659
case "CypherBool":
37-
return d["value"].(bool)
60+
return d["value"].(bool), nil
3861
case "CypherFloat":
39-
return d["value"].(float64)
62+
return d["value"].(float64), nil
4063
case "CypherNull":
41-
return nil
64+
return nil, nil
4265
case "CypherList":
4366
lc := d["value"].([]interface{})
4467
ln := make([]interface{}, len(lc))
68+
var err error
4569
for i, x := range lc {
46-
ln[i] = cypherToNative(x)
70+
if ln[i], err = cypherToNative(x); err != nil {
71+
return nil, err
72+
}
4773
}
48-
return ln
74+
return ln, nil
4975
case "CypherMap":
5076
mc := d["value"].(map[string]interface{})
5177
mn := make(map[string]interface{})
78+
var err error
5279
for k, x := range mc {
53-
mn[k] = cypherToNative(x)
80+
if mn[k], err = cypherToNative(x); err != nil {
81+
return nil, err
82+
}
5483
}
55-
return mn
84+
return mn, nil
5685
}
5786
panic(fmt.Sprintf("Don't know how to convert %s to native", n))
5887
}

testkit-backend/backend.go

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -256,13 +256,16 @@ func (b *backend) toTransactionConfigApply(data map[string]interface{}) func(*ne
256256
}
257257
}
258258

259-
func (b *backend) toCypherAndParams(data map[string]interface{}) (string, map[string]interface{}) {
259+
func (b *backend) toCypherAndParams(data map[string]interface{}) (string, map[string]interface{}, error) {
260260
cypher := data["cypher"].(string)
261261
params, _ := data["params"].(map[string]interface{})
262+
var err error
262263
for i, p := range params {
263-
params[i] = cypherToNative(p)
264+
if params[i], err = cypherToNative(p); err != nil {
265+
return "", nil, err
266+
}
264267
}
265-
return cypher, params
268+
return cypher, params, nil
266269
}
267270

268271
func (b *backend) handleTransactionFunc(isRead bool, data map[string]interface{}) {
@@ -500,7 +503,11 @@ func (b *backend) handleRequest(req map[string]interface{}) {
500503

501504
case "SessionRun":
502505
sessionState := b.sessionStates[data["sessionId"].(string)]
503-
cypher, params := b.toCypherAndParams(data)
506+
cypher, params, err := b.toCypherAndParams(data)
507+
if err != nil {
508+
b.writeError(err)
509+
return
510+
}
504511
result, err := sessionState.session.Run(ctx, cypher, params, b.toTransactionConfigApply(data))
505512
if err != nil {
506513
b.writeError(err)
@@ -543,7 +550,11 @@ func (b *backend) handleRequest(req map[string]interface{}) {
543550
if tx, found = b.explicitTransactions[transactionId]; !found {
544551
tx = b.managedTransactions[transactionId]
545552
}
546-
cypher, params := b.toCypherAndParams(data)
553+
cypher, params, err := b.toCypherAndParams(data)
554+
if err != nil {
555+
b.writeError(err)
556+
return
557+
}
547558
result, err := tx.Run(ctx, cypher, params)
548559
if err != nil {
549560
b.writeError(err)
@@ -735,6 +746,7 @@ func (b *backend) handleRequest(req map[string]interface{}) {
735746
"Feature:API:Liveness.Check",
736747
"Feature:API:Result.List",
737748
"Feature:API:Result.Peek",
749+
"Feature:API:Type.Temporal",
738750
"Feature:Auth:Custom",
739751
"Feature:Auth:Bearer",
740752
"Feature:Auth:Kerberos",
@@ -744,6 +756,7 @@ func (b *backend) handleRequest(req map[string]interface{}) {
744756
"Feature:Bolt:4.3",
745757
"Feature:Bolt:4.4",
746758
"Feature:Bolt:5.0",
759+
"Feature:Bolt:Patch:UTC",
747760
"Feature:Impersonation",
748761
"Feature:TLS:1.1",
749762
"Feature:TLS:1.2",

0 commit comments

Comments
 (0)