From 765d6b67198a0ea3c783072be67511b8abcd9390 Mon Sep 17 00:00:00 2001 From: Vianney Mixtur Date: Sat, 10 Jun 2023 16:17:15 +0200 Subject: [PATCH 1/5] Removed automatic transformation of objects to statement --- monggregate/base.py | 53 +++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/monggregate/base.py b/monggregate/base.py index 1187bf2..aaf95b6 100644 --- a/monggregate/base.py +++ b/monggregate/base.py @@ -7,36 +7,12 @@ # 3rd Party imports # --------------------------- -from pydantic import BaseModel as PydanticBaseModel, BaseConfig, validator +from pydantic import BaseModel as PydanticBaseModel, BaseConfig +from humps import camelize class BaseModel(PydanticBaseModel, ABC): """Mongreggate base class""" - @validator("*", pre=True) - @classmethod - def resolve(cls, expression:Any)->dict|list[dict]: - """Resolves an expression encapsulated in an object from a class inheriting from BaseModel""" - - def isbasemodel(instance:Any)->bool: - """Returns true if instance is an instance of BaseModel""" - - return isinstance(instance, BaseModel) - - if isbasemodel(expression): - output:dict|list = expression.statement - elif isinstance(expression, list) and any(map(isbasemodel, expression)): - output = [] - for element in expression: - if isinstance(element, BaseModel): - output.append(element.statement) - else: - output.append(element) - #elif isinstance(expression, dict): # Does this case really exist ? - else: - output = expression - - return output - @property @abstractmethod def statement(self)->dict: @@ -56,3 +32,28 @@ class Config(BaseConfig): allow_population_by_field_name = True underscore_attrs_are_private = True + alias_generator = camelize + + +def isbasemodel(instance:Any)->bool: + """Returns true if instance is an instance of BaseModel""" + + return isinstance(instance, BaseModel) + +def resolve(obj:Any)->dict|list[dict]: + """Resolves an expression encapsulated in an object from a class inheriting from BaseModel""" + + if isbasemodel(obj): + output:dict|list = obj.statement + elif isinstance(obj, list) and any(map(isbasemodel, obj)): + output = [] + for element in obj: + if isinstance(element, BaseModel): + output.append(element.statement) + else: + output.append(element) + #elif isinstance(expression, dict): # Does this case really exist ? + else: + output = obj + + return output From c1e4bffb367988d3736115b1fc44969ff0cb1df6 Mon Sep 17 00:00:00 2001 From: Vianney Mixtur Date: Sat, 10 Jun 2023 16:19:01 +0200 Subject: [PATCH 2/5] Improved pipelines - Made collection really optional - Deprecated OnCallEnum - Simplified double mode for __call__ - Made pipeline list-like --- monggregate/pipeline.py | 93 +++++++++++++++++++++++++---------------- 1 file changed, 57 insertions(+), 36 deletions(-) diff --git a/monggregate/pipeline.py b/monggregate/pipeline.py index e445eab..dd69a07 100644 --- a/monggregate/pipeline.py +++ b/monggregate/pipeline.py @@ -29,20 +29,6 @@ from monggregate.utils import StrEnum -class OnCallEnum(StrEnum): - """ - Possible behaviors on pipeline call - - * RUN => the pipeline will execute itself and query the database - - * EXPORT => the pipeline will generate a list of statements that will need - to be run externally - - """ - - RUN = "run" - EXPORT = "export" - class Pipeline(BaseModel): # pylint: disable=too-many-public-methods """ @@ -102,10 +88,10 @@ class Pipeline(BaseModel): # pylint: disable=too-many-public-methods """ + stages : list[Stage] = [] _db : Database | None # necessary to execute the pipeline - on_call : OnCallEnum = OnCallEnum.EXPORT collection : str | None - stages : list[Stage] = [] + class Config(BaseConfig): """Configuration Class for Pipeline""" @@ -118,29 +104,21 @@ class Config(BaseConfig): #------------------------------------------------- def __call__(self)->list[dict]: """Makes a pipeline instance callable and executes the entire pipeline when called""" + + return self.run() - _on_call_map = { - OnCallEnum.EXPORT:self.export, - OnCallEnum.RUN:self.run - } - - return _on_call_map[self.on_call]() - - def __getitem__(self, index:int)->Stage: - """Returns a stage from the pipeline""" - # https://realpython.com/inherit-python-list/ - return self.stages[index] - - + def run(self)->list[dict]: """Executes the entire pipeline""" - stages = self.export() - if self._db is not None: - array = list(self._db[self.collection].aggregate(pipeline=stages)) - else: - raise AttributeError("run is not available when no database is provided") + if self._db is None: + raise ValueError("db is not defined. Please indicate which database to run the pipeline on") + + if not self.collection: + raise ValueError("collection is not defined. Please indicate which collection to run the pipeline on") + stages = self.export() + array = list(self._db[self.collection].aggregate(pipeline=stages)) return array @@ -165,10 +143,53 @@ def to_statements(self)->list[dict]: return self.export() + # -------------------------------------------------- + # Pipeline List Methods + #--------------------------------------------------- + def __add__(self, other:"Pipeline")->"Pipeline": + """Concatenates two pipelines together""" + if not isinstance(other, Pipeline): + raise TypeError(f"unsupported operand type(s) for +: 'Pipeline' and '{type(other)}'") + + return Pipeline( + _db=self._db, + collection=self.collection, + stages=self.stages + other.stages + ) + + def __getitem__(self, index:int)->Stage: + """Returns a stage from the pipeline""" + # https://realpython.com/inherit-python-list/ + return self.stages[index] + + def __setitem__(self, index:int, stage:Stage)->None: + """Sets a stage in the pipeline""" + self.stages[index] = stage + + def __delitem__(self, index:int)->None: + """Deletes a stage from the pipeline""" + del self.stages[index] + + def __len__(self)->int: + """Returns the length of the pipeline""" + return len(self.stages) + + def append(self, stage:Stage)->None: + """Appends a stage to the pipeline""" + self.stages.append(stage) + + def insert(self, index:int, stage:Stage)->None: + """Inserts a stage in the pipeline""" + self.stages.insert(index, stage) + + def extend(self, stages:list[Stage])->None: + """Extends the pipeline with a list of stages""" + self.stages.extend(stages) + - #----------------------------------------------------------- + #--------------------------------------------------- # Stages - #----------------------------------------------------------- + #--------------------------------------------------- # The below methods wrap the constructors of the classes of the same name def add_fields(self, document:dict={}, **kwargs:Any)->"Pipeline": From c20a7852e2c999e48ef97c1899bd4f44e260192d Mon Sep 17 00:00:00 2001 From: Vianney Mixtur Date: Sun, 11 Jun 2023 14:46:11 +0200 Subject: [PATCH 3/5] Upgraded resolve to take care of nested statements - Made resolve a BaseModel classmethod - Tested it on two operators --- monggregate/base.py | 15 +++++++++++++-- monggregate/operators/boolean/and_.py | 5 +++-- monggregate/operators/boolean/or_.py | 4 ++-- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/monggregate/base.py b/monggregate/base.py index aaf95b6..1ad50df 100644 --- a/monggregate/base.py +++ b/monggregate/base.py @@ -13,6 +13,12 @@ class BaseModel(PydanticBaseModel, ABC): """Mongreggate base class""" + @classmethod + def resolve(cls, obj:Any)->dict|list[dict]: + """xxx""" + + return resolve(obj) + @property @abstractmethod def statement(self)->dict: @@ -21,7 +27,6 @@ def statement(self)->dict: # this is a lazy attribute # what is currently in generate statement should go in here - def __call__(self)->dict: """Makes an instance of any class inheriting from this class callable""" @@ -52,7 +57,13 @@ def resolve(obj:Any)->dict|list[dict]: output.append(element.statement) else: output.append(element) - #elif isinstance(expression, dict): # Does this case really exist ? + elif isinstance(obj, dict): + output = {} + for key, value in obj.items(): + if isinstance(value, BaseModel): + output[key] = value.statement + else: + output[key] = resolve(value) else: output = obj diff --git a/monggregate/operators/boolean/and_.py b/monggregate/operators/boolean/and_.py index 36ab284..ded177f 100644 --- a/monggregate/operators/boolean/and_.py +++ b/monggregate/operators/boolean/and_.py @@ -68,9 +68,9 @@ class And(BooleanOperator): @property def statement(self) -> dict: - return { + return self.resolve({ "$and" : self.expressions - } + }) def and_(*args:Any)->dict: """Returns an $and statement""" @@ -78,3 +78,4 @@ def and_(*args:Any)->dict: return And( expressions=list(args) ).statement + diff --git a/monggregate/operators/boolean/or_.py b/monggregate/operators/boolean/or_.py index 3518faa..82ffc26 100644 --- a/monggregate/operators/boolean/or_.py +++ b/monggregate/operators/boolean/or_.py @@ -44,9 +44,9 @@ class Or(BooleanOperator): @property def statement(self) -> dict: - return { + return self.resolve({ "$or" : self.expressions - } + }) def or_(*args:Any)->dict: """Returns an $or statement""" From e686115129be6f872fc6c6b63d2a4a5bebf91f8e Mon Sep 17 00:00:00 2001 From: Vianney Mixtur Date: Sun, 11 Jun 2023 14:59:26 +0200 Subject: [PATCH 4/5] Added resolve in front of all statements --- monggregate/base.py | 2 +- monggregate/operators/accumulators/avg.py | 5 +++-- monggregate/operators/accumulators/count.py | 4 ++-- monggregate/operators/accumulators/first.py | 4 ++-- monggregate/operators/accumulators/last.py | 4 ++-- monggregate/operators/accumulators/max.py | 4 ++-- monggregate/operators/accumulators/min.py | 4 ++-- monggregate/operators/accumulators/push.py | 4 ++-- monggregate/operators/accumulators/sum.py | 4 ++-- monggregate/operators/array/array_to_object.py | 4 ++-- monggregate/operators/array/filter.py | 4 ++-- monggregate/operators/array/first.py | 4 ++-- monggregate/operators/array/in_.py | 4 ++-- monggregate/operators/array/is_array.py | 4 ++-- monggregate/operators/array/last.py | 4 ++-- monggregate/operators/array/max_n.py | 4 ++-- monggregate/operators/array/min_n.py | 4 ++-- monggregate/operators/array/size.py | 4 ++-- monggregate/operators/array/sort_array.py | 4 ++-- monggregate/operators/boolean/not_.py | 4 ++-- monggregate/operators/comparison/cmp.py | 4 ++-- monggregate/operators/comparison/eq.py | 4 ++-- monggregate/operators/comparison/gt.py | 4 ++-- monggregate/operators/comparison/gte.py | 4 ++-- monggregate/operators/comparison/lt.py | 4 ++-- monggregate/operators/comparison/lte.py | 4 ++-- monggregate/operators/comparison/ne.py | 4 ++-- monggregate/operators/objects/merge_objects.py | 4 ++-- monggregate/operators/objects/object_to_array.py | 4 ++-- monggregate/stages/bucket.py | 4 ++-- monggregate/stages/bucket_auto.py | 4 ++-- monggregate/stages/count.py | 4 ++-- monggregate/stages/group.py | 4 ++-- monggregate/stages/limit.py | 4 ++-- monggregate/stages/lookup.py | 2 +- monggregate/stages/match.py | 2 +- monggregate/stages/out.py | 2 +- monggregate/stages/project.py | 2 +- monggregate/stages/replace_root.py | 2 +- monggregate/stages/sample.py | 4 ++-- monggregate/stages/set.py | 2 +- monggregate/stages/skip.py | 4 ++-- monggregate/stages/sort.py | 2 +- monggregate/stages/sort_by_count.py | 4 ++-- monggregate/stages/unwind.py | 2 +- 45 files changed, 82 insertions(+), 81 deletions(-) diff --git a/monggregate/base.py b/monggregate/base.py index 1ad50df..1408b4b 100644 --- a/monggregate/base.py +++ b/monggregate/base.py @@ -15,7 +15,7 @@ class BaseModel(PydanticBaseModel, ABC): @classmethod def resolve(cls, obj:Any)->dict|list[dict]: - """xxx""" + """Resolves an expression encapsulated in an object from a class inheriting from BaseModel""" return resolve(obj) diff --git a/monggregate/operators/accumulators/avg.py b/monggregate/operators/accumulators/avg.py index ee2fa45..97afe0b 100644 --- a/monggregate/operators/accumulators/avg.py +++ b/monggregate/operators/accumulators/avg.py @@ -89,9 +89,10 @@ class Average(Accumulator): @property def statement(self) -> dict: - return { + return self.resolve({ "$avg" : self.expression - } + }) + Avg = Average def average(expression:Any)->dict: diff --git a/monggregate/operators/accumulators/count.py b/monggregate/operators/accumulators/count.py index 5dc81a3..8e0fcb9 100644 --- a/monggregate/operators/accumulators/count.py +++ b/monggregate/operators/accumulators/count.py @@ -58,9 +58,9 @@ class Count(Accumulator): @property def statement(self) -> dict: - return { + return self.resolve({ "$count" : {} - } + }) def count()->dict: """Creates a $count statement""" diff --git a/monggregate/operators/accumulators/first.py b/monggregate/operators/accumulators/first.py index 102daef..19fee72 100644 --- a/monggregate/operators/accumulators/first.py +++ b/monggregate/operators/accumulators/first.py @@ -77,9 +77,9 @@ class First(Accumulator): @property def statement(self) -> dict: - return { + return self.resolve({ "$first" : self.expression - } + }) def first(expression:Any)->dict: """Creates a push statement""" diff --git a/monggregate/operators/accumulators/last.py b/monggregate/operators/accumulators/last.py index 4b1b092..72654f3 100644 --- a/monggregate/operators/accumulators/last.py +++ b/monggregate/operators/accumulators/last.py @@ -71,9 +71,9 @@ class Last(Accumulator): @property def statement(self) -> dict: - return { + return self.resolve({ "$last" : self.expression - } + }) def last(expression:Any)->dict: """Creates a push statement""" diff --git a/monggregate/operators/accumulators/max.py b/monggregate/operators/accumulators/max.py index e88a325..ceec253 100644 --- a/monggregate/operators/accumulators/max.py +++ b/monggregate/operators/accumulators/max.py @@ -95,9 +95,9 @@ class Max(Accumulator): @property def statement(self) -> dict: - return { + return self.resolve({ "$max" : self.expression - } + }) def max(expression:Any)->dict: # pylint: disable=redefined-builtin """Creates a push statement""" diff --git a/monggregate/operators/accumulators/min.py b/monggregate/operators/accumulators/min.py index 4f930eb..cc5c2ea 100644 --- a/monggregate/operators/accumulators/min.py +++ b/monggregate/operators/accumulators/min.py @@ -95,9 +95,9 @@ class Min(Accumulator): @property def statement(self) -> dict: - return { + return self.resolve({ "$min" : self.expression - } + }) def min(expression:Any)->dict: """Creates a $min statement""" diff --git a/monggregate/operators/accumulators/push.py b/monggregate/operators/accumulators/push.py index a59e4a1..eea216b 100644 --- a/monggregate/operators/accumulators/push.py +++ b/monggregate/operators/accumulators/push.py @@ -48,9 +48,9 @@ class Push(Accumulator): @property def statement(self) -> dict: - return { + return self.resolve({ "$push" : self.expression - } + }) def push(expression:Any)->dict: """Creates a push statement""" diff --git a/monggregate/operators/accumulators/sum.py b/monggregate/operators/accumulators/sum.py index a6e68f4..915a32d 100644 --- a/monggregate/operators/accumulators/sum.py +++ b/monggregate/operators/accumulators/sum.py @@ -104,9 +104,9 @@ class Sum(Accumulator): @property def statement(self) -> dict: - return { + return self.resolve({ "$sum" : self.expression - } + }) def sum(*args:Content)->dict: # pylint: disable=redefined-builtin """Creates a $sum statement""" diff --git a/monggregate/operators/array/array_to_object.py b/monggregate/operators/array/array_to_object.py index e7dc649..e254600 100644 --- a/monggregate/operators/array/array_to_object.py +++ b/monggregate/operators/array/array_to_object.py @@ -68,9 +68,9 @@ class ArrayToObject(ArrayOperator): @property def statement(self) -> dict: - return { + return self.resolve({ "$arrayToObject" : self.expression - } + }) def array_to_object(expression:Any)->dict: """Returns an $arrayToObject statement""" diff --git a/monggregate/operators/array/filter.py b/monggregate/operators/array/filter.py index 4895734..3f445c1 100644 --- a/monggregate/operators/array/filter.py +++ b/monggregate/operators/array/filter.py @@ -75,14 +75,14 @@ class Filter(ArrayOperator): @property def statement(self) -> dict: - return { + return self.resolve({ "$filter":{ "input" : self.expression, "cond" : self.query, "as" : self.let, "limit" : self.limit } - } + }) def filter(expression:Any, let:str, query:Any, limit:int|None=None)->dict: # pylint: disable=redefined-builtin """Returns a $filter statement""" diff --git a/monggregate/operators/array/first.py b/monggregate/operators/array/first.py index 4b2ef5c..c626149 100644 --- a/monggregate/operators/array/first.py +++ b/monggregate/operators/array/first.py @@ -112,9 +112,9 @@ class First(ArrayOnlyOperator): @property def statement(self) -> dict: - return { + return self.resolve({ "$first":self.expression - } + }) def first(array:Any)->dict: """Returns a $first statement""" diff --git a/monggregate/operators/array/in_.py b/monggregate/operators/array/in_.py index 86ce742..08378ff 100644 --- a/monggregate/operators/array/in_.py +++ b/monggregate/operators/array/in_.py @@ -50,9 +50,9 @@ class In(ArrayOperator): @property def statement(self) -> dict: - return { + return self.resolve({ "$in":[self.left, self.right] - } + }) def in_(left:Any, right:Any)->dict: """Returns a $maxN statement""" diff --git a/monggregate/operators/array/is_array.py b/monggregate/operators/array/is_array.py index a80267f..aca898e 100644 --- a/monggregate/operators/array/is_array.py +++ b/monggregate/operators/array/is_array.py @@ -40,9 +40,9 @@ class IsArray(ArrayOnlyOperator): @property def statement(self) -> dict: - return { + return self.resolve({ "$isArray":self.expression - } + }) def is_array(array:Any)->dict: """Returns a $isArray statement""" diff --git a/monggregate/operators/array/last.py b/monggregate/operators/array/last.py index 3091829..13acfad 100644 --- a/monggregate/operators/array/last.py +++ b/monggregate/operators/array/last.py @@ -116,9 +116,9 @@ class Last(ArrayOnlyOperator): @property def statement(self) -> dict: - return { + return self.resolve({ "$last":self.expression - } + }) def last(array:Any)->dict: """Returns a $last statement""" diff --git a/monggregate/operators/array/max_n.py b/monggregate/operators/array/max_n.py index 768f9e0..05e7a4a 100644 --- a/monggregate/operators/array/max_n.py +++ b/monggregate/operators/array/max_n.py @@ -65,12 +65,12 @@ class MaxN(ArrayOperator): @property def statement(self) -> dict: - return { + return self.resolve({ "$maxN" : { "n" : self.limit, "input" : self.expression } - } + }) def max_n(expression:Any, limit:Any=1)->dict: """Returns a $maxN statement""" diff --git a/monggregate/operators/array/min_n.py b/monggregate/operators/array/min_n.py index 73b7b7e..8e9e32a 100644 --- a/monggregate/operators/array/min_n.py +++ b/monggregate/operators/array/min_n.py @@ -65,12 +65,12 @@ class MinN(ArrayOperator): @property def statement(self) -> dict: - return { + return self.resolve({ "$minN" : { "n" : self.limit, "input" : self.expression } - } + }) def min_n(expression:Any, limit:Any=1)->dict: """Returns a $minN statement""" diff --git a/monggregate/operators/array/size.py b/monggregate/operators/array/size.py index 446e514..d43eaaf 100644 --- a/monggregate/operators/array/size.py +++ b/monggregate/operators/array/size.py @@ -42,9 +42,9 @@ class Size(ArrayOnlyOperator): @property def statement(self) -> dict: - return { + return self.resolve({ "$size":self.expression - } + }) def size(array:Any)->dict: """Returns a $size statement""" diff --git a/monggregate/operators/array/sort_array.py b/monggregate/operators/array/sort_array.py index 36def54..5ca519e 100644 --- a/monggregate/operators/array/sort_array.py +++ b/monggregate/operators/array/sort_array.py @@ -101,12 +101,12 @@ class SortArray(ArrayOperator): @property def statement(self) -> dict: - return { + return self.resolve({ "$sortArray":{ "input" : self.expression, "sortBy" : self.by } - } + }) def sort_array(expression:Any, sort_by:dict[str, Literal[1, -1]])->dict: """Returns a $first statement""" diff --git a/monggregate/operators/boolean/not_.py b/monggregate/operators/boolean/not_.py index 6f4a181..052291f 100644 --- a/monggregate/operators/boolean/not_.py +++ b/monggregate/operators/boolean/not_.py @@ -43,9 +43,9 @@ class Not(BooleanOperator): @property def statement(self) -> dict: - return { + return self.resolve({ "$not" : [self.expression] - } + }) def not_(expression:Any)->dict: """Returns an $not statement""" diff --git a/monggregate/operators/comparison/cmp.py b/monggregate/operators/comparison/cmp.py index 7ae0b9c..b21f3f1 100644 --- a/monggregate/operators/comparison/cmp.py +++ b/monggregate/operators/comparison/cmp.py @@ -44,9 +44,9 @@ class Compare(Comparator): @property def statement(self) -> dict: - return { + return self.resolve({ "$cmp":[self.left, self.right] - } + }) Cmp = Compare diff --git a/monggregate/operators/comparison/eq.py b/monggregate/operators/comparison/eq.py index 8fad5f1..6439061 100644 --- a/monggregate/operators/comparison/eq.py +++ b/monggregate/operators/comparison/eq.py @@ -43,9 +43,9 @@ class Equal(Comparator): @property def statement(self) -> dict: - return { + return self.resolve({ "$eq":[self.left, self.right] - } + }) Eq = Equal diff --git a/monggregate/operators/comparison/gt.py b/monggregate/operators/comparison/gt.py index 62ce0ae..dc13ae4 100644 --- a/monggregate/operators/comparison/gt.py +++ b/monggregate/operators/comparison/gt.py @@ -41,9 +41,9 @@ class GreatherThan(Comparator): @property def statement(self) -> dict: - return { + return self.resolve({ "$gt":[self.left, self.right] - } + }) Gt = GreatherThan diff --git a/monggregate/operators/comparison/gte.py b/monggregate/operators/comparison/gte.py index 496e4f9..239073c 100644 --- a/monggregate/operators/comparison/gte.py +++ b/monggregate/operators/comparison/gte.py @@ -39,9 +39,9 @@ class GreatherThanOrEqual(Comparator): @property def statement(self) -> dict: - return { + return self.resolve({ "$gte":[self.left, self.right] - } + }) Gte = GreatherThanOrEqual diff --git a/monggregate/operators/comparison/lt.py b/monggregate/operators/comparison/lt.py index 5e48f07..d970d87 100644 --- a/monggregate/operators/comparison/lt.py +++ b/monggregate/operators/comparison/lt.py @@ -38,9 +38,9 @@ class LowerThan(Comparator): @property def statement(self) -> dict: - return { + return self.resolve({ "$lt":[self.left, self.right] - } + }) Lt = LowerThan diff --git a/monggregate/operators/comparison/lte.py b/monggregate/operators/comparison/lte.py index 137d8eb..136f3a9 100644 --- a/monggregate/operators/comparison/lte.py +++ b/monggregate/operators/comparison/lte.py @@ -39,9 +39,9 @@ class LowerThanOrEqual(Comparator): @property def statement(self) -> dict: - return { + return self.resolve({ "$lte":[self.left, self.right] - } + }) Lte = LowerThanOrEqual diff --git a/monggregate/operators/comparison/ne.py b/monggregate/operators/comparison/ne.py index dff916b..7cd5593 100644 --- a/monggregate/operators/comparison/ne.py +++ b/monggregate/operators/comparison/ne.py @@ -42,9 +42,9 @@ class NotEqual(Comparator): @property def statement(self) -> dict: - return { + return self.resolve({ "$ne":[self.left, self.right] - } + }) Ne = NotEqual diff --git a/monggregate/operators/objects/merge_objects.py b/monggregate/operators/objects/merge_objects.py index 73af8f6..9941eb6 100644 --- a/monggregate/operators/objects/merge_objects.py +++ b/monggregate/operators/objects/merge_objects.py @@ -59,9 +59,9 @@ class MergeObjects(ArrayOperator): @property def statement(self) -> dict: - return { + return self.resolve({ "$mergeObjects" : self.expression - } + }) def merge_objects(expression:Any)->dict: """Returns a merge_objects statement""" diff --git a/monggregate/operators/objects/object_to_array.py b/monggregate/operators/objects/object_to_array.py index c1128f7..81a12f7 100644 --- a/monggregate/operators/objects/object_to_array.py +++ b/monggregate/operators/objects/object_to_array.py @@ -44,9 +44,9 @@ class ObjectToArray(ArrayOperator): @property def statement(self) -> dict: - return { + return self.resolve({ "$objectToArray" : self.expression - } + }) def object_to_array(expression:Any)->dict: """Returns a *objectToArray statement""" diff --git a/monggregate/stages/bucket.py b/monggregate/stages/bucket.py index 148a7f2..33bbbeb 100644 --- a/monggregate/stages/bucket.py +++ b/monggregate/stages/bucket.py @@ -112,11 +112,11 @@ def statement(self) -> dict: # Generates statement #-------------------------------------- - return { + return self.resolve({ "$bucket" : { "groupBy" : self.by, "boundaries" :self.boundaries, "default" : self.default, "output" : self.output } - } + }) diff --git a/monggregate/stages/bucket_auto.py b/monggregate/stages/bucket_auto.py index 24dd872..f08c07f 100644 --- a/monggregate/stages/bucket_auto.py +++ b/monggregate/stages/bucket_auto.py @@ -154,11 +154,11 @@ def statement(self) -> dict: # NOTE : maybe it would be better to use _to_unique_list here # or to further validate by. - return { + return self.resolve({ "$bucketAuto" : { "groupBy" : self.by, "buckets" : self.buckets, "output" : self.output, "granularity" : self.granularity.value if self.granularity else None } - } + }) diff --git a/monggregate/stages/count.py b/monggregate/stages/count.py index f28a081..75f872f 100644 --- a/monggregate/stages/count.py +++ b/monggregate/stages/count.py @@ -57,6 +57,6 @@ class Count(Stage): @property def statement(self)-> dict: - return { + return self.resolve({ "$count" : self.name - } + }) diff --git a/monggregate/stages/group.py b/monggregate/stages/group.py index abc1d9c..03c0a2d 100644 --- a/monggregate/stages/group.py +++ b/monggregate/stages/group.py @@ -111,6 +111,6 @@ def statement(self) -> dict[str, dict]: """Generates set stage statement from arguments""" - return { + return self.resolve({ "$group":self.query - } + }) diff --git a/monggregate/stages/limit.py b/monggregate/stages/limit.py index d975e5a..3624397 100644 --- a/monggregate/stages/limit.py +++ b/monggregate/stages/limit.py @@ -68,6 +68,6 @@ class Limit(Stage): @property def statement(self)->dict: - return { + return self.resolve({ "$limit" : self.value - } + }) diff --git a/monggregate/stages/lookup.py b/monggregate/stages/lookup.py index d9ea07b..2cb4529 100644 --- a/monggregate/stages/lookup.py +++ b/monggregate/stages/lookup.py @@ -401,4 +401,4 @@ def statement(self)->dict: } } - return statement + return self.resolve(statement) diff --git a/monggregate/stages/match.py b/monggregate/stages/match.py index 96f6ba4..c401ce9 100644 --- a/monggregate/stages/match.py +++ b/monggregate/stages/match.py @@ -66,4 +66,4 @@ class Match(Stage): @property def statement(self) -> dict: - return {"$match":self.query} + return self.resolve({"$match":self.query}) diff --git a/monggregate/stages/out.py b/monggregate/stages/out.py index 821dce0..37c2285 100644 --- a/monggregate/stages/out.py +++ b/monggregate/stages/out.py @@ -148,4 +148,4 @@ def statement(self)->dict: "$out" : self.collection } - return statement + return self.resolve(statement) diff --git a/monggregate/stages/project.py b/monggregate/stages/project.py index 13b2d1e..5c90a05 100644 --- a/monggregate/stages/project.py +++ b/monggregate/stages/project.py @@ -250,4 +250,4 @@ def _to_projection(projection:dict, projection_args:list[str]|dict, include:bool def statement(self)->dict[str, dict]: """Generates statement from other attributes""" - return {"$project":self.projection} + return self.resolve({"$project":self.projection}) diff --git a/monggregate/stages/replace_root.py b/monggregate/stages/replace_root.py index 716c0af..e86a36d 100644 --- a/monggregate/stages/replace_root.py +++ b/monggregate/stages/replace_root.py @@ -101,4 +101,4 @@ def statement(self)->dict: expression = self.document - return {"$replaceRoot":{"newRoot":expression}} + return self.resolve({"$replaceRoot":{"newRoot":expression}}) diff --git a/monggregate/stages/sample.py b/monggregate/stages/sample.py index efb7ad5..8290f02 100644 --- a/monggregate/stages/sample.py +++ b/monggregate/stages/sample.py @@ -70,8 +70,8 @@ class Sample(Stage): def statement(self)->dict: """Generate statement from arguments""" - return { + return self.resolve({ "$sample" : { "size" : self.value } - } + }) diff --git a/monggregate/stages/set.py b/monggregate/stages/set.py index a4e5540..9f81609 100644 --- a/monggregate/stages/set.py +++ b/monggregate/stages/set.py @@ -53,4 +53,4 @@ class Set(Stage): def statement(self)->dict[str, dict]: """Generates set stage statement from arguments""" - return {"$set":self.document} + return self.resolve({"$set":self.document}) diff --git a/monggregate/stages/skip.py b/monggregate/stages/skip.py index 4252c80..f3d52de 100644 --- a/monggregate/stages/skip.py +++ b/monggregate/stages/skip.py @@ -81,6 +81,6 @@ class Skip(Stage): def statement(self)->dict: """Generate statement from arguments""" - return { + return self.resolve({ "$skip" : self.value - } + }) diff --git a/monggregate/stages/sort.py b/monggregate/stages/sort.py index 4ccbd53..d2294ad 100644 --- a/monggregate/stages/sort.py +++ b/monggregate/stages/sort.py @@ -264,4 +264,4 @@ def _to_query(query:dict, sort_args:list[str]|dict, direction:bool)->None: def statement(self)->dict[str, dict]: """Generates statement from other attributes""" - return {"$sort":self.query} + return self.resolve({"$sort":self.query}) diff --git a/monggregate/stages/sort_by_count.py b/monggregate/stages/sort_by_count.py index 5209e77..93c8f1a 100644 --- a/monggregate/stages/sort_by_count.py +++ b/monggregate/stages/sort_by_count.py @@ -73,6 +73,6 @@ class SortByCount(Stage): def statement(self)->dict: """Generates sort_by_count stage statement from SortByCount class keywords arguments""" - return { + return self.resolve({ "$sortByCount" : self.by - } + }) diff --git a/monggregate/stages/unwind.py b/monggregate/stages/unwind.py index ea02fb3..95efcdd 100644 --- a/monggregate/stages/unwind.py +++ b/monggregate/stages/unwind.py @@ -107,4 +107,4 @@ def statement(self)->dict[str, dict]: if self.always: params["preserveNullAndEmptyArrays"] = self.always - return {"$unwind" : params} + return self.resolve({"$unwind" : params}) From 93c59b2295ed64c170925163ccb4f68c35ff3538 Mon Sep 17 00:00:00 2001 From: Vianney Mixtur Date: Sun, 11 Jun 2023 15:01:50 +0200 Subject: [PATCH 5/5] bump version 0.11.0 -> 0.12.0 --- monggregate/__init__.py | 2 +- pyproject.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/monggregate/__init__.py b/monggregate/__init__.py index 0129ff7..5473566 100644 --- a/monggregate/__init__.py +++ b/monggregate/__init__.py @@ -3,7 +3,7 @@ from monggregate.pipeline import Pipeline from monggregate.expressions.expressions import Expression -__version__ = "0.11.0" +__version__ = "0.12.0" __author__ = "Vianney Mixtur" __contact__ = "prenom.nom@outlook.fr" __copyright__ = "Copyright © 2022 Vianney Mixtur" diff --git a/pyproject.toml b/pyproject.toml index 64e1516..5cbfcca 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" [project] name = "monggregate" -version = "0.11.0" +version = "0.12.0" description = "MongoDB aggregation pipelines made easy. Joins, grouping, counting and much more..." readme = "README.md" authors = [{ name = "Vianney Mixtur", email = "vianney.mixtur@outlook.fr" }] @@ -33,7 +33,7 @@ dev = ["bumpver", "pytest", "mypy", "pylint"] Homepage = "https://github.com/VianneyMI/monggregate" [tool.bumpver] -current_version = "0.11.0" +current_version = "0.12.0" version_pattern = "MAJOR.MINOR.PATCH" commit_message = "bump version {old_version} -> {new_version}" commit = true