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 ]):
@@ -872,7 +873,9 @@ def resolve_redisearch_query(cls, expression: ExpressionOrNegated) -> str:
872
873
873
874
return result
874
875
875
- async def execute (self , exhaust_results = True , return_raw_result = False ):
876
+ async def execute (
877
+ self , exhaust_results = True , return_raw_result = False , return_query_args = False
878
+ ):
876
879
args : List [Union [str , bytes ]] = [
877
880
"FT.SEARCH" ,
878
881
self .model .Meta .index_name ,
@@ -897,6 +900,9 @@ async def execute(self, exhaust_results=True, return_raw_result=False):
897
900
if self .nocontent :
898
901
args .append ("NOCONTENT" )
899
902
903
+ if return_query_args :
904
+ return self .model .Meta .index_name , args
905
+
900
906
# Reset the cache if we're executing from offset 0.
901
907
if self .offset == 0 :
902
908
self ._model_cache .clear ()
@@ -930,6 +936,10 @@ async def execute(self, exhaust_results=True, return_raw_result=False):
930
936
self ._model_cache += _results
931
937
return self ._model_cache
932
938
939
+ async def get_query (self ):
940
+ query = self .copy ()
941
+ return await query .execute (return_query_args = True )
942
+
933
943
async def first (self ):
934
944
query = self .copy (offset = 0 , limit = 1 , sort_fields = self .sort_fields )
935
945
results = await query .execute (exhaust_results = False )
@@ -1414,6 +1424,8 @@ def outer_type_or_annotation(field):
1414
1424
if not isinstance (field .annotation , type ):
1415
1425
raise AttributeError (f"could not extract outer type from field { field } " )
1416
1426
return field .annotation
1427
+ elif get_origin (field .annotation ) == Literal :
1428
+ return str
1417
1429
else :
1418
1430
return field .annotation .__args__ [0 ]
1419
1431
@@ -2057,21 +2069,33 @@ def schema_for_type(
2057
2069
# find any values marked as indexed.
2058
2070
if is_container_type and not is_vector :
2059
2071
field_type = get_origin (typ )
2060
- embedded_cls = get_args (typ )
2061
- if not embedded_cls :
2062
- log .warning (
2063
- "Model %s defined an empty list or tuple field: %s" , cls , name
2072
+ if field_type == Literal :
2073
+ path = f"{ json_path } .{ name } "
2074
+ return cls .schema_for_type (
2075
+ path ,
2076
+ name ,
2077
+ name_prefix ,
2078
+ str ,
2079
+ field_info ,
2080
+ parent_type = field_type ,
2081
+ )
2082
+ else :
2083
+ embedded_cls = get_args (typ )
2084
+ if not embedded_cls :
2085
+ log .warning (
2086
+ "Model %s defined an empty list or tuple field: %s" , cls , name
2087
+ )
2088
+ return ""
2089
+ path = f"{ json_path } .{ name } [*]"
2090
+ embedded_cls = embedded_cls [0 ]
2091
+ return cls .schema_for_type (
2092
+ path ,
2093
+ name ,
2094
+ name_prefix ,
2095
+ embedded_cls ,
2096
+ field_info ,
2097
+ parent_type = field_type ,
2064
2098
)
2065
- return ""
2066
- embedded_cls = embedded_cls [0 ]
2067
- return cls .schema_for_type (
2068
- f"{ json_path } .{ name } [*]" ,
2069
- name ,
2070
- name_prefix ,
2071
- embedded_cls ,
2072
- field_info ,
2073
- parent_type = field_type ,
2074
- )
2075
2099
elif field_is_model :
2076
2100
name_prefix = f"{ name_prefix } _{ name } " if name_prefix else name
2077
2101
sub_fields = []
0 commit comments