14
14
ClassVar ,
15
15
Dict ,
16
16
List ,
17
+ Literal ,
17
18
Mapping ,
18
19
Optional ,
19
20
Sequence ,
@@ -141,10 +142,10 @@ def embedded(cls):
141
142
142
143
def is_supported_container_type (typ : Optional [type ]) -> bool :
143
144
# TODO: Wait, why don't we support indexing sets?
144
- if typ == list or typ == tuple :
145
+ if typ == list or typ == tuple or typ == Literal :
145
146
return True
146
147
unwrapped = get_origin (typ )
147
- return unwrapped == list or unwrapped == tuple
148
+ return unwrapped == list or unwrapped == tuple or unwrapped == Literal
148
149
149
150
150
151
def validate_model_fields (model : Type ["RedisModel" ], field_values : Dict [str , Any ]):
@@ -889,7 +890,9 @@ def resolve_redisearch_query(cls, expression: ExpressionOrNegated) -> str:
889
890
890
891
return result
891
892
892
- async def execute (self , exhaust_results = True , return_raw_result = False ):
893
+ async def execute (
894
+ self , exhaust_results = True , return_raw_result = False , return_query_args = False
895
+ ):
893
896
args : List [Union [str , bytes ]] = [
894
897
"FT.SEARCH" ,
895
898
self .model .Meta .index_name ,
@@ -914,6 +917,9 @@ async def execute(self, exhaust_results=True, return_raw_result=False):
914
917
if self .nocontent :
915
918
args .append ("NOCONTENT" )
916
919
920
+ if return_query_args :
921
+ return self .model .Meta .index_name , args
922
+
917
923
# Reset the cache if we're executing from offset 0.
918
924
if self .offset == 0 :
919
925
self ._model_cache .clear ()
@@ -947,6 +953,10 @@ async def execute(self, exhaust_results=True, return_raw_result=False):
947
953
self ._model_cache += _results
948
954
return self ._model_cache
949
955
956
+ async def get_query (self ):
957
+ query = self .copy ()
958
+ return await query .execute (return_query_args = True )
959
+
950
960
async def first (self ):
951
961
query = self .copy (offset = 0 , limit = 1 , sort_fields = self .sort_fields )
952
962
results = await query .execute (exhaust_results = False )
@@ -1436,6 +1446,8 @@ def outer_type_or_annotation(field):
1436
1446
if not isinstance (field .annotation , type ):
1437
1447
raise AttributeError (f"could not extract outer type from field { field } " )
1438
1448
return field .annotation
1449
+ elif get_origin (field .annotation ) == Literal :
1450
+ return str
1439
1451
else :
1440
1452
return field .annotation .__args__ [0 ]
1441
1453
@@ -2081,21 +2093,33 @@ def schema_for_type(
2081
2093
# find any values marked as indexed.
2082
2094
if is_container_type and not is_vector :
2083
2095
field_type = get_origin (typ )
2084
- embedded_cls = get_args (typ )
2085
- if not embedded_cls :
2086
- log .warning (
2087
- "Model %s defined an empty list or tuple field: %s" , cls , name
2096
+ if field_type == Literal :
2097
+ path = f"{ json_path } .{ name } "
2098
+ return cls .schema_for_type (
2099
+ path ,
2100
+ name ,
2101
+ name_prefix ,
2102
+ str ,
2103
+ field_info ,
2104
+ parent_type = field_type ,
2105
+ )
2106
+ else :
2107
+ embedded_cls = get_args (typ )
2108
+ if not embedded_cls :
2109
+ log .warning (
2110
+ "Model %s defined an empty list or tuple field: %s" , cls , name
2111
+ )
2112
+ return ""
2113
+ path = f"{ json_path } .{ name } [*]"
2114
+ embedded_cls = embedded_cls [0 ]
2115
+ return cls .schema_for_type (
2116
+ path ,
2117
+ name ,
2118
+ name_prefix ,
2119
+ embedded_cls ,
2120
+ field_info ,
2121
+ parent_type = field_type ,
2088
2122
)
2089
- return ""
2090
- embedded_cls = embedded_cls [0 ]
2091
- return cls .schema_for_type (
2092
- f"{ json_path } .{ name } [*]" ,
2093
- name ,
2094
- name_prefix ,
2095
- embedded_cls ,
2096
- field_info ,
2097
- parent_type = field_type ,
2098
- )
2099
2123
elif field_is_model :
2100
2124
name_prefix = f"{ name_prefix } _{ name } " if name_prefix else name
2101
2125
sub_fields = []
0 commit comments