From e6efedbbab3ba050536aa2786daec4c9f3951356 Mon Sep 17 00:00:00 2001 From: yubarajshrestha Date: Wed, 21 Sep 2022 08:25:38 +0545 Subject: [PATCH 1/3] Adds oldest, latest methods to QueryBuilder, fixes #790 --- src/masoniteorm/models/Model.py | 2 ++ src/masoniteorm/query/QueryBuilder.py | 32 +++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/masoniteorm/models/Model.py b/src/masoniteorm/models/Model.py index ce3d8fc9..b3fd6cc8 100644 --- a/src/masoniteorm/models/Model.py +++ b/src/masoniteorm/models/Model.py @@ -255,6 +255,8 @@ class Model(TimeStampsMixin, ObservesEvents, metaclass=ModelMeta): "where_doesnt_have", "with_", "with_count", + "latest", + "oldest" ] __cast_map__ = {} diff --git a/src/masoniteorm/query/QueryBuilder.py b/src/masoniteorm/query/QueryBuilder.py index 9ac9ddf1..52b35844 100644 --- a/src/masoniteorm/query/QueryBuilder.py +++ b/src/masoniteorm/query/QueryBuilder.py @@ -2266,3 +2266,35 @@ def get_schema(self): return Schema( connection=self.connection, connection_details=self._connection_details ) + + def latest(self, *fields): + """Gets the latest record. + + Returns: + querybuilder + """ + + if not fields: + fields = ("created_at",) + + table = self.get_table_name() + fields = map(lambda field: f"`{table}`.`{field}`", fields) + sql = " desc, ".join(fields) + " desc" + + return self.order_by_raw(sql) + + def oldest(self, *fields): + """Gets the oldest record. + + Returns: + querybuilder + """ + + if not fields: + fields = ("created_at",) + + table = self.get_table_name() + fields = map(lambda field: f"`{table}`.`{field}`", fields) + sql = " asc, ".join(fields) + " asc" + + return self.order_by_raw(sql) From 89992b76c5719c7d9d19d36df08ef795e97627b8 Mon Sep 17 00:00:00 2001 From: yubarajshrestha Date: Sat, 8 Oct 2022 15:20:48 +0545 Subject: [PATCH 2/3] Changed raw query to order_by --- src/masoniteorm/query/QueryBuilder.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/masoniteorm/query/QueryBuilder.py b/src/masoniteorm/query/QueryBuilder.py index 52b35844..a1e127d6 100644 --- a/src/masoniteorm/query/QueryBuilder.py +++ b/src/masoniteorm/query/QueryBuilder.py @@ -2277,11 +2277,7 @@ def latest(self, *fields): if not fields: fields = ("created_at",) - table = self.get_table_name() - fields = map(lambda field: f"`{table}`.`{field}`", fields) - sql = " desc, ".join(fields) + " desc" - - return self.order_by_raw(sql) + return self.order_by(column=",".join(fields), direction="DESC") def oldest(self, *fields): """Gets the oldest record. @@ -2293,8 +2289,4 @@ def oldest(self, *fields): if not fields: fields = ("created_at",) - table = self.get_table_name() - fields = map(lambda field: f"`{table}`.`{field}`", fields) - sql = " asc, ".join(fields) + " asc" - - return self.order_by_raw(sql) + return self.order_by(column=",".join(fields), direction="ASC") From 7d0ee4de6df0b36329ec7bc6e0bd7aa243543967 Mon Sep 17 00:00:00 2001 From: yubarajshrestha Date: Mon, 10 Oct 2022 15:18:47 +0545 Subject: [PATCH 3/3] Added Latest/Oldest Test Cases --- .../mssql/builder/test_mssql_query_builder.py | 24 ++++++++++++++++ tests/mysql/builder/test_query_builder.py | 28 +++++++++++++++++++ .../builder/test_postgres_query_builder.py | 28 +++++++++++++++++++ .../builder/test_sqlite_query_builder.py | 28 +++++++++++++++++++ 4 files changed, 108 insertions(+) diff --git a/tests/mssql/builder/test_mssql_query_builder.py b/tests/mssql/builder/test_mssql_query_builder.py index a3b45079..3fbf671f 100644 --- a/tests/mssql/builder/test_mssql_query_builder.py +++ b/tests/mssql/builder/test_mssql_query_builder.py @@ -411,3 +411,27 @@ def test_truncate_without_foreign_keys(self): builder = self.get_builder(dry=True) sql = builder.truncate(foreign_keys=True) self.assertEqual(sql, "TRUNCATE TABLE [users]") + + def test_latest(self): + builder = self.get_builder() + builder.latest("email") + self.assertEqual( + builder.to_sql(), "SELECT * FROM [users] ORDER BY [email] DESC" + ) + + def test_latest_multiple(self): + builder = self.get_builder() + builder.latest("email", "created_at") + self.assertEqual( + builder.to_sql(), "SELECT * FROM [users] ORDER BY [email] DESC, [created_at] DESC" + ) + + def test_oldest(self): + builder = self.get_builder() + builder.oldest("email") + self.assertEqual(builder.to_sql(), "SELECT * FROM [users] ORDER BY [email] ASC") + + def test_oldest_multiple(self): + builder = self.get_builder() + builder.oldest("email", "created_at") + self.assertEqual(builder.to_sql(), "SELECT * FROM [users] ORDER BY [email] ASC, [created_at] ASC") diff --git a/tests/mysql/builder/test_query_builder.py b/tests/mysql/builder/test_query_builder.py index 8ce5df4e..cd188787 100644 --- a/tests/mysql/builder/test_query_builder.py +++ b/tests/mysql/builder/test_query_builder.py @@ -917,3 +917,31 @@ def update_lock(self): builder.truncate() """ return "SELECT * FROM `users` WHERE `users`.`votes` >= '100' FOR UPDATE" + + def test_latest(self): + builder = self.get_builder() + builder.latest('email') + sql = getattr( + self, inspect.currentframe().f_code.co_name.replace("test_", "") + )() + self.assertEqual(builder.to_sql(), sql) + + def test_oldest(self): + builder = self.get_builder() + builder.oldest('email') + sql = getattr( + self, inspect.currentframe().f_code.co_name.replace("test_", "") + )() + self.assertEqual(builder.to_sql(), sql) + + def latest(self): + """ + builder.order_by('email', 'des') + """ + return "SELECT * FROM `users` ORDER BY `email` DESC" + + def oldest(self): + """ + builder.order_by('email', 'asc') + """ + return "SELECT * FROM `users` ORDER BY `email` ASC" \ No newline at end of file diff --git a/tests/postgres/builder/test_postgres_query_builder.py b/tests/postgres/builder/test_postgres_query_builder.py index d905e0d8..46a98ffb 100644 --- a/tests/postgres/builder/test_postgres_query_builder.py +++ b/tests/postgres/builder/test_postgres_query_builder.py @@ -772,3 +772,31 @@ def shared_lock(self): builder.truncate() """ return """SELECT * FROM "users" WHERE "users"."votes" >= '100' FOR SHARE""" + + def test_latest(self): + builder = self.get_builder() + builder.latest('email') + sql = getattr( + self, inspect.currentframe().f_code.co_name.replace("test_", "") + )() + self.assertEqual(builder.to_sql(), sql) + + def test_oldest(self): + builder = self.get_builder() + builder.oldest('email') + sql = getattr( + self, inspect.currentframe().f_code.co_name.replace("test_", "") + )() + self.assertEqual(builder.to_sql(), sql) + + def oldest(self): + """ + builder.order_by('email', 'asc') + """ + return """SELECT * FROM "users" ORDER BY "email" ASC""" + + def latest(self): + """ + builder.order_by('email', 'des') + """ + return """SELECT * FROM "users" ORDER BY "email" DESC""" \ No newline at end of file diff --git a/tests/sqlite/builder/test_sqlite_query_builder.py b/tests/sqlite/builder/test_sqlite_query_builder.py index 7fa4a80d..0449e000 100644 --- a/tests/sqlite/builder/test_sqlite_query_builder.py +++ b/tests/sqlite/builder/test_sqlite_query_builder.py @@ -971,3 +971,31 @@ def truncate_without_foreign_keys(self): 'DELETE FROM "users"', "PRAGMA foreign_keys = ON", ] + + def test_latest(self): + builder = self.get_builder() + builder.latest('email') + sql = getattr( + self, inspect.currentframe().f_code.co_name.replace("test_", "") + )() + self.assertEqual(builder.to_sql(), sql) + + def test_oldest(self): + builder = self.get_builder() + builder.oldest('email') + sql = getattr( + self, inspect.currentframe().f_code.co_name.replace("test_", "") + )() + self.assertEqual(builder.to_sql(), sql) + + def oldest(self): + """ + builder.order_by('email', 'asc') + """ + return """SELECT * FROM "users" ORDER BY "email" ASC""" + + def latest(self): + """ + builder.order_by('email', 'des') + """ + return """SELECT * FROM "users" ORDER BY "email" DESC"""