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