def test_from_ast(self): expected = [ AST( 'filter', AST( 'cond_eq', [ AST('prop', 'foo'), AST('val', 'bar') ] ) ) ] attrs = { 'find_elements.return_value': [] } self.feature.configure_mock(**attrs) q = self.query.from_ast(expected) self.assertIsInstance(q, Query) self.assertEqual(q.ast, expected) list(q) self.feature.find_elements.assert_called_with(expected)
def get_ast(self): ast = AST( 'join_{0}'.format(self.name), [self.left.get_ast(), self.right.get_ast()]) if self.inverted: return AST('not', ast) else: return ast
def process_query(self, query): if query['type'] == Driver.QUERY_CREATE: ast = AST('insert', query['update']) doc = self.wupdate.walk(self.mbuilder.parse(ast), {}) return self.obj.insert(doc) elif query['type'] in [Driver.QUERY_READ, Driver.QUERY_COUNT]: ast = query['filter'] mfilter, s = {}, slice(None) aggregation = False if ast: ast = AST('query', ast) result = self.wfilter.walk(self.mbuilder.parse(ast)) if isinstance(result, tuple): mfilter, s = result else: aggregation = True if not aggregation: result = self.obj.find(mfilter, skip=s.start, limit=s.stop) else: result = self.obj.aggregate(result) if query['type'] == Driver.QUERY_COUNT: result = result.count() return result elif query['type'] == Driver.QUERY_UPDATE: filter_ast = AST('query', query['filter']) update_ast = AST('update', query['update']) mfilter, _ = self.wfilter.walk(self.mbuilder.parse(filter_ast)) uspec = self.wupdate.walk(self.mbuilder.parse(update_ast), {}) result = self.obj.update(mfilter, uspec, multi=True) return result.modified_count elif query['type'] == Driver.QUERY_DELETE: ast = AST('query', query['filter']) mfilter, _ = self.wfilter.walk(self.mbuilder.parse(ast)) result = self.obj.delete(mfilter, multi=True) return result.deleted_count
def update(self, *fields): """ Update elements matching the query. :param fields: Assignments :type fields: list of A :returns: Number of modified elements. :rtype: int """ c = self._copy() fields_ast = [] for field in fields: if not isinstance(field, A): raise TypeError('Supplied field is not supported: {0}'.format( type(field))) fields_ast.append(field.get_ast()) c.ast.append(AST('update', fields_ast)) return self.manager.execute(c.ast)
def delete(self): """ Delete element from store. """ condition = self._get_filter() self.driver.remove_elements([AST('filter', condition.get_ast())])
def get_ast(self): """ Returns simplified AST. :returns: AST node as dict :rtype: dict """ return AST('node', self.name)
def group(self, key, *expressions): """ Group elements by key matching the query using the expressions. :param key: Key used to group elements :type key: str :param expressions: Expressions :type expressions: list of CombinableExpression :returns: Grouped elements. """ c = self._copy() c.ast.append( AST('group', [AST('prop', key)] + [expression.get_ast() for expression in expressions])) return self.manager.execute(c.ast)
def delete(self): """ Delete elements matching the query. :returns: Number of deleted elements. :rtype: int """ c = self._copy() c.ast.append(AST('delete', None)) return self.manager.execute(c.ast)
def count(self): """ Count elements matched by this query. :returns: Number of matching elements :rtype: int """ c = self._copy() c.ast.append(AST('count', None)) return self.manager.execute(c.ast)
def get(self, condition): """ Get a single element matching the filter. :param condition: Filter :type condition: C or CombinedCondition :returns: Matching element or None :rtype: Model or None """ if not isinstance(condition, (C, CombinedCondition)): raise TypeError('Supplied condition is not supported: {0}'.format( type(condition))) return self.execute(AST('get', condition.get_ast()))
def __getitem__(self, s): """ Returns a new query with a slice of filtered elements. :param s: query's slice :type s: slice :returns: Query :rtype: Query """ c = self._copy() if not isinstance(s, slice): s = slice(s) c.ast.append(AST('slice', s)) return c
def get(self, condition): """ Add filter to the query, and get a single element matching the query. :param condition: Filter :type condition: C or CombinedCondition :returns: Matching element or None :rtype: Model or None """ c = self._copy() if not isinstance(condition, (C, CombinedCondition)): raise TypeError('Supplied condition is not supported: {0}'.format( type(condition))) c.ast.append(AST('get', condition.get_ast())) return self.manager.execute(c.ast)
def exclude(self, condition): """ Returns a new query with a new (negated) filter added. :param condition: Filter :type condition: C or CombinedCondition :returns: Query :rtype: Query """ c = self._copy() if not isinstance(condition, (C, CombinedCondition)): raise TypeError('Supplied condition is not supported: {0}'.format( type(condition))) c.ast.append(AST('exclude', condition.get_ast())) return c
def create(self, *fields): """ Put a new element into the store. :param fields: List of assignments :type fields: list of A :returns: Created element :rtype: Model """ fields_ast = [] for field in fields: if not isinstance(field, A): raise TypeError('Supplied field is not supported: {0}'.format( type(field))) fields_ast.append(field.get_ast()) return self.execute(AST('create', fields_ast))
def test_validate_ast(self): with self.assertRaises(ASTSingleStatementError): self.query.validate_ast(AST('not_get_or_create', 'unused')) for stmt in ['update', 'delete', 'get', 'count', 'group']: with self.assertRaises(ASTLastStatementError): self.query.validate_ast([ AST(stmt, 'unused'), AST('unused', 'unused') ]) with self.assertRaises(ASTInvalidStatementError): self.query.validate_ast([ AST('unknown', 'unused') ]) with self.assertRaises(ASTInvalidFormatError): self.query.validate_ast('invalid format') self.query.validate_ast([ AST('filter', 'unused'), AST('update', 'unused') ])
def get_ast(self): return AST('cond_{0}'.format(self.operator), [AST('prop', self.name), self.value.get_ast()])
def get_ast(self): return AST( 'op_{0}'.format(self.name), [self.left.get_ast(), self.right.get_ast()])
def get_ast(self): return AST('ref', self.name)
def get_ast(self): return AST('func_{0}'.format(self.name), [arg.get_ast() for arg in self.arguments])
def get_ast(self): return AST('val', self.name)
def get_ast(self): return AST('assign', [ AST('prop', self.name), self.value.get_ast() if self.value else AST('val', None) ])