Skip to content

Conversation

ArnabChatterjee20k
Copy link
Contributor

@ArnabChatterjee20k ArnabChatterjee20k commented Sep 1, 2025

What does this PR do?

(Provide a description of what this PR does.)

Test Plan

(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work.)

Related PRs and Issues

(If this PR is related to any other PR or resolves any issue or related to any issue link all related PR and issues here.)

Have you read the Contributing Guidelines on issues?

(Write your answer here.)

Summary by CodeRabbit

  • New Features

    • Added distance-based filters (distanceEqual, distanceNotEqual, distanceGreaterThan, distanceLessThan) with an optional meters flag (default true in most SDKs).
    • Added spatial relationship filters (intersects, notIntersects, crosses, notCrosses, overlaps, notOverlaps, touches, notTouches) across SDKs.
    • Swift: improved support for nested array values in query payloads.
  • Tests

    • Expanded test coverage across all language SDKs to exercise the new spatial distance and relation query helpers.

Copy link

coderabbitai bot commented Sep 1, 2025

Walkthrough

Adds 12 query-builder methods across SDK templates: four distance-based methods (distanceEqual, distanceNotEqual, distanceGreaterThan, distanceLessThan) accepting attribute, values, distance and an optional meters flag (values encoded as [values, distance, meters]); and eight spatial-predicate methods (intersects, notIntersects, crosses, notCrosses, overlaps, notOverlaps, touches, notTouches) accepting attribute and values. Implementations were added to Android, Dart (identical block duplicated in file), Deno, .NET, Go, Kotlin, PHP, Python, React Native, Ruby, Swift (also adds QueryValue.array and nested-array conversion), and Web. Tests expanded across all language test suites.


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c55bb73 and f8cdda6.

📒 Files selected for processing (1)
  • tests/languages/go/tests.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/languages/go/tests.go
⏰ 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). (3)
  • GitHub Check: build (8.3, AppleSwift56)
  • GitHub Check: build (8.3, Swift56)
  • GitHub Check: build (8.3, Android14Java17)
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch spatial-type-queries

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (6)
templates/web/src/query.ts.twig (3)

350-357: Add minimal validation for distance inputs.

Guard against negative or non-finite distances to fail fast.

   static distanceEqual = (attribute: string, values: GeometryValues, distance: number): string =>
-    new Query("distanceEqual", attribute, [values, distance]).toString();
+    (Number.isFinite(distance) && distance >= 0)
+      ? new Query("distanceEqual", attribute, [values, distance]).toString()
+      : (() => { throw new Error("distance must be a non-negative finite number"); })();

(Repeat for the other distance methods.)


401-472: Tighten geometry param typing for spatial predicates.

Prefer a named alias over any[] for clarity and to keep parity with distance methods.

-  static intersects = (attribute: string, values: any[]): string =>
+  static intersects = (attribute: string, values: GeometryValues): string =>
     new Query("intersects", attribute, values).toString();

-  static notIntersects = (attribute: string, values: any[]): string =>
+  static notIntersects = (attribute: string, values: GeometryValues): string =>
     new Query("notIntersects", attribute, values).toString();

-  static crosses = (attribute: string, values: any[]): string =>
+  static crosses = (attribute: string, values: GeometryValues): string =>
     new Query("crosses", attribute, values).toString();

-  static notCrosses = (attribute: string, values: any[]): string =>
+  static notCrosses = (attribute: string, values: GeometryValues): string =>
     new Query("notCrosses", attribute, values).toString();

-  static overlaps = (attribute: string, values: any[]): string =>
+  static overlaps = (attribute: string, values: GeometryValues): string =>
     new Query("overlaps", attribute, values).toString();

-  static notOverlaps = (attribute: string, values: any[]): string =>
+  static notOverlaps = (attribute: string, values: GeometryValues): string =>
     new Query("notOverlaps", attribute, values).toString();

-  static touches = (attribute: string, values: any[]): string =>
+  static touches = (attribute: string, values: GeometryValues): string =>
     new Query("touches", attribute, values).toString();

-  static notTouches = (attribute: string, values: any[]): string =>
+  static notTouches = (attribute: string, values: GeometryValues): string =>
     new Query("notTouches", attribute, values).toString();

351-356: Clarify JSDoc: specify value format and units.

State expected coordinate/geometry format (e.g., [lon, lat] in WGS84 or GeoJSON) and distance units (meters? kilometers?), plus geodesic vs planar behavior.

templates/react-native/src/query.ts.twig (3)

211-214: Fix JSDoc param type mismatch (values).

Doc says @param {number[]} values but the signature uses any[]. Align the doc to avoid misleading users.

-   * @param {number[]} values
+   * @param {any[]} values

248-319: Use GeometryValues alias for spatial predicates.

Keep consistency with distance methods and improve readability.

-  static intersects = (attribute: string, values: any[]): string =>
+  static intersects = (attribute: string, values: GeometryValues): string =>
     new Query("intersects", attribute, values).toString();

-  static notIntersects = (attribute: string, values: any[]): string =>
+  static notIntersects = (attribute: string, values: GeometryValues): string =>
     new Query("notIntersects", attribute, values).toString();

-  static crosses = (attribute: string, values: any[]): string =>
+  static crosses = (attribute: string, values: GeometryValues): string =>
     new Query("crosses", attribute, values).toString();

-  static notCrosses = (attribute: string, values: any[]): string =>
+  static notCrosses = (attribute: string, values: GeometryValues): string =>
     new Query("notCrosses", attribute, values).toString();

-  static overlaps = (attribute: string, values: any[]): string =>
+  static overlaps = (attribute: string, values: GeometryValues): string =>
     new Query("overlaps", attribute, values).toString();

-  static notOverlaps = (attribute: string, values: any[]): string =>
+  static notOverlaps = (attribute: string, values: GeometryValues): string =>
     new Query("notOverlaps", attribute, values).toString();

-  static touches = (attribute: string, values: any[]): string =>
+  static touches = (attribute: string, values: GeometryValues): string =>
     new Query("touches", attribute, values).toString();

-  static notTouches = (attribute: string, values: any[]): string =>
+  static notTouches = (attribute: string, values: GeometryValues): string =>
     new Query("notTouches", attribute, values).toString();

197-239: Optional: validate distance inputs.

Same guard as proposed for web template.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3ad8053 and 1345677.

📒 Files selected for processing (12)
  • templates/android/library/src/main/java/io/package/Query.kt.twig (1 hunks)
  • templates/dart/lib/query.dart.twig (1 hunks)
  • templates/deno/src/query.ts.twig (1 hunks)
  • templates/dotnet/Package/Query.cs.twig (1 hunks)
  • templates/go/query.go.twig (1 hunks)
  • templates/kotlin/src/main/kotlin/io/appwrite/Query.kt.twig (1 hunks)
  • templates/php/src/Query.php.twig (1 hunks)
  • templates/python/package/query.py.twig (1 hunks)
  • templates/react-native/src/query.ts.twig (1 hunks)
  • templates/ruby/lib/container/query.rb.twig (1 hunks)
  • templates/swift/Sources/Query.swift.twig (1 hunks)
  • templates/web/src/query.ts.twig (1 hunks)
⏰ 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). (19)
  • GitHub Check: build (8.3, Python311)
  • GitHub Check: build (8.3, Deno1303)
  • GitHub Check: build (8.3, WebChromium)
  • GitHub Check: build (8.3, Ruby27)
  • GitHub Check: build (8.3, Swift56)
  • GitHub Check: build (8.3, AppleSwift56)
  • GitHub Check: build (8.3, Python310)
  • GitHub Check: build (8.3, PHP83)
  • GitHub Check: build (8.3, Python312)
  • GitHub Check: build (8.3, PHP80)
  • GitHub Check: build (8.3, Node18)
  • GitHub Check: build (8.3, KotlinJava8)
  • GitHub Check: build (8.3, KotlinJava17)
  • GitHub Check: build (8.3, KotlinJava11)
  • GitHub Check: build (8.3, FlutterStable)
  • GitHub Check: build (8.3, FlutterBeta)
  • GitHub Check: build (8.3, DotNet60)
  • GitHub Check: build (8.3, Android5Java17)
  • GitHub Check: build (8.3, Android14Java17)
🔇 Additional comments (13)
templates/python/package/query.py.twig (1)

146-192: LGTM: Python spatial/distance query helpers match existing patterns and payload shapes.
Consistent snake_case API and correct [values, distance] packaging.

templates/ruby/lib/container/query.rb.twig (1)

155-201: LGTM: Ruby DSL adds spatial/distance methods with correct serialization and parity.
Constructor args and [values, distance] structure look good.

templates/kotlin/src/main/kotlin/io/appwrite/Query.kt.twig (1)

76-98: LGTM: Kotlin additions mirror existing factories and preserve JSON shape.
Use of Number for distance and listOf(values, distance) is appropriate.

templates/dotnet/Package/Query.cs.twig (1)

205-263: LGTM: .NET methods correctly emit nested payload [values, distance].
Signatures and ToString() usage are consistent with the rest of the class.

templates/php/src/Query.php.twig (2)

456-549: Spatial predicates block looks good.

Signatures, docs, and serialization mirror existing patterns. No issues from a PHP standpoint.


411-414: The script above will accurately detect the extra nesting in the PHP template and confirm whether dotnet and Swift templates have the same issue. Once we have those results, we can finalize the diff to remove the double brackets and ensure consistency across all SDKs.

templates/swift/Sources/Query.swift.twig (1)

433-495: Spatial/distance API looks good; depends on serializer fix above.

Signatures and payload shapes align with other SDKs. After adding array support to QueryValue, these builders should serialize correctly.

You can spot-check with a playground by calling distanceEqual("loc", values: [[10.0, 20.0]], distance: 1000) and ensuring "values":[[[10.0,20.0]],1000] appears in description.

templates/android/library/src/main/java/io/package/Query.kt.twig (1)

289-399: LGTM on new spatial/distance builders.

Signatures, docs, and payload shapes match the cross-language pattern. No issues found.

templates/go/query.go.twig (1)

321-415: LGTM on Go helpers.

Functions produce the expected nested payload ([]interface{}{values, distance}) and mirror existing parseQuery usage. No issues found.

templates/dart/lib/query.dart.twig (1)

170-216: LGTM on Dart additions.

APIs and payload shapes align with other SDKs; jsonEncode will handle nested lists correctly.

templates/web/src/query.ts.twig (1)

349-473: API surface LGTM overall.

Additions are consistent with existing Query API and serialization approach.

templates/react-native/src/query.ts.twig (2)

196-319: API surface LGTM overall.

Additions match the existing pattern and serialization contract.


196-319: Spatial filter methods parity verified
All 12 spatial‐filter methods are present in every SDK template and the React Native docs consistently use any[] (no stray number[]).

Copy link
Member

@abnegate abnegate left a comment

Choose a reason for hiding this comment

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

Looks good, let's update the tests too

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
templates/go/query.go.twig (1)

251-255: Syntax error: extra closing brace in OrderDesc

There’s an extra “}” after parseQuery, which will fail to compile.

-  return parseQuery(queryOptions{
-    Method:    "orderDesc",
-    Attribute: &attribute,
-  })}
+  return parseQuery(queryOptions{
+    Method:    "orderDesc",
+    Attribute: &attribute,
+  })
♻️ Duplicate comments (2)
templates/deno/src/query.ts.twig (1)

200-246: Remove unsafe casts: widen types to model distance payloads

The new helpers cast [[values, distance, meters]] to QueryTypesList, which doesn’t cover that shape. Define a tuple type and update Query.values to accept it; then drop the casts.

Apply these diffs:

  1. Types and class field/signature:
-type QueryTypesSingle = string | number | boolean;
-export type QueryTypesList = string[] | number[] | boolean[] | Query[];
-export type QueryTypes = QueryTypesSingle | QueryTypesList;
+type QueryTypesSingle = string | number | boolean;
+export type QueryTypesList = string[] | number[] | boolean[] | Query[];
+export type QueryTypes = QueryTypesSingle | QueryTypesList;
+// New: support distance payloads [[values, distance, meters]]
+export type DistancePayload = [any[], number, boolean];
+export type QueryValues = QueryTypesList | DistancePayload[];
@@
 export class Query {
   method: string;
   attribute: AttributesTypes | undefined;
-  values: QueryTypesList | undefined;
+  values: QueryValues | undefined;
@@
-  constructor(
+  constructor(
     method: string,
     attribute?: AttributesTypes,
-    values?: QueryTypes
+    values?: QueryTypes | DistancePayload[]
   ) {
@@
-        this.values = [values] as QueryTypesList;
+        this.values = [values] as QueryValues;
  1. Drop casts in distance helpers:
-  static distanceEqual = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceEqual", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceEqual = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
+    new Query("distanceEqual", attribute, [[values, distance, meters]]).toString();
@@
-  static distanceNotEqual = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceNotEqual", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceNotEqual = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
+    new Query("distanceNotEqual", attribute, [[values, distance, meters]]).toString();
@@
-  static distanceGreaterThan = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceGreaterThan", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceGreaterThan = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
+    new Query("distanceGreaterThan", attribute, [[values, distance, meters]]).toString();
@@
-  static distanceLessThan = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceLessThan", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceLessThan = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
+    new Query("distanceLessThan", attribute, [[values, distance, meters]]).toString();
templates/swift/Sources/Query.swift.twig (1)

401-431: Swift: values for distance methods will be dropped at serialization. Add array support to QueryValue.

values: [[values, distance, meters]] is a nested heterogeneous array, but QueryValue cannot encode arrays, so values becomes nil and is omitted.

Apply the following changes outside this block to support arrays and recursive conversion:

@@
 enum QueryValue: Codable {
-    case string(String)
-    case int(Int)
-    case double(Double)
-    case bool(Bool)
-    case query(Query)
+    case string(String)
+    case int(Int)
+    case double(Double)
+    case bool(Bool)
+    case query(Query)
+    case array([QueryValue])
@@
     init(from decoder: Decoder) throws {
         let container = try decoder.singleValueContainer()
         // Attempt to decode each type
         if let stringValue = try? container.decode(String.self) {
             self = .string(stringValue)
         } else if let intValue = try? container.decode(Int.self) {
             self = .int(intValue)
         } else if let doubleValue = try? container.decode(Double.self) {
             self = .double(doubleValue)
         } else if let boolValue = try? container.decode(Bool.self) {
             self = .bool(boolValue)
         } else if let queryValue = try? container.decode(Query.self) {
             self = .query(queryValue)
+        } else if let arrayValue = try? container.decode([QueryValue].self) {
+            self = .array(arrayValue)
         } else {
             throw DecodingError.dataCorruptedError(in: container, debugDescription: "QueryValue cannot be decoded")
         }
     }
@@
     func encode(to encoder: Encoder) throws {
         var container = encoder.singleValueContainer()
         switch self {
         case .string(let value):
             try container.encode(value)
         case .int(let value):
             try container.encode(value)
         case .double(let value):
             try container.encode(value)
         case .bool(let value):
             try container.encode(value)
         case .query(let value):
             try container.encode(value)
+        case .array(let value):
+            try container.encode(value)
         }
     }
@@
-    private static func convertToQueryValueArray(_ values: Any?) -> [QueryValue]? {
+    private static func convertToQueryValueArray(_ values: Any?) -> [QueryValue]? {
         switch values {
         case let valueArray as [QueryValue]:
             return valueArray
         case let stringArray as [String]:
             return stringArray.map { .string($0) }
         case let intArray as [Int]:
             return intArray.map { .int($0) }
         case let doubleArray as [Double]:
             return doubleArray.map { .double($0) }
         case let boolArray as [Bool]:
             return boolArray.map { .bool($0) }
         case let queryArray as [Query]:
             return queryArray.map { .query($0) }
+        case let anyArray as [Any]:
+            return anyArray.compactMap { convertAnyToQueryValue($0) }
         case let stringValue as String:
             return [.string(stringValue)]
         case let intValue as Int:
             return [.int(intValue)]
         case let doubleValue as Double:
             return [.double(doubleValue)]
         case let boolValue as Bool:
             return [.bool(boolValue)]
         case let queryValue as Query:
             return [.query(queryValue)]
         default:
             return nil
         }
     }
+
+    private static func convertAnyToQueryValue(_ value: Any) -> QueryValue? {
+        switch value {
+        case let v as String: return .string(v)
+        case let v as Int:    return .int(v)
+        case let v as Double: return .double(v)
+        case let v as Bool:   return .bool(v)
+        case let v as Query:  return .query(v)
+        case let v as [Any]:
+            let mapped = v.compactMap { convertAnyToQueryValue($0) }
+            return .array(mapped)
+        default:
+            return nil
+        }
+    }

This also fixes the geometry helpers below.

🧹 Nitpick comments (12)
templates/go/query.go.twig (2)

321-351: DRY the four distance helpers via a shared builder

Each function repeats the same payload construction. Introduce a small helper and call it for consistency and easier maintenance.

Apply within this range:

-func DistanceEqual(attribute string, values []interface{}, distance float64, meters bool) string {
-	return parseQuery(queryOptions{
-		Method:    "distanceEqual",
-		Attribute: &attribute,
-		Values:    &[]interface{}{[]interface{}{values, distance, meters}},
-	})
-}
+func DistanceEqual(attribute string, values []interface{}, distance float64, meters bool) string {
+	return distanceQuery("distanceEqual", attribute, values, distance, meters)
+}
 
-func DistanceNotEqual(attribute string, values []interface{}, distance float64, meters bool) string {
-	return parseQuery(queryOptions{
-		Method:    "distanceNotEqual",
-		Attribute: &attribute,
-		Values:    &[]interface{}{[]interface{}{values, distance, meters}},
-	})
-}
+func DistanceNotEqual(attribute string, values []interface{}, distance float64, meters bool) string {
+	return distanceQuery("distanceNotEqual", attribute, values, distance, meters)
+}
 
-func DistanceGreaterThan(attribute string, values []interface{}, distance float64, meters bool) string {
-	return parseQuery(queryOptions{
-		Method:    "distanceGreaterThan",
-		Attribute: &attribute,
-		Values:    &[]interface{}{[]interface{}{values, distance, meters}},
-	})
-}
+func DistanceGreaterThan(attribute string, values []interface{}, distance float64, meters bool) string {
+	return distanceQuery("distanceGreaterThan", attribute, values, distance, meters)
+}
 
-func DistanceLessThan(attribute string, values []interface{}, distance float64, meters bool) string {
-	return parseQuery(queryOptions{
-		Method:    "distanceLessThan",
-		Attribute: &attribute,
-		Values:    &[]interface{}{[]interface{}{values, distance, meters}},
-	})
-}
+func DistanceLessThan(attribute string, values []interface{}, distance float64, meters bool) string {
+	return distanceQuery("distanceLessThan", attribute, values, distance, meters)
+}

Add this helper (outside the changed hunk):

func distanceQuery(method, attribute string, values []interface{}, distance float64, meters bool) string {
	return parseQuery(queryOptions{
		Method:    method,
		Attribute: &attribute,
		Values:    &[]interface{}{[]interface{}{values, distance, meters}},
	})
}

353-414: Factor the 8 spatial helpers through a single builder

These methods are identical aside from the method string. Reduce duplication with a tiny helper.

Within this range:

-func Intersects(attribute string, values []interface{}) string {
-	return parseQuery(queryOptions{
-		Method:    "intersects",
-		Attribute: &attribute,
-		Values:    &values,
-	})
-}
+func Intersects(attribute string, values []interface{}) string {
+	return spatialQuery("intersects", attribute, values)
+}
@@
-func NotTouches(attribute string, values []interface{}) string {
-	return parseQuery(queryOptions{
-		Method:    "notTouches",
-		Attribute: &attribute,
-		Values:    &values,
-	})
-}
+func NotTouches(attribute string, values []interface{}) string {
+	return spatialQuery("notTouches", attribute, values)
+}

Add once (outside the changed hunk):

func spatialQuery(method, attribute string, values []interface{}) string {
	return parseQuery(queryOptions{
		Method:    method,
		Attribute: &attribute,
		Values:    &values,
	})
}
templates/ruby/lib/container/query.rb.twig (2)

155-169: Deduplicate distance_ with a private helper*

All four methods differ only by the method string. Use a single builder to reduce repetition and risk of divergence.

Within this range:

-def distance_equal(attribute, values, distance, meters = false)
-    return Query.new("distanceEqual", attribute, [[values, distance, meters]]).to_s
-end
+def distance_equal(attribute, values, distance, meters = false)
+    return distance_query("distanceEqual", attribute, values, distance, meters)
+end
@@
-def distance_not_equal(attribute, values, distance, meters = false)
-    return Query.new("distanceNotEqual", attribute, [[values, distance, meters]]).to_s
-end
+def distance_not_equal(attribute, values, distance, meters = false)
+    return distance_query("distanceNotEqual", attribute, values, distance, meters)
+end
@@
-def distance_greater_than(attribute, values, distance, meters = false)
-    return Query.new("distanceGreaterThan", attribute, [[values, distance, meters]]).to_s
-end
+def distance_greater_than(attribute, values, distance, meters = false)
+    return distance_query("distanceGreaterThan", attribute, values, distance, meters)
+end
@@
-def distance_less_than(attribute, values, distance, meters = false)
-    return Query.new("distanceLessThan", attribute, [[values, distance, meters]]).to_s
-end
+def distance_less_than(attribute, values, distance, meters = false)
+    return distance_query("distanceLessThan", attribute, values, distance, meters)
+end

Add once in this class’ singleton scope:

private
def distance_query(method, attribute, values, distance, meters)
  Query.new(method, attribute, [[values, distance, meters]]).to_s
end

171-201: Optional: add brief YARD docs for new methods

Short comments for parameters (attribute, values, distance, meters) would align with surrounding public API docs and ease SDK consumers’ usage.

templates/dart/lib/query.dart.twig (1)

170-185: Add lightweight input guards for distance helpers

Guarding obvious invalid inputs (negative/NaN distance, empty coordinates) improves DX without runtime cost in release (asserts stripped).

-static String distanceEqual(String attribute, List<dynamic> values, double distance, [bool meters = false]) =>
-    Query._('distanceEqual', attribute, [[values, distance, meters]]).toString();
+static String distanceEqual(String attribute, List<dynamic> values, double distance, [bool meters = false]) {
+  assert(values.isNotEmpty, 'values must not be empty');
+  assert(distance.isFinite && distance >= 0, 'distance must be a non-negative finite number');
+  return Query._('distanceEqual', attribute, [[values, distance, meters]]).toString();
+}

Replicate the same pattern for the other three distance methods in this hunk.

templates/kotlin/src/main/kotlin/io/appwrite/Query.kt.twig (2)

76-118: Fix KDoc tag: use @return (not @returns)

KDoc recognizes @return; current @returns won’t render properly.

- * @returns The query string.
+ * @return The query string.

Apply to all four distance KDoc blocks in this hunk.


120-134: Optional: share distance builder to avoid duplication

A tiny helper keeps method bodies uniform.

Example:

private fun distanceQuery(method: String, attribute: String, values: List<Any>, distance: Number, meters: Boolean) =
    Query(method, attribute, listOf(listOf(values, distance, meters))).toJson()

// Usage:
fun distanceEqual(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) =
    distanceQuery("distanceEqual", attribute, values, distance, meters)
templates/deno/src/query.ts.twig (1)

1-5: Optional: tighten attribute/values docs

Consider documenting the expected geometry format (e.g., [lng, lat], GeoJSON arrays) to reduce ambiguity for SDK users.

templates/android/library/src/main/java/io/package/Query.kt.twig (2)

289-331: Confirm serializer supports nested heterogeneous arrays for distance queries.

values is serialized as [[values, distance, meters]] (List containing a nested List with mixed types). If toJson isn’t robust to nested mixed arrays, payload may drop or mis-encode. Add a unit test for one happy-path example and verify equivalence with server expectations.

Example quick check to add to tests (pseudocode):

  • distanceEqual("geo", listOf(1.0, 2.0), 1000, true) should JSON-encode values as [[[1.0,2.0],1000,true]]

333-404: Tighten docs and consider a geometry alias for clarity.

The spatial methods accept values: List<Any>, which is flexible but opaque. Consider typealias Geometry = List<Any> and clarify accepted shapes (e.g., [lon, lat], LineString, Polygon rings) in KDoc to reduce misuse.

- * @param values The coordinate values.
+ * @param values Geometry coordinates (e.g., [lon, lat] or GeoJSON-like arrays).
templates/react-native/src/query.ts.twig (2)

196-244: Type-safety: replace any[] and casts; model distance args explicitly.

Drop as QueryTypesList and define Geometry/Distance tuple types so nested arrays are typed and safe.

Apply within this block:

-  static distanceEqual = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceEqual", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceEqual = (attribute: string, values: GeometryValues, distance: number, meters: boolean = false): string =>
+    new Query("distanceEqual", attribute, [[values, distance, meters]]).toString();

-  static distanceNotEqual = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceNotEqual", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceNotEqual = (attribute: string, values: GeometryValues, distance: number, meters: boolean = false): string =>
+    new Query("distanceNotEqual", attribute, [[values, distance, meters]]).toString();

-  static distanceGreaterThan = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceGreaterThan", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceGreaterThan = (attribute: string, values: GeometryValues, distance: number, meters: boolean = false): string =>
+    new Query("distanceGreaterThan", attribute, [[values, distance, meters]]).toString();

-  static distanceLessThan = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceLessThan", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceLessThan = (attribute: string, values: GeometryValues, distance: number, meters: boolean = false): string =>
+    new Query("distanceLessThan", attribute, [[values, distance, meters]]).toString();

And at the top (types):

 type QueryTypesSingle = string | number | boolean;
-export type QueryTypesList = string[] | number[] | boolean[] | Query[];
+export type GeometryValues = unknown[];                 // e.g., [lon, lat] or nested coords
+export type DistanceArgs = [GeometryValues, number, boolean?];
+export type QueryTypesList =
+  | string[]
+  | number[]
+  | boolean[]
+  | Query[]
+  | GeometryValues
+  | DistanceArgs[];
 export type QueryTypes = QueryTypesSingle | QueryTypesList;

245-324: Also type geometry relations methods (avoid any[]).

Mirror the GeometryValues type to these methods.

-  static intersects = (attribute: string, values: any[]): string =>
+  static intersects = (attribute: string, values: GeometryValues): string =>
     new Query("intersects", attribute, values).toString();
-  static notIntersects = (attribute: string, values: any[]): string =>
+  static notIntersects = (attribute: string, values: GeometryValues): string =>
     new Query("notIntersects", attribute, values).toString();
-  static crosses = (attribute: string, values: any[]): string =>
+  static crosses = (attribute: string, values: GeometryValues): string =>
     new Query("crosses", attribute, values).toString();
-  static notCrosses = (attribute: string, values: any[]): string =>
+  static notCrosses = (attribute: string, values: GeometryValues): string =>
     new Query("notCrosses", attribute, values).toString();
-  static overlaps = (attribute: string, values: any[]): string =>
+  static overlaps = (attribute: string, values: GeometryValues): string =>
     new Query("overlaps", attribute, values).toString();
-  static notOverlaps = (attribute: string, values: any[]): string =>
+  static notOverlaps = (attribute: string, values: GeometryValues): string =>
     new Query("notOverlaps", attribute, values).toString();
-  static touches = (attribute: string, values: any[]): string =>
+  static touches = (attribute: string, values: GeometryValues): string =>
     new Query("touches", attribute, values).toString();
-  static notTouches = (attribute: string, values: any[]): string =>
+  static notTouches = (attribute: string, values: GeometryValues): string =>
     new Query("notTouches", attribute, values).toString();
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1345677 and d5b7173.

📒 Files selected for processing (12)
  • templates/android/library/src/main/java/io/package/Query.kt.twig (1 hunks)
  • templates/dart/lib/query.dart.twig (1 hunks)
  • templates/deno/src/query.ts.twig (1 hunks)
  • templates/dotnet/Package/Query.cs.twig (1 hunks)
  • templates/go/query.go.twig (1 hunks)
  • templates/kotlin/src/main/kotlin/io/appwrite/Query.kt.twig (1 hunks)
  • templates/php/src/Query.php.twig (1 hunks)
  • templates/python/package/query.py.twig (1 hunks)
  • templates/react-native/src/query.ts.twig (1 hunks)
  • templates/ruby/lib/container/query.rb.twig (1 hunks)
  • templates/swift/Sources/Query.swift.twig (1 hunks)
  • templates/web/src/query.ts.twig (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • templates/python/package/query.py.twig
  • templates/php/src/Query.php.twig
  • templates/dotnet/Package/Query.cs.twig
  • templates/web/src/query.ts.twig
🔇 Additional comments (3)
templates/dart/lib/query.dart.twig (1)

186-216: LGTM on spatial helpers

Signatures and payload shape match existing conventions.

templates/deno/src/query.ts.twig (1)

248-326: LGTM on spatial helpers

Signatures and serialization align with existing conventions.

templates/swift/Sources/Query.swift.twig (1)

433-495: Geometry helpers depend on the array support fix above.

Without the QueryValue.array/recursive conversion, [Any] payloads here will also be lost. Re-test after applying the encoder changes.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (4)
templates/deno/src/query.ts.twig (1)

209-246: Remove unsafe casts and widen types for distance payloads

Current casts to QueryTypesList are unsound; model the payload explicitly and drop the casts.

-  static distanceEqual = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceEqual", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceEqual = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
+    new Query("distanceEqual", attribute, [[values, distance, meters]]).toString();

-  static distanceNotEqual = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceNotEqual", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceNotEqual = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
+    new Query("distanceNotEqual", attribute, [[values, distance, meters]]).toString();

-  static distanceGreaterThan = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceGreaterThan", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceGreaterThan = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
+    new Query("distanceGreaterThan", attribute, [[values, distance, meters]]).toString();

-  static distanceLessThan = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceLessThan", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceLessThan = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
+    new Query("distanceLessThan", attribute, [[values, distance, meters]]).toString();

Additions required outside this hunk (type support for the new payload):

// At top-level types:
export type DistancePayload = [any[], number, boolean];
export type QueryValues = QueryTypesList | DistancePayload[];

// In class:
values: QueryValues | undefined;

constructor(method: string, attribute?: AttributesTypes, values?: QueryValues) { /* rest unchanged */ }
templates/web/src/query.ts.twig (1)

359-396: Remove unsafe casts; add GeometryValues/DistancePayload types and tighten method signatures.

The as QueryTypesList casts are unsound, and any[] leaks type-safety. Define explicit tuple/geometry types and remove the casts. Also keep the outer array (list of one payload) to stay consistent with other SDKs.

Apply within this block:

-  static distanceEqual = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceEqual", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceEqual = (attribute: string, values: GeometryValues, distance: number, meters: boolean = false): string =>
+    new Query("distanceEqual", attribute, [[values, distance, meters] as DistancePayload]).toString();

-  static distanceNotEqual = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceNotEqual", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceNotEqual = (attribute: string, values: GeometryValues, distance: number, meters: boolean = false): string =>
+    new Query("distanceNotEqual", attribute, [[values, distance, meters] as DistancePayload]).toString();

-  static distanceGreaterThan = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceGreaterThan", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceGreaterThan = (attribute: string, values: GeometryValues, distance: number, meters: boolean = false): string =>
+    new Query("distanceGreaterThan", attribute, [[values, distance, meters] as DistancePayload]).toString();

-  static distanceLessThan = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceLessThan", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceLessThan = (attribute: string, values: GeometryValues, distance: number, meters: boolean = false): string =>
+    new Query("distanceLessThan", attribute, [[values, distance, meters] as DistancePayload]).toString();

Add these type defs near the top (outside the changed block):

export type GeometryValues = unknown[]; // e.g., coordinates or GeoJSON
export type DistancePayload = [GeometryValues, number, boolean];

And widen the list union to accept these payloads (outside the changed block):

export type QueryTypesList =
  | string[] | number[] | boolean[] | Query[]
  | GeometryValues
  | DistancePayload[];
templates/swift/Sources/Query.swift.twig (1)

401-431: Swift encoder drops nested/heterogeneous arrays; distance values will be omitted.*

values: [[values, distance, meters]] becomes [Any] of nested arrays which convertToQueryValueArray can’t encode; JSON omits values.

Implement array support and recursive conversion:

// 1) Extend QueryValue
enum QueryValue: Codable {
    case string(String)
    case int(Int)
    case double(Double)
    case bool(Bool)
    case query(Query)
    case array([QueryValue]) // NEW

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let v = try? container.decode(String.self) { self = .string(v) }
        else if let v = try? container.decode(Int.self) { self = .int(v) }
        else if let v = try? container.decode(Double.self) { self = .double(v) }
        else if let v = try? container.decode(Bool.self) { self = .bool(v) }
        else if let v = try? container.decode(Query.self) { self = .query(v) }
        else if let v = try? container.decode([QueryValue].self) { self = .array(v) } // NEW
        else { throw DecodingError.dataCorruptedError(in: container, debugDescription: "QueryValue cannot be decoded") }
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .string(let v): try container.encode(v)
        case .int(let v): try container.encode(v)
        case .double(let v): try container.encode(v)
        case .bool(let v): try container.encode(v)
        case .query(let v): try container.encode(v)
        case .array(let v): try container.encode(v) // NEW
        }
    }
}

// 2) Teach converter to handle [Any] recursively
private static func convertToQueryValueArray(_ values: Any?) -> [QueryValue]? {
    switch values {
    case let valueArray as [QueryValue]:
        return valueArray
    case let stringArray as [String]:
        return stringArray.map { .string($0) }
    case let intArray as [Int]:
        return intArray.map { .int($0) }
    case let doubleArray as [Double]:
        return doubleArray.map { .double($0) }
    case let boolArray as [Bool]:
        return boolArray.map { .bool($0) }
    case let queryArray as [Query]:
        return queryArray.map { .query($0) }
    case let anyArray as [Any]:
        return anyArray.compactMap { convertAnyToQueryValue($0) } // NEW
    case let stringValue as String:
        return [.string(stringValue)]
    case let intValue as Int:
        return [.int(intValue)]
    case let doubleValue as Double:
        return [.double(doubleValue)]
    case let boolValue as Bool:
        return [.bool(boolValue)]
    case let queryValue as Query:
        return [.query(queryValue)]
    default:
        return nil
    }
}

// 3) Helper for recursive mapping
private static func convertAnyToQueryValue(_ value: Any) -> QueryValue? {
    switch value {
    case let v as String: return .string(v)
    case let v as Int:    return .int(v)
    case let v as Double: return .double(v)
    case let v as Bool:   return .bool(v)
    case let v as Query:  return .query(v)
    case let v as [Any]:
        let mapped = v.compactMap { convertAnyToQueryValue($0) }
        return .array(mapped)
    default:
        return nil
    }
}

Please add a simple unit test asserting distanceEqual(_:values:distance:meters:) produces a JSON whose values is a non-empty array with the nested triplet.

templates/react-native/src/query.ts.twig (1)

206-208: Fix payload shape and drop unsafe casts for distance queries.

The extra outer array turns the payload into [[values, distance, meters]] instead of [values, distance, meters]. That’s a wire-format/contract bug. Also, any[] + as QueryTypesList bypasses type-safety.

Apply this diff within these methods:

-  static distanceEqual = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceEqual", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceEqual = (attribute: string, values: GeometryValues, distance: number, meters: boolean = false): string =>
+    new Query("distanceEqual", attribute, [values, distance, meters]).toString();

-  static distanceNotEqual = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceNotEqual", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceNotEqual = (attribute: string, values: GeometryValues, distance: number, meters: boolean = false): string =>
+    new Query("distanceNotEqual", attribute, [values, distance, meters]).toString();

-  static distanceGreaterThan = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceGreaterThan", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceGreaterThan = (attribute: string, values: GeometryValues, distance: number, meters: boolean = false): string =>
+    new Query("distanceGreaterThan", attribute, [values, distance, meters]).toString();

-  static distanceLessThan = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceLessThan", attribute, [[values, distance, meters]] as QueryTypesList).toString();
+  static distanceLessThan = (attribute: string, values: GeometryValues, distance: number, meters: boolean = false): string =>
+    new Query("distanceLessThan", attribute, [values, distance, meters]).toString();

Additionally (outside the changed hunk), update type defs near the top to make this type-safe and remove casts:

 type QueryTypesSingle = string | number | boolean;
-export type QueryTypesList = string[] | number[] | boolean[] | Query[];
+export type GeometryValues = unknown[];
+export type DistanceValues = [GeometryValues, number] | [GeometryValues, number, boolean];
+export type QueryTypesList = string[] | number[] | boolean[] | Query[] | GeometryValues | DistanceValues;
 export type QueryTypes = QueryTypesSingle | QueryTypesList;

Run to confirm parity with the web template and catch shape/cast mismatches:

#!/bin/bash
# Compare RN vs Web templates for distance helpers
rg -n "distance(Equal|NotEqual|GreaterThan|LessThan)" templates/{react-native,web}/src/query.ts.twig -C2
# Inspect presence of 'meters' and ensure no nested brackets `[[` in RN distance payloads
rg -n "distance(Equal|NotEqual|GreaterThan|LessThan).*\\[\\[" templates/react-native/src/query.ts.twig -C1

Also applies to: 218-220, 230-232, 242-244

🧹 Nitpick comments (11)
templates/python/package/query.py.twig (1)

162-192: Add minimal usage docs/types for new spatial predicates

Add brief docstrings to clarify accepted geometry formats (GeoJSON, [lon, lat], WKT?) and whether multiple geometries are supported in one call.

Example:

     @staticmethod
-    def intersects(attribute, values):
+    def intersects(attribute, values):
+        """Return spatial intersects query.
+        values: GeoJSON geometry or list of geometries."""
         return str(Query("intersects", attribute, values))

I can open a follow-up PR to add docstrings/tests across templates.

templates/ruby/lib/container/query.rb.twig (1)

171-201: Optional: support splat for single/multiple geometries

Allow passing either a single geometry or multiple without array-wrapping.

-            def intersects(attribute, values)
-                return Query.new("intersects", attribute, values).to_s
+            def intersects(attribute, *values)
+                vals = values.length == 1 ? values.first : values
+                return Query.new("intersects", attribute, vals).to_s
             end

Apply similarly to not_intersects, crosses, not_crosses, overlaps, not_overlaps, touches, not_touches.

Please confirm if multiple geometries per predicate are supported by the API before merging this change.

templates/kotlin/src/main/kotlin/io/appwrite/Query.kt.twig (2)

76-118: Fix KDoc tag: use @return (not @returns) in all distance docs

Keeps docs consistent with KDoc.

@@
- * @returns The query string.
+ * @return The query string.
@@
- * @returns The query string.
+ * @return The query string.
@@
- * @returns The query string.
+ * @return The query string.
@@
- * @returns The query string.
+ * @return The query string.

120-134: Add brief KDoc for spatial predicates

The new spatial helpers lack KDoc while distance ones have it. Add 1–2 line summaries for parity.

templates/dart/lib/query.dart.twig (2)

171-184: Allow integer distances: use num instead of double

Matches Kotlin’s Number and PHP’s int|float; avoids forcing callers to cast.

- static String distanceEqual(String attribute, List<dynamic> values, double distance, [bool meters = false]) =>
+ static String distanceEqual(String attribute, List<dynamic> values, num distance, [bool meters = false]) =>
@@
- static String distanceNotEqual(String attribute, List<dynamic> values, double distance, [bool meters = false]) =>
+ static String distanceNotEqual(String attribute, List<dynamic> values, num distance, [bool meters = false]) =>
@@
- static String distanceGreaterThan(String attribute, List<dynamic> values, double distance, [bool meters = false]) =>
+ static String distanceGreaterThan(String attribute, List<dynamic> values, num distance, [bool meters = false]) =>
@@
- static String distanceLessThan(String attribute, List<dynamic> values, double distance, [bool meters = false]) =>
+ static String distanceLessThan(String attribute, List<dynamic> values, num distance, [bool meters = false]) =>

170-186: Document meters parameter in Dart docs

Add a short sentence noting units toggle to reduce ambiguity.

templates/php/src/Query.php.twig (1)

403-454: Docblocks: add missing $meters parameter

Three distance docs omit the meters param; add for consistency.

@@
-     * @param int|float $distance
+     * @param int|float $distance
+     * @param bool $meters
@@
-     * @param int|float $distance
+     * @param int|float $distance
+     * @param bool $meters
@@
-     * @param int|float $distance
+     * @param int|float $distance
+     * @param bool $meters
templates/web/src/query.ts.twig (1)

405-476: Replace any[] with GeometryValues for spatial predicates.

Improve type-safety and documentation for geometry inputs.

-  static intersects = (attribute: string, values: any[]): string =>
+  static intersects = (attribute: string, values: GeometryValues): string =>
     new Query("intersects", attribute, values).toString();

-  static notIntersects = (attribute: string, values: any[]): string =>
+  static notIntersects = (attribute: string, values: GeometryValues): string =>
     new Query("notIntersects", attribute, values).toString();

-  static crosses = (attribute: string, values: any[]): string =>
+  static crosses = (attribute: string, values: GeometryValues): string =>
     new Query("crosses", attribute, values).toString();

-  static notCrosses = (attribute: string, values: any[]): string =>
+  static notCrosses = (attribute: string, values: GeometryValues): string =>
     new Query("notCrosses", attribute, values).toString();

-  static overlaps = (attribute: string, values: any[]): string =>
+  static overlaps = (attribute: string, values: GeometryValues): string =>
     new Query("overlaps", attribute, values).toString();

-  static notOverlaps = (attribute: string, values: any[]): string =>
+  static notOverlaps = (attribute: string, values: GeometryValues): string =>
     new Query("notOverlaps", attribute, values).toString();

-  static touches = (attribute: string, values: any[]): string =>
+  static touches = (attribute: string, values: GeometryValues): string =>
     new Query("touches", attribute, values).toString();

-  static notTouches = (attribute: string, values: any[]): string =>
+  static notTouches = (attribute: string, values: GeometryValues): string =>
     new Query("notTouches", attribute, values).toString();
templates/android/library/src/main/java/io/package/Query.kt.twig (1)

298-331: Add @jvmoverloads to distance for Java consumers.*

Default params aren’t visible to Java; add overloads for better interop.

-        fun distanceEqual(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) = Query("distanceEqual", attribute, listOf(listOf(values, distance, meters))).toJson()
+        @JvmOverloads
+        fun distanceEqual(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) =
+            Query("distanceEqual", attribute, listOf(listOf(values, distance, meters))).toJson()

-        fun distanceNotEqual(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) = Query("distanceNotEqual", attribute, listOf(listOf(values, distance, meters))).toJson()
+        @JvmOverloads
+        fun distanceNotEqual(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) =
+            Query("distanceNotEqual", attribute, listOf(listOf(values, distance, meters))).toJson()

-        fun distanceGreaterThan(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) = Query("distanceGreaterThan", attribute, listOf(listOf(values, distance, meters))).toJson()
+        @JvmOverloads
+        fun distanceGreaterThan(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) =
+            Query("distanceGreaterThan", attribute, listOf(listOf(values, distance, meters))).toJson()

-        fun distanceLessThan(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) = Query("distanceLessThan", attribute, listOf(listOf(values, distance, meters))).toJson()
+        @JvmOverloads
+        fun distanceLessThan(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) =
+            Query("distanceLessThan", attribute, listOf(listOf(values, distance, meters))).toJson()
templates/react-native/src/query.ts.twig (2)

252-324: Tighten geometry method signatures: avoid any[], use a shared GeometryValues type.

Keeps parity with the web template and improves DX without hiding errors.

Apply this diff:

-  static intersects = (attribute: string, values: any[]): string =>
+  static intersects = (attribute: string, values: GeometryValues): string =>
     new Query("intersects", attribute, values).toString();

-  static notIntersects = (attribute: string, values: any[]): string =>
+  static notIntersects = (attribute: string, values: GeometryValues): string =>
     new Query("notIntersects", attribute, values).toString();

-  static crosses = (attribute: string, values: any[]): string =>
+  static crosses = (attribute: string, values: GeometryValues): string =>
     new Query("crosses", attribute, values).toString();

-  static notCrosses = (attribute: string, values: any[]): string =>
+  static notCrosses = (attribute: string, values: GeometryValues): string =>
     new Query("notCrosses", attribute, values).toString();

-  static overlaps = (attribute: string, values: any[]): string =>
+  static overlaps = (attribute: string, values: GeometryValues): string =>
     new Query("overlaps", attribute, values).toString();

-  static notOverlaps = (attribute: string, values: any[]): string =>
+  static notOverlaps = (attribute: string, values: GeometryValues): string =>
     new Query("notOverlaps", attribute, values).toString();

-  static touches = (attribute: string, values: any[]): string =>
+  static touches = (attribute: string, values: GeometryValues): string =>
     new Query("touches", attribute, values).toString();

-  static notTouches = (attribute: string, values: any[]): string =>
+  static notTouches = (attribute: string, values: GeometryValues): string =>
     new Query("notTouches", attribute, values).toString();

197-205: Clarify docs: shape and units.

Document that:

  • values is a geometry/coordinates array (state expected coordinate order).
  • distance must be non-negative.
  • meters defaults to false (and what false means).

Example tweak:

- * @param {any[]} values
- * @param {number} distance
- * @param {boolean} meters
+ * @param {GeometryValues} values Coordinates/geometry (e.g. [lon, lat] or polygon ring)
+ * @param {number} distance Non-negative distance value
+ * @param {boolean} meters If true, distance is in meters; otherwise default unit (e.g., kilometers)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1345677 and d5b7173.

📒 Files selected for processing (12)
  • templates/android/library/src/main/java/io/package/Query.kt.twig (1 hunks)
  • templates/dart/lib/query.dart.twig (1 hunks)
  • templates/deno/src/query.ts.twig (1 hunks)
  • templates/dotnet/Package/Query.cs.twig (1 hunks)
  • templates/go/query.go.twig (1 hunks)
  • templates/kotlin/src/main/kotlin/io/appwrite/Query.kt.twig (1 hunks)
  • templates/php/src/Query.php.twig (1 hunks)
  • templates/python/package/query.py.twig (1 hunks)
  • templates/react-native/src/query.ts.twig (1 hunks)
  • templates/ruby/lib/container/query.rb.twig (1 hunks)
  • templates/swift/Sources/Query.swift.twig (1 hunks)
  • templates/web/src/query.ts.twig (1 hunks)
🔇 Additional comments (7)
templates/go/query.go.twig (1)

353-415: Accept single geometry or slice in geometry predicates
Update the eight geometry functions (Intersects, NotIntersects, Crosses, NotCrosses, Overlaps, NotOverlaps, Touches, NotTouches) to match other helpers by accepting value interface{} and calling toArray(value) internally:

-func Intersects(attribute string, values []interface{}) string {
-   return parseQuery(queryOptions{
-       Method:    "intersects",
-       Attribute: &attribute,
-       Values:    &values,
-   })
-}
+func Intersects(attribute string, value interface{}) string {
+   values := toArray(value)
+   return parseQuery(queryOptions{
+       Method:    "intersects",
+       Attribute: &attribute,
+       Values:    &values,
+   })
+}

Repeat for all eight predicates. Ensure a matching toArray helper exists and behaves like other helpers. Add unit tests to round-trip the JSON and assert the shape of Values for single vs. multiple geometries.

templates/kotlin/src/main/kotlin/io/appwrite/Query.kt.twig (1)

85-118: Confirm backend distance operator payload shape
Validate that the API contract expects a nested-array payload—[[values, distance, meters]]—for all distance filters, including the meters flag.

templates/dotnet/Package/Query.cs.twig (2)

205-223: LGTM: correct shape and parity for distance helpers

The nested List { List { values, distance, meters } } matches other templates.


225-263: LGTM: spatial predicates mirror existing pattern

Constructors and return shape are consistent with the rest of the class.

templates/php/src/Query.php.twig (1)

456-550: LGTM: spatial predicates mirror existing API and serialization

Naming, signatures, and return values are consistent with prior helpers.

templates/web/src/query.ts.twig (1)

359-396: Define and document a custom geo-distance payload
Appwrite has no native distance operator, so these distance* methods are purely client-side conventions. Choose a stable tuple shape (e.g. [coordinates, distance] or [coordinates, distance, "m"]), implement matching server-side support or a dedicated endpoint, and document the format in the SDK.

Likely an incorrect or invalid review comment.

templates/android/library/src/main/java/io/package/Query.kt.twig (1)

298-331: Verify backend supports 3-element distance tuple
All client SDKs emit geospatial queries as ["distanceEqual", attribute, [[values, distance, meters]]] (e.g. Query.kt.twig:298) and PostGIS’s geography signature ST_DWithin(geography, geography, distance_meters, use_spheroid) accepts an optional boolean (use_spheroid=false is valid) (postgis.net). Confirm Appwrite’s server correctly handles the 3-argument form (treating the third element as the meters/​use_spheroid flag) or gracefully falls back to the 2-argument geometry form to avoid breaking existing deployments.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (27)
tests/languages/go/tests.go (2)

223-231: DRY up: reuse shared coords and distance to reduce repetition.
Define variables once and use them in all Distance* calls for readability and easier updates.

Apply this diff:

 // Spatial Distance query tests
-fmt.Println(query.DistanceEqual("location", []interface{}{40.7128, -74.0060}, 1000, false))
-	fmt.Println(query.DistanceEqual("location", []interface{}{40.7128, -74.0060}, 1000, true))
-	fmt.Println(query.DistanceNotEqual("location", []interface{}{40.7128, -74.0060}, 1000, false))
-	fmt.Println(query.DistanceNotEqual("location", []interface{}{40.7128, -74.0060}, 1000, true))
-	fmt.Println(query.DistanceGreaterThan("location", []interface{}{40.7128, -74.0060}, 1000, false))
-	fmt.Println(query.DistanceGreaterThan("location", []interface{}{40.7128, -74.0060}, 1000, true))
-	fmt.Println(query.DistanceLessThan("location", []interface{}{40.7128, -74.0060}, 1000, false))
-	fmt.Println(query.DistanceLessThan("location", []interface{}{40.7128, -74.0060}, 1000, true))
+loc := []interface{}{40.7128, -74.0060}
+dist := 1000
+fmt.Println(query.DistanceEqual("location", loc, dist, false))
+fmt.Println(query.DistanceEqual("location", loc, dist, true))
+fmt.Println(query.DistanceNotEqual("location", loc, dist, false))
+fmt.Println(query.DistanceNotEqual("location", loc, dist, true))
+fmt.Println(query.DistanceGreaterThan("location", loc, dist, false))
+fmt.Println(query.DistanceGreaterThan("location", loc, dist, true))
+fmt.Println(query.DistanceLessThan("location", loc, dist, false))
+fmt.Println(query.DistanceLessThan("location", loc, dist, true))

233-241: Point geometry for Crosses/Overlaps/Touches may be underspecified—consider adding line/polygon cases.
These predicates are typically defined for linear/areal geometries. Add at least one example with a LineString and Polygon to catch encoding issues for complex shapes.

For example (coordinate order per your API):

 // Spatial query tests
-fmt.Println(query.Intersects("location", []interface{}{40.7128, -74.0060}))
+fmt.Println(query.Intersects("location", loc))
 fmt.Println(query.NotIntersects("location", []interface{}{40.7128, -74.0060}))
-fmt.Println(query.Crosses("location", []interface{}{40.7128, -74.0060}))
+line := []interface{}{[]interface{}{-74.01, 40.70}, []interface{}{-74.00, 40.72}}
+fmt.Println(query.Crosses("location", line))
 fmt.Println(query.NotCrosses("location", []interface{}{40.7128, -74.0060}))
-fmt.Println(query.Overlaps("location", []interface{}{40.7128, -74.0060}))
+polygon := []interface{}{
+  []interface{}{-74.01, 40.70}, []interface{}{-74.01, 40.72},
+  []interface{}{-74.00, 40.72}, []interface{}{-74.00, 40.70},
+  []interface{}{-74.01, 40.70},
+}
+fmt.Println(query.Overlaps("location", polygon))
 fmt.Println(query.NotOverlaps("location", []interface{}{40.7128, -74.0060}))
 fmt.Println(query.Touches("location", []interface{}{40.7128, -74.0060}))
 fmt.Println(query.NotTouches("location", []interface{}{40.7128, -74.0060}))
tests/languages/flutter/tests.dart (1)

198-207: Distance queries: add explicit meters=false and fractional-distance tests; confirm coord order.

  • Add tests for fractional distance (e.g., 1.5) and explicit meters=false to cover both parameter states.
  • Verify whether coordinate order is [lat, lon] or [lon, lat] in documentation/templates to ensure consistency.
   // Spatial Distance query tests
   print(Query.distanceEqual("location", [40.7128, -74.0060], 1000));
+  // explicit meters=false and fractional distance checks
+  print(Query.distanceEqual("location", [40.7128, -74.0060], 1.5));
+  print(Query.distanceEqual("location", [40.7128, -74.0060], 1500, false));
   print(Query.distanceEqual("location", [40.7128, -74.0060], 1000, true));
tests/languages/dart/tests.dart (2)

183-191: Use representative geometries for spatial predicates; point-only may not meaningfully exercise crosses/overlaps/touches

Intersects with a point is fine; crosses/overlaps/touches typically involve LineString/Polygon. Add at least one Polygon/LineString case if supported to catch encoding/serialization issues.

Example addition within this block:

+  final polygon = {
+    "type": "Polygon",
+    "coordinates": [
+      [
+        [-74.01, 40.71], [-74.01, 40.72],
+        [-74.00, 40.72], [-74.00, 40.71],
+        [-74.01, 40.71]
+      ]
+    ]
+  };
+  print(Query.intersects("location", polygon));
+  // If supported:
+  // print(Query.overlaps("location", polygon));

193-197: Duplicate OR test — remove or repurpose to cover spatial + scalar composition

This OR is identical to the one above (Lines 164–167). It adds noise without extra coverage.

Apply:

-  print(Query.or([
-    Query.equal("released", true),
-    Query.lessThan("releasedYear", 1990)
-  ]));

Optional replacement to exercise spatial composition:

+  print(Query.or([
+    Query.distanceLessThan("location", [40.7128, -74.0060], 1000),
+    Query.equal("released", true)
+  ]));
tests/languages/kotlin/Tests.kt (2)

191-200: Add explicit meters=false coverage and DRY the coordinates.

Covers both overloads today (3-arg, 4-arg with true), but missing an explicit false path. Also, the repeated literal coordinates can be factored to reduce duplication and cut copy/paste errors.

             // Spatial Distance query tests
+            val coords = listOf(40.7128, -74.0060)
-            writeToFile(Query.distanceEqual("location", listOf(40.7128, -74.0060), 1000))
-            writeToFile(Query.distanceEqual("location", listOf(40.7128, -74.0060), 1000, true))
-            writeToFile(Query.distanceNotEqual("location", listOf(40.7128, -74.0060), 1000))
-            writeToFile(Query.distanceNotEqual("location", listOf(40.7128, -74.0060), 1000, true))
-            writeToFile(Query.distanceGreaterThan("location", listOf(40.7128, -74.0060), 1000))
-            writeToFile(Query.distanceGreaterThan("location", listOf(40.7128, -74.0060), 1000, true))
-            writeToFile(Query.distanceLessThan("location", listOf(40.7128, -74.0060), 1000))
-            writeToFile(Query.distanceLessThan("location", listOf(40.7128, -74.0060), 1000, true))
+            writeToFile(Query.distanceEqual("location", coords, 1000))
+            writeToFile(Query.distanceEqual("location", coords, 1000, true))
+            writeToFile(Query.distanceEqual("location", coords, 1000, false))
+            writeToFile(Query.distanceNotEqual("location", coords, 1000))
+            writeToFile(Query.distanceNotEqual("location", coords, 1000, true))
+            writeToFile(Query.distanceNotEqual("location", coords, 1000, false))
+            writeToFile(Query.distanceGreaterThan("location", coords, 1000))
+            writeToFile(Query.distanceGreaterThan("location", coords, 1000, true))
+            writeToFile(Query.distanceGreaterThan("location", coords, 1000, false))
+            writeToFile(Query.distanceLessThan("location", coords, 1000))
+            writeToFile(Query.distanceLessThan("location", coords, 1000, true))
+            writeToFile(Query.distanceLessThan("location", coords, 1000, false))
+            // numeric type variance
+            writeToFile(Query.distanceEqual("location", coords, 1000.0))

210-210: Add a composition case to ensure new predicates play well with AND/OR.

One combined example catches serialization of nested new queries inside logical combinators.

             writeToFile(Query.notTouches("location", listOf(40.7128, -74.0060)))
+            // Composition with logical operators
+            writeToFile(
+                Query.and(
+                    listOf(
+                        Query.distanceLessThan("location", listOf(40.7128, -74.0060), 1000),
+                        Query.intersects("location", listOf(40.7128, -74.0060))
+                    )
+                )
+            )
tests/languages/python/tests.py (1)

160-169: Use geometry-shaped values for spatial predicates.

Point arrays work syntactically but don’t exercise realistic inputs for intersects/crosses/overlaps/touches, which typically involve line/polygon geometry. Add a small line and polygon to better cover encoding and serialization.

Apply this diff:

-# Spatial query tests
-print(Query.intersects("location", [40.7128, -74.0060]))
-print(Query.not_intersects("location", [40.7128, -74.0060]))
-print(Query.crosses("location", [40.7128, -74.0060]))
-print(Query.not_crosses("location", [40.7128, -74.0060]))
-print(Query.overlaps("location", [40.7128, -74.0060]))
-print(Query.not_overlaps("location", [40.7128, -74.0060]))
-print(Query.touches("location", [40.7128, -74.0060]))
-print(Query.not_touches("location", [40.7128, -74.0060]))
+# Spatial query tests
+# NOTE: Replace coordinate order with [lon, lat] if the spec requires GeoJSON order.
+point = [-74.0060, 40.7128]
+line = [[-74.01, 40.70], [-74.00, 40.72]]
+polygon = [[
+  [-74.02, 40.70], [-74.00, 40.70], [-74.00, 40.72], [-74.02, 40.72], [-74.02, 40.70]
+]]
+print(Query.intersects("location", polygon))
+print(Query.not_intersects("location", polygon))
+print(Query.crosses("location", line))
+print(Query.not_crosses("location", line))
+print(Query.overlaps("location", polygon))
+print(Query.not_overlaps("location", polygon))
+print(Query.touches("location", point))
+print(Query.not_touches("location", point))

If other language tests already standardize on point arrays for these predicates, keep parity and skip this change. The grep script above will surface that.

tests/languages/web/node.js (2)

200-209: DRY the repeated literals for readability

Factor the location and distance into constants to reduce noise and prevent typos.

-// Spatial Distance query tests
-console.log(Query.distanceEqual("location", [40.7128, -74.0060], 1000));
-console.log(Query.distanceEqual("location", [40.7128, -74.0060], 1000, true));
-console.log(Query.distanceNotEqual("location", [40.7128, -74.0060], 1000));
-console.log(Query.distanceNotEqual("location", [40.7128, -74.0060], 1000, true));
-console.log(Query.distanceGreaterThan("location", [40.7128, -74.0060], 1000));
-console.log(Query.distanceGreaterThan("location", [40.7128, -74.0060], 1000, true));
-console.log(Query.distanceLessThan("location", [40.7128, -74.0060], 1000));
-console.log(Query.distanceLessThan("location", [40.7128, -74.0060], 1000, true));
+// Spatial Distance query tests
+const attr = "location";
+const loc = [40.7128, -74.0060];
+const dist = 1000;
+console.log(Query.distanceEqual(attr, loc, dist));
+console.log(Query.distanceEqual(attr, loc, dist, true));
+console.log(Query.distanceNotEqual(attr, loc, dist));
+console.log(Query.distanceNotEqual(attr, loc, dist, true));
+console.log(Query.distanceGreaterThan(attr, loc, dist));
+console.log(Query.distanceGreaterThan(attr, loc, dist, true));
+console.log(Query.distanceLessThan(attr, loc, dist));
+console.log(Query.distanceLessThan(attr, loc, dist, true));

210-219: Same DRY tweak for spatial predicates

Keeps the block concise and consistent with the distance section.

-// Spatial query tests
-console.log(Query.intersects("location", [40.7128, -74.0060]));
-console.log(Query.notIntersects("location", [40.7128, -74.0060]));
-console.log(Query.crosses("location", [40.7128, -74.0060]));
-console.log(Query.notCrosses("location", [40.7128, -74.0060]));
-console.log(Query.overlaps("location", [40.7128, -74.0060]));
-console.log(Query.notOverlaps("location", [40.7128, -74.0060]));
-console.log(Query.touches("location", [40.7128, -74.0060]));
-console.log(Query.notTouches("location", [40.7128, -74.0060]));
+// Spatial query tests
+console.log(Query.intersects(attr, loc));
+console.log(Query.notIntersects(attr, loc));
+console.log(Query.crosses(attr, loc));
+console.log(Query.notCrosses(attr, loc));
+console.log(Query.overlaps(attr, loc));
+console.log(Query.notOverlaps(attr, loc));
+console.log(Query.touches(attr, loc));
+console.log(Query.notTouches(attr, loc));
tests/languages/php/test.php (2)

165-173: Reduce duplication with local vars for attribute/coords/distance

Improves readability and keeps the series consistent.

-// Spatial Distance query tests
-echo Query::distanceEqual('location', [40.7128, -74.0060], 1000) . "\n";
-echo Query::distanceEqual('location', [40.7128, -74.0060], 1000, true) . "\n";
-echo Query::distanceNotEqual('location', [40.7128, -74.0060], 1000) . "\n";
-echo Query::distanceNotEqual('location', [40.7128, -74.0060], 1000, true) . "\n";
-echo Query::distanceGreaterThan('location', [40.7128, -74.0060], 1000) . "\n";
-echo Query::distanceGreaterThan('location', [40.7128, -74.0060], 1000, true) . "\n";
-echo Query::distanceLessThan('location', [40.7128, -74.0060], 1000) . "\n";
-echo Query::distanceLessThan('location', [40.7128, -74.0060], 1000, true) . "\n";
+// Spatial Distance query tests
+$attr = 'location';
+$loc = [40.7128, -74.0060];
+$dist = 1000;
+echo Query::distanceEqual($attr, $loc, $dist) . "\n";
+echo Query::distanceEqual($attr, $loc, $dist, true) . "\n";
+echo Query::distanceNotEqual($attr, $loc, $dist) . "\n";
+echo Query::distanceNotEqual($attr, $loc, $dist, true) . "\n";
+echo Query::distanceGreaterThan($attr, $loc, $dist) . "\n";
+echo Query::distanceGreaterThan($attr, $loc, $dist, true) . "\n";
+echo Query::distanceLessThan($attr, $loc, $dist) . "\n";
+echo Query::distanceLessThan($attr, $loc, $dist, true) . "\n";

175-184: Apply the same DRY approach to spatial predicates

Matches the distance section and reduces repetition.

-// Spatial query tests
-echo Query::intersects('location', [40.7128, -74.0060]) . "\n";
-echo Query::notIntersects('location', [40.7128, -74.0060]) . "\n";
-echo Query::crosses('location', [40.7128, -74.0060]) . "\n";
-echo Query::notCrosses('location', [40.7128, -74.0060]) . "\n";
-echo Query::overlaps('location', [40.7128, -74.0060]) . "\n";
-echo Query::notOverlaps('location', [40.7128, -74.0060]) . "\n";
-echo Query::touches('location', [40.7128, -74.0060]) . "\n";
-echo Query::notTouches('location', [40.7128, -74.0060]) . "\n";
+// Spatial query tests
+echo Query::intersects($attr, $loc) . "\n";
+echo Query::notIntersects($attr, $loc) . "\n";
+echo Query::crosses($attr, $loc) . "\n";
+echo Query::notCrosses($attr, $loc) . "\n";
+echo Query::overlaps($attr, $loc) . "\n";
+echo Query::notOverlaps($attr, $loc) . "\n";
+echo Query::touches($attr, $loc) . "\n";
+echo Query::notTouches($attr, $loc) . "\n";
tests/languages/node/test.js (1)

275-283: DRY the inputs and add lightweight assertions instead of only logging.

Cuts duplication and gives minimal safety without coupling to exact payload format.

Apply this diff in-place:

-    // Spatial Distance query tests
-    console.log(Query.distanceEqual("location", [40.7128, -74.0060], 1000));
-    console.log(Query.distanceEqual("location", [40.7128, -74.0060], 1000, true));
-    console.log(Query.distanceNotEqual("location", [40.7128, -74.0060], 1000));
-    console.log(Query.distanceNotEqual("location", [40.7128, -74.0060], 1000, true));
-    console.log(Query.distanceGreaterThan("location", [40.7128, -74.0060], 1000));
-    console.log(Query.distanceGreaterThan("location", [40.7128, -74.0060], 1000, true));
-    console.log(Query.distanceLessThan("location", [40.7128, -74.0060], 1000));
-    console.log(Query.distanceLessThan("location", [40.7128, -74.0060], 1000, true));
+    // Spatial Distance query tests
+    const coords = [40.7128, -74.0060];
+    const radius = 1000;
+    let s;
+    s = Query.distanceEqual("location", coords, radius);
+    console.log(s); console.assert(typeof s === 'string' && s.includes('distanceEqual'), 'distanceEqual should serialize');
+    console.log(Query.distanceEqual("location", coords, radius, true));
+    s = Query.distanceNotEqual("location", coords, radius);
+    console.log(s); console.assert(s.includes('distanceNotEqual'), 'distanceNotEqual should serialize');
+    console.log(Query.distanceNotEqual("location", coords, radius, true));
+    s = Query.distanceGreaterThan("location", coords, radius);
+    console.log(s); console.assert(s.includes('distanceGreaterThan'), 'distanceGreaterThan should serialize');
+    console.log(Query.distanceGreaterThan("location", coords, radius, true));
+    s = Query.distanceLessThan("location", coords, radius);
+    console.log(s); console.assert(s.includes('distanceLessThan'), 'distanceLessThan should serialize');
+    console.log(Query.distanceLessThan("location", coords, radius, true));
tests/languages/apple/Tests.swift (2)

198-207: Add light assertions for distance queries (keep prints) + cover meters=false.

Right now these are smoke prints only. Add a couple of cheap string checks to catch regressions and explicitly exercise meters: false.

Apply this diff:

-        print(Query.distanceEqual("location", values: [40.7128, -74.0060], distance: 1000))
-        print(Query.distanceEqual("location", values: [40.7128, -74.0060], distance: 1000, meters: true))
+        let dEq = Query.distanceEqual("location", values: [40.7128, -74.0060], distance: 1000)
+        print(dEq)
+        XCTAssertTrue(dEq.contains("distanceEqual") && dEq.contains("location") && dEq.contains("1000"))
+        let dEqMeters = Query.distanceEqual("location", values: [40.7128, -74.0060], distance: 1000, meters: true)
+        print(dEqMeters)
+        XCTAssertTrue(dEqMeters.contains("distanceEqual") && dEqMeters.contains("true"))
+        // Explicit meters: false sanity check
+        let dEqMetersFalse = Query.distanceEqual("location", values: [40.7128, -74.0060], distance: 1000, meters: false)
+        XCTAssertTrue(dEqMetersFalse.contains("distanceEqual"))
         print(Query.distanceNotEqual("location", values: [40.7128, -74.0060], distance: 1000))
         print(Query.distanceNotEqual("location", values: [40.7128, -74.0060], distance: 1000, meters: true))
         print(Query.distanceGreaterThan("location", values: [40.7128, -74.0060], distance: 1000))
         print(Query.distanceGreaterThan("location", values: [40.7128, -74.0060], distance: 1000, meters: true))
         print(Query.distanceLessThan("location", values: [40.7128, -74.0060], distance: 1000))
         print(Query.distanceLessThan("location", values: [40.7128, -74.0060], distance: 1000, meters: true))

208-217: Basic assertions for spatial predicates + double-check argument shape.

Add minimal checks for 1–2 ops; keep the rest as prints. Also confirm whether these ops expect a point or a geometry (e.g., LineString/Polygon) to avoid false positives.

Apply this diff:

-        print(Query.intersects("location", values: [40.7128, -74.0060]))
-        print(Query.notIntersects("location", values: [40.7128, -74.0060]))
+        let sIntersects = Query.intersects("location", values: [40.7128, -74.0060])
+        print(sIntersects)
+        XCTAssertTrue(sIntersects.contains("intersects") && sIntersects.contains("location"))
+        let sNotIntersects = Query.notIntersects("location", values: [40.7128, -74.0060])
+        print(sNotIntersects)
+        XCTAssertTrue(sNotIntersects.contains("notIntersects"))
         print(Query.crosses("location", values: [40.7128, -74.0060]))
         print(Query.notCrosses("location", values: [40.7128, -74.0060]))
         print(Query.overlaps("location", values: [40.7128, -74.0060]))
         print(Query.notOverlaps("location", values: [40.7128, -74.0060]))
         print(Query.touches("location", values: [40.7128, -74.0060]))
         print(Query.notTouches("location", values: [40.7128, -74.0060]))

If docs require [lon, lat] (GeoJSON) rather than [lat, lon], adjust the order in tests for correctness.

tests/languages/deno/tests.ts (1)

190-209: Minor DRY: reuse a coords constant.

Reduces repetition and improves readability without changing output.

Apply within this block:

   // Spatial Distance query tests
-  console.log(Query.distanceEqual("location", [40.7128, -74.0060], 1000));
-  console.log(Query.distanceEqual("location", [40.7128, -74.0060], 1000, true));
-  console.log(Query.distanceNotEqual("location", [40.7128, -74.0060], 1000));
-  console.log(Query.distanceNotEqual("location", [40.7128, -74.0060], 1000, true));
-  console.log(Query.distanceGreaterThan("location", [40.7128, -74.0060], 1000));
-  console.log(Query.distanceGreaterThan("location", [40.7128, -74.0060], 1000, true));
-  console.log(Query.distanceLessThan("location", [40.7128, -74.0060], 1000));
-  console.log(Query.distanceLessThan("location", [40.7128, -74.0060], 1000, true));
+  const coords = [40.7128, -74.0060];
+  console.log(Query.distanceEqual("location", coords, 1000));
+  console.log(Query.distanceEqual("location", coords, 1000, true));
+  console.log(Query.distanceNotEqual("location", coords, 1000));
+  console.log(Query.distanceNotEqual("location", coords, 1000, true));
+  console.log(Query.distanceGreaterThan("location", coords, 1000));
+  console.log(Query.distanceGreaterThan("location", coords, 1000, true));
+  console.log(Query.distanceLessThan("location", coords, 1000));
+  console.log(Query.distanceLessThan("location", coords, 1000, true));
 
   // Spatial query tests
-  console.log(Query.intersects("location", [40.7128, -74.0060]));
-  console.log(Query.notIntersects("location", [40.7128, -74.0060]));
-  console.log(Query.crosses("location", [40.7128, -74.0060]));
-  console.log(Query.notCrosses("location", [40.7128, -74.0060]));
-  console.log(Query.overlaps("location", [40.7128, -74.0060]));
-  console.log(Query.notOverlaps("location", [40.7128, -74.0060]));
-  console.log(Query.touches("location", [40.7128, -74.0060]));
-  console.log(Query.notTouches("location", [40.7128, -74.0060]));
+  console.log(Query.intersects("location", coords));
+  console.log(Query.notIntersects("location", coords));
+  console.log(Query.crosses("location", coords));
+  console.log(Query.notCrosses("location", coords));
+  console.log(Query.overlaps("location", coords));
+  console.log(Query.notOverlaps("location", coords));
+  console.log(Query.touches("location", coords));
+  console.log(Query.notTouches("location", coords));
tests/languages/ruby/tests.rb (2)

165-173: Cover both unit modes and fractional distances.

Add one case with meters=false explicitly and one with fractional distance to ensure encoding is stable.

 # Spatial Distance query tests
 puts Query.distance_equal("location", [40.7128, -74.0060], 1000)
+puts Query.distance_equal("location", [40.7128, -74.0060], 1500, false)
+puts Query.distance_equal("location", [40.7128, -74.0060], 1.25)
 puts Query.distance_equal("location", [40.7128, -74.0060], 1000, true)

175-183: Use non-point geometries for relation predicates.

crosses/overlaps/touches semantics are clearer with LineString/Polygon inputs; consider adding at least one example for each to validate serialization of nested arrays.

Example shapes (adjust to the format expected by the backend):

  • LineString: [[-74.01, 40.70], [-73.99, 40.72]]
  • Polygon: [[[-74.02, 40.70], [-74.02, 40.72], [-73.98, 40.72], [-73.98, 40.70], [-74.02, 40.70]]]
tests/languages/swift/Tests.swift (3)

189-196: Units: clarify default when meters is omitted.

If the default unit isn’t meters (e.g., kilometers), distance: 1000 may unintentionally mean 1000 km. Consider either passing meters: true everywhere or using a distance that clearly matches the default unit.


199-206: Use geometry types that match predicate semantics.

Predicates like crosses/overlaps/touches are generally non-meaningful for a point. Add a line and polygon case to exercise these predicates realistically.

Example:

let line: [[Double]] = [[-74.0060, 40.7128], [-73.9352, 40.7306]]
let poly: [[[Double]]] = [[
  [-74.02, 40.70], [-74.00, 40.70], [-74.00, 40.72], [-74.02, 40.72], [-74.02, 40.70]
]]

print(Query.crosses("location", values: line))
print(Query.overlaps("location", values: poly))
print(Query.touches("location", values: line))

188-197: DRY up repeated literals for readability.

Extract the coordinates and distance to constants to reduce duplication and typos.

-        // Spatial Distance query tests
-        print(Query.distanceEqual("location", values: [40.7128, -74.0060], distance: 1000))
-        print(Query.distanceEqual("location", values: [40.7128, -74.0060], distance: 1000, meters: true))
-        print(Query.distanceNotEqual("location", values: [40.7128, -74.0060], distance: 1000))
-        print(Query.distanceNotEqual("location", values: [40.7128, -74.0060], distance: 1000, meters: true))
-        print(Query.distanceGreaterThan("location", values: [40.7128, -74.0060], distance: 1000))
-        print(Query.distanceGreaterThan("location", values: [40.7128, -74.0060], distance: 1000, meters: true))
-        print(Query.distanceLessThan("location", values: [40.7128, -74.0060], distance: 1000))
-        print(Query.distanceLessThan("location", values: [40.7128, -74.0060], distance: 1000, meters: true))
+        // Spatial Distance query tests
+        let nyc: [Double] = [40.7128, -74.0060] // verify order per spec
+        let d: Double = 1000
+        print(Query.distanceEqual("location", values: nyc, distance: d))
+        print(Query.distanceEqual("location", values: nyc, distance: d, meters: true))
+        print(Query.distanceNotEqual("location", values: nyc, distance: d))
+        print(Query.distanceNotEqual("location", values: nyc, distance: d, meters: true))
+        print(Query.distanceGreaterThan("location", values: nyc, distance: d))
+        print(Query.distanceGreaterThan("location", values: nyc, distance: d, meters: true))
+        print(Query.distanceLessThan("location", values: nyc, distance: d))
+        print(Query.distanceLessThan("location", values: nyc, distance: d, meters: true))
tests/languages/android/Tests.kt (4)

225-243: DRY the repeated coordinates into a constant for readability.

-            // Spatial Distance query tests
-            writeToFile(Query.distanceEqual("location", listOf(40.7128, -74.0060), 1000))
-            writeToFile(Query.distanceEqual("location", listOf(40.7128, -74.0060), 1000, true))
-            writeToFile(Query.distanceNotEqual("location", listOf(40.7128, -74.0060), 1000))
-            writeToFile(Query.distanceNotEqual("location", listOf(40.7128, -74.0060), 1000, true))
-            writeToFile(Query.distanceGreaterThan("location", listOf(40.7128, -74.0060), 1000))
-            writeToFile(Query.distanceGreaterThan("location", listOf(40.7128, -74.0060), 1000, true))
-            writeToFile(Query.distanceLessThan("location", listOf(40.7128, -74.0060), 1000))
-            writeToFile(Query.distanceLessThan("location", listOf(40.7128, -74.0060), 1000, true))
+            // Spatial Distance query tests
+            val nyc = listOf(40.7128, -74.0060) // verify order per spec
+            writeToFile(Query.distanceEqual("location", nyc, 1000))
+            writeToFile(Query.distanceEqual("location", nyc, 1000, true))
+            writeToFile(Query.distanceNotEqual("location", nyc, 1000))
+            writeToFile(Query.distanceNotEqual("location", nyc, 1000, true))
+            writeToFile(Query.distanceGreaterThan("location", nyc, 1000))
+            writeToFile(Query.distanceGreaterThan("location", nyc, 1000, true))
+            writeToFile(Query.distanceLessThan("location", nyc, 1000))
+            writeToFile(Query.distanceLessThan("location", nyc, 1000, true))
@@
-            // Spatial query tests
-            writeToFile(Query.intersects("location", listOf(40.7128, -74.0060)))
-            writeToFile(Query.notIntersects("location", listOf(40.7128, -74.0060)))
-            writeToFile(Query.crosses("location", listOf(40.7128, -74.0060)))
-            writeToFile(Query.notCrosses("location", listOf(40.7128, -74.0060)))
-            writeToFile(Query.overlaps("location", listOf(40.7128, -74.0060)))
-            writeToFile(Query.notOverlaps("location", listOf(40.7128, -74.0060)))
-            writeToFile(Query.touches("location", listOf(40.7128, -74.0060)))
-            writeToFile(Query.notTouches("location", listOf(40.7128, -74.0060)))
+            // Spatial query tests
+            writeToFile(Query.intersects("location", nyc))
+            writeToFile(Query.notIntersects("location", nyc))
+            writeToFile(Query.crosses("location", nyc))
+            writeToFile(Query.notCrosses("location", nyc))
+            writeToFile(Query.overlaps("location", nyc))
+            writeToFile(Query.notOverlaps("location", nyc))
+            writeToFile(Query.touches("location", nyc))
+            writeToFile(Query.notTouches("location", nyc))

225-232: Add edge cases: decimal radius, zero radius, and explicit meters=false.

Catches serialization/typing regressions for Number vs Double and boolean flag handling.

             writeToFile(Query.distanceLessThan("location", nyc, 1000, true))
+
+            // Edge cases
+            writeToFile(Query.distanceEqual("location", nyc, 0))
+            writeToFile(Query.distanceEqual("location", nyc, 1000.5))
+            writeToFile(Query.distanceGreaterThan("location", nyc, 999.9, false))
+            writeToFile(Query.distanceLessThan("location", nyc, 1000.1, false))

234-242: Include at least one polygon/line geometry to exercise nested array encoding.

Point-only inputs don’t stress the serializer for crosses/overlaps/touches; polygons/lines will.

             writeToFile(Query.notTouches("location", nyc))
+
+            // Additional geometry inputs
+            val square: List<List<List<Double>>> = listOf(
+                listOf(
+                    listOf(-74.01, 40.70), listOf(-74.00, 40.70),
+                    listOf(-74.00, 40.71), listOf(-74.01, 40.71),
+                    listOf(-74.01, 40.70)
+                )
+            )
+            val line: List<List<Double>> = listOf(
+                listOf(-74.01, 40.705), listOf(-74.00, 40.705)
+            )
+            writeToFile(Query.intersects("location", square))
+            writeToFile(Query.overlaps("location", square))
+            writeToFile(Query.crosses("location", line))

223-243: Optional: assert minimal structure to catch regressions, not just log.

Keep file logging, but add a couple of substring assertions to verify operator names and bracket structure.

-            writeToFile(Query.distanceEqual("location", nyc, 1000))
+            val q = Query.distanceEqual("location", nyc, 1000)
+            org.junit.Assert.assertTrue(q.startsWith("distanceEqual("))
+            writeToFile(q)
tests/languages/dotnet/Tests.cs (2)

172-181: Prefer strong typing and avoid repetition in distance tests

Use List and reuse a single coordinates/radius instance for clarity and better overload resolution.

-            // Spatial Distance query tests
-            TestContext.WriteLine(Query.DistanceEqual("location", new List<object> { 40.7128, -74.0060 }, 1000));
-            TestContext.WriteLine(Query.DistanceEqual("location", new List<object> { 40.7128, -74.0060 }, 1000, true));
-            TestContext.WriteLine(Query.DistanceNotEqual("location", new List<object> { 40.7128, -74.0060 }, 1000));
-            TestContext.WriteLine(Query.DistanceNotEqual("location", new List<object> { 40.7128, -74.0060 }, 1000, true));
-            TestContext.WriteLine(Query.DistanceGreaterThan("location", new List<object> { 40.7128, -74.0060 }, 1000));
-            TestContext.WriteLine(Query.DistanceGreaterThan("location", new List<object> { 40.7128, -74.0060 }, 1000, true));
-            TestContext.WriteLine(Query.DistanceLessThan("location", new List<object> { 40.7128, -74.0060 }, 1000));
-            TestContext.WriteLine(Query.DistanceLessThan("location", new List<object> { 40.7128, -74.0060 }, 1000, true));
+            // Spatial Distance query tests
+            var coords = new List<double> { 40.7128, -74.0060 };
+            var radius = 1000;
+            TestContext.WriteLine(Query.DistanceEqual("location", coords, radius));
+            TestContext.WriteLine(Query.DistanceEqual("location", coords, radius, true));
+            TestContext.WriteLine(Query.DistanceNotEqual("location", coords, radius));
+            TestContext.WriteLine(Query.DistanceNotEqual("location", coords, radius, true));
+            TestContext.WriteLine(Query.DistanceGreaterThan("location", coords, radius));
+            TestContext.WriteLine(Query.DistanceGreaterThan("location", coords, radius, true));
+            TestContext.WriteLine(Query.DistanceLessThan("location", coords, radius));
+            TestContext.WriteLine(Query.DistanceLessThan("location", coords, radius, true));

183-191: Reuse typed coordinates for spatial predicates

Keep consistency with the distance block and avoid recreating lists.

-            // Spatial query tests
-            TestContext.WriteLine(Query.Intersects("location", new List<object> { 40.7128, -74.0060 }));
-            TestContext.WriteLine(Query.NotIntersects("location", new List<object> { 40.7128, -74.0060 }));
-            TestContext.WriteLine(Query.Crosses("location", new List<object> { 40.7128, -74.0060 }));
-            TestContext.WriteLine(Query.NotCrosses("location", new List<object> { 40.7128, -74.0060 }));
-            TestContext.WriteLine(Query.Overlaps("location", new List<object> { 40.7128, -74.0060 }));
-            TestContext.WriteLine(Query.NotOverlaps("location", new List<object> { 40.7128, -74.0060 }));
-            TestContext.WriteLine(Query.Touches("location", new List<object> { 40.7128, -74.0060 }));
-            TestContext.WriteLine(Query.NotTouches("location", new List<object> { 40.7128, -74.0060 }));
+            // Spatial query tests
+            TestContext.WriteLine(Query.Intersects("location", coords));
+            TestContext.WriteLine(Query.NotIntersects("location", coords));
+            TestContext.WriteLine(Query.Crosses("location", coords));
+            TestContext.WriteLine(Query.NotCrosses("location", coords));
+            TestContext.WriteLine(Query.Overlaps("location", coords));
+            TestContext.WriteLine(Query.NotOverlaps("location", coords));
+            TestContext.WriteLine(Query.Touches("location", coords));
+            TestContext.WriteLine(Query.NotTouches("location", coords));
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d5b7173 and edfd144.

📒 Files selected for processing (15)
  • tests/Base.php (1 hunks)
  • tests/languages/android/Tests.kt (1 hunks)
  • tests/languages/apple/Tests.swift (1 hunks)
  • tests/languages/dart/tests.dart (1 hunks)
  • tests/languages/deno/tests.ts (1 hunks)
  • tests/languages/dotnet/Tests.cs (1 hunks)
  • tests/languages/flutter/tests.dart (1 hunks)
  • tests/languages/go/tests.go (1 hunks)
  • tests/languages/kotlin/Tests.kt (1 hunks)
  • tests/languages/node/test.js (1 hunks)
  • tests/languages/php/test.php (1 hunks)
  • tests/languages/python/tests.py (1 hunks)
  • tests/languages/ruby/tests.rb (1 hunks)
  • tests/languages/swift/Tests.swift (1 hunks)
  • tests/languages/web/node.js (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
tests/languages/android/Tests.kt (1)
tests/languages/kotlin/Tests.kt (1)
  • writeToFile (235-238)
tests/languages/kotlin/Tests.kt (1)
tests/languages/android/Tests.kt (1)
  • writeToFile (268-271)
🔇 Additional comments (16)
tests/languages/go/tests.go (2)

223-241: LGTM: added spatial distance and predicate query coverage fits the new builders.


223-241: Confirm coordinate order and units semantics.
Many spatial APIs expect [lon, lat] (GeoJSON) while others use [lat, lon]. Also, clarify what the bool flag toggles (meters vs kilometers). Ensure the test data matches the builder’s expected shape so the serialized strings are correct; adjust the order or add a short comment if needed.

tests/languages/flutter/tests.dart (1)

208-217: Add polygon and line test cases and verify coordinate ordering

  • Single-point tests don’t cover complex geometries—include a small polygon (e.g., box around NYC) and a line crossing it to validate shape encoding.
  • GeoJSON expects [longitude, latitude]; ensure the Flutter SDK handles coord order consistently with other languages.
tests/languages/dart/tests.dart (1)

173-182: DRY constants & confirm coordinate order

  • Optional: hoist [40.7128, -74.0060] and 1000 into final location and const radius to reduce repetition.
  • Confirm expected coordinate ordering ([latitude, longitude] vs [longitude, latitude]).
  • All existing language tests cover only the default (no flag) and explicit true cases; adding an explicit false in Dart alone breaks parity—either omit it here or introduce false-case tests across all languages.
tests/languages/kotlin/Tests.kt (2)

191-210: Baseline coverage for new methods looks good.

Both overloads are exercised and aligned with existing query helper test style.


202-210: Exercise polygon inputs for spatial predicates
Add a closed‐ring polygon example to Tests.kt to ensure nested arrays serialize correctly, for example:

// Simple polygon around lower Manhattan (closed ring)
val polygon = listOf(
    listOf(
        listOf(-74.018, 40.700), listOf(-74.018, 40.740),
        listOf(-73.990, 40.740), listOf(-73.990, 40.700),
        listOf(-74.018, 40.700)
    )
)
writeToFile(Query.intersects("location", polygon))
writeToFile(Query.overlaps("location", polygon))

Confirm the expected coordinate order (lon, lat vs. lat, lon) in the Kotlin template before merging.

tests/languages/node/test.js (2)

275-293: LGTM: good coverage for new spatial query APIs.

The added calls exercise all four distance and eight spatial predicates. This helps validate serialization for both default and explicit meters flags.


285-293: Verify coordinate order in Node spatial predicates
Tests at tests/languages/node/test.js lines 286–293 use [40.7128, -74.0060] (lat, lon); confirm the SDK expects [lon, lat] or GeoJSON geometries, and add a non-point (e.g. polygon or linestring) example if supported.

tests/languages/apple/Tests.swift (1)

198-207: Swift Query distance methods use correct parameter labels
Confirmed that distanceEqual, distanceNotEqual, distanceGreaterThan, and distanceLessThan in Query.swift are defined with the values:, distance:, and meters: labels, matching the test invocations.

tests/languages/deno/tests.ts (3)

191-209: Cross-language parity verified. Deno test calls for spatial queries match other SDKs in method names, argument order, and default handling.


201-208: Ignore geometry type validation for spatial predicates. Appwrite’s SDK methods for intersects, crosses, overlaps, etc., simply serialize whatever JSON is passed and the backend currently has no built-in spatial operators or GeoJSON requirements; using point arrays is consistent across all language SDKs.

Likely an incorrect or invalid review comment.


191-198: Confirm default meters flag and serialized payload shape for all distance helpers*

  • Omitting the 4th argument must default to false.
  • Queries should serialize as [[values, distance, meters]], with the meters boolean always present and in the third position.
tests/languages/swift/Tests.swift (2)

188-207: Spatial query tests added — LGTM.

Good coverage of the new distance and spatial predicates, consistent with existing print-style tests in this file.


188-207: Ignore the values: vs. value: warning for spatial methods; they correctly use values: to accept multiple coordinates.

Likely an incorrect or invalid review comment.

tests/languages/dotnet/Tests.cs (2)

172-191: Spatial tests addition looks good

Covers both default and meters=true paths for distance, and all predicate variants. Nice parity with other language suites.


172-191: Verify geospatial parameter semantics
Confirm that the Distance* query methods expect coordinates in [longitude, latitude] order (not [latitude, longitude]) and validate whether meters=false defaults to kilometers (and true to meters) against the server implementation to avoid mismatched queries.

tests/Base.php Outdated
Comment on lines 121 to 136
'{"method":"distanceEqual","attribute":"location","values":[[[40.7128,-74.0060],1000,false]]}',
'{"method":"distanceEqual","attribute":"location","values":[[[40.7128,-74.0060],1000,true]]}',
'{"method":"distanceNotEqual","attribute":"location","values":[[[40.7128,-74.0060],1000,false]]}',
'{"method":"distanceNotEqual","attribute":"location","values":[[[40.7128,-74.0060],1000,true]]}',
'{"method":"distanceGreaterThan","attribute":"location","values":[[[40.7128,-74.0060],1000,false]]}',
'{"method":"distanceGreaterThan","attribute":"location","values":[[[40.7128,-74.0060],1000,true]]}',
'{"method":"distanceLessThan","attribute":"location","values":[[[40.7128,-74.0060],1000,false]]}',
'{"method":"distanceLessThan","attribute":"location","values":[[[40.7128,-74.0060],1000,true]]}',
'{"method":"intersects","attribute":"location","values":[[40.7128,-74.0060]]}',
'{"method":"notIntersects","attribute":"location","values":[[40.7128,-74.0060]]}',
'{"method":"crosses","attribute":"location","values":[[40.7128,-74.0060]]}',
'{"method":"notCrosses","attribute":"location","values":[[40.7128,-74.0060]]}',
'{"method":"overlaps","attribute":"location","values":[[40.7128,-74.0060]]}',
'{"method":"notOverlaps","attribute":"location","values":[[40.7128,-74.0060]]}',
'{"method":"touches","attribute":"location","values":[[40.7128,-74.0060]]}',
'{"method":"notTouches","attribute":"location","values":[[40.7128,-74.0060]]}',
Copy link

@coderabbitai coderabbitai bot Sep 3, 2025

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Distance/spatial expected payloads look consistent; verify meters flag and coord order across SDKs

Good additions. Two asks to avoid flaky cross-language failures:

  • Ensure every SDK always serializes distance tuple as [[coords, distance, meters]] even when meters is omitted (should default to false and still be emitted).
  • Confirm the coordinate order is the intended one for Appwrite (you use [40.7128, -74.0060] = [lat, lon]). If the platform expects GeoJSON order [lon, lat], adjust tests/templates accordingly.

Run this to spot-check templates for explicit meters handling and surface occurrences to review:


🏁 Script executed:

#!/bin/bash
set -euo pipefail
echo "Distance methods across templates:"
rg -nP -C2 '(distanceEqual|distanceNotEqual|distanceGreaterThan|distanceLessThan)' templates

echo -e "\nMeters flag usage across templates:"
rg -nP -C2 '\bmeters\b' templates

echo -e "\nDistance method calls in tests (3-arg vs 4-arg):"
rg -nP -n 'distance(Equal|NotEqual|GreaterThan|LessThan)\s*\(' tests/languages -g '!**/node_modules/**'

Length of output: 65030


🌐 Web query:

For Appwrite Database spatial queries, what is the authoritative coordinate order for points in Query helpers (latitude, longitude vs longitude, latitude)?

💡 Result:

Authoritative order is longitude, latitude (x, y) — follow the GeoJSON / RFC 7946 convention. [1][2]

Note: Appwrite docs don't clearly state a different canonical order; community threads show Appwrite users storing separate latitude/longitude fields. If you use GeoJSON-style positions or any spatial helpers that follow common GIS conventions, send coordinates as [longitude, latitude]. [3][4]

Sources:

  • RFC 7946 (GeoJSON: "first two elements are longitude and latitude"). [1]
  • GeoJSON explainer (summary of lon,lat order). [2]
  • Appwrite forum thread discussing GeoPoint usage / storing lat & lon. [3]
  • Appwrite threads about location queries and bounding calculations. [4]

Swap coordinate order to [longitude, latitude] per GeoJSON compliance

Default meters flag is already emitted across all SDKs and requires no changes. Update all test payloads and examples (e.g. tests/Base.php lines 121–136 and tests/languages/*) to use [-74.0060, 40.7128] instead of [40.7128, -74.0060], aligning with the GeoJSON (RFC 7946) [lon, lat] convention.

🤖 Prompt for AI Agents
In tests/Base.php around lines 121 to 136, the geolocation coordinate arrays are
using [latitude, longitude] (e.g. [40.7128,-74.0060]) but must follow GeoJSON
RFC 7946 [longitude, latitude]; update every occurrence in this block to swap
the two values to [-74.0060,40.7128] (and do the same for similar examples under
tests/languages/*), ensuring all test payload strings retain their original
structure and flags but with coordinates reordered to [lon, lat].

Copy link
Member

Choose a reason for hiding this comment

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

@ArnabChatterjee20k Is this legit 🤔 should we flip them?

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

@ArnabChatterjee20k ArnabChatterjee20k force-pushed the spatial-type-queries branch 2 times, most recently from 07581a7 to 89804f6 Compare September 3, 2025 15:47
Copy link

@coderabbitai coderabbitai bot left a comment

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 (1)
templates/deno/src/query.ts.twig (1)

1-15: Type hole: QueryTypes/QueryTypesList don’t allow the distance payload tuple.

The new distance helpers pass [any[], number, boolean], which isn’t assignable to QueryTypes or QueryTypesList and will fail TS type-checking. Introduce a dedicated tuple type and widen the class to accept it.

 type QueryTypesSingle = string | number | boolean;
-export type QueryTypesList = string[] | number[] | boolean[] | Query[];
-export type QueryTypes = QueryTypesSingle | QueryTypesList;
+export type QueryTypesList = string[] | number[] | boolean[] | Query[];
+export type QueryTypes = QueryTypesSingle | QueryTypesList;
+// Distance payload: [coordinates/geometry, distance, meters?]
+export type DistancePayload = [any[], number, boolean];
+export type QueryValues = QueryTypesList | DistancePayload;

 export class Query {
   method: string;
   attribute: AttributesTypes | undefined;
-  values: QueryTypesList | undefined;
+  values: QueryValues | undefined;

   constructor(
     method: string,
     attribute?: AttributesTypes,
-    values?: QueryTypes
+    values?: QueryValues
   ) {
🧹 Nitpick comments (2)
templates/dart/lib/query.dart.twig (1)

170-184: Dedup the 4 distance helpers with a tiny private helper.

Reduces repetition and keeps payload shape consistent.

-  /// Filter resources where [attribute] is at a specific distance from the given coordinates.
-  static String distanceEqual(String attribute, List<dynamic> values, double distance, [bool meters = false]) =>
-      Query._('distanceEqual', attribute, [values, distance, meters]).toString();
+  static String _distance(String op, String attribute, List<dynamic> values, double distance, [bool meters = false]) =>
+      Query._(op, attribute, [values, distance, meters]).toString();
+
+  /// Filter resources where [attribute] is at a specific distance from the given coordinates.
+  static String distanceEqual(String attribute, List<dynamic> values, double distance, [bool meters = false]) =>
+      _distance('distanceEqual', attribute, values, distance, meters);
 
   /// Filter resources where [attribute] is not at a specific distance from the given coordinates.
-  static String distanceNotEqual(String attribute, List<dynamic> values, double distance, [bool meters = false]) =>
-      Query._('distanceNotEqual', attribute, [values, distance, meters]).toString();
+  static String distanceNotEqual(String attribute, List<dynamic> values, double distance, [bool meters = false]) =>
+      _distance('distanceNotEqual', attribute, values, distance, meters);
 
   /// Filter resources where [attribute] is at a distance greater than the specified value from the given coordinates.
-  static String distanceGreaterThan(String attribute, List<dynamic> values, double distance, [bool meters = false]) =>
-      Query._('distanceGreaterThan', attribute, [values, distance, meters]).toString();
+  static String distanceGreaterThan(String attribute, List<dynamic> values, double distance, [bool meters = false]) =>
+      _distance('distanceGreaterThan', attribute, values, distance, meters);
 
   /// Filter resources where [attribute] is at a distance less than the specified value from the given coordinates.
-  static String distanceLessThan(String attribute, List<dynamic> values, double distance, [bool meters = false]) =>
-      Query._('distanceLessThan', attribute, [values, distance, meters]).toString();
+  static String distanceLessThan(String attribute, List<dynamic> values, double distance, [bool meters = false]) =>
+      _distance('distanceLessThan', attribute, values, distance, meters);
templates/android/library/src/main/java/io/package/Query.kt.twig (1)

289-332: Factor a private distance builder to remove repetition; clarify units in KDoc.

Keeps payload stable and improves readability; briefly note what meters=false means.

-        fun distanceEqual(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) = Query("distanceEqual", attribute, listOf(values, distance, meters)).toJson()
+        private fun distance(op: String, attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) =
+            Query(op, attribute, listOf(values, distance, meters)).toJson()
+        /** Filter where attribute is at a specific distance from coordinates. meters=false: document unit the server expects (clarify). */
+        fun distanceEqual(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) =
+            distance("distanceEqual", attribute, values, distance, meters)
 
-        fun distanceNotEqual(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) = Query("distanceNotEqual", attribute, listOf(values, distance, meters)).toJson()
+        fun distanceNotEqual(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) =
+            distance("distanceNotEqual", attribute, values, distance, meters)
 
-        fun distanceGreaterThan(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) = Query("distanceGreaterThan", attribute, listOf(values, distance, meters)).toJson()
+        fun distanceGreaterThan(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) =
+            distance("distanceGreaterThan", attribute, values, distance, meters)
 
-        fun distanceLessThan(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) = Query("distanceLessThan", attribute, listOf(values, distance, meters)).toJson()
+        fun distanceLessThan(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) =
+            distance("distanceLessThan", attribute, values, distance, meters)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b5b22bd and 9c57616.

📒 Files selected for processing (12)
  • templates/android/library/src/main/java/io/package/Query.kt.twig (1 hunks)
  • templates/dart/lib/query.dart.twig (1 hunks)
  • templates/deno/src/query.ts.twig (1 hunks)
  • templates/go/query.go.twig (1 hunks)
  • templates/kotlin/src/main/kotlin/io/appwrite/Query.kt.twig (1 hunks)
  • templates/php/src/Query.php.twig (1 hunks)
  • templates/python/package/query.py.twig (1 hunks)
  • templates/react-native/src/query.ts.twig (1 hunks)
  • templates/ruby/lib/container/query.rb.twig (1 hunks)
  • templates/swift/Sources/Query.swift.twig (1 hunks)
  • templates/web/src/query.ts.twig (1 hunks)
  • tests/Base.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (9)
  • templates/react-native/src/query.ts.twig
  • templates/web/src/query.ts.twig
  • templates/python/package/query.py.twig
  • tests/Base.php
  • templates/swift/Sources/Query.swift.twig
  • templates/ruby/lib/container/query.rb.twig
  • templates/php/src/Query.php.twig
  • templates/go/query.go.twig
  • templates/kotlin/src/main/kotlin/io/appwrite/Query.kt.twig
🔇 Additional comments (3)
templates/dart/lib/query.dart.twig (1)

186-216: Spatial relation helpers look good.

Payloads and naming are consistent with the rest of the template.

templates/deno/src/query.ts.twig (1)

248-326: Spatial relation helpers: consistent and fine.

No type issues; payload is any[] which matches existing patterns.

templates/android/library/src/main/java/io/package/Query.kt.twig (1)

334-403: Spatial relation helpers look consistent and correct.

Names and payloads align with other SDKs.

@ArnabChatterjee20k ArnabChatterjee20k force-pushed the spatial-type-queries branch 2 times, most recently from f0d2467 to e32b5ea Compare September 3, 2025 16:39
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
templates/swift/Sources/Query.swift.twig (2)

11-27: Add Codable support for .array and fix non-exhaustive switch (compile-time error).

.array was added to QueryValue but init(from:) and encode(to:) don’t handle it. Encoding will not compile, and decoding or/and payloads with nested arrays will fail.

Apply:

@@
     init(from decoder: Decoder) throws {
         let container = try decoder.singleValueContainer()
@@
-        } else if let queryValue = try? container.decode(Query.self) {
-            self = .query(queryValue)
+        } else if let queryValue = try? container.decode(Query.self) {
+            self = .query(queryValue)
+        } else if let arrayValue = try? container.decode([QueryValue].self) {
+            self = .array(arrayValue)
         } else {
             throw DecodingError.dataCorruptedError(in: container, debugDescription: "QueryValue cannot be decoded")
         }
     }
@@
     func encode(to encoder: Encoder) throws {
         var container = encoder.singleValueContainer()
         switch self {
@@
         case .query(let value):
             try container.encode(value)
+        case .array(let value):
+            try container.encode(value)
         }
     }

Also applies to: 29-43


89-91: Fix [Any] mapping: double return + scalars incorrectly wrapped as arrays.

Current code won’t compile and turns numbers/bools into .array([.double/.bool]). Replace with recursive element mapping plus a helper.

Apply:

-        case let anyArray as [Any]:
-            return return [.array(anyArray.compactMap { convertToQueryValueArray($0).map { .array($0) } })]
+        case let anyArray as [Any]:
+            return anyArray.compactMap { convertAnyToQueryValue($0) }

Add this helper inside Query (below convertToQueryValueArray):

private static func convertAnyToQueryValue(_ value: Any) -> QueryValue? {
    switch value {
    case let v as String: return .string(v)
    case let v as Int:    return .int(v)
    case let v as Double: return .double(v)
    case let v as Bool:   return .bool(v)
    case let v as Query:  return .query(v)
    case let v as [Any]:
        let mapped = v.compactMap { convertAnyToQueryValue($0) }
        return .array(mapped)
    default:
        return nil
    }
}
🧹 Nitpick comments (4)
templates/swift/Sources/Query.swift.twig (2)

404-434: Distance payload shape OK; relies on heterogeneous/nested array support.

Once the converter/Codable fixes land, these will serialize as [values, distance, meters] as intended. Optionally assert non-negative distance to catch misuse early.

Example:

-    public static func distanceEqual(_ attribute: String, values: [Any], distance: Double, meters: Bool = false) -> String {
+    public static func distanceEqual(_ attribute: String, values: [Any], distance: Double, meters: Bool = false) -> String {
+        precondition(distance >= 0, "distance must be non-negative")
         return Query(
             method: "distanceEqual",
             attribute: attribute,
             values: [values, distance, meters]
         ).description
     }

436-498: Spatial predicate methods look good; depend on recursive array conversion.

As long as values are arrays (e.g., coordinates/rings), serialization will work after the converter fix. If GeoJSON objects are expected, we’ll need dictionary support; otherwise we’re fine.

If GeoJSON dictionaries are needed, confirm and I’ll extend QueryValue/converter to support [String: Any] safely.

tests/languages/dart/tests.dart (2)

174-182: Spatial predicate tests added — consider one complex geometry example.

Point inputs are fine for exercising builders, but a polygon/linestring case would also validate nested array serialization (useful for overlaps/crosses). Optional.


192-192: Strip trailing whitespace on blank line.

Tiny formatting nit to keep diffs clean.

-  
+
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between abaab11 and 538f015.

📒 Files selected for processing (2)
  • templates/swift/Sources/Query.swift.twig (3 hunks)
  • tests/languages/dart/tests.dart (2 hunks)
⏰ 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). (19)
  • GitHub Check: build (8.3, Ruby31)
  • GitHub Check: build (8.3, WebNode)
  • GitHub Check: build (8.3, WebChromium)
  • GitHub Check: build (8.3, Python311)
  • GitHub Check: build (8.3, AppleSwift56)
  • GitHub Check: build (8.3, Swift56)
  • GitHub Check: build (8.3, PHP80)
  • GitHub Check: build (8.3, Python39)
  • GitHub Check: build (8.3, Node18)
  • GitHub Check: build (8.3, Python313)
  • GitHub Check: build (8.3, PHP83)
  • GitHub Check: build (8.3, KotlinJava17)
  • GitHub Check: build (8.3, Go112)
  • GitHub Check: build (8.3, KotlinJava11)
  • GitHub Check: build (8.3, FlutterStable)
  • GitHub Check: build (8.3, FlutterBeta)
  • GitHub Check: build (8.3, DartStable)
  • GitHub Check: build (8.3, Android14Java17)
  • GitHub Check: build (8.3, Android5Java17)
🔇 Additional comments (1)
tests/languages/dart/tests.dart (1)

164-173: Distance query tests approved – positional signatures and [values, distance, meters] payload order match template

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
templates/swift/Sources/Query.swift.twig (2)

9-9: Enum case added but Codable not updated — arrays still won’t encode/decode.

.array([QueryValue]) is introduced but init(from:) and encode(to:) don’t handle it, so nested arrays used by distance/spatial queries won’t serialize and will be dropped on round-trip.

Apply:

 enum QueryValue: Codable {
@@
     init(from decoder: Decoder) throws {
         let container = try decoder.singleValueContainer()
         // Attempt to decode each type
         if let stringValue = try? container.decode(String.self) {
             self = .string(stringValue)
         } else if let intValue = try? container.decode(Int.self) {
             self = .int(intValue)
         } else if let doubleValue = try? container.decode(Double.self) {
             self = .double(doubleValue)
         } else if let boolValue = try? container.decode(Bool.self) {
             self = .bool(boolValue)
         } else if let queryValue = try? container.decode(Query.self) {
             self = .query(queryValue)
+        } else if let arrayValue = try? container.decode([QueryValue].self) {
+            self = .array(arrayValue)
         } else {
             throw DecodingError.dataCorruptedError(in: container, debugDescription: "QueryValue cannot be decoded")
         }
     }
@@
     func encode(to encoder: Encoder) throws {
         var container = encoder.singleValueContainer()
         switch self {
         case .string(let value):
             try container.encode(value)
         case .int(let value):
             try container.encode(value)
         case .double(let value):
             try container.encode(value)
         case .bool(let value):
             try container.encode(value)
         case .query(let value):
             try container.encode(value)
+        case .array(let value):
+            try container.encode(value)
         }
     }

89-91: [Any] conversion is incorrect — produces double-nested .array and collapses elements.

Current code returns a single-element [.array([... .array(...) ...])]. Map each Any to a QueryValue instead.

-        case let anyArray as [Any]:
-            return [.array(anyArray.compactMap { convertToQueryValueArray($0).map { .array($0) } })]
+        case let anyArray as [Any]:
+            return anyArray.compactMap { convertAnyToQueryValue($0) }

Add helper (outside the selected range, inside Query):

private static func convertAnyToQueryValue(_ value: Any) -> QueryValue? {
    switch value {
    case let v as String: return .string(v)
    case let v as Int:    return .int(v)
    case let v as Double: return .double(v)
    case let v as Bool:   return .bool(v)
    case let v as Query:  return .query(v)
    case let v as [Any]:  return .array(v.compactMap { convertAnyToQueryValue($0) })
    default:              return nil
    }
}
🧹 Nitpick comments (3)
templates/swift/Sources/Query.swift.twig (1)

436-498: Clarify/extend support for Geo payload shapes.

If callers may pass GeoJSON objects (dictionaries), QueryValue lacks a dictionary/object case; today only scalars/arrays work. Either document that values must be arrays of scalars/arrays, or add an .object([String: QueryValue]) case plus converter support.

tests/languages/web/index.html (2)

277-285: Spatial predicates: add a polygon/linestring case and parameterize logs

Current calls use a single point array. Add at least one polygon/linestring input to exercise encoding for non-point geometries, and parameterize to avoid repetition.

-            // Spatial query tests
-            console.log(Query.intersects("location", [40.7128, -74]));
-            console.log(Query.notIntersects("location", [40.7128, -74]));
-            console.log(Query.crosses("location", [40.7128, -74]));
-            console.log(Query.notCrosses("location", [40.7128, -74]));
-            console.log(Query.overlaps("location", [40.7128, -74]));
-            console.log(Query.notOverlaps("location", [40.7128, -74]));
-            console.log(Query.touches("location", [40.7128, -74]));
-            console.log(Query.notTouches("location", [40.7128, -74]));
+            // Spatial predicate tests
+            const point = [40.7128, -74];
+            const polygon = [[[-74.02,40.70],[-74.00,40.70],[-74.00,40.72],[-74.02,40.72],[-74.02,40.70]]];
+            [
+              Query.intersects("location", point),
+              Query.notIntersects("location", point),
+              Query.crosses("location", point),
+              Query.notCrosses("location", point),
+              Query.overlaps("location", polygon),
+              Query.notOverlaps("location", polygon),
+              Query.touches("location", point),
+              Query.notTouches("location", point),
+            ].forEach(q => console.log(q));

Please also confirm lat/lon order expected by the builder (here we use [lat, lon]). If the API expects [lon, lat] or GeoJSON geometry, adjust inputs accordingly.


267-276: Distance query tests: dedupe logs, add assertions & verify helpers

  • Replace the eight repetitive console.log(Query.distance… ) calls in tests/languages/web/index.html (lines 267–276) with an array of Query invocations and .forEach to reduce duplication.
  • Add a console.assert to catch regressions, e.g.
    console.assert(Query.distanceEqual("location", pt, radius) !== Query.distanceEqual("location", pt, radius, true), "Expected meters flag to alter serialization");
  • Confirm that the static methods Query.distanceEqual/NotEqual/GreaterThan/LessThan are implemented and exported in the JS SDK.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 538f015 and 7d18e50.

📒 Files selected for processing (2)
  • templates/swift/Sources/Query.swift.twig (3 hunks)
  • tests/languages/web/index.html (1 hunks)
⏰ 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). (17)
  • GitHub Check: build (8.3, AppleSwift56)
  • GitHub Check: build (8.3, Swift56)
  • GitHub Check: build (8.3, WebChromium)
  • GitHub Check: build (8.3, WebNode)
  • GitHub Check: build (8.3, Go118)
  • GitHub Check: build (8.3, Ruby30)
  • GitHub Check: build (8.3, KotlinJava11)
  • GitHub Check: build (8.3, Python311)
  • GitHub Check: build (8.3, PHP83)
  • GitHub Check: build (8.3, Python39)
  • GitHub Check: build (8.3, Node18)
  • GitHub Check: build (8.3, FlutterBeta)
  • GitHub Check: build (8.3, FlutterStable)
  • GitHub Check: build (8.3, Go112)
  • GitHub Check: build (8.3, DotNet90)
  • GitHub Check: build (8.3, Android5Java17)
  • GitHub Check: build (8.3, Android14Java17)
🔇 Additional comments (1)
templates/swift/Sources/Query.swift.twig (1)

404-434: Distance builders rely on proper nested-array encoding — currently broken by converter/Codable gaps.

Once the two fixes above land, these will serialize as [ <values-array>, <distance>, <meters> ] as intended. Please re-run Swift tests for these builders.

Example to validate locally:

let q = Query.distanceLessThan("geo", values: [[10.0,20.0]], distance: 1000, meters: true)
print(q) // expect: {"method":"distanceLessThan","attribute":"geo","values":[[[10,20]],1000,true]}

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (3)
templates/swift/Sources/Query.swift.twig (1)

9-10: Swift nested-array encoding fix looks good (resolves prior drop of values).

Adding case array([QueryValue]) with matching decode/encode handles heterogeneous/nested arrays required by distance queries. This addresses the earlier serialization gap.

Also applies to: 24-26, 47-48

tests/languages/swift/Tests.swift (1)

189-206: Swap to [longitude, latitude] in all spatial tests.

Tests currently use [lat, lon]. Use [lon, lat] to match GeoJSON order and avoid confusion when these examples are copied into real apps.

-        print(Query.distanceEqual("location", values: [[40.7128, -74], [40.7128, -74]], distance: 1000))
-        print(Query.distanceEqual("location", values: [40.7128, -74], distance: 1000, meters: true))
-        print(Query.distanceNotEqual("location", values: [40.7128, -74], distance: 1000))
-        print(Query.distanceNotEqual("location", values: [40.7128, -74], distance: 1000, meters: true))
-        print(Query.distanceGreaterThan("location", values: [40.7128, -74], distance: 1000))
-        print(Query.distanceGreaterThan("location", values: [40.7128, -74], distance: 1000, meters: true))
-        print(Query.distanceLessThan("location", values: [40.7128, -74], distance: 1000))
-        print(Query.distanceLessThan("location", values: [40.7128, -74], distance: 1000, meters: true))
+        print(Query.distanceEqual("location", values: [[-74.0, 40.7128], [-74.0, 40.7128]], distance: 1000))
+        print(Query.distanceEqual("location", values: [-74.0, 40.7128], distance: 1000, meters: true))
+        print(Query.distanceNotEqual("location", values: [-74.0, 40.7128], distance: 1000))
+        print(Query.distanceNotEqual("location", values: [-74.0, 40.7128], distance: 1000, meters: true))
+        print(Query.distanceGreaterThan("location", values: [-74.0, 40.7128], distance: 1000))
+        print(Query.distanceGreaterThan("location", values: [-74.0, 40.7128], distance: 1000, meters: true))
+        print(Query.distanceLessThan("location", values: [-74.0, 40.7128], distance: 1000))
+        print(Query.distanceLessThan("location", values: [-74.0, 40.7128], distance: 1000, meters: true))
@@
-        print(Query.intersects("location", values: [40.7128, -74]))
-        print(Query.notIntersects("location", values: [40.7128, -74]))
-        print(Query.crosses("location", values: [40.7128, -74]))
-        print(Query.notCrosses("location", values: [40.7128, -74]))
-        print(Query.overlaps("location", values: [40.7128, -74]))
-        print(Query.notOverlaps("location", values: [40.7128, -74]))
-        print(Query.touches("location", values: [40.7128, -74]))
-        print(Query.notTouches("location", values: [40.7128, -74]))
+        print(Query.intersects("location", values: [-74.0, 40.7128]))
+        print(Query.notIntersects("location", values: [-74.0, 40.7128]))
+        print(Query.crosses("location", values: [-74.0, 40.7128]))
+        print(Query.notCrosses("location", values: [-74.0, 40.7128]))
+        print(Query.overlaps("location", values: [-74.0, 40.7128]))
+        print(Query.notOverlaps("location", values: [-74.0, 40.7128]))
+        print(Query.touches("location", values: [-74.0, 40.7128]))
+        print(Query.notTouches("location", values: [-74.0, 40.7128]))
templates/go/query.go.twig (1)

321-351: Normalize input and build a typed payload slice before passing to parseQuery.

Use toArray(values) for parity with existing helpers and to ensure single vs. multi inputs serialize consistently. Also pass a named slice instead of taking the address of a composite literal for clarity.

-func DistanceEqual(attribute string, values interface{}, distance float64, meters bool) string {
-	return parseQuery(queryOptions{
-		Method:    "distanceEqual",
-		Attribute: &attribute,
-		Values:    &[]interface{}{values, distance, meters},
-	})
-}
+func DistanceEqual(attribute string, values interface{}, distance float64, meters bool) string {
+	coords := toArray(values)
+	payload := []interface{}{coords, distance, meters}
+	return parseQuery(queryOptions{
+		Method:    "distanceEqual",
+		Attribute: &attribute,
+		Values:    &payload,
+	})
+}
 
-func DistanceNotEqual(attribute string, values interface{}, distance float64, meters bool) string {
-	return parseQuery(queryOptions{
-		Method:    "distanceNotEqual",
-		Attribute: &attribute,
-		Values:    &[]interface{}{values, distance, meters},
-	})
-}
+func DistanceNotEqual(attribute string, values interface{}, distance float64, meters bool) string {
+	coords := toArray(values)
+	payload := []interface{}{coords, distance, meters}
+	return parseQuery(queryOptions{
+		Method:    "distanceNotEqual",
+		Attribute: &attribute,
+		Values:    &payload,
+	})
+}
 
-func DistanceGreaterThan(attribute string, values interface{}, distance float64, meters bool) string {
-	return parseQuery(queryOptions{
-		Method:    "distanceGreaterThan",
-		Attribute: &attribute,
-		Values:    &[]interface{}{values, distance, meters},
-	})
-}
+func DistanceGreaterThan(attribute string, values interface{}, distance float64, meters bool) string {
+	coords := toArray(values)
+	payload := []interface{}{coords, distance, meters}
+	return parseQuery(queryOptions{
+		Method:    "distanceGreaterThan",
+		Attribute: &attribute,
+		Values:    &payload,
+	})
+}
 
-func DistanceLessThan(attribute string, values interface{}, distance float64, meters bool) string {
-	return parseQuery(queryOptions{
-		Method:    "distanceLessThan",
-		Attribute: &attribute,
-		Values:    &[]interface{}{values, distance, meters},
-	})
-}
+func DistanceLessThan(attribute string, values interface{}, distance float64, meters bool) string {
+	coords := toArray(values)
+	payload := []interface{}{coords, distance, meters}
+	return parseQuery(queryOptions{
+		Method:    "distanceLessThan",
+		Attribute: &attribute,
+		Values:    &payload,
+	})
+}

To confirm expected JSON shape for these helpers, run:

#!/bin/bash
# Inspect test expectations for distance* queries
rg -n -C2 -i 'distance(Equal|NotEqual|GreaterThan|LessThan)' tests
🧹 Nitpick comments (10)
templates/swift/Sources/Query.swift.twig (4)

96-119: Preserve empty arrays instead of dropping them.

convertToQueryValueArray returns nil when nestedValues is empty, which omits values entirely. If an empty array is a valid, intentional signal, prefer encoding [] to distinguish “empty” from “absent”.

Apply:

-            return nestedValues.isEmpty ? nil : nestedValues
+            return nestedValues

433-463: Confirm wire contract for distance queries: [coords, distance, meters].

Double-check backend expects the triplet in this exact order and that meters is a Bool flag (vs unit enum). Ensure parity with other SDKs in this PR.

Optional: add brief docs to clarify units and coordinate order for users.

+    /// Returns a query filtering by distance from a coordinate or between two coordinates.
+    /// - Parameters:
+    ///   - attribute: Field name.
+    ///   - values: Either [lon, lat] or [[lon, lat], [lon, lat]].
+    ///   - distance: Radius or threshold distance.
+    ///   - meters: When true, distance is in meters (otherwise default server unit).

465-527: Document expected coordinate order and geometry shape.

Spatial predicates typically expect GeoJSON order [longitude, latitude]. Add a short doc comment to prevent misuse. If polygons/lines are supported, specify the shape format.

+    /// Spatial predicate using GeoJSON-style coordinates.
+    /// - Parameters:
+    ///   - attribute: Field name.
+    ///   - values: Coordinates in [lon, lat] or geometry arrays (e.g., polygon).

529-535: Minor: align numeric types for consistency.

parseValue(_:) funnels primitives into [Any]. Mixed Int/Double in the same coordinate array is fine in JSON, but consider normalizing to Double when values represent coordinates to avoid subtle test discrepancies.

tests/languages/swift/Tests.swift (1)

189-197: Optional: diversify distance test data.

Using two identical points for distanceEqual doesn’t help spot regressions. Consider two distinct points to better exercise comparisons.

-        print(Query.distanceEqual("location", values: [[-74.0, 40.7128], [-74.0, 40.7128]], distance: 1000))
+        print(Query.distanceEqual("location", values: [[-74.0060, 40.7128], [-73.9352, 40.7306]], distance: 1000))
tests/languages/kotlin/Tests.kt (2)

201-210: Use geometry-appropriate inputs for spatial predicates.

crosses/overlaps/touches typically require line/polygon geometries; a point may be semantically weak. Consider adding polygon/line cases in addition to the point.

Example additions (place after Line 210):

// Additional geometry cases for stronger coverage
val line = listOf(listOf(40.7120, -74.0100), listOf(40.7150, -74.0000))
val polygon = listOf(
    listOf(
        listOf(40.7100, -74.0150),
        listOf(40.7100, -73.9950),
        listOf(40.7250, -73.9950),
        listOf(40.7250, -74.0150),
        listOf(40.7100, -74.0150)
    )
)
writeToFile(Query.intersects("location", polygon))
writeToFile(Query.crosses("location", line))
writeToFile(Query.overlaps("location", polygon))
writeToFile(Query.touches("location", polygon))

191-200: Use Doubles for coordinates in Kotlin tests

Mixing Double and Int literals (e.g. -74 vs -74.0) can lead to inconsistent JSON across SDKs. Update all coordinate literals in tests/languages/kotlin/Tests.kt to Double:

-            writeToFile(Query.distanceEqual("location", listOf(listOf(40.7128, -74), listOf(40.7128, -74)), 1000))
+            writeToFile(Query.distanceEqual("location", listOf(listOf(40.7128, -74.0), listOf(40.7128, -74.0)), 1000))
-            writeToFile(Query.distanceEqual("location", listOf(40.7128, -74), 1000, true))
+            writeToFile(Query.distanceEqual("location", listOf(40.7128, -74.0), 1000, true))
-            writeToFile(Query.distanceNotEqual("location", listOf(40.7128, -74), 1000))
+            writeToFile(Query.distanceNotEqual("location", listOf(40.7128, -74.0), 1000))
-            writeToFile(Query.distanceNotEqual("location", listOf(40.7128, -74), 1000, true))
+            writeToFile(Query.distanceNotEqual("location", listOf(40.7128, -74.0), 1000, true))
-            writeToFile(Query.distanceGreaterThan("location", listOf(40.7128, -74), 1000))
+            writeToFile(Query.distanceGreaterThan("location", listOf(40.7128, -74.0), 1000))
-            writeToFile(Query.distanceGreaterThan("location", listOf(40.7128, -74), 1000, true))
+            writeToFile(Query.distanceGreaterThan("location", listOf(40.7128, -74.0), 1000, true))
-            writeToFile(Query.distanceLessThan("location", listOf(40.7128, -74), 1000))
+            writeToFile(Query.distanceLessThan("location", listOf(40.7128, -74.0), 1000))
-            writeToFile(Query.distanceLessThan("location", listOf(40.7128, -74), 1000, true))
+            writeToFile(Query.distanceLessThan("location", listOf(40.7128, -74.0), 1000, true))

Run to confirm no mixed-int coords remain:

rg -nP -C1 '40\.7128,\s*-74(\D)' tests/languages/kotlin/Tests.kt
tests/languages/dotnet/Tests.cs (3)

172-181: Use [lon, lat] ordering and consistent numeric types for points; DRY the repeated coords.

Likely the API expects GeoJSON order [longitude, latitude]. Current tests use [40.7128, -74] (lat, lon) and mix double/int, which can serialize inconsistently across locales. Also, the coordinate literal is repeated 8x.

Please confirm the expected coordinate order in the generator/API. If it is [lon, lat], consider this refactor for clarity and consistency:

-            // Spatial Distance query tests
-            TestContext.WriteLine(Query.DistanceEqual("location", new List<List<object>> { new List<object> { 40.7128, -74 }, new List<object> { 40.7128, -74 } }, 1000));
-            TestContext.WriteLine(Query.DistanceEqual("location", new List<object> { 40.7128, -74 }, 1000, true));
-            TestContext.WriteLine(Query.DistanceNotEqual("location", new List<object> { 40.7128, -74 }, 1000));
-            TestContext.WriteLine(Query.DistanceNotEqual("location", new List<object> { 40.7128, -74 }, 1000, true));
-            TestContext.WriteLine(Query.DistanceGreaterThan("location", new List<object> { 40.7128, -74 }, 1000));
-            TestContext.WriteLine(Query.DistanceGreaterThan("location", new List<object> { 40.7128, -74 }, 1000, true));
-            TestContext.WriteLine(Query.DistanceLessThan("location", new List<object> { 40.7128, -74 }, 1000));
-            TestContext.WriteLine(Query.DistanceLessThan("location", new List<object> { 40.7128, -74 }, 1000, true));
+            // Spatial Distance query tests
+            var nyc = new List<object> { -74.0, 40.7128 }; // [lon, lat]
+            var nycPair = new List<List<object>> { nyc, nyc };
+            TestContext.WriteLine(Query.DistanceEqual("location", nycPair, 1000));
+            TestContext.WriteLine(Query.DistanceEqual("location", nyc, 1000, true));
+            TestContext.WriteLine(Query.DistanceNotEqual("location", nyc, 1000));
+            TestContext.WriteLine(Query.DistanceNotEqual("location", nyc, 1000, true));
+            TestContext.WriteLine(Query.DistanceGreaterThan("location", nyc, 1000));
+            TestContext.WriteLine(Query.DistanceGreaterThan("location", nyc, 1000, true));
+            TestContext.WriteLine(Query.DistanceLessThan("location", nyc, 1000));
+            TestContext.WriteLine(Query.DistanceLessThan("location", nyc, 1000, true));

Additionally, if the last bool is a unit flag, prefer named argument usage once you confirm the parameter name (e.g., meters: true) to improve readability.


172-181: Add at least one assertion to make the new tests meaningful beyond compile-time.

Right now these lines only print. Add a minimal assertion to catch serialization regressions.

-            TestContext.WriteLine(Query.DistanceLessThan("location", nyc, 1000, true));
+            var distanceQuery = Query.DistanceLessThan("location", nyc, 1000, true);
+            TestContext.WriteLine(distanceQuery);
+            Assert.That(distanceQuery, Does.StartWith("distanceLessThan("));

If you have a canonical expected string format, assert the full string instead.


182-191: Reuse the extracted point and keep ordering consistent for spatial predicates.

Mirror the same [lon, lat] ordering and avoid repeating literals.

-            // Spatial query tests
-            TestContext.WriteLine(Query.Intersects("location", new List<object> { 40.7128, -74 }));
-            TestContext.WriteLine(Query.NotIntersects("location", new List<object> { 40.7128, -74 }));
-            TestContext.WriteLine(Query.Crosses("location", new List<object> { 40.7128, -74 }));
-            TestContext.WriteLine(Query.NotCrosses("location", new List<object> { 40.7128, -74 }));
-            TestContext.WriteLine(Query.Overlaps("location", new List<object> { 40.7128, -74 }));
-            TestContext.WriteLine(Query.NotOverlaps("location", new List<object> { 40.7128, -74 }));
-            TestContext.WriteLine(Query.Touches("location", new List<object> { 40.7128, -74 }));
-            TestContext.WriteLine(Query.NotTouches("location", new List<object> { 40.7128, -74 }));
+            // Spatial query tests
+            TestContext.WriteLine(Query.Intersects("location", nyc));
+            TestContext.WriteLine(Query.NotIntersects("location", nyc));
+            TestContext.WriteLine(Query.Crosses("location", nyc));
+            TestContext.WriteLine(Query.NotCrosses("location", nyc));
+            TestContext.WriteLine(Query.Overlaps("location", nyc));
+            TestContext.WriteLine(Query.NotOverlaps("location", nyc));
+            TestContext.WriteLine(Query.Touches("location", nyc));
+            TestContext.WriteLine(Query.NotTouches("location", nyc));

Optional: add one assertion here too (e.g., StartsWith("intersects(")).

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7d18e50 and c0cb073.

📒 Files selected for processing (18)
  • templates/go/query.go.twig (1 hunks)
  • templates/swift/Sources/Query.swift.twig (5 hunks)
  • tests/Base.php (1 hunks)
  • tests/languages/android/Tests.kt (1 hunks)
  • tests/languages/apple/Tests.swift (1 hunks)
  • tests/languages/dart/tests.dart (2 hunks)
  • tests/languages/deno/tests.ts (1 hunks)
  • tests/languages/dotnet/Tests.cs (1 hunks)
  • tests/languages/flutter/tests.dart (1 hunks)
  • tests/languages/go/tests.go (1 hunks)
  • tests/languages/kotlin/Tests.kt (1 hunks)
  • tests/languages/node/test.js (1 hunks)
  • tests/languages/php/test.php (1 hunks)
  • tests/languages/python/tests.py (1 hunks)
  • tests/languages/ruby/tests.rb (1 hunks)
  • tests/languages/swift/Tests.swift (1 hunks)
  • tests/languages/web/index.html (1 hunks)
  • tests/languages/web/node.js (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (13)
  • tests/languages/web/index.html
  • tests/languages/node/test.js
  • tests/languages/android/Tests.kt
  • tests/languages/ruby/tests.rb
  • tests/languages/apple/Tests.swift
  • tests/Base.php
  • tests/languages/flutter/tests.dart
  • tests/languages/deno/tests.ts
  • tests/languages/dart/tests.dart
  • tests/languages/go/tests.go
  • tests/languages/web/node.js
  • tests/languages/python/tests.py
  • tests/languages/php/test.php
🧰 Additional context used
🧬 Code graph analysis (1)
tests/languages/kotlin/Tests.kt (1)
tests/languages/android/Tests.kt (1)
  • writeToFile (268-271)
🔇 Additional comments (1)
tests/languages/kotlin/Tests.kt (1)

191-200: Confirm Kotlin spatial query overloads accept both single-point and multi-point inputs.
Tests use both List<Double> and List<List<Double>> for distanceEqual (and related methods); please verify the method signatures in Query.kt and their serialization logic correctly handle both shapes.

Comment on lines 172 to 191
// Spatial Distance query tests
TestContext.WriteLine(Query.DistanceEqual("location", new List<List<object>> { new List<object> { 40.7128, -74 }, new List<object> { 40.7128, -74 } }, 1000));
TestContext.WriteLine(Query.DistanceEqual("location", new List<object> { 40.7128, -74 }, 1000, true));
TestContext.WriteLine(Query.DistanceNotEqual("location", new List<object> { 40.7128, -74 }, 1000));
TestContext.WriteLine(Query.DistanceNotEqual("location", new List<object> { 40.7128, -74 }, 1000, true));
TestContext.WriteLine(Query.DistanceGreaterThan("location", new List<object> { 40.7128, -74 }, 1000));
TestContext.WriteLine(Query.DistanceGreaterThan("location", new List<object> { 40.7128, -74 }, 1000, true));
TestContext.WriteLine(Query.DistanceLessThan("location", new List<object> { 40.7128, -74 }, 1000));
TestContext.WriteLine(Query.DistanceLessThan("location", new List<object> { 40.7128, -74 }, 1000, true));

// Spatial query tests
TestContext.WriteLine(Query.Intersects("location", new List<object> { 40.7128, -74 }));
TestContext.WriteLine(Query.NotIntersects("location", new List<object> { 40.7128, -74 }));
TestContext.WriteLine(Query.Crosses("location", new List<object> { 40.7128, -74 }));
TestContext.WriteLine(Query.NotCrosses("location", new List<object> { 40.7128, -74 }));
TestContext.WriteLine(Query.Overlaps("location", new List<object> { 40.7128, -74 }));
TestContext.WriteLine(Query.NotOverlaps("location", new List<object> { 40.7128, -74 }));
TestContext.WriteLine(Query.Touches("location", new List<object> { 40.7128, -74 }));
TestContext.WriteLine(Query.NotTouches("location", new List<object> { 40.7128, -74 }));

Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify .NET method signatures and the meaning of the trailing bool.

Before merging, confirm the generated C# signatures match these call sites (esp. whether values accept both point and point[] for distance ops) and whether the trailing boolean indeed means “meters”.

Run this script to inspect the signatures and parameter names across the repo:

If point arrays must be [lon, lat], consider adding a short comment to the test explaining the ordering to future readers.


🏁 Script executed:

#!/bin/bash
# Find C# Query helpers and check spatial signatures/param names
fd -t f -e cs Query | xargs -r -n1 -I{} sh -c 'echo "== {} =="; rg -nP -C2 "(class\\s+Query\\b|Distance(Equal|NotEqual|GreaterThan|LessThan)\\s*\\(|Intersects\\s*\\(|NotIntersects\\s*\\(|Crosses\\s*\\(|NotCrosses\\s*\\(|Overlaps\\s*\\(|NotOverlaps\\s*\\(|Touches\\s*\\(|NotTouches\\s*\\()" "{}"'
# Specifically check for a named 'meters' (or similar) parameter
rg -nP -C1 --type=cs 'Distance(Equal|NotEqual|GreaterThan|LessThan)\s*\([^)]*?(meters|isMeters|useMeters)\s*:' || true
# Show these test call sites for context
rg -n -C2 'Distance(Equal|NotEqual|GreaterThan|LessThan)\(|Intersects\(' tests/languages/dotnet/Tests.cs

Length of output: 2191


🏁 Script executed:

#!/bin/bash
# Locate the Query class definition
rg -nP 'class\s+Query\b' -t cs -n -C2

# Inspect all Distance* overloads and their signatures
rg -nP 'public\s+static\s+\S+\s+DistanceEqual\(' -t cs -n -C2
rg -nP 'public\s+static\s+\S+\s+DistanceNotEqual\(' -t cs -n -C2
rg -nP 'public\s+static\s+\S+\s+DistanceGreaterThan\(' -t cs -n -C2
rg -nP 'public\s+static\s+\S+\s+DistanceLessThan\(' -t cs -n -C2

# Inspect spatial predicate signatures
rg -nP 'public\s+static\s+\S+\s+(Intersects|NotIntersects|Crosses|NotCrosses|Overlaps|NotOverlaps|Touches|NotTouches)\(' -t cs -n -C2

Length of output: 443


🏁 Script executed:

#!/bin/bash
# Show the Tests.cs header to identify imports and namespace
echo ">> Tests.cs header <<"
sed -n '1,50p' tests/languages/dotnet/Tests.cs

# Locate the Query class definition(s)
echo ">> Query class definitions <<"
rg -nP --no-ignore 'class\s+Query\b' -n -C2

# Find all static Distance* method definitions
echo ">> DistanceEqual definitions <<"
rg -nP 'public\s+static\s+\S+\s+DistanceEqual\(' -t cs -n -C2
echo ">> DistanceNotEqual definitions <<"
rg -nP 'public\s+static\s+\S+\s+DistanceNotEqual\(' -t cs -n -C2
echo ">> DistanceGreaterThan definitions <<"
rg -nP 'public\s+static\s+\S+\s+DistanceGreaterThan\(' -t cs -n -C2
echo ">> DistanceLessThan definitions <<"
rg -nP 'public\s+static\s+\S+\s+DistanceLessThan\(' -t cs -n -C2

# Find all static spatial predicate method definitions
for m in Intersects NotIntersects Crosses NotCrosses Overlaps NotOverlaps Touches NotTouches; do
  echo ">> $m definitions <<"
  rg -nP "public\s+static\s+\S+\s+$m\(" -t cs -n -C2
done

Length of output: 7535


🏁 Script executed:

#!/bin/bash
# Display the C# Query template to inspect spatial method signatures
sed -n '1,200p' templates/dotnet/Package/Query.cs.twig

Length of output: 6826


🏁 Script executed:

#!/bin/bash
# List all template files in the .NET Package directory
ls -R templates/dotnet/Package

Length of output: 617


🏁 Script executed:

#!/bin/bash
# Display the Extensions template for .NET to locate spatial methods
echo ">> templates/dotnet/Package/Extensions/Extensions.cs.twig <<"
sed -n '1,200p' templates/dotnet/Package/Extensions/Extensions.cs.twig

# Search for any Distance* definitions in the Extensions template
echo ">> Spatial methods in Extensions.cs.twig <<"
rg -nP 'public\s+static\s+\S+\s+Distance(Equal|NotEqual|GreaterThan|LessThan)\(' -n templates/dotnet/Package/Extensions/Extensions.cs.twig

# Search for Intersects/* in Extensions template
echo ">> Spatial predicates in Extensions.cs.twig <<"
rg -nP 'public\s+static\s+\S+\s+(Intersects|NotIntersects|Crosses|NotCrosses|Overlaps|NotOverlaps|Touches|NotTouches)\(' -n templates/dotnet/Package/Extensions/Extensions.cs.twig

Length of output: 9795


Implement missing spatial query methods in .NET Query class
Tests reference Query.DistanceEqual, DistanceNotEqual, DistanceGreaterThan, DistanceLessThan (both point and point‐array overloads, with optional bool), and spatial predicates (Intersects, NotIntersects, Crosses, NotCrosses, Overlaps, NotOverlaps, Touches, NotTouches), but none of these are defined in Query.cs.twig. Add static methods matching these signatures (name the trailing bool parameter clearly, e.g. isMeters) so the tests compile and behavior is documented.

🤖 Prompt for AI Agents
In tests/languages/dotnet/Tests.cs around lines 172-191, the tests call missing
spatial methods on the Query class; add static methods to Query.cs.twig for
DistanceEqual, DistanceNotEqual, DistanceGreaterThan, DistanceLessThan (each
with overloads accepting either List<object> (point) or List<List<object>>
(point array) and an optional trailing bool parameter named isMeters), and add
spatial predicate methods Intersects, NotIntersects, Crosses, NotCrosses,
Overlaps, NotOverlaps, Touches, NotTouches (each accepting the field name and a
point as List<object>). Implement each method to construct and return the same
query object shape used by existing Query methods (mirror naming/structure and
serialization conventions used elsewhere in Query.cs.twig) and include XML doc
comments describing parameters and behavior.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (2)
templates/go/query.go.twig (2)

353-415: Accept interface{} + toArray for spatial predicates (parity and ergonomics).

Requiring []interface{} makes typical inputs like []float64 unusable without manual conversion. Match other helpers: accept interface{} and call toArray.

-func Intersects(attribute string, values []interface{}) string {
-	return parseQuery(queryOptions{
-		Method:    "intersects",
-		Attribute: &attribute,
-		Values:    &values,
-	})
-}
+func Intersects(attribute string, value interface{}) string {
+	vals := toArray(value)
+	return parseQuery(queryOptions{
+		Method:    "intersects",
+		Attribute: &attribute,
+		Values:    &vals,
+	})
+}
 
-func NotIntersects(attribute string, values []interface{}) string {
+func NotIntersects(attribute string, value interface{}) string {
-	return parseQuery(queryOptions{
-		Method:    "notIntersects",
-		Attribute: &attribute,
-		Values:    &values,
-	})
+	vals := toArray(value)
+	return parseQuery(queryOptions{
+		Method:    "notIntersects",
+		Attribute: &attribute,
+		Values:    &vals,
+	})
 }
 
-func Crosses(attribute string, values []interface{}) string {
+func Crosses(attribute string, value interface{}) string {
-	return parseQuery(queryOptions{
-		Method:    "crosses",
-		Attribute: &attribute,
-		Values:    &values,
-	})
+	vals := toArray(value)
+	return parseQuery(queryOptions{
+		Method:    "crosses",
+		Attribute: &attribute,
+		Values:    &vals,
+	})
 }
 
-func NotCrosses(attribute string, values []interface{}) string {
+func NotCrosses(attribute string, value interface{}) string {
-	return parseQuery(queryOptions{
-		Method:    "notCrosses",
-		Attribute: &attribute,
-		Values:    &values,
-	})
+	vals := toArray(value)
+	return parseQuery(queryOptions{
+		Method:    "notCrosses",
+		Attribute: &attribute,
+		Values:    &vals,
+	})
 }
 
-func Overlaps(attribute string, values []interface{}) string {
+func Overlaps(attribute string, value interface{}) string {
-	return parseQuery(queryOptions{
-		Method:    "overlaps",
-		Attribute: &attribute,
-		Values:    &values,
-	})
+	vals := toArray(value)
+	return parseQuery(queryOptions{
+		Method:    "overlaps",
+		Attribute: &attribute,
+		Values:    &vals,
+	})
 }
 
-func NotOverlaps(attribute string, values []interface{}) string {
+func NotOverlaps(attribute string, value interface{}) string {
-	return parseQuery(queryOptions{
-		Method:    "notOverlaps",
-		Attribute: &attribute,
-		Values:    &values,
-	})
+	vals := toArray(value)
+	return parseQuery(queryOptions{
+		Method:    "notOverlaps",
+		Attribute: &attribute,
+		Values:    &vals,
+	})
 }
 
-func Touches(attribute string, values []interface{}) string {
+func Touches(attribute string, value interface{}) string {
-	return parseQuery(queryOptions{
-		Method:    "touches",
-		Attribute: &attribute,
-		Values:    &values,
-	})
+	vals := toArray(value)
+	return parseQuery(queryOptions{
+		Method:    "touches",
+		Attribute: &attribute,
+		Values:    &vals,
+	})
 }
 
-func NotTouches(attribute string, values []interface{}) string {
-	return parseQuery(queryOptions{
-		Method:    "notTouches",
-		Attribute: &attribute,
-		Values:    &values,
-	})
-}
+func NotTouches(attribute string, value interface{}) string {
+	vals := toArray(value)
+	return parseQuery(queryOptions{
+		Method:    "notTouches",
+		Attribute: &attribute,
+		Values:    &vals,
+	})
+}

321-351: Fix payload shape and align API with existing helpers (wrap payload, accept single/multi value).

Current Values builds [values, distance, meters] directly and forces []interface{}. Expected shape is [[toArray(value), distance, meters]], and other helpers accept interface{} + toArray. Update all four Distance* funcs accordingly.

-func DistanceEqual(attribute string, values []interface{}, distance float64, meters bool) string {
-	return parseQuery(queryOptions{
-		Method:    "distanceEqual",
-		Attribute: &attribute,
-		Values:    &[]interface{}{values, distance, meters},
-	})
-}
+func DistanceEqual(attribute string, value interface{}, distance float64, meters bool) string {
+	payload := []interface{}{toArray(value), distance, meters}
+	wrapped := []interface{}{payload}
+	return parseQuery(queryOptions{
+		Method:    "distanceEqual",
+		Attribute: &attribute,
+		Values:    &wrapped,
+	})
+}
 
-func DistanceNotEqual(attribute string, values []interface{}, distance float64, meters bool) string {
-	return parseQuery(queryOptions{
-		Method:    "distanceNotEqual",
-		Attribute: &attribute,
-		Values:    &[]interface{}{values, distance, meters},
-	})
-}
+func DistanceNotEqual(attribute string, value interface{}, distance float64, meters bool) string {
+	payload := []interface{}{toArray(value), distance, meters}
+	wrapped := []interface{}{payload}
+	return parseQuery(queryOptions{
+		Method:    "distanceNotEqual",
+		Attribute: &attribute,
+		Values:    &wrapped,
+	})
+}
 
-func DistanceGreaterThan(attribute string, values []interface{}, distance float64, meters bool) string {
-	return parseQuery(queryOptions{
-		Method:    "distanceGreaterThan",
-		Attribute: &attribute,
-		Values:    &[]interface{}{values, distance, meters},
-	})
-}
+func DistanceGreaterThan(attribute string, value interface{}, distance float64, meters bool) string {
+	payload := []interface{}{toArray(value), distance, meters}
+	wrapped := []interface{}{payload}
+	return parseQuery(queryOptions{
+		Method:    "distanceGreaterThan",
+		Attribute: &attribute,
+		Values:    &wrapped,
+	})
+}
 
-func DistanceLessThan(attribute string, values []interface{}, distance float64, meters bool) string {
-	return parseQuery(queryOptions{
-		Method:    "distanceLessThan",
-		Attribute: &attribute,
-		Values:    &[]interface{}{values, distance, meters},
-	})
-}
+func DistanceLessThan(attribute string, value interface{}, distance float64, meters bool) string {
+	payload := []interface{}{toArray(value), distance, meters}
+	wrapped := []interface{}{payload}
+	return parseQuery(queryOptions{
+		Method:    "distanceLessThan",
+		Attribute: &attribute,
+		Values:    &wrapped,
+	})
+}
🧹 Nitpick comments (1)
templates/go/query.go.twig (1)

321-351: Nit: rename param to value for clarity.

Singular matches the rest of the file and avoids confusion between the outer values field vs. inner payload.

Also applies to: 353-415

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c0cb073 and b759e2b.

📒 Files selected for processing (2)
  • templates/go/query.go.twig (1 hunks)
  • tests/Base.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/Base.php

Copy link

@coderabbitai coderabbitai bot left a comment

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 (3)
tests/languages/dotnet/Tests.cs (1)

175-182: Confirm .NET Query Distance overloads and trailing bool semantics.*

Ensure the generated Query class exposes both point and point[] overloads and that the trailing bool indeed toggles meters (name may be meters/isMeters). Adds confidence before merge.

#!/bin/bash
# Verify .NET spatial Distance* method signatures and boolean parameter name
rg -nP -C2 'class\s+Query\b' templates/dotnet/Package/Query.cs.twig
rg -nP -C2 'public\s+static\s+\S+\s+Distance(Equal|NotEqual|GreaterThan|LessThan)\(' templates/dotnet/Package/Query.cs.twig
rg -nP -C1 'Distance(Equal|NotEqual|GreaterThan|LessThan)\([^)]*bool\s+(\w+)' templates/dotnet/Package/Query.cs.twig

# Show test call sites for cross-check
rg -n -C1 'Distance(Equal|NotEqual|GreaterThan|LessThan)\(' tests/languages/dotnet/Tests.cs
templates/react-native/src/query.ts.twig (2)

226-263: Drop unsafe casts; add proper geometry/distance types (parity with web).

Current [values, distance, meters] as QueryTypesList is unsound and can mask type bugs. Use explicit tuple/geometry types and remove casts. Mirrors prior feedback; updated here to include meters.

Apply within this block:

-  static distanceEqual = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceEqual", attribute, [values, distance, meters] as QueryTypesList).toString();
+  static distanceEqual = (attribute: string, values: GeometryValues, distance: number, meters: boolean = false): string =>
+    new Query("distanceEqual", attribute, [values, distance, meters]).toString();

-  static distanceNotEqual = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceNotEqual", attribute, [values, distance, meters] as QueryTypesList).toString();
+  static distanceNotEqual = (attribute: string, values: GeometryValues, distance: number, meters: boolean = false): string =>
+    new Query("distanceNotEqual", attribute, [values, distance, meters]).toString();

-  static distanceGreaterThan = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceGreaterThan", attribute, [values, distance, meters] as QueryTypesList).toString();
+  static distanceGreaterThan = (attribute: string, values: GeometryValues, distance: number, meters: boolean = false): string =>
+    new Query("distanceGreaterThan", attribute, [values, distance, meters]).toString();

-  static distanceLessThan = (attribute: string, values: any[], distance: number, meters: boolean = false): string =>
-    new Query("distanceLessThan", attribute, [values, distance, meters] as QueryTypesList).toString();
+  static distanceLessThan = (attribute: string, values: GeometryValues, distance: number, meters: boolean = false): string =>
+    new Query("distanceLessThan", attribute, [values, distance, meters]).toString();

Update JSDoc param types accordingly in this hunk.


272-343: Type the spatial predicates (values) and keep consistency.

Use the same GeometryValues alias; remove casts elsewhere if added later.

-  static intersects = (attribute: string, values: any[]): string =>
+  static intersects = (attribute: string, values: GeometryValues): string =>
     new Query("intersects", attribute, values).toString();

-  static notIntersects = (attribute: string, values: any[]): string =>
+  static notIntersects = (attribute: string, values: GeometryValues): string =>
     new Query("notIntersects", attribute, values).toString();

-  static crosses = (attribute: string, values: any[]): string =>
+  static crosses = (attribute: string, values: GeometryValues): string =>
     new Query("crosses", attribute, values).toString();

-  static notCrosses = (attribute: string, values: any[]): string =>
+  static notCrosses = (attribute: string, values: GeometryValues): string =>
     new Query("notCrosses", attribute, values).toString();

-  static overlaps = (attribute: string, values: any[]): string =>
+  static overlaps = (attribute: string, values: GeometryValues): string =>
     new Query("overlaps", attribute, values).toString();

-  static notOverlaps = (attribute: string, values: any[]): string =>
+  static notOverlaps = (attribute: string, values: GeometryValues): string =>
     new Query("notOverlaps", attribute, values).toString();

-  static touches = (attribute: string, values: any[]): string =>
+  static touches = (attribute: string, values: GeometryValues): string =>
     new Query("touches", attribute, values).toString();

-  static notTouches = (attribute: string, values: any[]): string =>
+  static notTouches = (attribute: string, values: GeometryValues): string =>
     new Query("notTouches", attribute, values).toString();

Add the supporting types near the top (outside this hunk):

// Types
type QueryTypesSingle = string | number | boolean;
export type GeometryValues = unknown[];            // keep broad; align with web template if it defines GeoJSON
export type DistanceValues = [GeometryValues, number, boolean?];
export type QueryTypesList =
  | string[] | number[] | boolean[] | Query[]
  | GeometryValues | DistanceValues;
export type QueryTypes = QueryTypesSingle | QueryTypesList;
🧹 Nitpick comments (12)
tests/languages/deno/tests.ts (5)

193-193: Avoid duplicate coordinates in multi-point distance test.

Using the same point twice weakens coverage. Swap the second point to a different location.

-  console.log(Query.distanceEqual("location", [[40.7128, -74], [40.7128, -74]], 1000));
+  console.log(Query.distanceEqual("location", [[40.7128, -74], [34.0522, -118.2437]], 1000));

If backend expects [lng, lat] instead of [lat, lng], use this alternative:

-  console.log(Query.distanceEqual("location", [[40.7128, -74], [40.7128, -74]], 1000));
+  console.log(Query.distanceEqual("location", [[-74, 40.7128], [-118.2437, 34.0522]], 1000));

193-200: Cover both single-point and multi-point inputs consistently across all distance methods.

Only distanceEqual exercises an array-of-points; mirror that for the other three to validate both overloads.

   console.log(Query.distanceNotEqual("location", [40.7128, -74], 1000));
+  console.log(Query.distanceNotEqual("location", [[40.7128, -74], [34.0522, -118.2437]], 1000));
   console.log(Query.distanceGreaterThan("location", [40.7128, -74], 1000));
+  console.log(Query.distanceGreaterThan("location", [[40.7128, -74], [34.0522, -118.2437]], 1000));
   console.log(Query.distanceLessThan("location", [40.7128, -74], 1000));
+  console.log(Query.distanceLessThan("location", [[40.7128, -74], [34.0522, -118.2437]], 1000));

203-210: Use appropriate geometry for spatial predicates (beyond points).

crosses/overlaps typically apply to lines/polygons. Add at least one LineString and Polygon case to exercise valid semantics.

-  console.log(Query.crosses("location", [40.7128, -74]));
+  // Example LineString crossing test
+  const line = [[-74.02, 40.70], [-73.98, 40.75]];
+  console.log(Query.crosses("location", line));
-  console.log(Query.overlaps("location", [40.7128, -74]));
+  // Example Polygon overlap test (closed ring)
+  const polygon = [[-74.02, 40.70], [-74.02, 40.75], [-73.98, 40.75], [-73.98, 40.70], [-74.02, 40.70]];
+  console.log(Query.overlaps("location", polygon));

192-201: Exercise meters flag and boundary cases.

Add tests for omitted meters (default), meters=false, zero/negative distance, and out-of-range coordinates to validate input handling.

+  // meters omitted (default)
+  console.log(Query.distanceEqual("location", [40.7128, -74], 1000));
+  // meters explicitly false
+  console.log(Query.distanceEqual("location", [40.7128, -74], 1000, false));
+  // boundary/invalid examples (should throw or be rejected upstream)
+  // console.log(Query.distanceLessThan("location", [95, -200], 1000)); // invalid lat/lng
+  // console.log(Query.distanceGreaterThan("location", [40.7128, -74], -5)); // invalid distance

192-210: Reduce duplication with shared fixtures.

Extract the point and radius into constants to improve readability and avoid typos.

TypeScript snippet to add near the top of the query tests:

const NYC = [40.7128, -74] as const; // swap order if backend expects [lng, lat]
const LA = [34.0522, -118.2437] as const;
const R1000 = 1000;

Then use NYC/LA/R1000 in the calls here.

tests/languages/dotnet/Tests.cs (2)

174-193: Reduce duplication; clarify coord order; exercise explicit bool path.

Minor cleanup and clarity. Also adds one explicit false-case to cover both boolean paths.

-            // Spatial Distance query tests
-            TestContext.WriteLine(Query.DistanceEqual("location", new List<List<object>> { new List<object> { 40.7128, -74 }, new List<object> { 40.7128, -74 } }, 1000));
-            TestContext.WriteLine(Query.DistanceEqual("location", new List<object> { 40.7128, -74 }, 1000, true));
-            TestContext.WriteLine(Query.DistanceNotEqual("location", new List<object> { 40.7128, -74 }, 1000));
-            TestContext.WriteLine(Query.DistanceNotEqual("location", new List<object> { 40.7128, -74 }, 1000, true));
-            TestContext.WriteLine(Query.DistanceGreaterThan("location", new List<object> { 40.7128, -74 }, 1000));
-            TestContext.WriteLine(Query.DistanceGreaterThan("location", new List<object> { 40.7128, -74 }, 1000, true));
-            TestContext.WriteLine(Query.DistanceLessThan("location", new List<object> { 40.7128, -74 }, 1000));
-            TestContext.WriteLine(Query.DistanceLessThan("location", new List<object> { 40.7128, -74 }, 1000, true));
+            // Spatial Distance query tests
+            // NOTE: Coordinates below are [lat, lon]. If the API expects [lon, lat], swap order.
+            var point = new List<object> { 40.7128, -74 };
+            var points = new List<List<object>> { point, point }; // exercise point[] overload
+            TestContext.WriteLine(Query.DistanceEqual("location", points, 1000));
+            TestContext.WriteLine(Query.DistanceEqual("location", point, 1000, true));
+            TestContext.WriteLine(Query.DistanceEqual("location", point, 1000, false)); // explicit boolean path
+            TestContext.WriteLine(Query.DistanceNotEqual("location", point, 1000));
+            TestContext.WriteLine(Query.DistanceNotEqual("location", point, 1000, true));
+            TestContext.WriteLine(Query.DistanceGreaterThan("location", point, 1000));
+            TestContext.WriteLine(Query.DistanceGreaterThan("location", point, 1000, true));
+            TestContext.WriteLine(Query.DistanceLessThan("location", point, 1000));
+            TestContext.WriteLine(Query.DistanceLessThan("location", point, 1000, true));
@@
-            // Spatial query tests
-            TestContext.WriteLine(Query.Intersects("location", new List<object> { 40.7128, -74 }));
-            TestContext.WriteLine(Query.NotIntersects("location", new List<object> { 40.7128, -74 }));
-            TestContext.WriteLine(Query.Crosses("location", new List<object> { 40.7128, -74 }));
-            TestContext.WriteLine(Query.NotCrosses("location", new List<object> { 40.7128, -74 }));
-            TestContext.WriteLine(Query.Overlaps("location", new List<object> { 40.7128, -74 }));
-            TestContext.WriteLine(Query.NotOverlaps("location", new List<object> { 40.7128, -74 }));
-            TestContext.WriteLine(Query.Touches("location", new List<object> { 40.7128, -74 }));
-            TestContext.WriteLine(Query.NotTouches("location", new List<object> { 40.7128, -74 }));
+            // Spatial query tests (point geometry)
+            TestContext.WriteLine(Query.Intersects("location", point));
+            TestContext.WriteLine(Query.NotIntersects("location", point));
+            TestContext.WriteLine(Query.Crosses("location", point));
+            TestContext.WriteLine(Query.NotCrosses("location", point));
+            TestContext.WriteLine(Query.Overlaps("location", point));
+            TestContext.WriteLine(Query.NotOverlaps("location", point));
+            TestContext.WriteLine(Query.Touches("location", point));
+            TestContext.WriteLine(Query.NotTouches("location", point));

185-192: Validate point geometry is acceptable for spatial predicates; consider polygon/line coverage.

If predicates like Crosses/Overlaps require non-point geometries, add one polygon/line example once supported; otherwise add a brief comment clarifying that points are valid inputs.

templates/android/library/src/main/java/io/package/Query.kt.twig (1)

316-349: Validate non-negative distance and avoid silent bad input.

Guard against invalid negative distances to prevent server-side errors and to fail fast in SDKs.

Apply to all four distance* methods:

-fun distanceEqual(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) = Query("distanceEqual", attribute, listOf(values, distance, meters)).toJson()
+fun distanceEqual(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false): String {
+    require(distance.toDouble() >= 0) { "distance must be >= 0" }
+    return Query("distanceEqual", attribute, listOf(values, distance, meters)).toJson()
+}

-fun distanceNotEqual(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) = Query("distanceNotEqual", attribute, listOf(values, distance, meters)).toJson()
+fun distanceNotEqual(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false): String {
+    require(distance.toDouble() >= 0) { "distance must be >= 0" }
+    return Query("distanceNotEqual", attribute, listOf(values, distance, meters)).toJson()
+}

-fun distanceGreaterThan(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) = Query("distanceGreaterThan", attribute, listOf(values, distance, meters)).toJson()
+fun distanceGreaterThan(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false): String {
+    require(distance.toDouble() >= 0) { "distance must be >= 0" }
+    return Query("distanceGreaterThan", attribute, listOf(values, distance, meters)).toJson()
+}

-fun distanceLessThan(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false) = Query("distanceLessThan", attribute, listOf(values, distance, meters)).toJson()
+fun distanceLessThan(attribute: String, values: List<Any>, distance: Number, meters: Boolean = false): String {
+    require(distance.toDouble() >= 0) { "distance must be >= 0" }
+    return Query("distanceLessThan", attribute, listOf(values, distance, meters)).toJson()
+}
templates/react-native/src/query.ts.twig (1)

214-215: Add basic validation: non-negative distance.

Lightweight runtime guard helps catch obvious mistakes early.

-  static distanceEqual = (attribute: string, values: GeometryValues, distance: number, meters: boolean = false): string =>
-    new Query("distanceEqual", attribute, [values, distance, meters]).toString();
+  static distanceEqual = (attribute: string, values: GeometryValues, distance: number, meters: boolean = false): string => {
+    if (distance < 0) throw new Error("distance must be >= 0");
+    return new Query("distanceEqual", attribute, [values, distance, meters]).toString();
+  }

Repeat for the other three distance helpers.

Also applies to: 217-225

templates/swift/Sources/Query.swift.twig (3)

96-119: Factor mapping into a reusable helper to reduce duplication.

Extract the nested mapping into a small helper (recursive) for readability and reuse.

// Outside this hunk:
private static func convertAnyToQueryValue(_ item: Any) -> QueryValue? {
    switch item {
    case let v as String: return .string(v)
    case let v as Int:    return .int(v)
    case let v as Double: return .double(v)
    case let v as Bool:   return .bool(v)
    case let v as Query:  return .query(v)
    case let v as [Any]:
        let mapped = v.compactMap { convertAnyToQueryValue($0) }
        return .array(mapped)
    default:
        return nil
    }
}

// Then here:
case let anyArray as [Any]:
    let nestedValues = anyArray.compactMap { convertAnyToQueryValue($0) }
    return nestedValues

447-477: Guard against negative distance.

Fail fast on invalid input; keeps behavior consistent across SDKs.

-    public static func distanceEqual(_ attribute: String, values: [Any], distance: Double, meters: Bool = false) -> String {
+    public static func distanceEqual(_ attribute: String, values: [Any], distance: Double, meters: Bool = false) -> String {
+        precondition(distance >= 0, "distance must be non-negative")
         return Query(
             method: "distanceEqual",
             attribute: attribute,
             values: [values, distance, meters]
         ).description
     }

Repeat for the other three distance* methods in this block.


479-541: Add missing Swift tests for nested spatial and distance payloads

  • Distance builders: add a test for values: [[x, y], [x2, y2]] with meters: true to verify the JSON shape.
  • Spatial builders (intersects, crosses, overlaps, touches and their negations): add tests asserting JSON for nested polygon arrays (e.g. values: [[[x1, y1], [x2, y2], …]]).
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b759e2b and 8c5b2d7.

📒 Files selected for processing (28)
  • templates/android/library/src/main/java/io/package/Query.kt.twig (1 hunks)
  • templates/dart/lib/query.dart.twig (1 hunks)
  • templates/deno/src/query.ts.twig (1 hunks)
  • templates/dotnet/Package/Query.cs.twig (1 hunks)
  • templates/go/query.go.twig (1 hunks)
  • templates/kotlin/src/main/kotlin/io/appwrite/Query.kt.twig (1 hunks)
  • templates/php/src/Query.php.twig (1 hunks)
  • templates/python/package/query.py.twig (1 hunks)
  • templates/react-native/src/query.ts.twig (1 hunks)
  • templates/ruby/lib/container/query.rb.twig (1 hunks)
  • templates/swift/Sources/Query.swift.twig (5 hunks)
  • templates/web/src/query.ts.twig (1 hunks)
  • tests/Base.php (1 hunks)
  • tests/languages/android/Tests.kt (1 hunks)
  • tests/languages/apple/Tests.swift (1 hunks)
  • tests/languages/dart/tests.dart (2 hunks)
  • tests/languages/deno/tests.ts (1 hunks)
  • tests/languages/dotnet/Tests.cs (1 hunks)
  • tests/languages/flutter/tests.dart (1 hunks)
  • tests/languages/go/tests.go (1 hunks)
  • tests/languages/kotlin/Tests.kt (1 hunks)
  • tests/languages/node/test.js (1 hunks)
  • tests/languages/php/test.php (1 hunks)
  • tests/languages/python/tests.py (1 hunks)
  • tests/languages/ruby/tests.rb (1 hunks)
  • tests/languages/swift/Tests.swift (1 hunks)
  • tests/languages/web/index.html (1 hunks)
  • tests/languages/web/node.js (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • tests/languages/web/index.html
🚧 Files skipped from review as they are similar to previous changes (22)
  • tests/Base.php
  • tests/languages/kotlin/Tests.kt
  • tests/languages/go/tests.go
  • tests/languages/python/tests.py
  • tests/languages/ruby/tests.rb
  • tests/languages/swift/Tests.swift
  • templates/php/src/Query.php.twig
  • tests/languages/apple/Tests.swift
  • templates/ruby/lib/container/query.rb.twig
  • tests/languages/node/test.js
  • templates/deno/src/query.ts.twig
  • tests/languages/android/Tests.kt
  • tests/languages/php/test.php
  • templates/go/query.go.twig
  • tests/languages/flutter/tests.dart
  • templates/dart/lib/query.dart.twig
  • templates/kotlin/src/main/kotlin/io/appwrite/Query.kt.twig
  • tests/languages/web/node.js
  • templates/python/package/query.py.twig
  • templates/web/src/query.ts.twig
  • templates/dotnet/Package/Query.cs.twig
  • tests/languages/dart/tests.dart
🔇 Additional comments (4)
tests/languages/deno/tests.ts (2)

192-211: Nice addition: new spatial query coverage looks good.

These calls exercise the new builders and keep parity with other languages.


193-200: Confirm coordinate order for spatial inputs. The SDK simply serializes the arrays you pass; verify against the service documentation whether coordinates must be [lat, lng] or [lng, lat], otherwise your filters will be silently wrong.

templates/android/library/src/main/java/io/package/Query.kt.twig (1)

351-421: Confirm nested/heterogeneous array serialization works with toJson.

These methods pass values as [List, Number, Boolean]. Ensure the Android/Kotlin serializer supports nested mixed-type arrays; Swift needed a custom variant to avoid dropping values.

If not supported, mirror Swift’s approach (custom encoder for nested arrays) or flatten the payload contract.

templates/swift/Sources/Query.swift.twig (1)

9-10: LGTM: nested array support fixes dropped distance payloads.

Adding QueryValue.array + encode/decode resolves the heterogeneous array serialization gap noted earlier.

Also applies to: 24-26, 47-49

Copy link

@coderabbitai coderabbitai bot left a comment

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 (3)
templates/dotnet/Package/Query.cs.twig (3)

213-231: DRY the distance-query builders with a tiny helper

All four distance methods duplicate the same payload construction. Centralize to reduce maintenance risk.

Apply within the current methods:

-            return new Query("distanceEqual", attribute, new List<object> { values, distance, meters }).ToString();
+            return BuildDistance("distanceEqual", attribute, values, distance, meters);
-            return new Query("distanceNotEqual", attribute, new List<object> { values, distance, meters }).ToString();
+            return BuildDistance("distanceNotEqual", attribute, values, distance, meters);
-            return new Query("distanceGreaterThan", attribute, new List<object> { values, distance, meters }).ToString();
+            return BuildDistance("distanceGreaterThan", attribute, values, distance, meters);
-            return new Query("distanceLessThan", attribute, new List<object> { values, distance, meters }).ToString();
+            return BuildDistance("distanceLessThan", attribute, values, distance, meters);

Add this helper inside the class (outside the changed hunk):

private static string BuildDistance(string method, string attribute, object values, double distance, bool meters)
{
    return new Query(method, attribute, new List<object> { values, distance, meters }).ToString();
}

213-231: Non-negative distance guard (optional)

Consider an early check to prevent negative distances; it’s a fast fail and clearer error than a backend 4xx.

Example:

-        public static string DistanceEqual(string attribute, object values, double distance, bool meters = false)
+        public static string DistanceEqual(string attribute, object values, double distance, bool meters = false)
         {
+            if (distance < 0) throw new ArgumentOutOfRangeException(nameof(distance), "Distance must be >= 0.");
             return BuildDistance("distanceEqual", attribute, values, distance, meters);
         }

(Repeat for the other three distance methods.)


213-271: Add XML docs for new public APIs

These are new surface area; brief remarks help IDE users and keep parity with other SDKs.

Example:

/// Builds a spatial distance-equality filter.
/// values: point [lon, lat] or compatible geometry. distance: numeric radius. meters: interpret distance in meters if true, else default units.
public static string DistanceEqual(...)

(Replicate concise summaries for all 12 methods.)

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 8c5b2d7 and 4743ae3.

📒 Files selected for processing (2)
  • templates/dotnet/Package/Query.cs.twig (1 hunks)
  • tests/languages/dotnet/Tests.cs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/languages/dotnet/Tests.cs
⏰ 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). (18)
  • GitHub Check: build (8.3, Swift56)
  • GitHub Check: build (8.3, WebNode)
  • GitHub Check: build (8.3, WebChromium)
  • GitHub Check: build (8.3, Ruby30)
  • GitHub Check: build (8.3, Node18)
  • GitHub Check: build (8.3, Python311)
  • GitHub Check: build (8.3, Python310)
  • GitHub Check: build (8.3, Ruby27)
  • GitHub Check: build (8.3, Python39)
  • GitHub Check: build (8.3, PHP83)
  • GitHub Check: build (8.3, DotNet80)
  • GitHub Check: build (8.3, Node20)
  • GitHub Check: build (8.3, KotlinJava8)
  • GitHub Check: build (8.3, Go112)
  • GitHub Check: build (8.3, FlutterBeta)
  • GitHub Check: build (8.3, FlutterStable)
  • GitHub Check: build (8.3, Android5Java17)
  • GitHub Check: build (8.3, Android14Java17)
🔇 Additional comments (1)
templates/dotnet/Package/Query.cs.twig (1)

233-271: Approve existing spatial predicate serialization
Current implementation correctly emits geometries as flat arrays (e.g. "values":[40.7128,-74]), matching the in-repo tests for Intersects, Crosses, Overlaps, and Touches.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
tests/Base.php (1)

123-138: Swap coordinates to [longitude, latitude] for GeoJSON compliance

The coordinates are currently in [lat, lon]. Please standardize on [lon, lat] across all spatial tests to avoid cross-SDK inconsistencies and align with GeoJSON/RFC 7946. (datatracker.ietf.org, macwright.com)

Apply this diff:

-        '{"method":"distanceEqual","attribute":"location","values":[[[40.7128, -74],[40.7128, -74]],1000,true]}',
-        '{"method":"distanceEqual","attribute":"location","values":[[40.7128,-74],1000,true]}',
-        '{"method":"distanceNotEqual","attribute":"location","values":[[40.7128,-74],1000,true]}',
-        '{"method":"distanceNotEqual","attribute":"location","values":[[40.7128,-74],1000,true]}',
-        '{"method":"distanceGreaterThan","attribute":"location","values":[[40.7128,-74],1000,true]}',
-        '{"method":"distanceGreaterThan","attribute":"location","values":[[40.7128,-74],1000,true]}',
-        '{"method":"distanceLessThan","attribute":"location","values":[[40.7128,-74],1000,true]}',
-        '{"method":"distanceLessThan","attribute":"location","values":[[40.7128,-74],1000,true]}',
-        '{"method":"intersects","attribute":"location","values":[40.7128,-74]}',
-        '{"method":"notIntersects","attribute":"location","values":[40.7128,-74]}',
-        '{"method":"crosses","attribute":"location","values":[40.7128,-74]}',
-        '{"method":"notCrosses","attribute":"location","values":[40.7128,-74]}',
-        '{"method":"overlaps","attribute":"location","values":[40.7128,-74]}',
-        '{"method":"notOverlaps","attribute":"location","values":[40.7128,-74]}',
-        '{"method":"touches","attribute":"location","values":[40.7128,-74]}',
-        '{"method":"notTouches","attribute":"location","values":[40.7128,-74]}',
+        '{"method":"distanceEqual","attribute":"location","values":[[[-74, 40.7128],[-74, 40.7128]],1000,true]}',
+        '{"method":"distanceEqual","attribute":"location","values":[[-74,40.7128],1000,true]}',
+        '{"method":"distanceNotEqual","attribute":"location","values":[[-74,40.7128],1000,true]}',
+        '{"method":"distanceNotEqual","attribute":"location","values":[[-74,40.7128],1000,true]}',
+        '{"method":"distanceGreaterThan","attribute":"location","values":[[-74,40.7128],1000,true]}',
+        '{"method":"distanceGreaterThan","attribute":"location","values":[[-74,40.7128],1000,true]}',
+        '{"method":"distanceLessThan","attribute":"location","values":[[-74,40.7128],1000,true]}',
+        '{"method":"distanceLessThan","attribute":"location","values":[[-74,40.7128],1000,true]}',
+        '{"method":"intersects","attribute":"location","values":[-74,40.7128]}',
+        '{"method":"notIntersects","attribute":"location","values":[-74,40.7128]}',
+        '{"method":"crosses","attribute":"location","values":[-74,40.7128]}',
+        '{"method":"notCrosses","attribute":"location","values":[-74,40.7128]}',
+        '{"method":"overlaps","attribute":"location","values":[-74,40.7128]}',
+        '{"method":"notOverlaps","attribute":"location","values":[-74,40.7128]}',
+        '{"method":"touches","attribute":"location","values":[-74,40.7128]}',
+        '{"method":"notTouches","attribute":"location","values":[-74,40.7128]}',
🧹 Nitpick comments (5)
tests/Base.php (1)

123-130: Clarify distance payload shape; duplicates look unintended

Line 123 passes two points inside values ([[p1, p2], distance, meters]) while the rest use a single point ([p, distance, meters]). Please confirm the intended contract and make all SDKs/tests consistent. Also, each operator appears twice with identical payloads—dedupe or vary one (e.g., different meters flag) as appropriate. Current Appwrite public docs don’t list distance/spatial operators; if these are new, link spec/PR in code comments. (appwrite.io)

templates/ruby/lib/container/query.rb.twig (2)

163-177: Document units, coordinate order, and payload expectations for distance_ methods*

Add brief YARD docs stating that coordinates must be [lon, lat] (GeoJSON order) and what the meters flag controls. Without docs, misuse is likely. (datatracker.ietf.org)

Apply this diff:

             def distance_equal(attribute, values, distance, meters = true)
-                return Query.new("distanceEqual", attribute, [values, distance, meters]).to_s
+                # @param attribute [String] Name of the spatial attribute
+                # @param values [Array] Geometry reference (e.g., [-74.0, 40.7128]) in [lon, lat] order
+                # @param distance [Numeric] Radius/threshold
+                # @param meters [Boolean] If true, distance is interpreted in meters
+                return Query.new("distanceEqual", attribute, [values, distance, meters]).to_s
             end

Repeat similar YARD notes for the other distance_* methods in this block.


179-209: Add minimal docs for geometry predicates (intersects/crosses/…); define accepted geometry shapes

State whether values accepts a point pair [lon, lat], GeoJSON geometry, or arrays thereof. Align this with tests and other SDKs. (datatracker.ietf.org)

Apply this diff starter:

             def intersects(attribute, values)
-                return Query.new("intersects", attribute, values).to_s
+                # @param values [Array|Hash] Geometry in [lon, lat] or GeoJSON geometry object
+                return Query.new("intersects", attribute, values).to_s
             end
templates/dart/lib/query.dart.twig (2)

178-192: Clarify coordinate order and units in distanceEqual/NotEqual/GreaterThan/LessThan docs

Add one line to each doc: coordinates are [longitude, latitude] per RFC 7946; meters controls unit interpretation. (datatracker.ietf.org)

Apply this diff pattern:

-  /// Filter resources where [attribute] is at a specific distance from the given coordinates.
+  /// Filter resources where [attribute] is at a specific distance from the given geometry.
+  /// Coordinates must be [longitude, latitude] per RFC 7946.

194-224: Document accepted geometry shapes for intersects/notIntersects/crosses/...

Specify whether values should be a single point [lon, lat], GeoJSON geometry, or arrays of geometries, and keep this consistent with tests. (datatracker.ietf.org)

Apply this diff pattern:

-  /// Filter resources where [attribute] intersects with the given geometry.
+  /// Filter resources where [attribute] intersects with the given geometry.
+  /// Pass a point as `[-74.0, 40.7128]` ([lon, lat]) or a GeoJSON geometry object.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4743ae3 and c55bb73.

📒 Files selected for processing (13)
  • templates/android/library/src/main/java/io/package/Query.kt.twig (1 hunks)
  • templates/dart/lib/query.dart.twig (1 hunks)
  • templates/deno/src/query.ts.twig (1 hunks)
  • templates/dotnet/Package/Query.cs.twig (1 hunks)
  • templates/go/query.go.twig (1 hunks)
  • templates/kotlin/src/main/kotlin/io/appwrite/Query.kt.twig (1 hunks)
  • templates/php/src/Query.php.twig (1 hunks)
  • templates/python/package/query.py.twig (1 hunks)
  • templates/react-native/src/query.ts.twig (1 hunks)
  • templates/ruby/lib/container/query.rb.twig (1 hunks)
  • templates/swift/Sources/Query.swift.twig (5 hunks)
  • templates/web/src/query.ts.twig (1 hunks)
  • tests/Base.php (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (10)
  • templates/kotlin/src/main/kotlin/io/appwrite/Query.kt.twig
  • templates/php/src/Query.php.twig
  • templates/dotnet/Package/Query.cs.twig
  • templates/python/package/query.py.twig
  • templates/react-native/src/query.ts.twig
  • templates/go/query.go.twig
  • templates/deno/src/query.ts.twig
  • templates/web/src/query.ts.twig
  • templates/android/library/src/main/java/io/package/Query.kt.twig
  • templates/swift/Sources/Query.swift.twig
⏰ 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). (12)
  • GitHub Check: build (8.3, WebChromium)
  • GitHub Check: build (8.3, KotlinJava8)
  • GitHub Check: build (8.3, PHP83)
  • GitHub Check: build (8.3, KotlinJava17)
  • GitHub Check: build (8.3, Node20)
  • GitHub Check: build (8.3, KotlinJava11)
  • GitHub Check: build (8.3, FlutterBeta)
  • GitHub Check: build (8.3, Android14Java17)
  • GitHub Check: build (8.3, DartStable)
  • GitHub Check: build (8.3, FlutterStable)
  • GitHub Check: build (8.3, DartBeta)
  • GitHub Check: build (8.3, Android5Java17)
🔇 Additional comments (2)
templates/ruby/lib/container/query.rb.twig (1)

163-209: Confirm server support for new operators or mark as experimental

Appwrite’s public Queries docs (as of Sep 5, 2025) don’t list distance/spatial operators. If these are server-backed, link the backend spec or mark these helpers experimental in comments to avoid user confusion until docs land. (appwrite.io)

templates/dart/lib/query.dart.twig (1)

178-224: Verify backend support before publishing

Same note as Ruby: these operators are not in the public Queries docs yet. If they’re slated for the next server release, consider adding an “Experimental” note in the docstrings to set expectations. (appwrite.io)

@abnegate abnegate merged commit aea747c into master Sep 5, 2025
75 of 76 checks passed
@abnegate abnegate deleted the spatial-type-queries branch September 5, 2025 09:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants