Skip to content

Add time-related query tests and enhance query result handling for da…#34

Open
MuhammadQadora wants to merge 8 commits into
masterfrom
32-add-support-for-date-time-and-datetime-in-the-go-client
Open

Add time-related query tests and enhance query result handling for da…#34
MuhammadQadora wants to merge 8 commits into
masterfrom
32-add-support-for-date-time-and-datetime-in-the-go-client

Conversation

@MuhammadQadora

@MuhammadQadora MuhammadQadora commented Jul 9, 2025

Copy link
Copy Markdown

fix #32

Summary by CodeRabbit

Release Notes

  • New Features
    • Added support for temporal types (date, time, datetime) and duration values in graph query results, enabling proper parsing and retrieval of temporal data from database queries.

✏️ Tip: You can customize this high-level summary in your review settings.

PR Summary by Typo

Overview

This PR introduces comprehensive tests for time-related query results and enhances the client's ability to correctly parse and handle TIME, DATE, DATETIME, and DURATION data types returned from the database. This ensures accurate representation of temporal values in the application.

Key Changes

  • Added new test cases in client_test.go to validate the parsing of TIME, DATE, DATETIME, and DURATION values.
  • Introduced new VALUE_ constants in query_result.go for DATETIME, DATE, TIME, and DURATION types.
  • Implemented parsing logic in query_result.go to convert these database temporal types into Go's time.Time and time.Duration objects.
  • Updated .gitignore to include .history/.

Work Breakdown

Category Lines Changed
New Work 89 (98.9%)
Rework 1 (1.1%)
Total Changes 90
To turn off PR summary, please visit Notification settings.

@MuhammadQadora
MuhammadQadora requested review from AviAvni and barakb July 9, 2025 08:16
@MuhammadQadora MuhammadQadora linked an issue Jul 9, 2025 that may be closed by this pull request
@coderabbitai

coderabbitai Bot commented Jul 9, 2025

Copy link
Copy Markdown
Contributor

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Four new test functions validate temporal and duration type parsing in graph query results. The parseScalar method in the query result handler now converts four new scalar types (DateTime, Date, Time, Duration) into Go time objects using Unix timestamp conversions.

Changes

Cohort / File(s) Summary
Temporal type parsing
query_result.go
Added four new scalar type constants (VALUE_DATETIME, VALUE_DATE, VALUE_TIME, VALUE_DURATION). Extended parseScalar method with time conversion logic: Unix timestamps for DateTime/Date, UnixMilli for Time, Duration conversions from seconds. Imported time package.
Test coverage
client_test.go
Added four test functions (TestGetTime, TestGetDate, TestGetDateTime, TestGetDuration) executing Cypher queries returning temporal and duration values. Tests verify correct Go type parsing and value assertions. Imported time package.
Gitignore
.gitignore
Added .history/ to OS-generated files section.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 A rabbit hops through dates with glee,
Temporal types now flow wild and free!
DateTime dances, Duration ticks on,
Time's gone from parsing—let tests be drawn! ⏰✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is truncated and incomplete, ending with 'for da…', but the core part 'Add time-related query tests and enhance query result handling' clearly relates to the main changes of adding temporal type tests and parsing logic.
Linked Issues check ✅ Passed The PR successfully implements all coding requirements from issue #32: new VALUE types for DATETIME, DATE, TIME, DURATION constants added; parseScalar logic implemented to convert temporal values to Go time.Time and time.Duration types; and comprehensive tests (TestGetTime, TestGetDate, TestGetDateTime, TestGetDuration) validate the parsing behavior.
Out of Scope Changes check ✅ Passed The .gitignore modification adding .history/ is a minor housekeeping change unrelated to the temporal types feature but does not conflict with or distract from the primary objectives.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@barakb
barakb requested a review from Copilot July 9, 2025 08:21

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c31628f and 7e49f57.

📒 Files selected for processing (2)
  • client_test.go (2 hunks)
  • query_result.go (3 hunks)
🧰 Additional context used
🪛 GitHub Actions: Go
client_test.go

[error] 315-317: TestGetTime failed due to panic: runtime error: invalid memory address or nil pointer dereference. Occurred in github.com/FalkorDB/falkordb-go.TestGetTime at client_test.go:317.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (go)
🔇 Additional comments (3)
query_result.go (2)

9-9: Good addition of time import for temporal data support.

The import is necessary for the new temporal data parsing functionality.


348-355: Critical: Confirm and adjust temporal data parsing (DATE, DATETIME, TIME)
The client currently assumes DATE and DATETIME are encoded as seconds since the Unix epoch and TIME as milliseconds since the epoch. There’s no evidence in the codebase or comments to back up these units or semantics. If TIME represents a time-of-day-only value (e.g., milliseconds since midnight), the existing conversion will yield an incorrect full‐date timestamp. Please verify the server’s encoding and update the conversions accordingly.

• File: query_result.go, lines 348–355

Suggested diff template:

 case VALUE_TIME:
-   return time.UnixMilli(v.(int64)), nil
+   // TODO: confirm TIME encoding (e.g., ms since midnight vs. epoch ms)
+   // If TIME is a time-of-day, convert v.(int64) into hours/minutes/seconds only:
+   //   ms := v.(int64)
+   //   h := ms / 3_600_000
+   //   m := (ms % 3_600_000) / 60_000
+   //   s := (ms % 60_000) / 1_000
+   //   ns := (ms % 1_000) * int64(time.Millisecond)
+   //   return time.Date(0, 1, 1, int(h), int(m), int(s), int(ns), time.UTC), nil
+   return time.UnixMilli(v.(int64)), nil
client_test.go (1)

6-6: Good addition of time import for temporal tests.

The import is necessary for the new temporal data type testing.

Comment thread query_result.go Outdated
Comment thread client_test.go
Comment thread client_test.go

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR extends query result handling by adding support for temporal data types (date, time, and datetime) and adds corresponding tests.

  • Added new constants and parsing logic in parseScalar for date, time, and datetime.
  • Introduced tests (TestGetTime, TestGetDate, TestGetDateTime) to verify correct handling of temporal values.

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
query_result.go Added VALUE_DATETIME, VALUE_DATE, VALUE_TIME constants and parsing cases for each type.
client_test.go Added tests to assert correct extraction of time, date, and datetime from query results.
Comments suppressed due to low confidence (2)

client_test.go:336

  • [nitpick] The alias as date is confusing in the datetime test. Consider using as datetime to clearly reflect the returned type.
	q := "RETURN localdatetime({year : 1984}) as date"

client_test.go:320

  • [nitpick] The TestGetTime only checks the hour component. Consider adding assertions for minutes, seconds, and timezone to fully validate the time.Time value.
	assert.Equal(t, timeValue.Hour(), 12, "Unexpected Time value")

Comment thread query_result.go Outdated
VALUE_MAP
VALUE_POINT
VALUE_VECTORF32
VALUE_DATETIME // Deprecated, use VALUE_POINT instead

Copilot AI Jul 9, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] The VALUE_DATETIME constant is marked deprecated but is still actively parsed. Consider removing it or updating the comment to reflect current usage or migration plan.

Suggested change
VALUE_DATETIME // Deprecated, use VALUE_POINT instead
VALUE_DATETIME // Deprecated: Retained for backward compatibility. Migrate to VALUE_POINT where possible.

Copilot uses AI. Check for mistakes.
Comment thread query_result.go
Comment on lines +349 to +355
return time.Unix(v.(int64), 0), nil

case VALUE_DATE:
return time.Unix(v.(int64), 0), nil

case VALUE_TIME:
return time.UnixMilli(v.(int64)), nil

Copilot AI Jul 9, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Directly asserting v.(int64) may panic if the stored value isn’t an int64. Use a safe type check (t, ok := v.(int64)) and return an error if the assertion fails.

Suggested change
return time.Unix(v.(int64), 0), nil
case VALUE_DATE:
return time.Unix(v.(int64), 0), nil
case VALUE_TIME:
return time.UnixMilli(v.(int64)), nil
timestamp, ok := v.(int64)
if !ok {
return nil, errors.New("expected int64 for VALUE_DATETIME")
}
return time.Unix(timestamp, 0), nil
case VALUE_DATE:
timestamp, ok := v.(int64)
if !ok {
return nil, errors.New("expected int64 for VALUE_DATE")
}
return time.Unix(timestamp, 0), nil
case VALUE_TIME:
timestamp, ok := v.(int64)
if !ok {
return nil, errors.New("expected int64 for VALUE_TIME")
}
return time.UnixMilli(timestamp), nil

Copilot uses AI. Check for mistakes.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (6)
.gitignore (1)

38-39: OK to add .history/; effectively redundant with top-level allowlist.

Given the leading "*" ignore and explicit allowlist, ".history/" and "Thumbs.db" are already ignored unless explicitly unignored elsewhere. Harmless to keep for clarity.

example_graph_test.go (5)

29-29: Prefer idiomatic Go name: ExampleFalkorDBNewTLS.

Minor style tweak to MixedCaps improves discoverability in docs.

-func ExampleFalkorDBNew_tls() {
+func ExampleFalkorDBNewTLS() {

7-7: Replace deprecated ioutil with os.ReadFile.

io/ioutil is deprecated; use os.ReadFile and drop the import.

-import (
-	"crypto/tls"
-	"crypto/x509"
-	"fmt"
-	"io/ioutil"
-	"log"
-	"os"
-	...
+import (
+	"crypto/tls"
+	"crypto/x509"
+	"fmt"
+	"log"
+	"os"
+	...
 )
@@
-	// Load CA cert
-	caCert, err := ioutil.ReadFile(tls_cacert)
+	// Load CA cert
+	caCert, err := os.ReadFile(tls_cacert)

Also applies to: 50-53


32-35: Fix typos in TLS comments.

-//     tls_cert - A a X.509 certificate to use for authenticating the  server to connected clients, masters or cluster peers. The file should be PEM formatted
-//     tls_key - A a X.509 private key to use for authenticating the  server to connected clients, masters or cluster peers. The file should be PEM formatted
-//	   tls_cacert - A PEM encoded CA's certificate file
+//     tls_cert   - An X.509 certificate to authenticate the server to connected clients, masters, or cluster peers. PEM formatted.
+//     tls_key    - An X.509 private key to authenticate the server to connected clients, masters, or cluster peers. PEM formatted.
+//     tls_cacert - A PEM-encoded CA certificate file.

38-41: Use negation instead of equality for booleans.

-	// Skip if we dont have all files to properly connect
-	if tlsready == false {
+	// Skip if we don't have all files to properly connect
+	if !tlsready {
 		return
 	}

62-69: Avoid endorsing insecure TLS by default. Gate InsecureSkipVerify behind an env flag.

Keeps the example safe-by-default while still allowing local testing.

-	// InsecureSkipVerify controls whether a client verifies the
-	// server's certificate chain and host name.
-	// If InsecureSkipVerify is true, TLS accepts any certificate
-	// presented by the server and any host name in that certificate.
-	// In this mode, TLS is susceptible to man-in-the-middle attacks.
-	// This should be used only for testing.
-	clientTLSConfig.InsecureSkipVerify = true
+	// Enable only for local testing if explicitly requested.
+	// WARNING: Susceptible to MITM; do not use in production.
+	if os.Getenv("FALKORDB_ALLOW_INSECURE") != "" {
+		clientTLSConfig.InsecureSkipVerify = true
+	}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d5d7598 and 0a000c3.

📒 Files selected for processing (2)
  • .gitignore (1 hunks)
  • example_graph_test.go (2 hunks)
🔇 Additional comments (1)
example_graph_test.go (1)

14-14: Rename to ExampleFalkorDB_SelectGraph looks good.

Example recognition by go test is preserved.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (2)
query_result.go (1)

349-361: Optional: guard type assertions to avoid panics.

Direct v.(int64) will panic on unexpected payloads. Switch to safe assertions with errors.

Example:

 case VALUE_DATETIME:
-    return time.Unix(v.(int64), 0).UTC(), nil
+    ts, ok := v.(int64)
+    if !ok { return nil, errors.New("expected int64 for VALUE_DATETIME") }
+    return time.Unix(ts, 0).UTC(), nil

Repeat for VALUE_DATE, VALUE_TIME, VALUE_DURATION.

client_test.go (1)

335-345: Harden TestGetDateTime: fix assert order and add safety checks.

Same issues as above.

 func TestGetDateTime(t *testing.T) {
   q := "RETURN localdatetime({year : 1984}) as date"
   res, err := graph.Query(q, nil, nil)
-  if err != nil {
-    t.Error(err)
-  }
-  res.Next()
-  r := res.Record()
-  dateTimeValue := r.GetByIndex(0).(time.Time)
-  assert.Equal(t, dateTimeValue.Year(), 1984, "Unexpected DateTime value")
+  if err != nil { t.Fatal(err) }
+  if res == nil { t.Fatal("Query result is nil") }
+  if !res.Next() { t.Fatal("empty result") }
+  r := res.Record()
+  val := r.GetByIndex(0)
+  dateTimeValue, ok := val.(time.Time)
+  if !ok { t.Fatalf("Expected time.Time, got %T", val) }
+  assert.Equal(t, 1984, dateTimeValue.Year(), "Unexpected DateTime value")
 }
🧹 Nitpick comments (1)
query_result.go (1)

52-56: Confirm wire protocol codes for new scalar types.

These rely on iota ordering. If server enum values differ, parsing will break. Consider pinning explicit values or add a compile-time comment with the server mapping.

Would you like a follow-up diff that assigns explicit numeric values to all VALUE_* constants to harden protocol compatibility?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0a000c3 and 7db0a62.

📒 Files selected for processing (2)
  • client_test.go (2 hunks)
  • query_result.go (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
client_test.go (1)
record.go (1)
  • Record (3-6)
🪛 GitHub Actions: Go
client_test.go

[error] 320-320: TestGetTime failed: Not equal: expected: 10, actual: 12. Unexpected Time value. Command: go test -v ./...

🔇 Additional comments (3)
query_result.go (2)

9-9: OK to import time.

Needed for new temporal parsing.


358-361: Duration unit check.

Code assumes server returns seconds. If server ever ships millis, this will be off by 1000x. Please confirm against FalkorDB PR #1126 and add a brief comment citing the server unit.

client_test.go (1)

6-6: OK to import time.

Required for new temporal/duration tests.

Comment thread client_test.go
Comment on lines +311 to +321
func TestGetTime(t *testing.T) {
q := "RETURN localtime({hour: 12}) AS time"
res, err := graph.Query(q, nil, nil)
if err != nil {
t.Error(err)
}
res.Next()
r := res.Record()
timeValue := r.GetByIndex(0).(time.Time)
assert.Equal(t, timeValue.Hour(), 12, "Unexpected Time value")
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Harden TestGetTime: fix assert arg order and add error/empty checks.

Current failure stems from reversed assert args and potential timezone drift. After normalizing to UTC in parser, update the test for robustness.

 func TestGetTime(t *testing.T) {
   q := "RETURN localtime({hour: 12}) AS time"
   res, err := graph.Query(q, nil, nil)
-  if err != nil {
-    t.Error(err)
-  }
-  res.Next()
-  r := res.Record()
-  timeValue := r.GetByIndex(0).(time.Time)
-  assert.Equal(t, timeValue.Hour(), 12, "Unexpected Time value")
+  if err != nil { t.Fatal(err) }
+  if res == nil { t.Fatal("Query result is nil") }
+  if !res.Next() { t.Fatal("empty result") }
+  r := res.Record()
+  val := r.GetByIndex(0)
+  timeValue, ok := val.(time.Time)
+  if !ok { t.Fatalf("Expected time.Time, got %T", val) }
+  assert.Equal(t, 12, timeValue.Hour(), "Unexpected Time value")
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
func TestGetTime(t *testing.T) {
q := "RETURN localtime({hour: 12}) AS time"
res, err := graph.Query(q, nil, nil)
if err != nil {
t.Error(err)
}
res.Next()
r := res.Record()
timeValue := r.GetByIndex(0).(time.Time)
assert.Equal(t, timeValue.Hour(), 12, "Unexpected Time value")
}
func TestGetTime(t *testing.T) {
q := "RETURN localtime({hour: 12}) AS time"
res, err := graph.Query(q, nil, nil)
if err != nil { t.Fatal(err) }
if res == nil { t.Fatal("Query result is nil") }
if !res.Next() { t.Fatal("empty result") }
r := res.Record()
val := r.GetByIndex(0)
timeValue, ok := val.(time.Time)
if !ok { t.Fatalf("Expected time.Time, got %T", val) }
assert.Equal(t, 12, timeValue.Hour(), "Unexpected Time value")
}
🧰 Tools
🪛 GitHub Actions: Go

[error] 320-320: TestGetTime failed: Not equal: expected: 10, actual: 12. Unexpected Time value. Command: go test -v ./...

🤖 Prompt for AI Agents
In client_test.go around lines 311 to 321, the TestGetTime has reversed assert
args and lacks checks for query errors/empty results and type assertion; update
the test to (1) fail immediately on err from graph.Query, (2) ensure res.Next()
returned true and fail the test if not, (3) retrieve the record and safely
type-assert the first field with an ok check, (4) convert the obtained time to
UTC before asserting the hour, and (5) call assert.Equal with expected value
first (12) and actual value second to fix argument order.

Comment thread client_test.go
Comment thread query_result.go
Comment on lines +349 to +357
case VALUE_DATETIME:
return time.Unix(v.(int64), 0), nil

case VALUE_DATE:
return time.Unix(v.(int64), 0), nil

case VALUE_TIME:
return time.UnixMilli(v.(int64)), nil

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix timezone drift: normalize temporal values to UTC.

Tests show hour mismatch for localtime; time.Unix/UnixMilli returns a Time in Local zone. Normalize to UTC to keep deterministic values across environments.

Apply:

 case VALUE_DATETIME:
-    return time.Unix(v.(int64), 0), nil
+    return time.Unix(v.(int64), 0).UTC(), nil

 case VALUE_DATE:
-    return time.Unix(v.(int64), 0), nil
+    return time.Unix(v.(int64), 0).UTC(), nil

 case VALUE_TIME:
-    return time.UnixMilli(v.(int64)), nil
+    return time.UnixMilli(v.(int64)).UTC(), nil
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
case VALUE_DATETIME:
return time.Unix(v.(int64), 0), nil
case VALUE_DATE:
return time.Unix(v.(int64), 0), nil
case VALUE_TIME:
return time.UnixMilli(v.(int64)), nil
case VALUE_DATETIME:
return time.Unix(v.(int64), 0).UTC(), nil
case VALUE_DATE:
return time.Unix(v.(int64), 0).UTC(), nil
case VALUE_TIME:
return time.UnixMilli(v.(int64)).UTC(), nil
🤖 Prompt for AI Agents
In query_result.go around lines 349 to 357, the temporal cases return time
values in the local zone causing timezone drift; update each return to normalize
to UTC by calling .UTC() on the constructed Time (e.g. time.Unix(v.(int64),
0).UTC(), and time.UnixMilli(v.(int64)).UTC()) so returned times are
deterministic across environments.

barakb
barakb previously approved these changes Sep 10, 2025
Comment thread query_result.go Outdated
@typo-app

typo-app Bot commented Jan 1, 2026

Copy link
Copy Markdown

Static Code Review 📊

✅ All quality checks passed!

@typo-app typo-app Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AI Code Review 🤖

Files Reviewed: 3
Comments Added: 2
Lines of Code Analyzed: 91
Critical Issues: 0

PR Health: Needs Attention

Give 👍 or 👎 on each review comment to help us improve.

Comment thread query_result.go
Comment on lines +350 to +362
case VALUE_DATETIME:
return time.Unix(v.(int64), 0), nil

case VALUE_DATE:
return time.Unix(v.(int64), 0), nil

case VALUE_TIME:
return time.UnixMilli(v.(int64)), nil

case VALUE_DURATION:
// FalkorDB returns duration values in seconds, convert to nanoseconds
return time.Duration(v.(int64)) * time.Second, nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Unsafe type assertion v.(int64) may panic on non-integer time values. Use a type switch to handle int64 and float64.

Suggested change
case VALUE_DATETIME:
return time.Unix(v.(int64), 0), nil
case VALUE_DATE:
return time.Unix(v.(int64), 0), nil
case VALUE_TIME:
return time.UnixMilli(v.(int64)), nil
case VALUE_DURATION:
// FalkorDB returns duration values in seconds, convert to nanoseconds
return time.Duration(v.(int64)) * time.Second, nil
case VALUE_DATETIME, VALUE_DATE:
var seconds float64
switch val := v.(type) {
case int64:
seconds = float64(val)
case float64:
seconds = val
default:
return nil, fmt.Errorf("unexpected type for DATETIME/DATE: %T", v)
}
sec := int64(seconds)
nsec := int64((seconds - float64(sec)) * 1e9)
return time.Unix(sec, nsec), nil
case VALUE_TIME:
ms, ok := v.(int64)
if !ok {
return nil, fmt.Errorf("unexpected type for TIME: %T", v)
}
return time.UnixMilli(ms), nil
case VALUE_DURATION:
// FalkorDB returns duration values in seconds, convert to nanoseconds
var seconds float64
switch val := v.(type) {
case int64:
seconds = float64(val)
case float64:
seconds = val
default:
return nil, fmt.Errorf("unexpected type for DURATION: %T", v)
}
return time.Duration(seconds * float64(time.Second)), nil

Comment thread client_test.go
Comment on lines +367 to +370
if err != nil {
t.Error(err)
}
timeValue := val.(time.Time)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Unsafe type assertion and improper error handling can cause a test panic. Use t.Fatal and a 'comma, ok' type assertion.

Suggested change
if err != nil {
t.Error(err)
}
timeValue := val.(time.Time)
if err != nil {
t.Fatal(err)
}
timeValue, ok := val.(time.Time)
if !ok {
t.Fatalf("Expected value to be of type time.Time, but got %T", val)
}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (4)
client_test.go (3)

395-409: Add safety checks for empty results and type assertions.

This test has the same issues as the previous temporal tests:

  1. Line 401: Check the return value of res.Next().
  2. Line 407: Use a safe type assertion.
🔎 Suggested improvements
 func TestGetDateTime(t *testing.T) {
 	q := "RETURN localdatetime({year : 1984}) as date"
 	res, err := graph.Query(q, nil, nil)
 	if err != nil {
 		t.Error(err)
+		return
 	}
-	res.Next()
+	if !res.Next() {
+		t.Fatal("expected at least one result")
+	}
 	r := res.Record()
 	val, err := r.GetByIndex(0)
 	if err != nil {
 		t.Error(err)
+		return
 	}
-	dateTimeValue := val.(time.Time)
+	dateTimeValue, ok := val.(time.Time)
+	if !ok {
+		t.Fatalf("expected time.Time, got %T", val)
+	}
 	assert.Equal(t, dateTimeValue.Year(), 1984, "Unexpected DateTime value")
 }

379-393: Add safety checks for empty results and type assertions.

Similar to TestGetTime, this test needs:

  1. Line 385: Check the return value of res.Next() to handle empty results.
  2. Line 391: Use a safe type assertion to prevent panics.
🔎 Suggested improvements
 func TestGetDate(t *testing.T) {
 	q := "RETURN date({year: 1984, month: 1, day: 1}) as date"
 	res, err := graph.Query(q, nil, nil)
 	if err != nil {
 		t.Error(err)
+		return
 	}
-	res.Next()
+	if !res.Next() {
+		t.Fatal("expected at least one result")
+	}
 	r := res.Record()
 	val, err := r.GetByIndex(0)
 	if err != nil {
 		t.Error(err)
+		return
 	}
-	dateValue := val.(time.Time)
+	dateValue, ok := val.(time.Time)
+	if !ok {
+		t.Fatalf("expected time.Time, got %T", val)
+	}
 	assert.Equal(t, dateValue.Year(), 1984, "Unexpected Date value")
 }

358-377: Add safety checks for empty results and type assertions.

The test lacks two important checks:

  1. Line 364: res.Next() is called without checking its return value. If the query returns no results, subsequent calls will operate on nil/invalid data.

  2. Line 370: The type assertion val.(time.Time) will panic if the value is not a time.Time.

🔎 Suggested improvements
 func TestGetTime(t *testing.T) {
 	q := "RETURN localtime({hour: 12}) AS time"
 	res, err := graph.Query(q, nil, nil)
 	if err != nil {
 		t.Error(err)
+		return
 	}
-	res.Next()
+	if !res.Next() {
+		t.Fatal("expected at least one result")
+	}
 	r := res.Record()
 	val, err := r.GetByIndex(0)
 	if err != nil {
 		t.Error(err)
+		return
 	}
-	timeValue := val.(time.Time)
+	timeValue, ok := val.(time.Time)
+	if !ok {
+		t.Fatalf("expected time.Time, got %T", val)
+	}
 
 	// Just verify we got a valid time.Time object
 	// Note: The actual time values may not match due to timezone/parsing issues
 	// This is a pre-existing issue in the TIME value parsing
 	assert.IsType(t, time.Time{}, timeValue, "Should return a time.Time object")
 	assert.False(t, timeValue.IsZero(), "Time should not be zero value")
 }
query_result.go (1)

350-361: Fix unsafe type assertions and normalize to UTC.

The temporal parsing cases have two issues:

  1. Unsafe type assertions: Direct assertions v.(int64) will panic if the server returns a different type (e.g., float64). Use safe type checking instead.

  2. Timezone drift: time.Unix() and time.UnixMilli() return times in the local timezone, causing non-deterministic values across environments. Normalize to UTC for consistency.

🔎 Proposed fixes
 case VALUE_DATETIME:
-	return time.Unix(v.(int64), 0), nil
+	timestamp, ok := v.(int64)
+	if !ok {
+		return nil, fmt.Errorf("expected int64 for VALUE_DATETIME, got %T", v)
+	}
+	return time.Unix(timestamp, 0).UTC(), nil

 case VALUE_DATE:
-	return time.Unix(v.(int64), 0), nil
+	timestamp, ok := v.(int64)
+	if !ok {
+		return nil, fmt.Errorf("expected int64 for VALUE_DATE, got %T", v)
+	}
+	return time.Unix(timestamp, 0).UTC(), nil

 case VALUE_TIME:
-	return time.UnixMilli(v.(int64)), nil
+	timestamp, ok := v.(int64)
+	if !ok {
+		return nil, fmt.Errorf("expected int64 for VALUE_TIME, got %T", v)
+	}
+	return time.UnixMilli(timestamp).UTC(), nil

 case VALUE_DURATION:
 	// FalkorDB returns duration values in seconds, convert to nanoseconds
-	return time.Duration(v.(int64)) * time.Second, nil
+	seconds, ok := v.(int64)
+	if !ok {
+		return nil, fmt.Errorf("expected int64 for VALUE_DURATION, got %T", v)
+	}
+	return time.Duration(seconds) * time.Second, nil
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8d39a9c and 649290c.

📒 Files selected for processing (2)
  • client_test.go
  • query_result.go
🧰 Additional context used
🧬 Code graph analysis (1)
client_test.go (1)
record.go (1)
  • Record (5-8)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Analyze (go)
🔇 Additional comments (1)
query_result.go (1)

9-9: LGTM!

The time import is necessary for the new temporal type support.

Comment thread client_test.go
Comment on lines +411 to +426
func TestGetDuration(t *testing.T) {
q := "RETURN duration({hours: 2, minutes: 30}) AS duration"
res, err := graph.Query(q, nil, nil)
if err != nil {
t.Error(err)
}
res.Next()
r := res.Record()
val, err := r.GetByIndex(0)
if err != nil {
t.Error(err)
}
durationValue := val.(time.Duration)
expectedDuration := 2*time.Hour + 30*time.Minute
assert.Equal(t, durationValue, expectedDuration, "Unexpected Duration value")
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add safety checks for empty results and type assertions.

This test needs the same improvements as the temporal tests:

  1. Line 417: Check the return value of res.Next().
  2. Line 423: Use a safe type assertion for time.Duration.
🔎 Suggested improvements
 func TestGetDuration(t *testing.T) {
 	q := "RETURN duration({hours: 2, minutes: 30}) AS duration"
 	res, err := graph.Query(q, nil, nil)
 	if err != nil {
 		t.Error(err)
+		return
 	}
-	res.Next()
+	if !res.Next() {
+		t.Fatal("expected at least one result")
+	}
 	r := res.Record()
 	val, err := r.GetByIndex(0)
 	if err != nil {
 		t.Error(err)
+		return
 	}
-	durationValue := val.(time.Duration)
+	durationValue, ok := val.(time.Duration)
+	if !ok {
+		t.Fatalf("expected time.Duration, got %T", val)
+	}
 	expectedDuration := 2*time.Hour + 30*time.Minute
 	assert.Equal(t, durationValue, expectedDuration, "Unexpected Duration value")
 }
🤖 Prompt for AI Agents
In client_test.go around lines 411-426, the test lacks safety checks: verify the
boolean result of res.Next() and fail the test if it returns false, and replace
the direct type assertion for time.Duration with a safe comma-ok assertion (fail
the test with a clear message if the type is not time.Duration); ensure you
still handle errors from r.GetByIndex as you already do.

@MuhammadQadora
MuhammadQadora requested a review from barakb January 1, 2026 13:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for Date time and DateTime in the go client

3 participants