diff --git a/src/masoniteorm/query/QueryBuilder.py b/src/masoniteorm/query/QueryBuilder.py index 13ce96b2..1bac3cc9 100644 --- a/src/masoniteorm/query/QueryBuilder.py +++ b/src/masoniteorm/query/QueryBuilder.py @@ -485,7 +485,9 @@ def where_raw(self, query: str, bindings=()): Returns: self """ - self._wheres += ((QueryExpression(query, "=", None, "value", raw=True)),) + self._wheres += ( + (QueryExpression(query, "=", None, "value", raw=True, bindings=bindings)), + ) return self def or_where(self, column: [str, int], *args) -> "self": @@ -1355,7 +1357,7 @@ def min(self, column): def _extract_operator_value(self, *args): - operators = ["=", ">", ">=", "<", "<=", "!=", "<>"] + operators = ["=", ">", ">=", "<", "<=", "!=", "<>", "like", "not like"] operator = operators[0] diff --git a/src/masoniteorm/query/grammars/BaseGrammar.py b/src/masoniteorm/query/grammars/BaseGrammar.py index eaf0760a..36fdd60b 100644 --- a/src/masoniteorm/query/grammars/BaseGrammar.py +++ b/src/masoniteorm/query/grammars/BaseGrammar.py @@ -392,7 +392,13 @@ def process_wheres(self, qmark=False, strip_first_where=False): keyword=keyword, query=where.column ) - self.add_binding(where.bindings) + if not isinstance(where.bindings, (list, tuple)): + raise ValueError( + f"Binings must be tuple or list. Received {type(where.bindings)}" + ) + + if where.bindings: + self.add_binding(*where.bindings) continue @@ -427,6 +433,10 @@ def process_wheres(self, qmark=False, strip_first_where=False): sql_string = self.where_not_null_string() elif equality == "EXISTS": sql_string = self.where_exists_string() + elif equality.upper() == "LIKE": + sql_string = self.where_like_string() + elif equality.upper() == "NOT LIKE": + sql_string = self.where_not_like_string() else: sql_string = self.where_string() diff --git a/src/masoniteorm/query/grammars/MSSQLGrammar.py b/src/masoniteorm/query/grammars/MSSQLGrammar.py index 5bcdfa23..fb15dc7b 100644 --- a/src/masoniteorm/query/grammars/MSSQLGrammar.py +++ b/src/masoniteorm/query/grammars/MSSQLGrammar.py @@ -53,6 +53,12 @@ def having_string(self): def where_exists_string(self): return "{keyword} EXISTS {value}" + def where_like_string(self): + return "{keyword} {column} LIKE {value}" + + def where_not_like_string(self): + return "{keyword} {column} NOT LIKE {value}" + def having_equality_string(self): return "HAVING {column} {equality} {value}" diff --git a/src/masoniteorm/query/grammars/MySQLGrammar.py b/src/masoniteorm/query/grammars/MySQLGrammar.py index 75683511..42697f2e 100644 --- a/src/masoniteorm/query/grammars/MySQLGrammar.py +++ b/src/masoniteorm/query/grammars/MySQLGrammar.py @@ -113,6 +113,12 @@ def not_between_string(self): def where_exists_string(self): return "{keyword} EXISTS {value}" + def where_like_string(self): + return "{keyword} {column} LIKE {value}" + + def where_not_like_string(self): + return "{keyword} {column} NOT LIKE {value}" + def subquery_alias_string(self): return "AS {alias}" diff --git a/src/masoniteorm/query/grammars/PostgresGrammar.py b/src/masoniteorm/query/grammars/PostgresGrammar.py index 1cf34729..6498d0b1 100644 --- a/src/masoniteorm/query/grammars/PostgresGrammar.py +++ b/src/masoniteorm/query/grammars/PostgresGrammar.py @@ -66,6 +66,12 @@ def not_between_string(self): def where_exists_string(self): return "{keyword} EXISTS {value}" + def where_like_string(self): + return "{keyword} {column} LIKE {value}" + + def where_not_like_string(self): + return "{keyword} {column} NOT LIKE {value}" + def subquery_alias_string(self): return "AS {alias}" diff --git a/src/masoniteorm/query/grammars/SQLiteGrammar.py b/src/masoniteorm/query/grammars/SQLiteGrammar.py index 9d5e80bc..3a03d835 100644 --- a/src/masoniteorm/query/grammars/SQLiteGrammar.py +++ b/src/masoniteorm/query/grammars/SQLiteGrammar.py @@ -69,6 +69,12 @@ def not_between_string(self): def where_exists_string(self): return "{keyword} EXISTS {value}" + def where_like_string(self): + return "{keyword} {column} LIKE {value}" + + def where_not_like_string(self): + return "{keyword} {column} NOT LIKE {value}" + def subquery_alias_string(self): return "AS {alias}" diff --git a/src/masoniteorm/testing/BaseTestCaseSelectGrammar.py b/src/masoniteorm/testing/BaseTestCaseSelectGrammar.py index 7840c441..b42c65b5 100644 --- a/src/masoniteorm/testing/BaseTestCaseSelectGrammar.py +++ b/src/masoniteorm/testing/BaseTestCaseSelectGrammar.py @@ -307,3 +307,17 @@ def test_can_compile_first_or_fail(self): self, inspect.currentframe().f_code.co_name.replace("test_", "") )() self.assertEqual(to_sql, sql) + + def test_where_like(self): + to_sql = self.builder.where("age", "like", "%name%").to_sql() + sql = getattr( + self, inspect.currentframe().f_code.co_name.replace("test_", "") + )() + self.assertEqual(to_sql, sql) + + def test_where_not_like(self): + to_sql = self.builder.where("age", "not like", "%name%").to_sql() + sql = getattr( + self, inspect.currentframe().f_code.co_name.replace("test_", "") + )() + self.assertEqual(to_sql, sql) diff --git a/tests/mssql/grammar/test_mssql_select_grammar.py b/tests/mssql/grammar/test_mssql_select_grammar.py index 46ad6381..32eb83a6 100644 --- a/tests/mssql/grammar/test_mssql_select_grammar.py +++ b/tests/mssql/grammar/test_mssql_select_grammar.py @@ -279,3 +279,17 @@ def can_compile_first_or_fail(self): builder.where("is_admin", "=", True).first_or_fail() """ return """SELECT TOP 1 * FROM [users] WHERE [users].[is_admin] = '1'""" + + def where_like(self): + """ + builder = self.get_builder() + builder.where("age", "like", "%name%") + """ + return """SELECT * FROM [users] WHERE [users].[age] LIKE '%name%'""" + + def where_not_like(self): + """ + builder = self.get_builder() + builder.where("age", "like", "%name%") + """ + return """SELECT * FROM [users] WHERE [users].[age] NOT LIKE '%name%'""" diff --git a/tests/mysql/builder/test_query_builder.py b/tests/mysql/builder/test_query_builder.py index 59847d76..4b7a4a25 100644 --- a/tests/mysql/builder/test_query_builder.py +++ b/tests/mysql/builder/test_query_builder.py @@ -50,6 +50,24 @@ def test_with_(self): )() self.assertEqual(builder.to_sql(), sql) + def test_where_like(self): + builder = self.get_builder() + builder.where("age", "like", "%name%") + + sql = getattr( + self, inspect.currentframe().f_code.co_name.replace("test_", "") + )() + self.assertEqual(builder.to_sql(), sql) + + def test_where_not_like(self): + builder = self.get_builder() + builder.where("age", "not like", "%name%") + + sql = getattr( + self, inspect.currentframe().f_code.co_name.replace("test_", "") + )() + self.assertEqual(builder.to_sql(), sql) + def test_max(self): builder = self.get_builder() builder.max("age") @@ -653,3 +671,17 @@ def or_where(self): return ( "SELECT * FROM `users` WHERE `users`.`age` = '20' OR `users`.`age` < '20'" ) + + def where_like(self): + """ + builder = self.get_builder() + builder.where("age", "like", "%name%") + """ + return "SELECT * FROM `users` WHERE `users`.`age` LIKE '%name%'" + + def where_not_like(self): + """ + builder = self.get_builder() + builder.where("age", "not like", "%name%") + """ + return "SELECT * FROM `users` WHERE `users`.`age` NOT LIKE '%name%'" diff --git a/tests/mysql/grammar/test_mysql_select_grammar.py b/tests/mysql/grammar/test_mysql_select_grammar.py index 4e115501..ea4ff028 100644 --- a/tests/mysql/grammar/test_mysql_select_grammar.py +++ b/tests/mysql/grammar/test_mysql_select_grammar.py @@ -273,3 +273,17 @@ def can_compile_first_or_fail(self): builder.where("is_admin", "=", True).first_or_fail() """ return """SELECT * FROM `users` WHERE `users`.`is_admin` = '1' LIMIT 1""" + + def where_not_like(self): + """ + builder = self.get_builder() + builder.where("age", "not like", "%name%").to_sql() + """ + return "SELECT * FROM `users` WHERE `users`.`age` NOT LIKE '%name%'" + + def where_like(self): + """ + builder = self.get_builder() + builder.where("age", "not like", "%name%").to_sql() + """ + return "SELECT * FROM `users` WHERE `users`.`age` LIKE '%name%'" diff --git a/tests/postgres/builder/test_postgres_query_builder.py b/tests/postgres/builder/test_postgres_query_builder.py index 9be70ee3..6512d3c8 100644 --- a/tests/postgres/builder/test_postgres_query_builder.py +++ b/tests/postgres/builder/test_postgres_query_builder.py @@ -40,6 +40,24 @@ def test_sum(self): )() self.assertEqual(builder.to_sql(), sql) + def test_where_like(self): + builder = self.get_builder() + builder.where("age", "like", "%name%") + + sql = getattr( + self, inspect.currentframe().f_code.co_name.replace("test_", "") + )() + self.assertEqual(builder.to_sql(), sql) + + def test_where_not_like(self): + builder = self.get_builder() + builder.where("age", "not like", "%name%") + + sql = getattr( + self, inspect.currentframe().f_code.co_name.replace("test_", "") + )() + self.assertEqual(builder.to_sql(), sql) + def test_max(self): builder = self.get_builder() builder.max("age") @@ -635,3 +653,17 @@ def or_where(self): builder.where('age', '20').or_where('age','<', 20) """ return """SELECT * FROM "users" WHERE "users"."age" = '20' OR "users"."age" < '20'""" + + def where_like(self): + """ + builder = self.get_builder() + builder.where("age", "like", "%name%") + """ + return """SELECT * FROM "users" WHERE "users"."age" LIKE '%name%'""" + + def where_not_like(self): + """ + builder = self.get_builder() + builder.where("age", "not like", "%name%") + """ + return """SELECT * FROM "users" WHERE "users"."age" NOT LIKE '%name%'""" diff --git a/tests/postgres/grammar/test_select_grammar.py b/tests/postgres/grammar/test_select_grammar.py index 421078ed..9ebb3388 100644 --- a/tests/postgres/grammar/test_select_grammar.py +++ b/tests/postgres/grammar/test_select_grammar.py @@ -273,3 +273,17 @@ def can_compile_first_or_fail(self): builder.where("is_admin", "=", True).first_or_fail() """ return """SELECT * FROM "users" WHERE "users"."is_admin" = '1' LIMIT 1""" + + def where_not_like(self): + """ + builder = self.get_builder() + builder.where("age", "not like", "%name%").to_sql() + """ + return """SELECT * FROM "users" WHERE "users"."age" NOT LIKE '%name%'""" + + def where_like(self): + """ + builder = self.get_builder() + builder.where("age", "not like", "%name%").to_sql() + """ + return """SELECT * FROM "users" WHERE "users"."age" LIKE '%name%'""" diff --git a/tests/sqlite/builder/test_sqlite_query_builder.py b/tests/sqlite/builder/test_sqlite_query_builder.py index 4289b11e..290736f1 100644 --- a/tests/sqlite/builder/test_sqlite_query_builder.py +++ b/tests/sqlite/builder/test_sqlite_query_builder.py @@ -30,6 +30,24 @@ def test_sum(self): )() self.assertEqual(builder.to_sql(), sql) + def test_where_like(self): + builder = self.get_builder() + builder.where("age", "like", "%name%") + + sql = getattr( + self, inspect.currentframe().f_code.co_name.replace("test_", "") + )() + self.assertEqual(builder.to_sql(), sql) + + def test_where_not_like(self): + builder = self.get_builder() + builder.where("age", "not like", "%name%") + + sql = getattr( + self, inspect.currentframe().f_code.co_name.replace("test_", "") + )() + self.assertEqual(builder.to_sql(), sql) + def test_max(self): builder = self.get_builder() builder.max("age") @@ -636,3 +654,17 @@ def or_where(self): builder.where('age', '20').or_where('age','<', 20) """ return """SELECT * FROM "users" WHERE "users"."age" = '20' OR "users"."age" < '20'""" + + def where_like(self): + """ + builder = self.get_builder() + builder.where("age", "like", "%name%") + """ + return """SELECT * FROM "users" WHERE "users"."age" LIKE '%name%'""" + + def where_not_like(self): + """ + builder = self.get_builder() + builder.where("age", "like", "%name%") + """ + return """SELECT * FROM "users" WHERE "users"."age" NOT LIKE '%name%'""" diff --git a/tests/sqlite/grammar/test_sqlite_select_grammar.py b/tests/sqlite/grammar/test_sqlite_select_grammar.py index bd1dd9cc..07d0baf5 100644 --- a/tests/sqlite/grammar/test_sqlite_select_grammar.py +++ b/tests/sqlite/grammar/test_sqlite_select_grammar.py @@ -273,3 +273,17 @@ def can_compile_first_or_fail(self): builder.where("is_admin", "=", True).first_or_fail() """ return """SELECT * FROM "users" WHERE "users"."is_admin" = '1' LIMIT 1""" + + def where_not_like(self): + """ + builder = self.get_builder() + builder.where("age", "not like", "%name%").to_sql() + """ + return """SELECT * FROM "users" WHERE "users"."age" NOT LIKE '%name%'""" + + def where_like(self): + """ + builder = self.get_builder() + builder.where("age", "not like", "%name%").to_sql() + """ + return """SELECT * FROM "users" WHERE "users"."age" LIKE '%name%'"""