Skip to content

Commit 2bd90f0

Browse files
committed
Add Extra integration tests + reverse parse -> timestamps
Use parse time format for match stage and add tests for aggregate queries with dates in match stage Remove extra aggregation pipeline because we handle it in query Re-disable match stage query
1 parent 781bd39 commit 2bd90f0

7 files changed

Lines changed: 769 additions & 34 deletions

lib/parse/query.rb

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,6 +1228,11 @@ def convert_for_aggregation(constraints)
12281228
# Handle nested constraints and convert Parse-specific types
12291229
case constraints
12301230
when Hash
1231+
# Check if this is a Parse Date hash and convert to raw ISO string
1232+
if constraints.keys == [:__type, :iso] && constraints[:__type] == "Date"
1233+
return constraints[:iso]
1234+
end
1235+
12311236
result = {}
12321237
constraints.each do |key, value|
12331238
result[key] = convert_for_aggregation(value)
@@ -1236,8 +1241,14 @@ def convert_for_aggregation(constraints)
12361241
when Array
12371242
constraints.map { |item| convert_for_aggregation(item) }
12381243
when Parse::Date
1239-
# Convert Parse::Date to MongoDB date format
1240-
{ "$date" => constraints.iso }
1244+
# Convert Parse::Date to raw ISO string for aggregation (Parse Server expects raw ISO strings in aggregation pipelines)
1245+
constraints.iso
1246+
when Time
1247+
# Convert Ruby Time objects to raw ISO string for aggregation (Parse Server expects raw ISO strings in aggregation pipelines)
1248+
constraints.utc.iso8601(3)
1249+
when DateTime
1250+
# Convert Ruby DateTime objects to raw ISO string for aggregation (Parse Server expects raw ISO strings in aggregation pipelines)
1251+
constraints.utc.iso8601(3)
12411252
when Parse::Object, Parse::Pointer
12421253
# Convert Parse objects/pointers to MongoDB pointer format
12431254
constraints.as_json
@@ -2436,34 +2447,50 @@ def convert_constraints_for_aggregation(constraints)
24362447
result
24372448
end
24382449

2439-
# Convert Ruby Date/Time objects to MongoDB date format for aggregation pipelines
2450+
# Convert Ruby Date/Time objects for aggregation pipelines
24402451
# @param obj [Object] the object to convert (Hash, Array, or value)
2441-
# @return [Object] the converted object with proper MongoDB dates
2442-
def convert_dates_for_aggregation(obj)
2452+
# @param for_match_stage [Boolean] if true, converts to Parse Date format; if false (default), converts to raw ISO strings which Parse Server expects in aggregation pipelines
2453+
# @return [Object] the converted object with dates in the appropriate format
2454+
def convert_dates_for_aggregation(obj, for_match_stage: false)
24432455
case obj
24442456
when Hash
24452457
# Handle Parse's JSON date format: {"__type": "Date", "iso": "..."} or {:__type => "Date", :iso => "..."}
24462458
if (obj["__type"] == "Date" || obj[:__type] == "Date") && (obj["iso"] || obj[:iso])
2447-
# For Parse Server aggregation, use raw ISO string
2448-
obj["iso"] || obj[:iso]
2459+
if for_match_stage
2460+
# For Parse Server aggregation match stages, keep the Parse Date format
2461+
{ "__type" => "Date", "iso" => (obj["iso"] || obj[:iso]) }
2462+
else
2463+
# For other stages, use raw ISO string
2464+
obj["iso"] || obj[:iso]
2465+
end
24492466
else
24502467
# Also handle field name mapping for built-in Parse fields
24512468
converted_hash = {}
24522469
obj.each do |key, value|
24532470
# For Parse Server aggregation, keep standard Parse field names
24542471
mapped_key = key
2455-
converted_hash[mapped_key] = convert_dates_for_aggregation(value)
2472+
converted_hash[mapped_key] = convert_dates_for_aggregation(value, for_match_stage: for_match_stage)
24562473
end
24572474
converted_hash
24582475
end
24592476
when Array
2460-
obj.map { |v| convert_dates_for_aggregation(v) }
2477+
obj.map { |v| convert_dates_for_aggregation(v, for_match_stage: for_match_stage) }
24612478
when Time, DateTime
2462-
# Parse Server automatically converts Ruby Time objects to Date objects
2463-
obj
2479+
if for_match_stage
2480+
# Convert Ruby Time/DateTime objects to Parse Server's JSON date format for match stages
2481+
{ "__type" => "Date", "iso" => obj.utc.iso8601(3) }
2482+
else
2483+
# For other stages, use raw ISO string
2484+
obj.utc.iso8601(3)
2485+
end
24642486
when Date
2465-
# Parse Server automatically converts Ruby Date objects to Date objects
2466-
obj
2487+
if for_match_stage
2488+
# Convert Ruby Date objects to Parse Server's JSON date format for match stages
2489+
{ "__type" => "Date", "iso" => obj.to_time.utc.iso8601(3) }
2490+
else
2491+
# For other stages, use raw ISO string
2492+
obj.to_time.utc.iso8601(3)
2493+
end
24672494
else
24682495
obj
24692496
end
@@ -2813,24 +2840,10 @@ def execute_group_aggregation(operation, aggregation_expr)
28132840
formatted_group_field = @query.send(:format_aggregation_field, @group_field)
28142841

28152842
# Build the aggregation pipeline
2843+
# Note: We don't add $match stage here because @query.aggregate() will automatically
2844+
# add match stages from the query's where conditions
28162845
pipeline = []
28172846

2818-
# Add match stage if there are where conditions (before unwind for efficiency)
2819-
compiled_where = @query.send(:compile_where)
2820-
if compiled_where.present?
2821-
# Convert field names for aggregation context and handle dates
2822-
aggregation_where = @query.send(:convert_constraints_for_aggregation, compiled_where)
2823-
2824-
# Debug output
2825-
if @query.instance_variable_get(:@verbose_aggregate)
2826-
puts "[DEBUG] Original constraints: #{compiled_where.inspect}"
2827-
puts "[DEBUG] Converted constraints: #{aggregation_where.inspect}"
2828-
end
2829-
2830-
stringified_where = @query.send(:convert_dates_for_aggregation, aggregation_where)
2831-
pipeline << { "$match" => stringified_where }
2832-
end
2833-
28342847
# Add unwind stage if flatten_arrays is enabled
28352848
if @flatten_arrays
28362849
pipeline << { "$unwind" => "$#{formatted_group_field}" }

0 commit comments

Comments
 (0)