Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # queries_executer_test.py
- # The Task:
- # ● Write a suitable script.
- # ● Allow your script to run with a “mongodb” like query format. (Note: Don’t use
- # mongodb. You only need to implement the query format.)
- # The script should support:
- # ○ $or, $and conditions
- # ○ $eq, $ne, $in, $nin, $gt, $gte, $lt and $lte
- # https://docs.mongodb.com/manual/reference/operator
- #
- # ● The script should get the query as an argument and print the documents found.
- # ● You are allowed to add as many functions as you need.
- # ● All combination of queries should be supported - not only those in the examples below.
- # ● Your solution should be generic so that if the inline DB is replaced with different
- # information and a relevant query is sent, the script will still work.
- #
- # Note: For the sake of this task, you are NOT required to handle performance optimizations;
- # you can assume that we always do a full table scan
- #
- # Examples:
- # Print information of product “cd” using “$eq”:
- # python main.py "{\"name\": {\"\$eq\": \"cd\"}}"
- # Result: { "name": "cd", "qty": 5, "price": 3.99 }
- #
- # Print products with low quantity (below 10) and price above $2:
- # python main.py "{\"\$and\": [{\"price\": {\"\$gt\": 1}}, {\"qty\": {\"\$lt\": 10}}]}"
- # Result: { "name": "cd", "qty": 5, "price": 3.99 } { "name": "ij", "qty": 3, "price": 1.99 }
- #
- # An example showing $and and $or together
- # python main.py "{\"\$and\": [{\"name\": {\"\$eq\": \"ij\"}}, {\"\$or\": [{\"price\": {\"\$lt\": 2}}, {\"qty\": {\"\$gte\": 15}}]}]}"
- # Result: { "name": "ij", "qty": 3, "price": 1.99 }
- import sys
- import errno
- import unittest
- from unittest.case import expectedFailure
- IS_DEBUG_MODE = True
- inventory = [
- { "name": "ab", "qty": 15, "price": 2.99 },
- { "name": "cd", "qty": 5, "price": 3.99 },
- { "name": "ij", "qty": 3, "price": 1.99 },
- { "name": "xy", "qty": 20, "price": 1.99 }
- ]
- def main():
- if len(sys.argv) == 2:
- input_query = parse_cmd_query_string(sys.argv[1])
- else:
- if IS_DEBUG_MODE:
- input_query = {"name": {"$eq": "cd"}}
- else:
- print("invalid number of arguments")
- sys.exit(errno.EINVAL)
- results = find(inventory, input_query)
- for record in results:
- print(record)
- print("End.")
- def find(db, query):
- executer = QueriesExecuter(db)
- return executer.execute(query)
- def parse_cmd_query_string(query_string):
- # TODO: Parse string
- return {}
- class QueriesExecuter:
- def __init__(self, data_source):
- self.data_source = data_source
- def execute(self, query):
- if not query or not isinstance(query, dict):
- raise Exception(f"Illegal query: {query}")
- results = []
- for row in self.data_source:
- if self._check_condition(row, query):
- results.append(row.copy())
- return results
- def _check_condition(self, row, condition):
- if not condition or not isinstance(condition, dict):
- raise Exception(f"Illegal condition: {condition}")
- if len(condition) != 1:
- raise Exception(f"Illegal condition length: {condition}")
- column_name_or_saved_word, value = list(condition.items())[0]
- if not column_name_or_saved_word:
- raise Exception(f"Illegal name: {column_name_or_saved_word}")
- if column_name_or_saved_word == "$and":
- return self._check_and_conditions(row, value)
- elif column_name_or_saved_word == "$or":
- return self._check_or_conditions(row, value)
- else:
- return self._check_column_conditions(row, column_name_or_saved_word, value)
- def _check_and_conditions(self, row, conditions):
- if not conditions or not isinstance(conditions, list):
- raise Exception(f"Illegal conditions: {conditions}")
- for condition in conditions:
- if not self._check_condition(row, condition):
- return False
- return True
- def _check_or_conditions(self, row, conditions):
- if not conditions or not isinstance(conditions, list):
- raise Exception(f"Illegal conditions: {conditions}")
- for condition in conditions:
- if self._check_condition(row, condition):
- return True
- return False
- def _check_column_conditions(self, row, col_name, conditions):
- if not row or not isinstance(row, dict):
- raise Exception("Illegal row")
- if not conditions or not isinstance(conditions, dict):
- raise Exception("Illegal conditions")
- if col_name not in row:
- raise Exception(f"Column name not found in table: {col_name}")
- operators_switcher = {
- "eq": self.operator_eq,
- "ne": self.operator_ne,
- "in": self.operator_in,
- "nin": self.operator_nin,
- "gt": self.operator_gt,
- "gte": self.operator_gte,
- "lt": self.operator_lt,
- "lte": self.operator_lte
- }
- for operator_name, second_val in conditions.items():
- clean_operator_name = operator_name[1:]
- if clean_operator_name not in operators_switcher:
- raise Exception(f"Illegal operator: {operator_name}")
- first_val = row[col_name]
- if not operators_switcher[clean_operator_name](first_val, second_val):
- return False
- return True
- @classmethod
- def operator_eq(cls, first, second):
- return first == second
- @classmethod
- def operator_ne(cls, first, second):
- return not cls.operator_eq(first, second)
- @classmethod
- def operator_in(cls, first, second):
- return first in second
- @classmethod
- def operator_nin(cls, first, second):
- return not cls.operator_in(first, second)
- @classmethod
- def operator_gt(cls, first, second):
- return first > second
- @classmethod
- def operator_gte(cls, first, second):
- return first >= second
- @classmethod
- def operator_lt(cls, first, second):
- return first < second
- @classmethod
- def operator_lte(cls, first, second):
- return first <= second
- class Test_QueriesExecuter(unittest.TestCase):
- db = [
- { "name": "ab", "qty": 15, "price": 2.99 },
- { "name": "cd", "qty": 5, "price": 3.99 },
- { "name": "ij", "qty": 3, "price": 1.99 },
- { "name": "xy", "qty": 20, "price": 1.99 }
- ]
- def test_simple_query(self):
- query = {"name": {"$eq": "cd"}}
- result = QueriesExecuter(self.db).execute(query)
- self.assertEqual(result, [
- { "name": "cd", "qty": 5, "price": 3.99 },
- ])
- def test_AND_query(self):
- query = {"$and": [
- {"price": {"$gt": 1}},
- {"qty": {"$lt": 10}},
- ]}
- result = QueriesExecuter(self.db).execute(query)
- self.assertEqual(result, [
- { "name": "cd", "qty": 5, "price": 3.99 },
- { "name": "ij", "qty": 3, "price": 1.99 },
- ])
- def test_AND_with_inner_OR_query(self):
- query = {
- "$and": [
- {"name": {"$eq": "ij"}},
- {"$or": [
- {"price": {"$lt": 2}},
- {"qty": {"$gte": 15}},
- ]
- }
- ]
- }
- result = QueriesExecuter(self.db).execute(query)
- self.assertEqual(result, [
- { "name": "ij", "qty": 3, "price": 1.99 },
- ])
- def test_AND_with_inner_dict_instead_list(self):
- query = {
- "$and": {"name": {"$eq": "ij"}}
- }
- with self.assertRaises(Exception):
- result = QueriesExecuter(self.db).execute(query)
- if __name__ == "__main__":
- main()
- # unittest.main()
Add Comment
Please, Sign In to add comment