@@ -2107,7 +2107,7 @@ def test_geo_params(client):
2107
2107
params_dict = {"lat" : "34.95126" , "lon" : "29.69465" , "radius" : 1000 , "units" : "km" }
2108
2108
q = Query ("@g:[$lon $lat $radius $units]" ).dialect (2 )
2109
2109
res = client .ft ().search (q , query_params = params_dict )
2110
- _assert_geosearch_result (client , res , ["doc1" , "doc2" , "doc3" ])
2110
+ _assert_search_result (client , res , ["doc1" , "doc2" , "doc3" ])
2111
2111
2112
2112
2113
2113
@pytest .mark .redismod
@@ -2124,13 +2124,13 @@ def test_geoshapes_query_intersects_and_disjoint(client):
2124
2124
Query ("@g:[intersects $shape]" ).dialect (3 ),
2125
2125
query_params = {"shape" : "POLYGON((15 15, 75 15, 50 70, 20 40, 15 15))" },
2126
2126
)
2127
- _assert_geosearch_result (client , intersection , ["doc_point2" , "doc_polygon1" ])
2127
+ _assert_search_result (client , intersection , ["doc_point2" , "doc_polygon1" ])
2128
2128
2129
2129
disjunction = client .ft ().search (
2130
2130
Query ("@g:[disjoint $shape]" ).dialect (3 ),
2131
2131
query_params = {"shape" : "POLYGON((15 15, 75 15, 50 70, 20 40, 15 15))" },
2132
2132
)
2133
- _assert_geosearch_result (client , disjunction , ["doc_point1" , "doc_polygon2" ])
2133
+ _assert_search_result (client , disjunction , ["doc_point1" , "doc_polygon2" ])
2134
2134
2135
2135
2136
2136
@pytest .mark .redismod
@@ -2148,19 +2148,19 @@ def test_geoshapes_query_contains_and_within(client):
2148
2148
Query ("@g:[contains $shape]" ).dialect (3 ),
2149
2149
query_params = {"shape" : "POINT(25 25)" },
2150
2150
)
2151
- _assert_geosearch_result (client , contains_a , ["doc_polygon1" ])
2151
+ _assert_search_result (client , contains_a , ["doc_polygon1" ])
2152
2152
2153
2153
contains_b = client .ft ().search (
2154
2154
Query ("@g:[contains $shape]" ).dialect (3 ),
2155
2155
query_params = {"shape" : "POLYGON((24 24, 24 26, 25 25, 24 24))" },
2156
2156
)
2157
- _assert_geosearch_result (client , contains_b , ["doc_polygon1" ])
2157
+ _assert_search_result (client , contains_b , ["doc_polygon1" ])
2158
2158
2159
2159
within = client .ft ().search (
2160
2160
Query ("@g:[within $shape]" ).dialect (3 ),
2161
2161
query_params = {"shape" : "POLYGON((15 15, 75 15, 50 70, 20 40, 15 15))" },
2162
2162
)
2163
- _assert_geosearch_result (client , within , ["doc_point2" , "doc_polygon1" ])
2163
+ _assert_search_result (client , within , ["doc_point2" , "doc_polygon1" ])
2164
2164
2165
2165
2166
2166
@pytest .mark .redismod
@@ -2324,19 +2324,153 @@ def test_geoshape(client: redis.Redis):
2324
2324
q2 = Query ("@geom:[CONTAINS $poly]" ).dialect (3 )
2325
2325
qp2 = {"poly" : "POLYGON((2 2, 2 50, 50 50, 50 2, 2 2))" }
2326
2326
result = client .ft ().search (q1 , query_params = qp1 )
2327
- _assert_geosearch_result (client , result , ["small" ])
2327
+ _assert_search_result (client , result , ["small" ])
2328
2328
result = client .ft ().search (q2 , query_params = qp2 )
2329
- _assert_geosearch_result (client , result , ["small" , "large" ])
2329
+ _assert_search_result (client , result , ["small" , "large" ])
2330
2330
2331
2331
2332
- def _assert_geosearch_result (client , result , expected_doc_ids ):
2332
+ @pytest .mark .redismod
2333
+ def test_search_missing_fields (client ):
2334
+ definition = IndexDefinition (prefix = ["property:" ], index_type = IndexType .HASH )
2335
+
2336
+ fields = [
2337
+ TextField ("title" , sortable = True ),
2338
+ TagField ("features" , index_missing = True ),
2339
+ TextField ("description" , index_missing = True ),
2340
+ ]
2341
+
2342
+ client .ft ().create_index (fields , definition = definition )
2343
+
2344
+ # All fields present
2345
+ client .hset (
2346
+ "property:1" ,
2347
+ mapping = {
2348
+ "title" : "Luxury Villa in Malibu" ,
2349
+ "features" : "pool,sea view,modern" ,
2350
+ "description" : "A stunning modern villa overlooking the Pacific Ocean." ,
2351
+ },
2352
+ )
2353
+
2354
+ # Missing features
2355
+ client .hset (
2356
+ "property:2" ,
2357
+ mapping = {
2358
+ "title" : "Downtown Flat" ,
2359
+ "description" : "Modern flat in central Paris with easy access to metro." ,
2360
+ },
2361
+ )
2362
+
2363
+ # Missing description
2364
+ client .hset (
2365
+ "property:3" ,
2366
+ mapping = {
2367
+ "title" : "Beachfront Bungalow" ,
2368
+ "features" : "beachfront,sun deck" ,
2369
+ },
2370
+ )
2371
+
2372
+ with pytest .raises (redis .exceptions .ResponseError ) as e :
2373
+ client .ft ().search (
2374
+ Query ("ismissing(@title)" ).dialect (5 ).return_field ("id" ).no_content ()
2375
+ )
2376
+ assert "to be defined with 'INDEXMISSING'" in e .value .args [0 ]
2377
+
2378
+ res = client .ft ().search (
2379
+ Query ("ismissing(@features)" ).dialect (5 ).return_field ("id" ).no_content ()
2380
+ )
2381
+ _assert_search_result (client , res , ["property:2" ])
2382
+
2383
+ res = client .ft ().search (
2384
+ Query ("-ismissing(@features)" ).dialect (5 ).return_field ("id" ).no_content ()
2385
+ )
2386
+ _assert_search_result (client , res , ["property:1" , "property:3" ])
2387
+
2388
+ res = client .ft ().search (
2389
+ Query ("ismissing(@description)" ).dialect (5 ).return_field ("id" ).no_content ()
2390
+ )
2391
+ _assert_search_result (client , res , ["property:3" ])
2392
+
2393
+ res = client .ft ().search (
2394
+ Query ("-ismissing(@description)" ).dialect (5 ).return_field ("id" ).no_content ()
2395
+ )
2396
+ _assert_search_result (client , res , ["property:1" , "property:2" ])
2397
+
2398
+
2399
+ @pytest .mark .redismod
2400
+ def test_search_empty_fields (client ):
2401
+ definition = IndexDefinition (prefix = ["property:" ], index_type = IndexType .HASH )
2402
+
2403
+ fields = [
2404
+ TextField ("title" , sortable = True ),
2405
+ TagField ("features" , index_empty = True ),
2406
+ TextField ("description" , index_empty = True ),
2407
+ ]
2408
+
2409
+ client .ft ().create_index (fields , definition = definition )
2410
+
2411
+ # All fields present
2412
+ client .hset (
2413
+ "property:1" ,
2414
+ mapping = {
2415
+ "title" : "Luxury Villa in Malibu" ,
2416
+ "features" : "pool,sea view,modern" ,
2417
+ "description" : "A stunning modern villa overlooking the Pacific Ocean." ,
2418
+ },
2419
+ )
2420
+
2421
+ # Empty features
2422
+ client .hset (
2423
+ "property:2" ,
2424
+ mapping = {
2425
+ "title" : "Downtown Flat" ,
2426
+ "features" : "" ,
2427
+ "description" : "Modern flat in central Paris with easy access to metro." ,
2428
+ },
2429
+ )
2430
+
2431
+ # Empty description
2432
+ client .hset (
2433
+ "property:3" ,
2434
+ mapping = {
2435
+ "title" : "Beachfront Bungalow" ,
2436
+ "features" : "beachfront,sun deck" ,
2437
+ "description" : "" ,
2438
+ },
2439
+ )
2440
+
2441
+ with pytest .raises (redis .exceptions .ResponseError ) as e :
2442
+ client .ft ().search (
2443
+ Query ("@title:''" ).dialect (5 ).return_field ("id" ).no_content ()
2444
+ )
2445
+ assert "to be defined with `INDEXEMPTY`" in e .value .args [0 ]
2446
+
2447
+ res = client .ft ().search (
2448
+ Query ("@features:{ }" ).dialect (5 ).return_field ("id" ).no_content ()
2449
+ )
2450
+ _assert_search_result (client , res , ["property:2" ])
2451
+
2452
+ res = client .ft ().search (
2453
+ Query ("-@features:{ }" ).dialect (5 ).return_field ("id" ).no_content ()
2454
+ )
2455
+ _assert_search_result (client , res , ["property:1" , "property:3" ])
2456
+
2457
+ res = client .ft ().search (
2458
+ Query ("@description:''" ).dialect (5 ).return_field ("id" ).no_content ()
2459
+ )
2460
+ _assert_search_result (client , res , ["property:3" ])
2461
+
2462
+ res = client .ft ().search (
2463
+ Query ("-@description:''" ).dialect (5 ).return_field ("id" ).no_content ()
2464
+ )
2465
+ _assert_search_result (client , res , ["property:1" , "property:2" ])
2466
+
2467
+
2468
+ def _assert_search_result (client , result , expected_doc_ids ):
2333
2469
"""
2334
2470
Make sure the result of a geo search is as expected, taking into account the RESP
2335
2471
version being used.
2336
2472
"""
2337
2473
if is_resp2_connection (client ):
2338
2474
assert set ([doc .id for doc in result .docs ]) == set (expected_doc_ids )
2339
- assert result .total == len (expected_doc_ids )
2340
2475
else :
2341
2476
assert set ([doc ["id" ] for doc in result ["results" ]]) == set (expected_doc_ids )
2342
- assert result ["total_results" ] == len (expected_doc_ids )
0 commit comments