From d4a3162d1e314c43b7d1e06daf7323e96f04e2bb Mon Sep 17 00:00:00 2001 From: Kieren Eaton <499977+circulon@users.noreply.github.com> Date: Sat, 16 May 2026 08:25:50 +0800 Subject: [PATCH 01/10] cleanup moved test related modules into test folder (seeds and migrations) removed unused UserObserver # Conflicts: # orm.sqlite3 # tests/integrations/migrations/2020_04_17_000000_create_friends_table.py # tests/integrations/migrations/2020_04_17_00000_create_articles_table.py --- app/observers/UserObserver.py | 101 ------------------ .../2018_01_09_043202_create_users_table.py | 28 ----- databases/migrations/__init__.py | 3 - .../2018_01_09_043202_create_users_table.py | 25 +++++ .../2020_04_17_000000_create_friends_table.py | 14 +-- .../2020_04_17_00000_create_articles_table.py | 14 +-- ...20_152904_create_table_schema_migration.py | 5 +- .../integrations}/seeds/database_seeder.py | 3 +- .../integrations}/seeds/user_table_seeder.py | 16 +-- tests/seeds/test_seeds.py | 5 +- 10 files changed, 56 insertions(+), 158 deletions(-) delete mode 100644 app/observers/UserObserver.py delete mode 100644 databases/migrations/2018_01_09_043202_create_users_table.py delete mode 100644 databases/migrations/__init__.py create mode 100644 tests/integrations/migrations/2018_01_09_043202_create_users_table.py rename {databases => tests/integrations}/migrations/2020_04_17_000000_create_friends_table.py (51%) rename {databases => tests/integrations}/migrations/2020_04_17_00000_create_articles_table.py (51%) rename {databases => tests/integrations}/migrations/2020_10_20_152904_create_table_schema_migration.py (85%) rename {databases => tests/integrations}/seeds/database_seeder.py (99%) rename {databases => tests/integrations}/seeds/user_table_seeder.py (55%) diff --git a/app/observers/UserObserver.py b/app/observers/UserObserver.py deleted file mode 100644 index 514350cb3..000000000 --- a/app/observers/UserObserver.py +++ /dev/null @@ -1,101 +0,0 @@ -"""User Observer""" - -from masoniteorm.models import Model - - -class UserObserver: - def created(self, clients): - """Handle the Clients "created" event. - - Args: - clients (masoniteorm.models.Model): Clients model. - """ - pass - - def creating(self, clients): - """Handle the Clients "creating" event. - - Args: - clients (masoniteorm.models.Model): Clients model. - """ - pass - - def saving(self, clients): - """Handle the Clients "saving" event. - - Args: - clients (masoniteorm.models.Model): Clients model. - """ - pass - - def saved(self, clients): - """Handle the Clients "saved" event. - - Args: - clients (masoniteorm.models.Model): Clients model. - """ - pass - - def updating(self, clients): - """Handle the Clients "updating" event. - - Args: - clients (masoniteorm.models.Model): Clients model. - """ - pass - - def updated(self, clients): - """Handle the Clients "updated" event. - - Args: - clients (masoniteorm.models.Model): Clients model. - """ - pass - - def booted(self, clients): - """Handle the Clients "booted" event. - - Args: - clients (masoniteorm.models.Model): Clients model. - """ - pass - - def booting(self, clients): - """Handle the Clients "booting" event. - - Args: - clients (masoniteorm.models.Model): Clients model. - """ - pass - - def hydrating(self, clients): - """Handle the Clients "hydrating" event. - - Args: - clients (masoniteorm.models.Model): Clients model. - """ - pass - - def hydrated(self, clients): - """Handle the Clients "hydrated" event. - - Args: - clients (masoniteorm.models.Model): Clients model. - """ - pass - - def deleting(self, clients): - """Handle the Clients "deleting" event. - - Args: - clients (masoniteorm.models.Model): Clients model. - """ - pass - - def deleted(self, clients): - """Handle the Clients "deleted" event. - - Args: - clients (masoniteorm.models.Model): Clients model. - """ - pass diff --git a/databases/migrations/2018_01_09_043202_create_users_table.py b/databases/migrations/2018_01_09_043202_create_users_table.py deleted file mode 100644 index 218419b99..000000000 --- a/databases/migrations/2018_01_09_043202_create_users_table.py +++ /dev/null @@ -1,28 +0,0 @@ -from src.masoniteorm.migrations import Migration -from tests.User import User - - -class CreateUsersTable(Migration): - - def up(self): - """Run the migrations.""" - with self.schema.create('users') as table: - table.increments('id') - table.string('name') - table.string('email').unique() - table.string('password') - table.string('second_password').nullable() - table.string('remember_token').nullable() - table.timestamp('verified_at').nullable() - table.timestamps() - - if not self.schema._dry: - User.on(self.connection).set_schema(self.schema_name).create({ - 'name': 'Joe', - 'email': 'joe@email.com', - 'password': 'secret' - }) - - def down(self): - """Revert the migrations.""" - self.schema.drop('users') diff --git a/databases/migrations/__init__.py b/databases/migrations/__init__.py deleted file mode 100644 index 488a71ce7..000000000 --- a/databases/migrations/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -import os -import sys -sys.path.append(os.getcwd()) diff --git a/tests/integrations/migrations/2018_01_09_043202_create_users_table.py b/tests/integrations/migrations/2018_01_09_043202_create_users_table.py new file mode 100644 index 000000000..3bc4a1fec --- /dev/null +++ b/tests/integrations/migrations/2018_01_09_043202_create_users_table.py @@ -0,0 +1,25 @@ +from src.masoniteorm.migrations import Migration +from tests.User import User + + +class CreateUsersTable(Migration): + def up(self): + """Run the migrations.""" + with self.schema.create("users") as table: + table.increments("id") + table.string("name") + table.string("email").unique() + table.string("password") + table.string("second_password").nullable() + table.string("remember_token").nullable() + table.timestamp("verified_at").nullable() + table.timestamps() + + if not self.schema._dry: + User.on(self.connection).set_schema(self.schema_name).create( + {"name": "Joe", "email": "joe@email.com", "password": "secret"} + ) + + def down(self): + """Revert the migrations.""" + self.schema.drop("users") diff --git a/databases/migrations/2020_04_17_000000_create_friends_table.py b/tests/integrations/migrations/2020_04_17_000000_create_friends_table.py similarity index 51% rename from databases/migrations/2020_04_17_000000_create_friends_table.py rename to tests/integrations/migrations/2020_04_17_000000_create_friends_table.py index 425f51134..3ccffed25 100644 --- a/databases/migrations/2020_04_17_000000_create_friends_table.py +++ b/tests/integrations/migrations/2020_04_17_000000_create_friends_table.py @@ -1,19 +1,19 @@ from src.masoniteorm.migrations.Migration import Migration -class CreateFriendsTable(Migration): - def up(self): +class CreateFriendsTable(Migration): + def up(self): """ Run the migrations. """ - with self.schema.create('friends') as table: - table.increments('id') - table.string('name') - table.integer('age') + with self.schema.create("friends") as table: + table.increments("id").primary() + table.string("name") + table.integer("age") def down(self): """ Revert the migrations. """ - self.schema.drop('friends') \ No newline at end of file + self.schema.drop("friends") diff --git a/databases/migrations/2020_04_17_00000_create_articles_table.py b/tests/integrations/migrations/2020_04_17_00000_create_articles_table.py similarity index 51% rename from databases/migrations/2020_04_17_00000_create_articles_table.py rename to tests/integrations/migrations/2020_04_17_00000_create_articles_table.py index 8fe7f70c7..fae850de2 100644 --- a/databases/migrations/2020_04_17_00000_create_articles_table.py +++ b/tests/integrations/migrations/2020_04_17_00000_create_articles_table.py @@ -1,18 +1,18 @@ from src.masoniteorm.migrations.Migration import Migration -class CreateArticlesTable(Migration): - def up(self): +class CreateArticlesTable(Migration): + def up(self): """ Run the migrations. """ - with self.schema.create('fans') as table: - table.increments('id') - table.string('name') - table.integer('age') + with self.schema.create("fans") as table: + table.increments("id").primary() + table.string("name") + table.integer("age") def down(self): """ Revert the migrations. """ - self.schema.drop('fans') \ No newline at end of file + self.schema.drop("fans") diff --git a/databases/migrations/2020_10_20_152904_create_table_schema_migration.py b/tests/integrations/migrations/2020_10_20_152904_create_table_schema_migration.py similarity index 85% rename from databases/migrations/2020_10_20_152904_create_table_schema_migration.py rename to tests/integrations/migrations/2020_10_20_152904_create_table_schema_migration.py index 63268b9e1..71990752e 100644 --- a/databases/migrations/2020_10_20_152904_create_table_schema_migration.py +++ b/tests/integrations/migrations/2020_10_20_152904_create_table_schema_migration.py @@ -4,14 +4,13 @@ class CreateTableSchemaMigration(Migration): - def up(self): """ Run the migrations. """ with self.schema.create("table_schema") as table: - table.increments('id') - table.string('name') + table.increments("id") + table.string("name") table.timestamps() def down(self): diff --git a/databases/seeds/database_seeder.py b/tests/integrations/seeds/database_seeder.py similarity index 99% rename from databases/seeds/database_seeder.py rename to tests/integrations/seeds/database_seeder.py index 974d926d7..299cbbee4 100644 --- a/databases/seeds/database_seeder.py +++ b/tests/integrations/seeds/database_seeder.py @@ -1,10 +1,11 @@ """Base Database Seeder Module.""" from src.masoniteorm.seeds import Seeder + from .user_table_seeder import UserTableSeeder -class DatabaseSeeder(Seeder): +class DatabaseSeeder(Seeder): def run(self): """Run the database seeds.""" self.call(UserTableSeeder) diff --git a/databases/seeds/user_table_seeder.py b/tests/integrations/seeds/user_table_seeder.py similarity index 55% rename from databases/seeds/user_table_seeder.py rename to tests/integrations/seeds/user_table_seeder.py index 5e6843615..20187a5ce 100644 --- a/databases/seeds/user_table_seeder.py +++ b/tests/integrations/seeds/user_table_seeder.py @@ -1,16 +1,18 @@ """UserTableSeeder Seeder.""" -from src.masoniteorm.seeds import Seeder from src.masoniteorm.factories import Factory as factory +from src.masoniteorm.seeds import Seeder from tests.User import User -factory.register(User, lambda faker: {'email': faker.email()}) +factory.register(User, lambda faker: {"email": faker.email()}) -class UserTableSeeder(Seeder): +class UserTableSeeder(Seeder): def run(self): """Run the database seeds.""" - factory(User, 5).create({ - 'name': 'Joe', - 'password': 'joe', - }) + factory(User, 5).create( + { + "name": "Joe", + "password": "joe", + } + ) diff --git a/tests/seeds/test_seeds.py b/tests/seeds/test_seeds.py index cfa110097..8d7881f1f 100644 --- a/tests/seeds/test_seeds.py +++ b/tests/seeds/test_seeds.py @@ -1,11 +1,14 @@ import unittest -from databases.seeds.user_table_seeder import UserTableSeeder from src.masoniteorm.seeds import Seeder class TestSeeds(unittest.TestCase): def test_can_run_seeds(self): + from tests.integrations.databases.seeds.user_table_seeder import ( + UserTableSeeder, + ) + seeder = Seeder(dry=True) seeder.call(UserTableSeeder) From e4dcc27443b6ac2ec2fccc809486c9427ed007e4 Mon Sep 17 00:00:00 2001 From: Kieren Eaton <499977+circulon@users.noreply.github.com> Date: Sat, 16 May 2026 08:37:34 +0800 Subject: [PATCH 02/10] fixed migrations path for ci tests # Conflicts: # .github/workflows/pythonapp.yml --- .github/workflows/pythonapp.yml | 102 +++++++++++++++++++------------- 1 file changed, 62 insertions(+), 40 deletions(-) diff --git a/.github/workflows/pythonapp.yml b/.github/workflows/pythonapp.yml index 316f69efa..8c5997d87 100644 --- a/.github/workflows/pythonapp.yml +++ b/.github/workflows/pythonapp.yml @@ -1,73 +1,95 @@ -name: Test Application +name: CI -on: [push, pull_request] +on: + push: + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: - build: + lint: + name: Lint runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 + with: + python-version: "3.12" + cache: pip + - name: Install dev dependencies + run: make init-ci + - name: Lint & format check + run: make check + test: + name: Python ${{ matrix.python-version }} + runs-on: ubuntu-latest + needs: lint services: postgres: - image: postgres:10.8 + image: postgres:16 env: POSTGRES_USER: postgres POSTGRES_PASSWORD: postgres POSTGRES_DB: postgres ports: - # will assign a random free host port - 5432/tcp - # needed because the postgres container does not provide a healthcheck - options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5 - + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 mysql: - image: mysql:5.7 + image: mysql:8.0 env: MYSQL_ALLOW_EMPTY_PASSWORD: yes MYSQL_DATABASE: orm ports: - - 3306 - options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 - + - 3306/tcp + options: >- + --health-cmd "mysqladmin ping" + --health-interval 10s + --health-timeout 5s + --health-retries 5 strategy: + fail-fast: false matrix: - python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] - name: Python ${{ matrix.python-version }} + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] steps: - - uses: actions/checkout@v3 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v3 + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - make init-ci - - name: Test with pytest + cache: pip + - name: Install test dependencies + run: make init-ci + - name: Run migrations env: POSTGRES_DATABASE_HOST: localhost + POSTGRES_DATABASE_PORT: ${{ job.services.postgres.ports[5432] }} POSTGRES_DATABASE_DATABASE: postgres POSTGRES_DATABASE_USER: postgres POSTGRES_DATABASE_PASSWORD: postgres - POSTGRES_DATABASE_PORT: ${{ job.services.postgres.ports[5432] }} MYSQL_DATABASE_HOST: localhost + MYSQL_DATABASE_PORT: ${{ job.services.mysql.ports[3306] }} MYSQL_DATABASE_DATABASE: orm MYSQL_DATABASE_USER: root - MYSQL_DATABASE_PORT: ${{ job.services.mysql.ports[3306] }} DB_CONFIG_PATH: tests/integrations/config/database.py run: | - python orm migrate --connection postgres - python orm migrate --connection mysql - make test - lint: - runs-on: ubuntu-latest - name: Lint - steps: - - uses: actions/checkout@v3 - - name: Set up Python 3.6 - uses: actions/setup-python@v3 - with: - python-version: 3.12 - - name: Install Flake8 - run: | - pip install flake8-pyproject - - name: Lint - run: make lint + python orm migrate --connection postgres -d tests/integrations/migrations + python orm migrate --connection mysql -d tests/integrations/migrations + - name: Run tests + env: + POSTGRES_DATABASE_HOST: localhost + POSTGRES_DATABASE_PORT: ${{ job.services.postgres.ports[5432] }} + POSTGRES_DATABASE_DATABASE: postgres + POSTGRES_DATABASE_USER: postgres + POSTGRES_DATABASE_PASSWORD: postgres + MYSQL_DATABASE_HOST: localhost + MYSQL_DATABASE_PORT: ${{ job.services.mysql.ports[3306] }} + MYSQL_DATABASE_DATABASE: orm + MYSQL_DATABASE_USER: root + DB_CONFIG_PATH: tests/integrations/config/database.py + run: make test From 6ad9266be24a15a05438ff5899ecc3e2c9f5f6cc Mon Sep 17 00:00:00 2001 From: Kieren Eaton <499977+circulon@users.noreply.github.com> Date: Sat, 16 May 2026 08:44:02 +0800 Subject: [PATCH 03/10] fixed seeds path # Conflicts: # tests/seeds/test_seeds.py --- tests/seeds/test_seeds.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/seeds/test_seeds.py b/tests/seeds/test_seeds.py index 8d7881f1f..6c97ca485 100644 --- a/tests/seeds/test_seeds.py +++ b/tests/seeds/test_seeds.py @@ -5,9 +5,7 @@ class TestSeeds(unittest.TestCase): def test_can_run_seeds(self): - from tests.integrations.databases.seeds.user_table_seeder import ( - UserTableSeeder, - ) + from tests.integrations.seeds.user_table_seeder import UserTableSeeder seeder = Seeder(dry=True) seeder.call(UserTableSeeder) From c238f249ae116256b7bcf1affe73455873fc2ea1 Mon Sep 17 00:00:00 2001 From: Kieren Eaton <499977+circulon@users.noreply.github.com> Date: Sat, 16 May 2026 10:58:53 +0800 Subject: [PATCH 04/10] fixed sqlite tests sqlite tests now use migrations and seeders for standard testing deleted orm.sqlite3 file # Conflicts: # .gitignore # orm.sqlite3 # tests/integrations/migrations/2018_01_09_043202_create_users_table.py # tests/integrations/seeds/user_table_seeder.py # tests/sqlite/models/test_sqlite_model.py --- .gitignore | 4 +- orm.sqlite3 | Bin 188416 -> 0 bytes .../2018_01_09_043202_create_users_table.py | 15 +- .../2020_04_17_00000_create_articles_table.py | 10 +- ...2021_01_01_000002_create_profiles_table.py | 16 +++ .../2021_01_01_000004_create_logos_table.py | 17 +++ .../2021_01_01_000005_create_likes_table.py | 18 +++ ...021_01_01_000006_create_observers_table.py | 15 ++ .../2021_01_01_000007_create_stores_table.py | 16 +++ ...2021_01_01_000008_create_products_table.py | 16 +++ ...01_01_000009_create_product_store_table.py | 19 +++ .../seeds/article_table_seeder.py | 29 ++++ tests/integrations/seeds/database_seeder.py | 22 ++- tests/integrations/seeds/like_table_seeder.py | 28 ++++ tests/integrations/seeds/logo_table_seeder.py | 28 ++++ .../seeds/profile_table_seeder.py | 27 ++++ .../integrations/seeds/store_table_seeder.py | 130 ++++++++++++++++++ tests/integrations/seeds/user_table_seeder.py | 39 +++++- .../builder/test_sqlite_query_builder.py | 8 +- ...test_sqlite_query_builder_eager_loading.py | 4 +- tests/sqlite/conftest.py | 89 ++++++++++++ tests/sqlite/models/test_observers.py | 6 +- tests/sqlite/models/test_sqlite_model.py | 58 +++----- 23 files changed, 541 insertions(+), 73 deletions(-) delete mode 100644 orm.sqlite3 create mode 100644 tests/integrations/migrations/2021_01_01_000002_create_profiles_table.py create mode 100644 tests/integrations/migrations/2021_01_01_000004_create_logos_table.py create mode 100644 tests/integrations/migrations/2021_01_01_000005_create_likes_table.py create mode 100644 tests/integrations/migrations/2021_01_01_000006_create_observers_table.py create mode 100644 tests/integrations/migrations/2021_01_01_000007_create_stores_table.py create mode 100644 tests/integrations/migrations/2021_01_01_000008_create_products_table.py create mode 100644 tests/integrations/migrations/2021_01_01_000009_create_product_store_table.py create mode 100644 tests/integrations/seeds/article_table_seeder.py create mode 100644 tests/integrations/seeds/like_table_seeder.py create mode 100644 tests/integrations/seeds/logo_table_seeder.py create mode 100644 tests/integrations/seeds/profile_table_seeder.py create mode 100644 tests/integrations/seeds/store_table_seeder.py create mode 100644 tests/sqlite/conftest.py diff --git a/.gitignore b/.gitignore index 713b32f27..11fab6d34 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,4 @@ coverage.xml .coverage *.log build -/orm.sqlite3 -/.bootstrapped-pip -/.ignore-pre-commit +/.bootstrapped-* diff --git a/orm.sqlite3 b/orm.sqlite3 deleted file mode 100644 index cdda25e6cbe72200a2528df38cc8037284a18d9b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 188416 zcmeI5dvM&weaC@&zafdD&J-;XJV_>D9VOmT6lL17L`kQIElM^;Ig%eagLe=K>v*6K zpk&saQIATROkd7SleW`##(%UkZQ9PbZjz?c$;3&gO)^u*ZrV&Ae>85=cABKgI8!&% zrfKUg7Qh_<-ck0pjcxIJ8r|WyyWidYeXtAc4>%kzJbYF)6!D7ISdi#yUQl2W8Y704V#69ADU$bg&*=?N-d`PlE0mtPW(&a zmlKELKZrjc`={6+#x_O29(^>rH}aq1H^P4$J{IILDB>HRyS*}gu$nWYWthSpGY z>wSl}F)Pv6)UE3`LeXqC%QsKa`fJ*}rqj2uw|1JgrgFJqsFj*hww=r8mK!yfGr6VZ zxtgjkDAjURHi(<%yP+;BQgif9%5im!Hfz_TJD+!Y8h28~;Y3`mif7KvmQIys+^F)2 z__D4vNIzP+=PsT-OOg%Ms43zjQ!~d;Pt6P$$Hyhn&e09oSk^t|6M3@Fx^+4AZ7$T@ zx+9w1vxje9rQN1)WxcYXkU3zE2Yb8E)BT(~iy(A$(zUnqA{i}LR0`ASR9>uTi;GI# za5r&^!O106w zQY+Ubm71Y!G&?xRH!o1ei|V{7*XnwE>kcpFb_T)RGF;=rGabZM31^_tp`RD$WTUd+ zP?1KqMY2=AgoEH<7!Q+HGhU_2PJ7_>#eyJ%SDSpv3I2BtrWL07q>P; zTPWsc*@fAutfv#^;yRc;OuYw>ylA^+?h2`8IZkd~uh;s5yrk%ba>3r%(j3}Ed%e1c z_S#OiKQ?=MZ70&Bg-DHVdbM29YFa~_EnS+;(=4+3P`YHzRJqu|=(_URkl;Q(m=|NW?jL zo-7@lv;MjBv(_2hcQz574C#?XBr8e0N*gGb4P|kuT()ZST1iiX-n?PbsM%(o`fiRm z>2f?`p8K!6I&RHSyKb7E@YLzf>AreNNRP)N*`XnRWlhxucMXMj*UAg))n1Fz6MA!q zR^K}1w>Dy)YCEh6Jjc@(XmhdDTC%iukTesCm@8z<7pD#9GupW+b1$2qbDdj~o()@z z)Qi-EntD~y>088G9Ze&3CE|3s?FAzSOA|C1GRM2ye?+rE6D*XlXWz3bM9`rWqB)_c&rJI*{y5l}1&^G8{g1!a3wbQgU zRa+y%35{~}ywr9k=d27|N#13EE2Dj`ZwDdyoT``UI>Mbs4>nGmlFyMvpQ{=}(`w{E z+3J#MlasGwi#fSssMpA_B9R`M9__V+s|D9OpA<2D9PcvhTXAB+E_m>*6eJF;DQCt) zq;vDigujMX&Y`Y31#$%UEZND>75iMV`99%?!ewDB^B5XbR-lBemVHj;A6pD;9G&;4O}NNewcrm z|9SpVevtbn_rkg%{Y0sk>$$hDT}BYh?FTgFDNQ-LDC=6CtbWNTe@dws`$*WOD`d6szzktMCY`@P1a|VOHUNtipR)g_Eqpdsu~sScMa;!h@{BaaQ30 zR^b?{u*fPbunI?6h5K2B`&fk|tin92a4)OyZdRehDja4N4zUXFVioRT74Bvg?qU_@ zScQYELXlNCz$)CyD%`;;ypvVf&nn!`D(qtw-oYx&vI@7c3VT_FTUmuYtimmfIySK*!lI%J;^5$2l4k(-_&BQFCgoMlP0-JCJJq=!&*v z-k;f5Aq7TCY4RQrzR3ySCvSLx00@8p2!H?xfB*=900@8p2!H?xyr&5y10kNz1_Jb} zBym0zk7wzo8UKfbPjbQ=!aoQvlMTE;00ck)1V8`;KmY_l00ck)1V8`;-W3G4g~D8X zKS!RZ)G8`@_K`d`X+8?0Zwr!d^LI#3o3Vet9s7%gq#6D9TTfIM(!x)0vCJD><_+OB z;ZKDpgh}Byg{<(wcZH+q1PFit2!H?xfB*=900@8p2!H?xuoKAf;dp#-Y+lpmYl``J z3Hd7h=tzM)SaL`#kf%zDlcN)ZQ4(SgjIGEEn%1pI_|`?tKz;pMgzs_T_+adoAxN{RaYpmLmk)rubmnck}*#Q23g8|NmR$11}H&0T2KI5C8!X z009sH0T2KI5CDPq9D#T+#P#y#k7)#A0kTPdUY*?k=lbLJ&rh21Kl#yryg&d1KmY_l z00ck)1V8`;KmY_l00eGh0*L=_X@Ers|00ck)1V8`;KmY_l00cl_qY%LT|BbSz;U@@y00@8p2!H?xfB*=9 z00@At>0T2KI5C8!X009sH0T2LzjY0tT|2N8>hMyn+0w4eaAOHd& z00JNY0w4ea8<_y&|Bbx&;X4R`00@8p2!H?xfB*=900@AC>Qzm|SA{Zjgc^z-TG(l^ptx|}|rK9b&_9!LwRH&d^tUQ4~2dMWin z>iN`jsT(ORRZg8x9ZBs^4WxwRo5|OcuO(kizLb0+`F!%Zr9`o5n%Z{5b zb9@$j_NdR^@3Z&$>=B=x_t|@W_T4^P^4Y^ad&p_ML``s@Lp zz0+s!@Y#3z?0%oU-Dmgt>^ppR)@N_?*}Xn{tIzK7*;{<}W}m&uXA3?%w>h;|%UrYy&|{=I0Fzz;p8t2w9{2vmaKobueb0F1V8`;KmY_l00ck)1V8`;KmY`OWCWgx@8@J)*D9)P zC}KmYXpO2)T7R-j`sps|qifSiE!*Q`ck>aBiigBPVe&w6a&#gs z{3{m_UgU%qg}?Zb5kNyA00JNY0w4eaAOHd&00JNY0w4ea>k|<9FxNjg_&&L|C^rlm z(T^5JMhoq&fk2q+8yuXK8}mxX0;GXdzg0X3eAOHd&00JNY0w4eaAOHd& z00Qqd0{cP{j_1e5LID!onm4~kieqA7eDc77$#L^WxRrE3EKE!m?wK6FXJ5oBAMuwT zpByD$iCc($s88oSiy$wj}1P#GE*sQ>!^qtsBa`(#YrP@}iOxugQ(dg51c9xk^JJ zPf1kEvXK+3WXn(&mAv@S%$ez_nakpXrOV>5T9qWynJ2SDL;TGwZFi}mRhKJ9nKt4v z2E4uSeNZ`MCs(z#j~^G@ryGvrE|08*)!9n3$s(x59M>qOQtJc zr`9RI)?IBNn%%L3Zx-C%>UMYaogIDDeeSgy92#1KeGOlZ3%`=xvxje9r7hC8vR+wG z7G?K#pSNXq7HM6rif7KvmQIys+#cmc((fy3O(9I3{JdDv78jMe;Yl;chWN`9h3ZA*0UuywlSiCsiCy#M@1Ix{`=5>q^7bC~YR6h#RU= zYqdRG93PjQ9NmzOW!>pGO-+z-yR+?j_jmPm~!N|!`?LYzM*=2`{K9ZBbjv?}*SvjYSC2RBpywK>xJYf3|J zZEW`t$hFc*6$w!kyI~+%cEdJqx65XxT~W2H%h%NUe9r4XDPb~b6{6$aU2ILJLXH9U z*l_33iPcRwr)kD|d0pyUSgAJTu0ku*9|ayx@y zZW-=T<(gl4u~otu+Z1+QoRf{pfk8R%m+NtZzQ1{HUdq-xzTJ!aIi9B(3ojlFvOO~sPYTa=p zPo8*NR2JvRG&8iTO5InMj9&GMN{@|V`-myFkFf64_HopmYR#Wv+CfPg*?Mbk#d6VN zQ0yJ)c`Lu2(*wP%@M0>ruhxXb|wm&v|dTl4tqlHL~ZsXWIo{%wHxjNs_mh07WMXPBIakg}6 zHczvzkflJEEZa4|SV~BHg-G^DU$;?jbtwbJj2|tTTq(gGM@>ikJrh>&RtkN9~Vvr;0~C6-!ShDbHp< z?bxDLRj;gA?oOC%JF_$aXT^+Y(s9iTrPk8Ed=X75pB&5e<5p$)vvZm^S zyM{u%YvqOYYOh7<3B5T)t8bn1TN^P?wH?+3p5ti?w7DW_t+HA>NScX6%;l5ii_?bl z8SUJZxtC4Qxy~&~&xWJfY?g0cq#o4NtBOwFBHrp~8mTK0rvZR7WZY*)l4U&|T{c#h zTF|i?KEvo)z)BfLb@D1Wwo8jIg18Yl6QsR z%4jbG+AHdOPSwkFiQ!J8$Dvlhm?LXNS2c#F)yOfl)g{v==Viwhb8^K{uaOZ)!csDG z+RF@A3$Cbz6fu1q?=mA=fmXpTc<`+hBo3@8M?xM_1<9H4*U-v2)HSC-4(@AK^O70= zZ{|PE37-(S%+u+wq`r|lm28r~w6{BcZ|t6^5&6T=Cxb8YpN=GbQ9jIflEBSt%>y(l z`OpNNlIFr{iADkKtzF*9+0JlgsB_G9&c6aOTvx(h2veq;+(1YUotR zJy%bV3qR&+o~{O3^I`3k5${}k%c|q&&s~_EnIgRr+g_5xXL+filBZ-=+%Z1AUX&L* zOC0yh<|<8{uZt(o&y$>FY-oCpo=wQoymQqyvo19|M7Hb&_b;Y~HM}^FgPbFGuhc;NYTkGtHok^Uyaep*hDDXEWieIghJxH#`mGuR6$-Hu_uT8nz z>)zS|rmv2k&EG2xZP9Vy7S671zSZ}xd(qW7Lg30_Isk84;jvP0Xf@OG)`sNux0P#**cKhDl_KD*&<=aU{EpNM96?c!IbX^-bLgWPE-*VL-++Pur#b61Yp`_8+b9OG(a zX!sZXt$vf3h&JU>(>TKAk*lSylfu0J*1Y4O#ofAwWyx$0^gW$=zuvl}CeJA(^6qjT zUDLhwR}0OW7~Md(2AeyqdxNWKI-baB*Sr(@e|T@OOE~OVF17;iH7jqanc8VxR3z6h z{vYoUcj=|;@{)DqxH){$PK-`2Ur6 ziDT#n2!H?xfB*=900@8p2!H?xfB*=9z%2-jnt!NZZ0wZzGJLtGCxqg2iKKP3DWC;YqcUEv#K11}H&0T2KI z5C8!X009sH0T2KI5CDPq3W3?xt?R% zoE86nffL>k{$BV?;S28-2hmRu009sH0T2KI5C8!X009sH0T9@D1Tw=xZr3rD{K3!p z6>)5|nA{oUc1+90f@x&7lFZYpZfN8$p%+FA$%KW|cuWdYb@E8O@ z00ck)1V8`;KmY_l00ck)1m5ceqM;BM;Q5bijRZp+&sP&s@(4hH=f0GPkOu%r!cH^( zj|#tP-v9rm@KxbYgg+2IPE5Q&00ck)1V8`;KmY_l00ck)1V8`;enbS4QS!Wg;8;VE ztAWp?BO$Io@StKCHAUw?k_?-9?^{r0BXB8A!u`g8 zd`NB>dewaPzn7m@YgemD68hWK@_94lJPJn$p;rzG;NG9sIObH^?=C+RoI?O(gE;PixEMyZ!a8TUYZT zZm(5^cvf3hbycp*Ta(SxA+C=);X=z=CtKTT}fEq|9_bi{zdq<@S5=Q z|H3gyK>!3m00ck)1V8`;KmY_l00ck)1bzerHj`fgkS^9$L#c`ns`dG*wiqWr1kiV! zTn4Dh5%MztJr^%brO4y|15@OZK|`*o^zZ+bxEDC#mDG<5H-yW=Smr-6pU-?ab3U^z z{kQ2~PhU+JQ$I+3E_FPWNPZ>xOUZKbuEci}pG-WPIF^XV|1AEC@%P8~#J&^zMC`|6 zQ?Xd|)#xuopNQ^`{Bz{@A}f)jk!bjp@W;ZBhj)d(9eOeJOz21`68v)Tqru05xxlvq zzZsIV-?=ZDx72$-oq+9#44O% z6&_?2j$VHM_Cg?m|rce4s5R^c$KaEMiS7prg& zt8h1~a2KmE$0{6T6^g9F0aoEoR^bj-;hn6)epcajR$(8j@D5gCmQ}coRoKfa+{!BK zVHIv+6>eq}9t-sHJyKtqi^tRHG&jasi}?^)%`fXpL9>o+krJ|VCQGpxcit1!hXOtK0Stim{}Fvcp3vI--N!rkFC-!s&TK?5Z6 zG=opyXx$xpE2XA`WC|QMrvUGs0%0-*p3)ZT-6PsS$JsE-_r`n2IT{nw7}=Upb84+t z(HctKQ0qrmv?XU=jTPwc|Luh2-Rj9BEtE|Ebt8k80D6XIX_8ScNmJ!iQOf53vf*vkK3#3a43xXIX_0vI-wy S6`o-go@N!EVilfb6#ftP%h6o` diff --git a/tests/integrations/migrations/2018_01_09_043202_create_users_table.py b/tests/integrations/migrations/2018_01_09_043202_create_users_table.py index 3bc4a1fec..5316f16fa 100644 --- a/tests/integrations/migrations/2018_01_09_043202_create_users_table.py +++ b/tests/integrations/migrations/2018_01_09_043202_create_users_table.py @@ -1,25 +1,22 @@ from src.masoniteorm.migrations import Migration -from tests.User import User class CreateUsersTable(Migration): def up(self): """Run the migrations.""" with self.schema.create("users") as table: - table.increments("id") + table.increments("id").primary() table.string("name") - table.string("email").unique() - table.string("password") + table.string("email").unique().nullable() + table.integer("age").nullable() + table.boolean("is_admin").nullable() + table.boolean("active").nullable() + table.string("password").nullable() table.string("second_password").nullable() table.string("remember_token").nullable() table.timestamp("verified_at").nullable() table.timestamps() - if not self.schema._dry: - User.on(self.connection).set_schema(self.schema_name).create( - {"name": "Joe", "email": "joe@email.com", "password": "secret"} - ) - def down(self): """Revert the migrations.""" self.schema.drop("users") diff --git a/tests/integrations/migrations/2020_04_17_00000_create_articles_table.py b/tests/integrations/migrations/2020_04_17_00000_create_articles_table.py index fae850de2..fed179a3f 100644 --- a/tests/integrations/migrations/2020_04_17_00000_create_articles_table.py +++ b/tests/integrations/migrations/2020_04_17_00000_create_articles_table.py @@ -6,13 +6,15 @@ def up(self): """ Run the migrations. """ - with self.schema.create("fans") as table: + with self.schema.create("articles") as table: table.increments("id").primary() - table.string("name") - table.integer("age") + table.integer("user_id") + table.string("title").nullable() + table.integer("status").nullable() + table.datetime("published_date").nullable() def down(self): """ Revert the migrations. """ - self.schema.drop("fans") + self.schema.drop("articles") diff --git a/tests/integrations/migrations/2021_01_01_000002_create_profiles_table.py b/tests/integrations/migrations/2021_01_01_000002_create_profiles_table.py new file mode 100644 index 000000000..d0c32b9bb --- /dev/null +++ b/tests/integrations/migrations/2021_01_01_000002_create_profiles_table.py @@ -0,0 +1,16 @@ +"""CreateProfilesTable Migration.""" + +from src.masoniteorm.migrations import Migration + + +class CreateProfilesTable(Migration): + def up(self): + """Run the migrations.""" + with self.schema.create("profiles") as table: + table.increments("id").primary() + table.integer("user_id") + table.string("title").nullable() + + def down(self): + """Revert the migrations.""" + self.schema.drop("profiles") diff --git a/tests/integrations/migrations/2021_01_01_000004_create_logos_table.py b/tests/integrations/migrations/2021_01_01_000004_create_logos_table.py new file mode 100644 index 000000000..f37e3d11e --- /dev/null +++ b/tests/integrations/migrations/2021_01_01_000004_create_logos_table.py @@ -0,0 +1,17 @@ +"""CreateLogosTable Migration.""" + +from src.masoniteorm.migrations import Migration + + +class CreateLogosTable(Migration): + def up(self): + """Run the migrations.""" + with self.schema.create("logos") as table: + table.increments("id").primary() + table.integer("article_id") + table.string("url").nullable() + table.datetime("published_date").nullable() + + def down(self): + """Revert the migrations.""" + self.schema.drop("logos") diff --git a/tests/integrations/migrations/2021_01_01_000005_create_likes_table.py b/tests/integrations/migrations/2021_01_01_000005_create_likes_table.py new file mode 100644 index 000000000..40f782b7c --- /dev/null +++ b/tests/integrations/migrations/2021_01_01_000005_create_likes_table.py @@ -0,0 +1,18 @@ +"""CreateLikesTable Migration.""" + +from src.masoniteorm.migrations import Migration + + +class CreateLikesTable(Migration): + def up(self): + """Run the migrations.""" + with self.schema.create("likes") as table: + table.increments("id").primary() + # Polymorphic columns: record_type holds the morph map key, + # record_id holds the related model's PK. + table.string("record_type", 63) + table.integer("record_id") + + def down(self): + """Revert the migrations.""" + self.schema.drop("likes") diff --git a/tests/integrations/migrations/2021_01_01_000006_create_observers_table.py b/tests/integrations/migrations/2021_01_01_000006_create_observers_table.py new file mode 100644 index 000000000..c66598b17 --- /dev/null +++ b/tests/integrations/migrations/2021_01_01_000006_create_observers_table.py @@ -0,0 +1,15 @@ +"""CreateObserversTable Migration.""" + +from src.masoniteorm.migrations import Migration + + +class CreateObserversTable(Migration): + def up(self): + """Run the migrations.""" + with self.schema.create("observers") as table: + table.increments("id").primary() + table.string("name").nullable() + + def down(self): + """Revert the migrations.""" + self.schema.drop("observers") diff --git a/tests/integrations/migrations/2021_01_01_000007_create_stores_table.py b/tests/integrations/migrations/2021_01_01_000007_create_stores_table.py new file mode 100644 index 000000000..0e3b999e1 --- /dev/null +++ b/tests/integrations/migrations/2021_01_01_000007_create_stores_table.py @@ -0,0 +1,16 @@ +"""CreateStoresTable Migration.""" + +from src.masoniteorm.migrations import Migration + + +class CreateStoresTable(Migration): + def up(self): + """Run the migrations.""" + with self.schema.create("stores") as table: + table.increments("id").primary() + table.string("name") + table.timestamps() + + def down(self): + """Revert the migrations.""" + self.schema.drop("stores") diff --git a/tests/integrations/migrations/2021_01_01_000008_create_products_table.py b/tests/integrations/migrations/2021_01_01_000008_create_products_table.py new file mode 100644 index 000000000..2834ecf83 --- /dev/null +++ b/tests/integrations/migrations/2021_01_01_000008_create_products_table.py @@ -0,0 +1,16 @@ +"""CreateProductsTable Migration.""" + +from src.masoniteorm.migrations import Migration + + +class CreateProductsTable(Migration): + def up(self): + """Run the migrations.""" + with self.schema.create("products") as table: + table.increments("id").primary() + table.string("name") + table.timestamps() + + def down(self): + """Revert the migrations.""" + self.schema.drop("products") diff --git a/tests/integrations/migrations/2021_01_01_000009_create_product_store_table.py b/tests/integrations/migrations/2021_01_01_000009_create_product_store_table.py new file mode 100644 index 000000000..bb987346f --- /dev/null +++ b/tests/integrations/migrations/2021_01_01_000009_create_product_store_table.py @@ -0,0 +1,19 @@ +"""CreateProductStoreTable Migration.""" + +from src.masoniteorm.migrations import Migration + + +class CreateProductStoreTable(Migration): + def up(self): + """Run the migrations.""" + with self.schema.create("product_store") as table: + table.increments("id").primary() + table.integer("product_id") + table.integer("store_id") + # Pivot timestamps are checked explicitly in test_belongs_to_many. + table.datetime("created_at").default("CURRENT_TIMESTAMP") + table.datetime("updated_at").default("CURRENT_TIMESTAMP") + + def down(self): + """Revert the migrations.""" + self.schema.drop("product_store") diff --git a/tests/integrations/seeds/article_table_seeder.py b/tests/integrations/seeds/article_table_seeder.py new file mode 100644 index 000000000..72f434f4d --- /dev/null +++ b/tests/integrations/seeds/article_table_seeder.py @@ -0,0 +1,29 @@ +"""ArticleTableSeeder Seeder.""" + +from src.masoniteorm.models import Model +from src.masoniteorm.seeds import Seeder + + +class Article(Model): + __connection__ = "dev" + __timestamps__ = False + __table__ = "articles" + + +class ArticleTableSeeder(Seeder): + def run(self): + """ + Seed the articles table. + + test_can_access_has_many_relationship asserts len(user(id=1).articles) == 1, + so exactly one article linked to user_id=1 is required. + test_associate_records hydrates Article(id=1), so the row id must be 1. + published_date is used by test_can_access_relationship_date. + """ + Article.create( + { + "user_id": 1, + "title": "associate records", + "published_date": "2020-11-28 11:42:07", + } + ) diff --git a/tests/integrations/seeds/database_seeder.py b/tests/integrations/seeds/database_seeder.py index 299cbbee4..93b425dbc 100644 --- a/tests/integrations/seeds/database_seeder.py +++ b/tests/integrations/seeds/database_seeder.py @@ -2,10 +2,28 @@ from src.masoniteorm.seeds import Seeder +from .article_table_seeder import ArticleTableSeeder +from .like_table_seeder import LikeTableSeeder +from .logo_table_seeder import LogoTableSeeder +from .profile_table_seeder import ProfileTableSeeder +from .store_table_seeder import StoreTableSeeder from .user_table_seeder import UserTableSeeder class DatabaseSeeder(Seeder): def run(self): - """Run the database seeds.""" - self.call(UserTableSeeder) + """ + Run all database seeds in dependency order. + + Users must be seeded before profiles, articles, and likes since those + tables reference user IDs. Articles must exist before logos. + Stores and products are independent of the user graph. + """ + self.call( + UserTableSeeder, + ProfileTableSeeder, + ArticleTableSeeder, + LogoTableSeeder, + LikeTableSeeder, + StoreTableSeeder, + ) diff --git a/tests/integrations/seeds/like_table_seeder.py b/tests/integrations/seeds/like_table_seeder.py new file mode 100644 index 000000000..5d930a4f3 --- /dev/null +++ b/tests/integrations/seeds/like_table_seeder.py @@ -0,0 +1,28 @@ +"""LikeTableSeeder Seeder.""" + +from src.masoniteorm.models import Model +from src.masoniteorm.seeds import Seeder + + +class Like(Model): + __connection__ = "dev" + __timestamps__ = False + __table__ = "likes" + + +class LikeTableSeeder(Seeder): + def run(self): + """ + Seed the likes table for polymorphic relationship tests. + + test_can_get_polymorphic_relation and test_can_get_eager_load_polymorphic_relation + iterate over all likes and assert each resolves to an Articles or User instance. + The morph map is: {"user": User, "article": Articles}. + """ + Like.bulk_create( + [ + {"record_type": "article", "record_id": 1}, + {"record_type": "user", "record_id": 1}, + {"record_type": "user", "record_id": 2}, + ] + ) diff --git a/tests/integrations/seeds/logo_table_seeder.py b/tests/integrations/seeds/logo_table_seeder.py new file mode 100644 index 000000000..7690247be --- /dev/null +++ b/tests/integrations/seeds/logo_table_seeder.py @@ -0,0 +1,28 @@ +"""LogoTableSeeder Seeder.""" + +from src.masoniteorm.models import Model +from src.masoniteorm.seeds import Seeder + + +class Logo(Model): + __connection__ = "dev" + __timestamps__ = False + __table__ = "logos" + + +class LogoTableSeeder(Seeder): + def run(self): + """ + Seed the logos table. + + test_can_access_relationship_date calls article.logo.published_date.is_past(), + so a logo linked to article_id=1 with a past published_date is required. + test_loading_with_nested_with uses the nested 'articles.logo' eager load. + """ + Logo.create( + { + "article_id": 1, + "url": "google.com", + "published_date": "2020-11-28 11:42:07", + } + ) diff --git a/tests/integrations/seeds/profile_table_seeder.py b/tests/integrations/seeds/profile_table_seeder.py new file mode 100644 index 000000000..a2b99b539 --- /dev/null +++ b/tests/integrations/seeds/profile_table_seeder.py @@ -0,0 +1,27 @@ +"""ProfileTableSeeder Seeder.""" + +from src.masoniteorm.models import Model +from src.masoniteorm.seeds import Seeder + + +class Profile(Model): + __connection__ = "dev" + __timestamps__ = False + __table__ = "profiles" + + +class ProfileTableSeeder(Seeder): + def run(self): + """ + Seed the profiles table. + + test_can_access_relationship asserts User(id=1).profile is a Profile instance. + test_with asserts profile.title == 'title'. + Two profiles are required: one for each seeded user. + """ + Profile.bulk_create( + [ + {"user_id": 1, "title": "title"}, + {"user_id": 2, "title": "title"}, + ] + ) diff --git a/tests/integrations/seeds/store_table_seeder.py b/tests/integrations/seeds/store_table_seeder.py new file mode 100644 index 000000000..fa09528e7 --- /dev/null +++ b/tests/integrations/seeds/store_table_seeder.py @@ -0,0 +1,130 @@ +"""StoreTableSeeder Seeder.""" + +from src.masoniteorm.models import Model +from src.masoniteorm.seeds import Seeder + + +class Store(Model): + __connection__ = "dev" + __table__ = "stores" + + +class Product(Model): + __connection__ = "dev" + __table__ = "products" + + +class ProductStore(Model): + __connection__ = "dev" + __table__ = "product_store" + __timestamps__ = False + + +class StoreTableSeeder(Seeder): + def run(self): + """ + Seed stores, products, and the product_store pivot table. + + test_belongs_to_many hydrates Store(id=2) and asserts: + - store.products.count() == 3 + - first product id=4, name='Handgun' + - product created_at/updated_at == '2020-01-01T00:00:00+00:00' + + test_belongs_to_eager_many calls Store.with_('products').first() (store id=1) + and asserts store.products.count() == 3. + + Layout: + Store 1 (Walmart) → products 1, 2, 3 (Pants, Shirt, Flag) + Store 2 (Target) → products 4, 5, 6 (Handgun, Rifle, Machine Gun) + """ + Store.bulk_create( + [ + { + "name": "Walmart", + "created_at": "2020-01-01", + "updated_at": "2020-01-01", + }, + { + "name": "Target", + "created_at": "2020-01-01", + "updated_at": "2020-01-01", + }, + ] + ) + + Product.bulk_create( + [ + { + "name": "Pants", + "created_at": "2020-01-01", + "updated_at": "2020-01-01", + }, + { + "name": "Shirt", + "created_at": "2020-01-01", + "updated_at": "2020-01-01", + }, + { + "name": "Flag", + "created_at": "2020-01-01", + "updated_at": "2020-01-01", + }, + { + "name": "Handgun", + "created_at": "2020-01-01", + "updated_at": "2020-01-01", + }, + { + "name": "Rifle", + "created_at": "2020-01-01", + "updated_at": "2020-01-01", + }, + { + "name": "Machine Gun", + "created_at": "2020-01-01", + "updated_at": "2020-01-01", + }, + ] + ) + + # Pivot rows — store 1 gets products 1-3, store 2 gets products 4-6. + ProductStore.bulk_create( + [ + { + "product_id": 1, + "store_id": 1, + "created_at": "2020-01-01", + "updated_at": "2020-01-01", + }, + { + "product_id": 2, + "store_id": 1, + "created_at": "2020-01-01", + "updated_at": "2020-01-01", + }, + { + "product_id": 3, + "store_id": 1, + "created_at": "2020-01-01", + "updated_at": "2020-01-01", + }, + { + "product_id": 4, + "store_id": 2, + "created_at": "2020-01-01", + "updated_at": "2020-01-01", + }, + { + "product_id": 5, + "store_id": 2, + "created_at": "2020-01-01", + "updated_at": "2020-01-01", + }, + { + "product_id": 6, + "store_id": 2, + "created_at": "2020-01-01", + "updated_at": "2020-01-01", + }, + ] + ) diff --git a/tests/integrations/seeds/user_table_seeder.py b/tests/integrations/seeds/user_table_seeder.py index 20187a5ce..d83d05105 100644 --- a/tests/integrations/seeds/user_table_seeder.py +++ b/tests/integrations/seeds/user_table_seeder.py @@ -1,18 +1,45 @@ """UserTableSeeder Seeder.""" -from src.masoniteorm.factories import Factory as factory +from src.masoniteorm.models import Model from src.masoniteorm.seeds import Seeder -from tests.User import User -factory.register(User, lambda faker: {"email": faker.email()}) + +class User(Model): + __connection__ = "dev" + __timestamps__ = False class UserTableSeeder(Seeder): def run(self): - """Run the database seeds.""" - factory(User, 5).create( + """ + Seed the users table with deterministic data required by the test suite. + + User id=1 (Joe) is already created by the users migration. This seeder: + - Sets is_admin and active on the migration-created user so relationship + and casting tests have a known user to work with. + - Creates a second user (Bob) for the second profile relationship. + """ + # The migration inserts Joe as id=1 without is_admin/active. + # Update those columns so test_casting/test_setting have matching rows. + User.create( { "name": "Joe", - "password": "joe", + "email": "joe@email.com", + "password": "secret", + "age": 21, + "is_admin": 1, + "active": 1, + } + ) + + # Second user — linked to profile id=2 by ProfileTableSeeder. + User.create( + { + "name": "Bob", + "email": "bob@email.com", + "password": "secret", + "is_admin": 0, + "active": 1, + "age": 25, } ) diff --git a/tests/sqlite/builder/test_sqlite_query_builder.py b/tests/sqlite/builder/test_sqlite_query_builder.py index 3c3597eb4..341b1e79e 100644 --- a/tests/sqlite/builder/test_sqlite_query_builder.py +++ b/tests/sqlite/builder/test_sqlite_query_builder.py @@ -442,8 +442,7 @@ def test_between(self): def test_between_persisted(self): builder = QueryBuilder().table("users").on("dev") - users = builder.between("age", 1, 2).count() - + users = builder.between("age", 21, 25).count() self.assertEqual(users, 2) def test_not_between(self): @@ -456,9 +455,8 @@ def test_not_between(self): def test_not_between_persisted(self): builder = QueryBuilder().table("users").on("dev") - users = builder.where_not_null("id").not_between("age", 1, 2).count() - - self.assertEqual(users, 0) + users = builder.where_not_null("id").not_between("age", 1, 10).count() + self.assertEqual(users, 2) def test_where_in(self): builder = self.get_builder() diff --git a/tests/sqlite/builder/test_sqlite_query_builder_eager_loading.py b/tests/sqlite/builder/test_sqlite_query_builder_eager_loading.py index be95deadd..cfdf19274 100644 --- a/tests/sqlite/builder/test_sqlite_query_builder_eager_loading.py +++ b/tests/sqlite/builder/test_sqlite_query_builder_eager_loading.py @@ -88,8 +88,8 @@ def test_with_first(self): def test_with_where_no_relation(self): builder = self.get_builder() - result = builder.with_("profile").where("id", 5).first() - result.serialize() + user = builder.with_("profile").where("id", 3).first() + self.assertIsNone(user.profile) def test_with_multiple_per_same_relation(self): result = User.with_("articles", "articles.logo").where("id", 1).first() diff --git a/tests/sqlite/conftest.py b/tests/sqlite/conftest.py new file mode 100644 index 000000000..93070aef5 --- /dev/null +++ b/tests/sqlite/conftest.py @@ -0,0 +1,89 @@ +""" +Pytest configuration for tests/sqlite/. + +Ensures a clean, fully-migrated SQLite database before each test session by +running the integration migrations and seeds from tests/integrations/. + +Scoped to this directory intentionally — other test suites (mysql, postgres, +mssql) manage their own connections and do not need SQLite setup. +""" + +import os +import pathlib + +import pytest + +# Set config path before any ORM import so load_config() picks it up. +# Tests that import from tests.integrations.config.database build their own +# ConnectionResolver directly, so they are unaffected by this setting. +os.environ.setdefault("DB_CONFIG_PATH", "tests/integrations/config/database") + +from src.masoniteorm.migrations import Migration # noqa: E402 +from tests.integrations.seeds.database_seeder import ( # noqa: E402 + DatabaseSeeder, +) + +_SQLITE_DB = pathlib.Path("orm.sqlite3") +_MIGRATION_DIR = "tests/integrations/migrations" +_CONNECTION = "dev" + + +@pytest.fixture(scope="session", autouse=True) +def sqlite_db_session(): + """ + Session-scoped fixture that resets the SQLite database, runs all + integration migrations, then seeds initial data. + + Runs exactly once per pytest session, before the first test in + tests/sqlite/ executes. The autouse=True + conftest placement means every + test in this directory receives a consistently-seeded database without + needing to import or reference this fixture explicitly. + + Individual tests that need isolated state (e.g. test_attach_detach) manage + their own setUp/tearDown as normal — this fixture only establishes the base + schema and seed data those tests build on top of. + """ + _reset_db() + _run_migrations() + _run_seeds() + yield + # Leave the file in place for post-run inspection. + # The next session will reset it via _reset_db(). + + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + + +def _reset_db() -> None: + """Delete the SQLite file so every session starts from a clean slate.""" + if _SQLITE_DB.exists(): + _SQLITE_DB.unlink() + + +def _run_migrations() -> None: + """ + Run all unran migrations from tests/integrations/migrations/ against the + 'dev' (SQLite) connection. + + Migration.create_table_if_not_exists() is called first to bootstrap the + migrations tracking table on a fresh database. + """ + migration = Migration( + connection=_CONNECTION, + migration_directory=_MIGRATION_DIR, + ) + migration.create_table_if_not_exists() + migration.migrate() + + +def _run_seeds() -> None: + """ + Run the DatabaseSeeder from tests/integrations/seeds/. + + DatabaseSeeder.run() delegates to each registered sub-seeder (e.g. + UserTableSeeder) in order, so adding new seeders only requires updating + DatabaseSeeder — not this conftest. + """ + DatabaseSeeder(connection=_CONNECTION).run() diff --git a/tests/sqlite/models/test_observers.py b/tests/sqlite/models/test_observers.py index d4096b419..5561229a4 100644 --- a/tests/sqlite/models/test_observers.py +++ b/tests/sqlite/models/test_observers.py @@ -87,14 +87,14 @@ def test_updating_is_observed(self): # DB.rollback("dev") def test_booting_is_observed(self): - # DB.begin_transaction("dev") - user = Observer.hydrate({"id": 1, "name": "joe"}) + DB.begin_transaction("dev") + user = Observer.hydrate({"id": 10, "name": "bill"}) user.update({"name": "bill"}) self.assertEqual(TestM.observed_booting, 1) self.assertEqual(TestM.observed_booted, 1) - # DB.rollback("dev") + DB.rollback("dev") def test_deleting_is_observed(self): DB.begin_transaction("dev") diff --git a/tests/sqlite/models/test_sqlite_model.py b/tests/sqlite/models/test_sqlite_model.py index 530c66418..0fd8703ff 100644 --- a/tests/sqlite/models/test_sqlite_model.py +++ b/tests/sqlite/models/test_sqlite_model.py @@ -58,9 +58,7 @@ def test_update_specific_record(self): self.assertEqual( sql, - """UPDATE "users" SET "name" = 'joe' WHERE "id" = '{}'""".format( - user.id - ), + f"""UPDATE "users" SET "name" = 'joe' WHERE "id" = '{user.id}'""", ) def test_update_all_records(self): @@ -118,43 +116,33 @@ def test_update_only_changed_attributes(self): # unchanged name attribute is not updated self.assertEqual( sql, - """UPDATE "users" SET "username" = 'new' WHERE "id" = '{}'""".format( - user.id - ), + f"""UPDATE "users" SET "username" = 'new' WHERE "id" = '{user.id}'""", ) def test_can_force_update_on_method(self): user = User.first() sql = user.update( - {"name": user.name, "username": "new"}, force=True + {"name": "Frank", "username": "new"}, force=True ).to_sql() self.assertEqual( sql, - """UPDATE "users" SET "name" = 'bill', "username" = 'new' WHERE "id" = '{}'""".format( - user.id - ), + f"""UPDATE "users" SET "name" = 'Frank', "username" = 'new' WHERE "id" = '{user.id}'""", ) def test_can_force_update_on_model(self): user = UserForced.first() - sql = user.update({"name": user.name, "username": "new"}).to_sql() + sql = user.update({"name": "Fred", "username": "new"}).to_sql() self.assertEqual( sql, - """UPDATE "users" SET "name" = 'bill', "username" = 'new' WHERE "id" = '{}'""".format( - user.id - ), + f"""UPDATE "users" SET "name" = 'Fred', "username" = 'new' WHERE "id" = '{user.id}'""", ) def test_force_update(self): user = User.first() - sql = user.force_update( - {"name": user.name, "username": "new"} - ).to_sql() + sql = user.force_update({"name": "Bill", "username": "new"}).to_sql() self.assertEqual( sql, - """UPDATE "users" SET "name" = 'bill', "username" = 'new' WHERE "id" = '{}'""".format( - user.id - ), + f"""UPDATE "users" SET "name" = 'Bill', "username" = 'new' WHERE "id" = '{user.id}'""", ) def test_update_is_not_done_when_no_changes(self): @@ -167,7 +155,7 @@ class ModelUser(Model): __connection__ = "dev" __table__ = "users" - count = User.between("age", 1, 2).get().count() + count = User.between("age", 21, 25).get().count() self.assertEqual(count, 2) def test_should_collect_correct_amount_data_using_not_between(self): @@ -176,7 +164,7 @@ class ModelUser(Model): __table__ = "users" count = ( - User.where_not_null("id").not_between("age", 1, 2).get().count() + User.where_not_null("id").not_between("age", 21, 25).get().count() ) self.assertEqual(count, 0) @@ -188,23 +176,15 @@ def test_get_columns(self): "id", "name", "email", + "age", + "is_admin", + "active", "password", + "second_password", "remember_token", + "verified_at", "created_at", - "is_admin", - "age", - "boo", - "tool1", - "tool2", - "active", "updated_at", - "profile_id", - "name5", - "name6", - "age6", - "age7", - "age8", - "age10", ], ) @@ -221,19 +201,19 @@ def test_should_return_relation_applying_hidden_attributes(self): schema.drop_table_if_exists(table) with schema.create("users_hidden") as blueprint: - blueprint.increments("id") + blueprint.integer("id").primary() blueprint.string("name") blueprint.integer("token") blueprint.string("password") blueprint.timestamps() with schema.create("groups") as blueprint: - blueprint.increments("id") + blueprint.integer("id").primary() blueprint.string("name") blueprint.timestamps() with schema.create("group_user") as blueprint: - blueprint.increments("id") + blueprint.integer("id").primary() blueprint.unsigned_integer("group_id") blueprint.unsigned_integer("user_id") @@ -251,7 +231,7 @@ def test_should_return_relation_applying_hidden_attributes(self): user = UserHydrateHidden.first() group = Group.first() - group.attach_related("team", user) + group.attach("team", user) serialized = Group.first().serialize() From 7aeeeb2b4c5e49d397d2d286ede7b7b3fc11471c Mon Sep 17 00:00:00 2001 From: Kieren Eaton <499977+circulon@users.noreply.github.com> Date: Sat, 16 May 2026 11:09:38 +0800 Subject: [PATCH 05/10] moved conftest for use with other tests --- tests/{sqlite => }/conftest.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{sqlite => }/conftest.py (100%) diff --git a/tests/sqlite/conftest.py b/tests/conftest.py similarity index 100% rename from tests/sqlite/conftest.py rename to tests/conftest.py From 30fcf8335e6ee9e454a8bd1b0f0c3469613004cb Mon Sep 17 00:00:00 2001 From: Kieren Eaton <499977+circulon@users.noreply.github.com> Date: Sat, 16 May 2026 11:24:48 +0800 Subject: [PATCH 06/10] fixed timestamps --- .../2021_01_01_000009_create_product_store_table.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/integrations/migrations/2021_01_01_000009_create_product_store_table.py b/tests/integrations/migrations/2021_01_01_000009_create_product_store_table.py index bb987346f..4c3da2006 100644 --- a/tests/integrations/migrations/2021_01_01_000009_create_product_store_table.py +++ b/tests/integrations/migrations/2021_01_01_000009_create_product_store_table.py @@ -10,9 +10,7 @@ def up(self): table.increments("id").primary() table.integer("product_id") table.integer("store_id") - # Pivot timestamps are checked explicitly in test_belongs_to_many. - table.datetime("created_at").default("CURRENT_TIMESTAMP") - table.datetime("updated_at").default("CURRENT_TIMESTAMP") + table.timestamps() def down(self): """Revert the migrations.""" From 02bc1d16038116df7455cc2ac5a6368443278325 Mon Sep 17 00:00:00 2001 From: Kieren Eaton <499977+circulon@users.noreply.github.com> Date: Sat, 16 May 2026 12:45:53 +0800 Subject: [PATCH 07/10] removed unused config --- config/test-database.py | 35 ----------------------------------- 1 file changed, 35 deletions(-) delete mode 100644 config/test-database.py diff --git a/config/test-database.py b/config/test-database.py deleted file mode 100644 index a05058cbd..000000000 --- a/config/test-database.py +++ /dev/null @@ -1,35 +0,0 @@ -from src.masoniteorm.connections import ConnectionResolver - -DATABASES = { - "default": "mysql", - "mysql": { - "host": "127.0.0.1", - "driver": "mysql", - "database": "masonite", - "user": "root", - "password": "", - "port": 3306, - "log_queries": False, - "options": { - # - } - }, - "postgres": { - "host": "127.0.0.1", - "driver": "postgres", - "database": "masonite", - "user": "root", - "password": "", - "port": 5432, - "log_queries": False, - "options": { - # - } - }, - "sqlite": { - "driver": "sqlite", - "database": "masonite.sqlite3", - } -} - -DB = ConnectionResolver().set_connection_details(DATABASES) From 4dafbc1b31c5cff79b68722eecc5b838d07c844d Mon Sep 17 00:00:00 2001 From: Kieren Eaton <499977+circulon@users.noreply.github.com> Date: Sun, 17 May 2026 12:54:18 +0800 Subject: [PATCH 08/10] added check that all tests have an assertion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This addresses the issue where a test has been partially completed but no “assert” was added. In this case pytest classes the response as a technical pass the script will be run during pre-commit checks and as part of the CI test run --- .pre-commit-config.yaml | 10 +++++ makefile | 6 ++- scripts/check_test_asserts.py | 70 +++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 scripts/check_test_asserts.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e3bac65e7..b877d56eb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -30,3 +30,13 @@ repos: ^build| ^conda ) + + - repo: local + hooks: + - id: check-test-asserts + name: Check tests have assertions + description: Ensures every test method contains at least one assert statement + entry: python scripts/check_test_asserts.py + language: system + files: ^tests/.*test_.*\.py$ + pass_filenames: false diff --git a/makefile b/makefile index 1da923aaf..7aac3af67 100644 --- a/makefile +++ b/makefile @@ -20,13 +20,15 @@ init-ci: # Create MySQL Database # Create Postgres Database -test: init +test: init test-asserts python -m pytest tests ci: make test -check: format sort lint +check: format sort lint test-asserts lint: flake8 src/masoniteorm tests +test-asserts: + python scripts/check_test_asserts.py format: init black src/masoniteorm tests/ sort: init diff --git a/scripts/check_test_asserts.py b/scripts/check_test_asserts.py new file mode 100644 index 000000000..069b06752 --- /dev/null +++ b/scripts/check_test_asserts.py @@ -0,0 +1,70 @@ +import ast +import sys +from pathlib import Path + + +def has_assertion(method_body_lines): + for line in method_body_lines: + stripped = line.strip() + if stripped.startswith("self.assert"): + return True + if stripped.startswith("with self.assertRaises"): + return True + if stripped.startswith("with self.assertRaisesRegex"): + return True + if "assert " in stripped or "assert(" in stripped: + return True + return False + + +def main(): + tests_dir = Path("tests") + if not tests_dir.exists(): + print("No tests/ directory found") + sys.exit(0) + + test_files = sorted(tests_dir.rglob("test_*.py")) + failures = [] + + for filepath in test_files: + if "__pycache__" in str(filepath): + continue + + content = filepath.read_text() + try: + tree = ast.parse(content) + except SyntaxError as e: + print(f"SYNTAX ERROR in {filepath}: {e}") + failures.append(str(filepath)) + continue + + lines = content.splitlines() + + for node in ast.walk(tree): + if not isinstance(node, (ast.ClassDef,)): + continue + for item in node.body: + if not isinstance( + item, (ast.FunctionDef, ast.AsyncFunctionDef) + ): + continue + if not item.name.startswith("test_"): + continue + body_lines = lines[item.lineno - 1 : item.end_lineno] + if not has_assertion(body_lines): + failures.append( + f"{filepath}::{node.name}::{item.name} (line {item.lineno})" + ) + + if failures: + print(f"Found {len(failures)} test(s) without assertions:") + for f in failures: + print(f" {f}") + sys.exit(1) + else: + print("All tests have assertions.") + sys.exit(0) + + +if __name__ == "__main__": + main() From 6420fb2cdbd34c3ef40d14dc46e10ee92f686355 Mon Sep 17 00:00:00 2001 From: Kieren Eaton <499977+circulon@users.noreply.github.com> Date: Sun, 17 May 2026 12:58:30 +0800 Subject: [PATCH 09/10] updated tests cleaned up for readability - moved all grammar test values into the associated test. - renamed test classes where required Added assertions to tests that did not have them (causing false positive pass) Enabled commented out tests General cleanup and tidy --- tests/models/test_models.py | 82 +- .../mssql/builder/test_mssql_query_builder.py | 309 +++-- .../test_mssql_query_builder_relationships.py | 28 +- .../grammar/test_mssql_delete_grammar.py | 18 +- .../grammar/test_mssql_insert_grammar.py | 25 +- tests/mssql/grammar/test_mssql_qmark.py | 48 +- .../grammar/test_mssql_select_grammar.py | 973 +++++++------ .../grammar/test_mssql_update_grammar.py | 29 +- .../mssql/schema/test_mssql_schema_builder.py | 285 ++-- .../schema/test_mssql_schema_builder_alter.py | 149 +- tests/mysql/builder/test_query_builder.py | 1109 +++++---------- .../builder/test_query_builder_scopes.py | 34 +- .../test_mysql_connection_selects.py | 6 +- .../grammar/test_mysql_delete_grammar.py | 71 +- .../grammar/test_mysql_insert_grammar.py | 92 +- tests/mysql/grammar/test_mysql_qmark.py | 215 +-- .../grammar/test_mysql_select_grammar.py | 960 +++++++------ .../grammar/test_mysql_update_grammar.py | 114 +- tests/mysql/model/test_model.py | 92 +- .../relationships/test_belongs_to_many.py | 54 +- .../relationships/test_has_many_through.py | 35 +- .../relationships/test_has_one_through.py | 43 +- .../mysql/relationships/test_relationships.py | 64 +- .../mysql/schema/test_mysql_schema_builder.py | 65 +- .../schema/test_mysql_schema_builder_alter.py | 143 +- .../scopes/test_can_use_global_scopes.py | 15 +- tests/mysql/scopes/test_can_use_scopes.py | 22 +- tests/mysql/scopes/test_soft_delete.py | 68 +- .../builder/test_postgres_query_builder.py | 955 +++++-------- tests/postgres/grammar/test_delete_grammar.py | 69 +- tests/postgres/grammar/test_insert_grammar.py | 77 +- tests/postgres/grammar/test_select_grammar.py | 982 +++++++------ tests/postgres/grammar/test_update_grammar.py | 125 +- .../test_postgres_relationships.py | 37 +- .../schema/test_postgres_schema_builder.py | 60 +- .../test_postgres_schema_builder_alter.py | 178 ++- tests/scopes/test_default_global_scopes.py | 8 +- .../builder/test_sqlite_query_builder.py | 1210 ++++++----------- ...test_sqlite_query_builder_relationships.py | 32 +- .../grammar/test_sqlite_delete_grammar.py | 67 +- .../grammar/test_sqlite_insert_grammar.py | 92 +- .../grammar/test_sqlite_select_grammar.py | 965 +++++++------ .../grammar/test_sqlite_update_grammar.py | 124 +- tests/sqlite/models/test_sqlite_model.py | 86 +- .../test_sqlite_relationships.py | 57 +- .../schema/test_sqlite_schema_builder.py | 43 +- .../test_sqlite_schema_builder_alter.py | 61 +- tests/sqlite/schema/test_table.py | 38 +- tests/sqlite/schema/test_table_diff.py | 36 +- 49 files changed, 4703 insertions(+), 5747 deletions(-) diff --git a/tests/models/test_models.py b/tests/models/test_models.py index c2b759ed7..003ca0da1 100644 --- a/tests/models/test_models.py +++ b/tests/models/test_models.py @@ -109,14 +109,14 @@ def test_model_creates_when_new(self): model = ModelTest.hydrate({"id": 1, "username": "joe", "admin": True}) model.name = "Bill" - sql = model.save(query=True).to_sql() - self.assertTrue(sql.startswith("UPDATE")) + query_sql = model.save(query=True).to_sql() + self.assertTrue(query_sql.startswith("UPDATE")) model = ModelTest() model.name = "Bill" - sql = model.save(query=True).to_sql() - self.assertTrue(sql.startswith("INSERT")) + query_sql = model.save(query=True).to_sql() + self.assertTrue(query_sql.startswith("INSERT")) def test_model_can_cast_attributes(self): model = ModelTest.hydrate( @@ -216,9 +216,9 @@ def test_model_update_without_changes(self): model.username = "joe" model.name = "Bill" - sql = model.save(query=True).to_sql() - self.assertTrue(sql.startswith("UPDATE")) - self.assertNotIn("username", sql) + query_sql = model.save(query=True).to_sql() + self.assertTrue(query_sql.startswith("UPDATE")) + self.assertNotIn("username", query_sql) def test_force_update_on_model_class(self): model = ModelTestForced.hydrate( @@ -227,10 +227,10 @@ def test_force_update_on_model_class(self): model.username = "joe" model.name = "Bill" - sql = model.save(query=True).to_sql() - self.assertTrue(sql.startswith("UPDATE")) - self.assertIn("username", sql) - self.assertIn("name", sql) + query_sql = model.save(query=True).to_sql() + self.assertTrue(query_sql.startswith("UPDATE")) + self.assertIn("username", query_sql) + self.assertIn("name", query_sql) def test_only_method(self): model = ModelTestForced.hydrate( @@ -247,22 +247,22 @@ def test_model_update_without_changes_at_all(self): model.username = "joe" model.name = "Joe" - sql = model.save(query=True).to_sql() - self.assertFalse(sql.startswith("UPDATE")) + query_sql = model.save(query=True).to_sql() + self.assertFalse(query_sql.startswith("UPDATE")) def test_model_using_or_where(self): model = ModelTest() - sql = model.where("name", "=", "joe").or_where("is_vip", True).to_sql() - - self.assertEqual( - sql, - """SELECT * FROM `model_tests` WHERE `model_tests`.`name` = 'joe' OR `model_tests`.`is_vip` = '1'""", + query_sql = ( + model.where("name", "=", "joe").or_where("is_vip", True).to_sql() ) + expected_sql = """SELECT * FROM `model_tests` WHERE `model_tests`.`name` = 'joe' OR `model_tests`.`is_vip` = '1'""" + + self.assertEqual(query_sql, expected_sql) def test_model_using_or_where_and_chaining_wheres(self): model = ModelTest() - sql = ( + query_sql = ( model.where("name", "=", "joe") .or_where( lambda query: query.where("username", "Joseph").or_where( @@ -273,7 +273,7 @@ def test_model_using_or_where_and_chaining_wheres(self): ) self.assertTrue( - sql, + query_sql, """SELECT * FROM `model_tests` WHERE `model_tests`.`name` = 'joe' OR (`model_tests`.`username` = 'Joseph' OR `model_tests`.`age` >= '18'))""", ) @@ -301,34 +301,26 @@ def test_both_fillable_and_guarded_attributes_raise(self): InvalidFillableGuardedModelTest() def test_model_can_provide_default_select(self): - sql = ModelWithBaseModel.to_sql() - self.assertEqual( - sql, - """SELECT `users`.* FROM `users`""", - ) + query_sql = ModelWithBaseModel.to_sql() + expected_sql = """SELECT `users`.* FROM `users`""" + self.assertEqual(query_sql, expected_sql) def test_model_can_override_to_default_select(self): - sql = ModelWithBaseModel.select( + query_sql = ModelWithBaseModel.select( ["products.name", "products.id", "store.name"] ).to_sql() - self.assertEqual( - sql, - """SELECT `products`.`name`, `products`.`id`, `store`.`name` FROM `users`""", - ) + expected_sql = """SELECT `products`.`name`, `products`.`id`, `store`.`name` FROM `users`""" + self.assertEqual(query_sql, expected_sql) def test_model_can_use_aggregate_funcs_with_default_selects(self): - sql = ModelWithBaseModel.count().to_sql() - self.assertEqual( - sql, - """SELECT COUNT(*) AS m_count_reserved FROM `users`""", - ) - sql = ModelWithBaseModel.max("id").to_sql() - self.assertEqual( - sql, - """SELECT MAX(`users`.`id`) AS id FROM `users`""", - ) - sql = ModelWithBaseModel.min("id").to_sql() - self.assertEqual( - sql, - """SELECT MIN(`users`.`id`) AS id FROM `users`""", - ) + query_sql = ModelWithBaseModel.count().to_sql() + expected_sql = """SELECT COUNT(*) AS m_count_reserved FROM `users`""" + self.assertEqual(query_sql, expected_sql) + + query_sql = ModelWithBaseModel.max("id").to_sql() + expected_sql = """SELECT MAX(`users`.`id`) AS id FROM `users`""" + self.assertEqual(query_sql, expected_sql) + + query_sql = ModelWithBaseModel.min("id").to_sql() + expected_sql = """SELECT MIN(`users`.`id`) AS id FROM `users`""" + self.assertEqual(query_sql, expected_sql) diff --git a/tests/mssql/builder/test_mssql_query_builder.py b/tests/mssql/builder/test_mssql_query_builder.py index ea8cb484f..e57949b4f 100644 --- a/tests/mssql/builder/test_mssql_query_builder.py +++ b/tests/mssql/builder/test_mssql_query_builder.py @@ -38,77 +38,84 @@ def test_sum(self): builder = self.get_builder() builder.sum("age") - self.assertEqual( - builder.to_sql(), "SELECT SUM([users].[age]) AS age FROM [users]" - ) + query_sql = builder.to_sql() + expected_sql = "SELECT SUM([users].[age]) AS age FROM [users]" + self.assertEqual(query_sql, expected_sql) def test_where_like(self): builder = self.get_builder() builder.where("age", "like", "%name%") - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] WHERE [users].[age] LIKE '%name%'", + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM [users] WHERE [users].[age] LIKE '%name%'" ) + self.assertEqual(query_sql, expected_sql) def test_where_not_like(self): builder = self.get_builder() builder.where("age", "not like", "%name%") - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] WHERE [users].[age] NOT LIKE '%name%'", + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM [users] WHERE [users].[age] NOT LIKE '%name%'" ) + self.assertEqual(query_sql, expected_sql) def test_max(self): builder = self.get_builder() builder.max("age") - self.assertEqual( - builder.to_sql(), "SELECT MAX([users].[age]) AS age FROM [users]" - ) + query_sql = builder.to_sql() + expected_sql = "SELECT MAX([users].[age]) AS age FROM [users]" + self.assertEqual(query_sql, expected_sql) def test_min(self): builder = self.get_builder() builder.min("age") - self.assertEqual( - builder.to_sql(), "SELECT MIN([users].[age]) AS age FROM [users]" - ) + query_sql = builder.to_sql() + expected_sql = "SELECT MIN([users].[age]) AS age FROM [users]" + self.assertEqual(query_sql, expected_sql) def test_avg(self): builder = self.get_builder() builder.avg("age") - self.assertEqual( - builder.to_sql(), "SELECT AVG([users].[age]) AS age FROM [users]" - ) + query_sql = builder.to_sql() + expected_sql = "SELECT AVG([users].[age]) AS age FROM [users]" + self.assertEqual(query_sql, expected_sql) def test_all(self): builder = self.get_builder() builder.all() - self.assertEqual(builder.to_sql(), "SELECT * FROM [users]") + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM [users]" + self.assertEqual(query_sql, expected_sql) def test_get(self): builder = self.get_builder() builder.get() - self.assertEqual(builder.to_sql(), "SELECT * FROM [users]") + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM [users]" + self.assertEqual(query_sql, expected_sql) def test_first(self): builder = self.get_builder().first(query=True) - self.assertEqual(builder.to_sql(), "SELECT TOP 1 * FROM [users]") + query_sql = builder.to_sql() + expected_sql = "SELECT TOP 1 * FROM [users]" + self.assertEqual(query_sql, expected_sql) def test_select(self): builder = self.get_builder() builder.select("name", "email") - self.assertEqual( - builder.to_sql(), - "SELECT [users].[name], [users].[email] FROM [users]", - ) + query_sql = builder.to_sql() + expected_sql = "SELECT [users].[name], [users].[email] FROM [users]" + self.assertEqual(query_sql, expected_sql) def test_add_select_no_table(self): builder = self.get_builder(table=None) @@ -119,22 +126,21 @@ def test_add_select_no_table(self): "some_alias", lambda q: q.max("updated_at").table("another_table") ) - self.assertEqual( - builder.to_sql(), - ( - "SELECT " - "(SELECT MAX([different_table].[updated_at]) AS updated_at FROM [different_table]) AS other_test, " - "(SELECT MAX([another_table].[updated_at]) AS updated_at FROM [another_table]) AS some_alias" - ), + query_sql = builder.to_sql() + expected_sql = ( + "SELECT " + "(SELECT MAX([different_table].[updated_at]) AS updated_at FROM [different_table]) AS other_test, " + "(SELECT MAX([another_table].[updated_at]) AS updated_at FROM [another_table]) AS some_alias" ) + self.assertEqual(query_sql, expected_sql) def test_select_raw(self): builder = self.get_builder() builder.select_raw("count(email) as email_count") - self.assertEqual( - builder.to_sql(), "SELECT count(email) as email_count FROM [users]" - ) + query_sql = builder.to_sql() + expected_sql = "SELECT count(email) as email_count FROM [users]" + self.assertEqual(query_sql, expected_sql) def test_create(self): builder = self.get_builder().without_global_scopes() @@ -143,83 +149,79 @@ def test_create(self): query=True, ) - self.assertEqual( - builder.to_sql(), - "INSERT INTO [users] ([users].[name], [users].[email]) VALUES ('Corentin All', 'corentin@yopmail.com')", - ) + query_sql = builder.to_sql() + expected_sql = "INSERT INTO [users] ([users].[name], [users].[email]) VALUES ('Corentin All', 'corentin@yopmail.com')" + self.assertEqual(query_sql, expected_sql) def test_delete(self): builder = self.get_builder() builder.delete("name", "Joe", query=True) - self.assertEqual( - builder.to_sql(), - "DELETE FROM [users] WHERE [users].[name] = 'Joe'", - ) + query_sql = builder.to_sql() + expected_sql = "DELETE FROM [users] WHERE [users].[name] = 'Joe'" + self.assertEqual(query_sql, expected_sql) def test_where(self): builder = self.get_builder() builder.where("name", "Joe") - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] WHERE [users].[name] = 'Joe'", - ) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM [users] WHERE [users].[name] = 'Joe'" + self.assertEqual(query_sql, expected_sql) def test_where_exists(self): builder = self.get_builder() builder.where_exists("name") - self.assertEqual( - builder.to_sql(), "SELECT * FROM [users] WHERE EXISTS 'name'" - ) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM [users] WHERE EXISTS 'name'" + self.assertEqual(query_sql, expected_sql) def test_limit(self): builder = self.get_builder() builder.limit(5) - self.assertEqual(builder.to_sql(), "SELECT TOP 5 * FROM [users]") + query_sql = builder.to_sql() + expected_sql = "SELECT TOP 5 * FROM [users]" + self.assertEqual(query_sql, expected_sql) def test_offset(self): builder = self.get_builder() builder.offset(5) - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] OFFSET 5 ROWS FETCH NEXT 1 ROWS ONLY", + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM [users] OFFSET 5 ROWS FETCH NEXT 1 ROWS ONLY" ) + self.assertEqual(query_sql, expected_sql) def test_join(self): builder = self.get_builder() builder.join("profiles", "users.id", "=", "profiles.user_id") - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] INNER JOIN [profiles] ON [users].[id] = [profiles].[user_id]", - ) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM [users] INNER JOIN [profiles] ON [users].[id] = [profiles].[user_id]" + self.assertEqual(query_sql, expected_sql) def test_left_join(self): builder = self.get_builder() builder.left_join("profiles", "users.id", "=", "profiles.user_id") - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] LEFT JOIN [profiles] ON [users].[id] = [profiles].[user_id]", - ) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM [users] LEFT JOIN [profiles] ON [users].[id] = [profiles].[user_id]" + self.assertEqual(query_sql, expected_sql) def test_right_join(self): builder = self.get_builder() builder.right_join("profiles", "users.id", "=", "profiles.user_id") - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] RIGHT JOIN [profiles] ON [users].[id] = [profiles].[user_id]", - ) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM [users] RIGHT JOIN [profiles] ON [users].[id] = [profiles].[user_id]" + self.assertEqual(query_sql, expected_sql) def test_update(self): builder = self.get_builder().update( {"name": "Joe", "email": "joe@yopmail.com"}, dry=True ) - self.assertEqual( - builder.to_sql(), - "UPDATE [users] SET [users].[name] = 'Joe', [users].[email] = 'joe@yopmail.com'", - ) + query_sql = builder.to_sql() + expected_sql = "UPDATE [users] SET [users].[name] = 'Joe', [users].[email] = 'joe@yopmail.com'" + self.assertEqual(query_sql, expected_sql) # def test_increment(self): # builder = self.get_builder() @@ -238,82 +240,85 @@ def test_update(self): def test_count(self): builder = self.get_builder() builder.count("id") - self.assertEqual( - builder.to_sql(), "SELECT COUNT([users].[id]) AS id FROM [users]" - ) + query_sql = builder.to_sql() + expected_sql = "SELECT COUNT([users].[id]) AS id FROM [users]" + self.assertEqual(query_sql, expected_sql) def test_order_by_asc(self): builder = self.get_builder() builder.order_by("email", "asc") - self.assertEqual( - builder.to_sql(), "SELECT * FROM [users] ORDER BY [email] ASC" - ) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM [users] ORDER BY [email] ASC" + self.assertEqual(query_sql, expected_sql) def test_order_by_desc(self): builder = self.get_builder() builder.order_by("email", "desc") - self.assertEqual( - builder.to_sql(), "SELECT * FROM [users] ORDER BY [email] DESC" - ) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM [users] ORDER BY [email] DESC" + self.assertEqual(query_sql, expected_sql) def test_where_column(self): builder = self.get_builder() builder.where_column("name", "username") - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] WHERE [users].[name] = [users].[username]", + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM [users] WHERE [users].[name] = [users].[username]" ) + self.assertEqual(query_sql, expected_sql) def test_where_not_in(self): builder = self.get_builder() builder.where_not_in("id", [1, 2, 3]) - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] WHERE [users].[id] NOT IN ('1','2','3')", + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM [users] WHERE [users].[id] NOT IN ('1','2','3')" ) + self.assertEqual(query_sql, expected_sql) def test_between(self): builder = self.get_builder() builder.between("id", 2, 5) - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] WHERE [users].[id] BETWEEN '2' AND '5'", + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM [users] WHERE [users].[id] BETWEEN '2' AND '5'" ) + self.assertEqual(query_sql, expected_sql) def test_not_between(self): builder = self.get_builder() builder.not_between("id", 2, 5) - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] WHERE [users].[id] NOT BETWEEN '2' AND '5'", + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM [users] WHERE [users].[id] NOT BETWEEN '2' AND '5'" ) + self.assertEqual(query_sql, expected_sql) def test_where_in(self): builder = self.get_builder() builder.where_in("id", [1, 2, 3]) - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] WHERE [users].[id] IN ('1','2','3')", + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM [users] WHERE [users].[id] IN ('1','2','3')" ) + self.assertEqual(query_sql, expected_sql) def test_where_null(self): builder = self.get_builder() builder.where_null("name") - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] WHERE [users].[name] IS NULL", - ) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM [users] WHERE [users].[name] IS NULL" + self.assertEqual(query_sql, expected_sql) def test_where_not_null(self): builder = self.get_builder() builder.where_not_null("name") - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] WHERE [users].[name] IS NOT NULL", - ) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM [users] WHERE [users].[name] IS NOT NULL" + self.assertEqual(query_sql, expected_sql) def test_having(self): builder = self.get_builder(table="payments") @@ -321,19 +326,17 @@ def test_having(self): "salary", ">=", "1000" ) - self.assertEqual( - builder.to_sql(), - "SELECT [payments].[user_id], AVG([payments].[salary]) AS salary FROM [payments] GROUP BY [payments].[user_id] HAVING [payments].[salary] >= '1000'", - ) + query_sql = builder.to_sql() + expected_sql = "SELECT [payments].[user_id], AVG([payments].[salary]) AS salary FROM [payments] GROUP BY [payments].[user_id] HAVING [payments].[salary] >= '1000'" + self.assertEqual(query_sql, expected_sql) def test_group_by(self): builder = self.get_builder(table="payments") builder.select("user_id").min("salary").group_by("user_id") - self.assertEqual( - builder.to_sql(), - "SELECT [payments].[user_id], MIN([payments].[salary]) AS salary FROM [payments] GROUP BY [payments].[user_id]", - ) + query_sql = builder.to_sql() + expected_sql = "SELECT [payments].[user_id], MIN([payments].[salary]) AS salary FROM [payments] GROUP BY [payments].[user_id]" + self.assertEqual(query_sql, expected_sql) def test_builder_alone(self): self.assertTrue( @@ -359,100 +362,96 @@ def test_builder_alone(self): def test_where_lt(self): builder = self.get_builder() builder.where("age", "<", "20") - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] WHERE [users].[age] < '20'", - ) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM [users] WHERE [users].[age] < '20'" + self.assertEqual(query_sql, expected_sql) def test_where_lte(self): builder = self.get_builder() builder.where("age", "<=", "20") - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] WHERE [users].[age] <= '20'", - ) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM [users] WHERE [users].[age] <= '20'" + self.assertEqual(query_sql, expected_sql) def test_where_gt(self): builder = self.get_builder() builder.where("age", ">", "20") - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] WHERE [users].[age] > '20'", - ) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM [users] WHERE [users].[age] > '20'" + self.assertEqual(query_sql, expected_sql) def test_where_gte(self): builder = self.get_builder() builder.where("age", ">=", "20") - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] WHERE [users].[age] >= '20'", - ) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM [users] WHERE [users].[age] >= '20'" + self.assertEqual(query_sql, expected_sql) def test_where_ne(self): builder = self.get_builder() builder.where("age", "!=", "20") - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] WHERE [users].[age] != '20'", - ) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM [users] WHERE [users].[age] != '20'" + self.assertEqual(query_sql, expected_sql) def test_or_where(self): builder = self.get_builder() builder.where("age", "20").or_where("age", "<", 20) - self.assertEqual( - builder.to_sql(), - "SELECT * FROM [users] WHERE [users].[age] = '20' OR [users].[age] < '20'", - ) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM [users] WHERE [users].[age] = '20' OR [users].[age] < '20'" + self.assertEqual(query_sql, expected_sql) def test_can_call_with_schema(self): builder = self.get_builder() - sql = ( + query_sql = ( builder.table("information_schema.columns") .select("table_name") .where("table_name", "users") .to_sql() ) - self.assertEqual( - sql, - """SELECT [information_schema].[columns].[table_name] FROM [information_schema].[columns] WHERE [information_schema].[columns].[table_name] = 'users'""", - ) + expected_sql = """SELECT [information_schema].[columns].[table_name] FROM [information_schema].[columns] WHERE [information_schema].[columns].[table_name] = 'users'""" + self.assertEqual(query_sql, expected_sql) def test_truncate(self): builder = self.get_builder(dry=True) - sql = builder.truncate() - self.assertEqual(sql, "TRUNCATE TABLE [users]") + query_sql = builder.truncate() + expected_sql = "TRUNCATE TABLE [users]" + self.assertEqual(query_sql, expected_sql) 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]") + query_sql = builder.truncate(foreign_keys=True) + expected_sql = "TRUNCATE TABLE [users]" + self.assertEqual(query_sql, expected_sql) def test_latest(self): builder = self.get_builder() builder.latest("email") - self.assertEqual( - builder.to_sql(), "SELECT * FROM [users] ORDER BY [email] DESC" - ) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM [users] ORDER BY [email] DESC" + self.assertEqual(query_sql, expected_sql) 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", + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM [users] ORDER BY [email] DESC, [created_at] DESC" ) + self.assertEqual(query_sql, expected_sql) def test_oldest(self): builder = self.get_builder() builder.oldest("email") - self.assertEqual( - builder.to_sql(), "SELECT * FROM [users] ORDER BY [email] ASC" - ) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM [users] ORDER BY [email] ASC" + self.assertEqual(query_sql, expected_sql) 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", + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM [users] ORDER BY [email] ASC, [created_at] ASC" ) + self.assertEqual(query_sql, expected_sql) diff --git a/tests/mssql/builder/test_mssql_query_builder_relationships.py b/tests/mssql/builder/test_mssql_query_builder_relationships.py index ff070d407..cee68fc67 100644 --- a/tests/mssql/builder/test_mssql_query_builder_relationships.py +++ b/tests/mssql/builder/test_mssql_query_builder_relationships.py @@ -62,9 +62,9 @@ def get_builder(self, table="users"): def test_has(self): builder = self.get_builder() - sql = builder.has("articles").to_sql() + query_sql = builder.has("articles").to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM [users] WHERE EXISTS (""" """SELECT * FROM [articles] WHERE [articles].[user_id] = [users].[id]""" """)""", @@ -72,9 +72,9 @@ def test_has(self): def test_has_reference_to_self(self): builder = self.get_builder() - sql = builder.has("parent_dynamic").to_sql() + query_sql = builder.has("parent_dynamic").to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM [users] WHERE EXISTS (""" """SELECT * FROM [users] WHERE [users].[parent_dynamic_id] = [users].[id]""" """)""", @@ -82,9 +82,9 @@ def test_has_reference_to_self(self): def test_has_reference_to_self_using_class(self): builder = self.get_builder() - sql = builder.has("parent_specified").to_sql() + query_sql = builder.has("parent_specified").to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM [users] WHERE EXISTS (""" """SELECT * FROM [users] WHERE [users].[parent_specified_id] = [users].[id]""" """)""", @@ -92,20 +92,20 @@ def test_has_reference_to_self_using_class(self): def test_where_has_query(self): builder = self.get_builder() - sql = builder.where_has( + query_sql = builder.where_has( "articles", lambda q: q.where("active", 1) ).to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM [users] WHERE EXISTS (""" """SELECT * FROM [articles] WHERE [articles].[user_id] = [users].[id] AND [articles].[active] = '1'""" """)""", ) def test_relationship_multiple_has(self): - to_sql = User.has("articles", "profile").to_sql() + query_sql = User.has("articles", "profile").to_sql() self.assertEqual( - to_sql, + query_sql, """SELECT * FROM [users] WHERE EXISTS (""" """SELECT * FROM [articles] WHERE [articles].[user_id] = [users].[id]""" """) AND EXISTS (""" @@ -114,9 +114,9 @@ def test_relationship_multiple_has(self): ) def test_relationship_multiple_has_calls(self): - to_sql = User.has("articles").has("profile").to_sql() + query_sql = User.has("articles").has("profile").to_sql() self.assertEqual( - to_sql, + query_sql, """SELECT * FROM [users] WHERE EXISTS (""" """SELECT * FROM [articles] WHERE [articles].[user_id] = [users].[id]""" """) AND EXISTS (""" @@ -125,8 +125,8 @@ def test_relationship_multiple_has_calls(self): ) def test_nested_has(self): - to_sql = User.has("articles.logo").to_sql() + query_sql = User.has("articles.logo").to_sql() self.assertEqual( - to_sql, + query_sql, """SELECT * FROM [users] WHERE EXISTS (SELECT * FROM [articles] WHERE [articles].[user_id] = [users].[id] AND EXISTS (SELECT * FROM [logos] WHERE [logos].[article_id] = [articles].[id]))""", ) diff --git a/tests/mssql/grammar/test_mssql_delete_grammar.py b/tests/mssql/grammar/test_mssql_delete_grammar.py index 1e5007a07..2a2939604 100644 --- a/tests/mssql/grammar/test_mssql_delete_grammar.py +++ b/tests/mssql/grammar/test_mssql_delete_grammar.py @@ -4,26 +4,22 @@ from src.masoniteorm.query.grammars import MSSQLGrammar -class TestMySQLDeleteGrammar(unittest.TestCase): +class TestMSSQLDeleteGrammar(unittest.TestCase): def setUp(self): self.builder = QueryBuilder(MSSQLGrammar, table="users") def test_can_compile_delete(self): - to_sql = self.builder.delete("id", 1, query=True).to_sql() - - sql = "DELETE FROM [users] WHERE [users].[id] = '1'" - self.assertEqual(to_sql, sql) + query_sql = self.builder.delete("id", 1, query=True).to_sql() + expected_sql = "DELETE FROM [users] WHERE [users].[id] = '1'" + self.assertEqual(query_sql, expected_sql) def test_can_compile_delete_with_where(self): - to_sql = ( + query_sql = ( self.builder.where("age", 20) .where("profile", 1) .set_action("delete") .delete(query=True) .to_sql() ) - - sql = ( - "DELETE FROM [users] WHERE [users].[age] = '20' AND [users].[profile] = '1'" - ) - self.assertEqual(to_sql, sql) + expected_sql = "DELETE FROM [users] WHERE [users].[age] = '20' AND [users].[profile] = '1'" + self.assertEqual(query_sql, expected_sql) diff --git a/tests/mssql/grammar/test_mssql_insert_grammar.py b/tests/mssql/grammar/test_mssql_insert_grammar.py index 8980db786..94926b326 100644 --- a/tests/mssql/grammar/test_mssql_insert_grammar.py +++ b/tests/mssql/grammar/test_mssql_insert_grammar.py @@ -4,19 +4,18 @@ from src.masoniteorm.query.grammars import MSSQLGrammar -class TestMySQLInsertGrammar(unittest.TestCase): +class TestMSSQLInsertGrammar(unittest.TestCase): def setUp(self): self.builder = QueryBuilder(MSSQLGrammar, table="users") def test_can_compile_insert(self): - to_sql = self.builder.create({"name": "Joe"}, query=True).to_sql() - - sql = "INSERT INTO [users] ([users].[name]) VALUES ('Joe')" - self.assertEqual(to_sql, sql) + query_sql = self.builder.create({"name": "Joe"}, query=True).to_sql() + expected_sql = "INSERT INTO [users] ([users].[name]) VALUES ('Joe')" + self.assertEqual(query_sql, expected_sql) def test_can_compile_bulk_create(self): - to_sql = self.builder.bulk_create( - # These keys are intentionally out of order to show column to value alignment works + # Keys are intentionally out of order to verify column-to-value alignment + query_sql = self.builder.bulk_create( [ {"name": "Joe", "age": 5}, {"age": 35, "name": "Bill"}, @@ -24,14 +23,12 @@ def test_can_compile_bulk_create(self): ], query=True, ).to_sql() - - sql = "INSERT INTO [users] ([age], [name]) VALUES ('5', 'Joe'), ('35', 'Bill'), ('10', 'John')" - self.assertEqual(to_sql, sql) + expected_sql = "INSERT INTO [users] ([age], [name]) VALUES ('5', 'Joe'), ('35', 'Bill'), ('10', 'John')" + self.assertEqual(query_sql, expected_sql) def test_can_compile_bulk_create_qmark(self): - to_sql = self.builder.bulk_create( + query_sql = self.builder.bulk_create( [{"name": "Joe"}, {"name": "Bill"}, {"name": "John"}], query=True ).to_qmark() - - sql = "INSERT INTO [users] ([name]) VALUES (?), (?), (?)" - self.assertEqual(to_sql, sql) + expected_sql = "INSERT INTO [users] ([name]) VALUES (?), (?), (?)" + self.assertEqual(query_sql, expected_sql) diff --git a/tests/mssql/grammar/test_mssql_qmark.py b/tests/mssql/grammar/test_mssql_qmark.py index c28a8b11d..4740fdedd 100644 --- a/tests/mssql/grammar/test_mssql_qmark.py +++ b/tests/mssql/grammar/test_mssql_qmark.py @@ -10,33 +10,47 @@ def setUp(self): def test_can_compile_select(self): mark = self.builder.select("username").where("name", "Joe") - - sql = "SELECT [users].[username] FROM [users] WHERE [users].[name] = ?" - self.assertEqual(mark.to_qmark(), sql) + query_sql = mark.to_qmark() + expected_sql = ( + "SELECT [users].[username] FROM [users] WHERE [users].[name] = ?" + ) + self.assertEqual(query_sql, expected_sql) self.assertEqual(mark._bindings, ["Joe"]) def test_can_compile_update(self): - mark = self.builder.update({"name": "Bob"}, dry=True).where("name", "Joe") - - sql = "UPDATE [users] SET [users].[name] = ? WHERE [users].[name] = ?" - self.assertEqual(mark.to_qmark(), sql) + mark = self.builder.update({"name": "Bob"}, dry=True).where( + "name", "Joe" + ) + query_sql = mark.to_qmark() + expected_sql = ( + "UPDATE [users] SET [users].[name] = ? WHERE [users].[name] = ?" + ) + self.assertEqual(query_sql, expected_sql) self.assertEqual(mark._bindings, ["Bob", "Joe"]) def test_can_compile_insert(self): mark = self.builder.create({"name": "Bob"}, query=True) - - sql = "INSERT INTO [users] ([users].[name]) VALUES (?)" - self.assertEqual(mark.to_qmark(), sql) + query_sql = mark.to_qmark() + expected_sql = "INSERT INTO [users] ([users].[name]) VALUES (?)" + self.assertEqual(query_sql, expected_sql) self.assertEqual(mark._bindings, ["Bob"]) def test_can_compile_where_in(self): mark = self.builder.where_in("id", [1, 2, 3]) - - qmark_sql = "SELECT * FROM [users] WHERE [users].[id] IN (?, ?, ?)" - sql = "SELECT * FROM [users] WHERE [users].[id] IN ('1','2','3')" - self.assertEqual(mark.to_qmark(), qmark_sql) + query_sql = mark.to_qmark() + expected_sql = "SELECT * FROM [users] WHERE [users].[id] IN (?, ?, ?)" + self.assertEqual(query_sql, expected_sql) self.assertEqual(mark._bindings, [1, 2, 3]) - self.assertEqual(self.builder.where_in("id", [1, 2, 3]).to_sql(), sql) + # to_sql uses quoted values, not placeholders + query_sql = self.builder.where_in("id", [1, 2, 3]).to_sql() + expected_sql = ( + "SELECT * FROM [users] WHERE [users].[id] IN ('1','2','3')" + ) + self.assertEqual(query_sql, expected_sql) self.builder.reset() - # Assert that when passed string values it generates synonymous sql - self.assertEqual(self.builder.where_in("id", ["1", "2", "3"]).to_sql(), sql) + # String values should produce the same quoted SQL + query_sql = self.builder.where_in("id", ["1", "2", "3"]).to_sql() + expected_sql = ( + "SELECT * FROM [users] WHERE [users].[id] IN ('1','2','3')" + ) + self.assertEqual(query_sql, expected_sql) diff --git a/tests/mssql/grammar/test_mssql_select_grammar.py b/tests/mssql/grammar/test_mssql_select_grammar.py index a0595df8f..0beda8cfb 100644 --- a/tests/mssql/grammar/test_mssql_select_grammar.py +++ b/tests/mssql/grammar/test_mssql_select_grammar.py @@ -1,502 +1,617 @@ -import inspect import unittest +from src.masoniteorm.expressions import JoinClause +from src.masoniteorm.models import Model +from src.masoniteorm.query import QueryBuilder from src.masoniteorm.query.grammars import MSSQLGrammar -from src.masoniteorm.testing import BaseTestCaseSelectGrammar - - -class TestMSSQLGrammar(BaseTestCaseSelectGrammar, unittest.TestCase): - grammar = MSSQLGrammar - - def can_compile_select(self): - """ - self.builder.to_sql() - """ - return "SELECT * FROM [users]" - - def can_compile_with_columns(self): - """ - self.builder.select('username', 'password').to_sql() - """ - return "SELECT [users].[username], [users].[password] FROM [users]" - - def can_compile_with_where(self): - """ - self.builder.select('username', 'password').where('id', 1).to_sql() - """ - return "SELECT [users].[username], [users].[password] FROM [users] WHERE [users].[id] = '1'" - - def can_compile_with_several_where(self): - """ - self.builder.select('username', 'password').where('id', 1).where('username', 'joe').to_sql() - """ - return "SELECT [users].[username], [users].[password] FROM [users] WHERE [users].[id] = '1' AND [users].[username] = 'joe'" - - def can_compile_with_several_where_and_limit(self): - """ - self.builder.select('username', 'password').where('id', 1).where('username', 'joe').limit(10).to_sql() - """ - return "SELECT TOP 10 [users].[username], [users].[password] FROM [users] WHERE [users].[id] = '1' AND [users].[username] = 'joe'" - - def can_compile_with_sum(self): - """ - self.builder.sum('age').to_sql() - """ - return "SELECT SUM([users].[age]) AS age FROM [users]" - - def can_compile_order_by_and_first(self): - """ - self.builder.order_by('id', 'asc').first() - """ - return """SELECT TOP 1 * FROM [users] ORDER BY [id] ASC""" - - def can_compile_with_max(self): - """ - self.builder.max('age').to_sql() - """ - return "SELECT MAX([users].[age]) AS age FROM [users]" - - def can_compile_with_max_and_columns(self): - """ - self.builder.select('username').max('age').to_sql() - """ - return "SELECT [users].[username], MAX([users].[age]) AS age FROM [users]" - - def can_compile_with_max_and_columns_different_order(self): - """ - self.builder.max('age').select('username').to_sql() - """ - return "SELECT [users].[username], MAX([users].[age]) AS age FROM [users]" - - def can_compile_with_order_by(self): - """ - self.builder.select('username').order_by('age', 'desc').to_sql() - """ - return "SELECT [users].[username] FROM [users] ORDER BY [age] DESC" - - def can_compile_with_multiple_order_by(self): - """ - self.builder.select('username').order_by('age', 'desc').order_by('name').to_sql() - """ - return "SELECT [users].[username] FROM [users] ORDER BY [age] DESC, [name] ASC" - - def can_compile_with_group_by(self): - """ - self.builder.select('username').group_by('age').to_sql() - """ - return "SELECT [users].[username] FROM [users] GROUP BY [users].[age]" - - def can_compile_where_in(self): - """ - self.builder.select('username').where_in('age', [1,2,3]).to_sql() - """ - return "SELECT [users].[username] FROM [users] WHERE [users].[age] IN ('1','2','3')" - - def can_compile_where_in_empty(self): - """ - self.builder.where_in('age', []).to_sql() - """ - return """SELECT * FROM [users] WHERE 0 = 1""" - - def can_compile_where_null(self): - """ - self.builder.select('username').where_null('age').to_sql() - """ - return "SELECT [users].[username] FROM [users] WHERE [users].[age] IS NULL" - - def can_compile_where_not_null(self): - """ - self.builder.select('username').where_not_null('age').to_sql() - """ - return "SELECT [users].[username] FROM [users] WHERE [users].[age] IS NOT NULL" - - def can_compile_where_raw(self): - """ - self.builder.where_raw("`age` = '18'").to_sql() - """ - return "SELECT * FROM [users] WHERE [users].[age] = '18'" + + +class MockConnection: + connection_details = {} + + def make_connection(self): + return self + + +class TestMSSQLSelectGrammar(unittest.TestCase): + """Tests for SQL SELECT compilation with the MSSQL grammar. + + Each test is self-contained: it builds a query and asserts the expected + SQL string inline, with no separate data-provider class. + """ + + maxDiff = None + + def setUp(self): + self.builder = QueryBuilder( + MSSQLGrammar, + table="users", + connection_class=MockConnection, + model=Model(), + dry=True, + ) + + # ------------------------------------------------------------------ + # Basic SELECT + # ------------------------------------------------------------------ + + def test_can_compile_select(self): + query_sql = self.builder.to_sql() + expected_sql = "SELECT * FROM [users]" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_columns(self): + query_sql = self.builder.select("username", "password").to_sql() + expected_sql = ( + "SELECT [users].[username], [users].[password] FROM [users]" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_select_raw(self): + query_sql = self.builder.select_raw("COUNT(*)").to_sql() + expected_sql = "SELECT COUNT(*) FROM [users]" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_select_raw_with_select(self): + query_sql = self.builder.select("id").select_raw("COUNT(*)").to_sql() + expected_sql = "SELECT [users].[id], COUNT(*) FROM [users]" + self.assertEqual(query_sql, expected_sql) + + def test_select_distinct(self): + query_sql = self.builder.select("group").distinct().to_sql() + expected_sql = "SELECT DISTINCT [users].[group] FROM [users]" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_count(self): + query_sql = self.builder.count("*").to_sql() + expected_sql = "SELECT COUNT(*) AS m_count_reserved FROM [users]" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_count_column(self): + query_sql = self.builder.count("money").to_sql() + expected_sql = "SELECT COUNT([users].[money]) AS money FROM [users]" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_sum(self): + query_sql = self.builder.sum("age").to_sql() + expected_sql = "SELECT SUM([users].[age]) AS age FROM [users]" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_max(self): + query_sql = self.builder.max("age").to_sql() + expected_sql = "SELECT MAX([users].[age]) AS age FROM [users]" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_max_and_columns(self): + query_sql = self.builder.select("username").max("age").to_sql() + expected_sql = ( + "SELECT [users].[username], MAX([users].[age]) AS age FROM [users]" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_max_and_columns_different_order(self): + query_sql = self.builder.max("age").select("username").to_sql() + expected_sql = ( + "SELECT [users].[username], MAX([users].[age]) AS age FROM [users]" + ) + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # ORDER BY / GROUP BY / LIMIT / OFFSET + # ------------------------------------------------------------------ + + def test_can_compile_order_by_and_first(self): + query_sql = ( + self.builder.order_by("id", "asc").first(query=True).to_sql() + ) + expected_sql = "SELECT TOP 1 * FROM [users] ORDER BY [id] ASC" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_order_by(self): + query_sql = ( + self.builder.select("username").order_by("age", "desc").to_sql() + ) + expected_sql = ( + "SELECT [users].[username] FROM [users] ORDER BY [age] DESC" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_multiple_order_by(self): + query_sql = ( + self.builder.select("username") + .order_by("age", "desc") + .order_by("name") + .to_sql() + ) + expected_sql = "SELECT [users].[username] FROM [users] ORDER BY [age] DESC, [name] ASC" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_group_by(self): + query_sql = self.builder.select("username").group_by("age").to_sql() + expected_sql = ( + "SELECT [users].[username] FROM [users] GROUP BY [users].[age]" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_limit_and_offset(self): + query_sql = self.builder.limit(10).offset(10).to_sql() + expected_sql = ( + "SELECT * FROM [users] OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY" + ) + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # WHERE clauses + # ------------------------------------------------------------------ + + def test_can_compile_with_where(self): + query_sql = ( + self.builder.select("username", "password").where("id", 1).to_sql() + ) + expected_sql = "SELECT [users].[username], [users].[password] FROM [users] WHERE [users].[id] = '1'" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_several_where(self): + query_sql = ( + self.builder.select("username", "password") + .where("id", 1) + .where("username", "joe") + .to_sql() + ) + expected_sql = ( + "SELECT [users].[username], [users].[password] FROM [users]" + " WHERE [users].[id] = '1' AND [users].[username] = 'joe'" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_several_where_and_limit(self): + query_sql = ( + self.builder.select("username", "password") + .where("id", 1) + .where("username", "joe") + .limit(10) + .to_sql() + ) + expected_sql = ( + "SELECT TOP 10 [users].[username], [users].[password] FROM [users]" + " WHERE [users].[id] = '1' AND [users].[username] = 'joe'" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_or_where(self): + query_sql = self.builder.where("name", 2).or_where("name", 3).to_sql() + expected_sql = "SELECT * FROM [users] WHERE [users].[name] = '2' OR [users].[name] = '3'" + self.assertEqual(query_sql, expected_sql) + + def test_can_grouped_where(self): + query_sql = self.builder.where( + lambda q: q.where("age", 2).where("name", "Joe") + ).to_sql() + expected_sql = "SELECT * FROM [users] WHERE ([users].[age] = '2' AND [users].[name] = 'Joe')" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_in(self): + query_sql = ( + self.builder.select("username").where_in("age", [1, 2, 3]).to_sql() + ) + expected_sql = "SELECT [users].[username] FROM [users] WHERE [users].[age] IN ('1','2','3')" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_in_empty(self): + query_sql = self.builder.where_in("age", []).to_sql() + expected_sql = "SELECT * FROM [users] WHERE 0 = 1" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_not_in(self): + query_sql = ( + self.builder.select("username") + .where_not_in("age", [1, 2, 3]) + .to_sql() + ) + expected_sql = "SELECT [users].[username] FROM [users] WHERE [users].[age] NOT IN ('1','2','3')" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_null(self): + query_sql = self.builder.select("username").where_null("age").to_sql() + expected_sql = "SELECT [users].[username] FROM [users] WHERE [users].[age] IS NULL" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_not_null(self): + query_sql = ( + self.builder.select("username").where_not_null("age").to_sql() + ) + expected_sql = "SELECT [users].[username] FROM [users] WHERE [users].[age] IS NOT NULL" + self.assertEqual(query_sql, expected_sql) + + def test_or_where_null(self): + query_sql = ( + self.builder.where_null("column1") + .or_where_null("column2") + .to_sql() + ) + expected_sql = "SELECT * FROM [users] WHERE [users].[column1] IS NULL OR [users].[column2] IS NULL" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_column(self): + query_sql = self.builder.where_column("name", "email").to_sql() + expected_sql = ( + "SELECT * FROM [users] WHERE [users].[name] = [users].[email]" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_raw(self): + query_sql = self.builder.where_raw("[age] = '18'").to_sql() + expected_sql = "SELECT * FROM [users] WHERE [age] = '18'" + self.assertEqual(query_sql, expected_sql) def test_can_compile_where_raw_and_where_with_multiple_bindings(self): query = self.builder.where_raw( "[age] = ? AND [is_admin] = ?", [18, True] ).where("email", "test@example.com") - self.assertEqual( - query.to_qmark(), - "SELECT * FROM [users] WHERE [age] = ? AND [is_admin] = ? AND [users].[email] = ?", - ) + query_sql = query.to_qmark() + expected_sql = "SELECT * FROM [users] WHERE [age] = ? AND [is_admin] = ? AND [users].[email] = ?" + self.assertEqual(query_sql, expected_sql) self.assertEqual(query._bindings, [18, True, "test@example.com"]) - def can_compile_select_raw(self): - """ - self.builder.select_raw("COUNT(*)").to_sql() - """ - return "SELECT COUNT(*) FROM [users]" - - def can_compile_limit_and_offset(self): - """ - self.builder.limit(10).offset(10).to_sql() - """ - return "SELECT * FROM [users] OFFSET 10 ROWS FETCH NEXT 10 ROWS ONLY" - - def can_compile_select_raw_with_select(self): - """ - self.builder.select('id').select_raw("COUNT(*)").to_sql() - """ - return "SELECT [users].[id], COUNT(*) FROM [users]" - - def can_compile_having_raw(self): - """ - self.builder.select_raw("COUNT(*) as counts").having_raw("counts > 18").to_sql() - """ - return "SELECT COUNT(*) as counts FROM [users] HAVING counts > 18" - - def can_compile_count(self): - """ - self.builder.count().to_sql() - """ - - return "SELECT COUNT(*) AS m_count_reserved FROM [users]" - - def can_compile_count_column(self): - """ - self.builder.count().to_sql() - """ - - return "SELECT COUNT([users].[money]) AS money FROM [users]" - - def can_compile_where_column(self): - """ - self.builder.where_column('name', 'email').to_sql() - """ - - return "SELECT * FROM [users] WHERE [users].[name] = [users].[email]" - - def can_compile_or_where(self): - """ - self.builder.where('name', 2).or_where('name', 3).to_sql() - """ - return ( - "SELECT * FROM [users] WHERE [users].[name] = '2' OR [users].[name] = '3'" - ) - - def can_grouped_where(self): - """ - self.builder.where(lambda query: query.where('age', 2).where('name', 'Joe')).to_sql() - """ - return "SELECT * FROM [users] WHERE ([users].[age] = '2' AND [users].[name] = 'Joe')" - - def can_compile_sub_select(self): - """ - self.builder.where_in('name', - QueryBuilder(GrammarFactory.make(self.grammar), table='users').select('age') - ).to_sql() - """ + def test_can_user_where_raw_and_where(self): + query_sql = ( + self.builder.where_raw("age = '18'") + .where("name", "=", "James") + .to_sql() + ) + expected_sql = "SELECT * FROM [users] WHERE age = '18' AND [users].[name] = 'James'" + self.assertEqual(query_sql, expected_sql) - return "SELECT * FROM [users] WHERE [users].[name] IN (SELECT [users].[age] FROM [users])" + def test_where_like(self): + query_sql = self.builder.where("age", "like", "%name%").to_sql() + expected_sql = ( + "SELECT * FROM [users] WHERE [users].[age] LIKE '%name%'" + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_sub_select_where(self): - """ - self.builder.where_in('age', - QueryBuilder(GrammarFactory.make(self.grammar), table='users').select('age').where('age', 2).where('name', 'Joe') - ).to_sql() - """ + def test_where_not_like(self): + query_sql = self.builder.where("age", "not like", "%name%").to_sql() + expected_sql = ( + "SELECT * FROM [users] WHERE [users].[age] NOT LIKE '%name%'" + ) + self.assertEqual(query_sql, expected_sql) - return "SELECT * FROM [users] WHERE [users].[age] IN (SELECT [users].[age] FROM [users] WHERE [users].[age] = '2' AND [users].[name] = 'Joe')" + def test_where_regexp(self): + query_sql = self.builder.where("age", "regexp", "Joe").to_sql() + expected_sql = "SELECT * FROM [users] WHERE [users].[age] LIKE 'Joe'" + self.assertEqual(query_sql, expected_sql) - def can_compile_sub_select_value(self): - """ - self.builder.where('name', - self.builder.new().sum('age') - ).to_sql() - """ - - return "SELECT * FROM [users] WHERE [users].[name] = (SELECT SUM([users].[age]) AS age FROM [users])" + def test_where_not_regexp(self): + query_sql = self.builder.where("age", "not regexp", "Joe").to_sql() + expected_sql = ( + "SELECT * FROM [users] WHERE [users].[age] NOT LIKE 'Joe'" + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_complex_sub_select(self): - """ - self.builder.where_in('name', - (QueryBuilder(GrammarFactory.make(self.grammar), table='users') - .select('age').where_in('email', - QueryBuilder(GrammarFactory.make(self.grammar), table='users').select('email') - )) + def test_where_date(self): + query_sql = self.builder.where_date( + "created_at", "2022-06-01" ).to_sql() - """ - return "SELECT * FROM [users] WHERE [users].[name] IN (SELECT [users].[age] FROM [users] WHERE [users].[email] IN (SELECT [users].[email] FROM [users]))" + expected_sql = "SELECT * FROM [users] WHERE DATE([users].[created_at]) = '2022-06-01'" + self.assertEqual(query_sql, expected_sql) - def can_compile_exists(self): - """ - self.builder.select('age').where_exists( - self.builder.new().select('username').where('age', 12) + def test_where_exists_with_lambda(self): + query_sql = self.builder.where_exists( + lambda q: q.where("age", 1) ).to_sql() - """ - return "SELECT [users].[age] FROM [users] WHERE EXISTS (SELECT [users].[username] FROM [users] WHERE [users].[age] = '12')" + expected_sql = "SELECT * FROM [users] WHERE EXISTS (SELECT * FROM [users] WHERE [users].[age] = '1')" + self.assertEqual(query_sql, expected_sql) - def can_compile_not_exists(self): - """ - self.builder.select('age').where_not_exists( - self.builder.new().select('username').where('age', 12) + def test_where_not_exists_with_lambda(self): + query_sql = self.builder.where_not_exists( + lambda q: q.where("age", 1) ).to_sql() - """ - return "SELECT [users].[age] FROM [users] WHERE NOT EXISTS (SELECT [users].[username] FROM [users] WHERE [users].[age] = '12')" - - def can_compile_having(self): - """ - builder.sum('age').group_by('age').having('age').to_sql() - """ - return "SELECT SUM([users].[age]) AS age FROM [users] GROUP BY [users].[age] HAVING [users].[age]" - - def can_compile_having_order(self): - """ - builder.sum('age').group_by('age').having('age').order_by('age', 'desc').to_sql() - """ - return "SELECT SUM([users].[age]) AS age FROM [users] GROUP BY [users].[age] HAVING [users].[age] ORDER [users].[age] DESC" - - def can_compile_between(self): - """ - builder.between('age', 18, 21).to_sql() - """ - return "SELECT * FROM [users] WHERE [users].[age] BETWEEN '18' AND '21'" - - def can_compile_not_between(self): - """ - builder.not_between('age', 18, 21).to_sql() - """ - return "SELECT * FROM [users] WHERE [users].[age] NOT BETWEEN '18' AND '21'" - - def can_compile_where_not_in(self): - """ - self.builder.select('username').where_not_in('age', [1,2,3]).to_sql() - """ - return "SELECT [users].[username] FROM [users] WHERE [users].[age] NOT IN ('1','2','3')" - - def can_compile_having_with_expression(self): - """ - builder.sum('age').group_by('age').having('age', 10).to_sql() - """ - return "SELECT SUM([users].[age]) AS age FROM [users] GROUP BY [users].[age] HAVING [users].[age] = '10'" - - def can_compile_having_with_greater_than_expression(self): - """ - builder.sum('age').group_by('age').having('age', '>', 10).to_sql() - """ - return "SELECT SUM([users].[age]) AS age FROM [users] GROUP BY [users].[age] HAVING [users].[age] > '10'" - - def can_compile_join(self): - """ - builder.join('contacts', 'users.id', '=', 'contacts.user_id').to_sql() - """ - return "SELECT * FROM [users] INNER JOIN [contacts] ON [users].[id] = [contacts].[user_id]" - - def can_compile_left_join(self): - """ - builder.join('contacts', 'users.id', '=', 'contacts.user_id').to_sql() - """ - return "SELECT * FROM [users] LEFT JOIN [contacts] ON [users].[id] = [contacts].[user_id]" - - def can_compile_multiple_join(self): - """ - builder.join('contacts', 'users.id', '=', 'contacts.user_id').to_sql() - """ - return "SELECT * FROM [users] INNER JOIN [contacts] ON [users].[id] = [contacts].[user_id] INNER JOIN [posts] ON [comments].[post_id] = [posts].[id]" + expected_sql = "SELECT * FROM [users] WHERE NOT EXISTS (SELECT * FROM [users] WHERE [users].[age] = '1')" + self.assertEqual(query_sql, expected_sql) - def test_can_compile_where_raw(self): - to_sql = self.builder.where_raw("[age] = '18'").to_sql() - self.assertEqual(to_sql, "SELECT * FROM [users] WHERE [age] = '18'") + def test_can_compile_between(self): + query_sql = self.builder.between("age", 18, 21).to_sql() + expected_sql = ( + "SELECT * FROM [users] WHERE [users].[age] BETWEEN '18' AND '21'" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_not_between(self): + query_sql = self.builder.not_between("age", 18, 21).to_sql() + expected_sql = "SELECT * FROM [users] WHERE [users].[age] NOT BETWEEN '18' AND '21'" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_first_or_fail(self): + query_sql = ( + self.builder.where("is_admin", "=", True) + .first_or_fail(query=True) + .to_sql() + ) + expected_sql = ( + "SELECT TOP 1 * FROM [users] WHERE [users].[is_admin] = '1'" + ) + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # HAVING + # ------------------------------------------------------------------ + + def test_can_compile_having(self): + query_sql = ( + self.builder.sum("age").group_by("age").having("age").to_sql() + ) + expected_sql = "SELECT SUM([users].[age]) AS age FROM [users] GROUP BY [users].[age] HAVING [users].[age]" + self.assertEqual(query_sql, expected_sql) def test_can_compile_having_raw(self): - to_sql = ( + query_sql = ( self.builder.select_raw("COUNT(*) as counts") - .having_raw("counts > 10") + .having_raw("counts > 18") .to_sql() ) - self.assertEqual( - to_sql, "SELECT COUNT(*) as counts FROM [users] HAVING counts > 10" + expected_sql = ( + "SELECT COUNT(*) as counts FROM [users] HAVING counts > 18" ) + self.assertEqual(query_sql, expected_sql) - def test_can_compile_having_raw_order(self): - to_sql = ( + def test_can_compile_having_raw_with_order(self): + query_sql = ( self.builder.select_raw("COUNT(*) as counts") .having_raw("counts > 10") .order_by_raw("counts DESC") .to_sql() ) - self.assertEqual( - to_sql, - "SELECT COUNT(*) as counts FROM [users] HAVING counts > 10 ORDER BY counts DESC", + expected_sql = "SELECT COUNT(*) as counts FROM [users] HAVING counts > 10 ORDER BY counts DESC" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_having_with_expression(self): + query_sql = ( + self.builder.sum("age").group_by("age").having("age", 10).to_sql() + ) + expected_sql = "SELECT SUM([users].[age]) AS age FROM [users] GROUP BY [users].[age] HAVING [users].[age] = '10'" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_having_with_greater_than_expression(self): + query_sql = ( + self.builder.sum("age") + .group_by("age") + .having("age", ">", 10) + .to_sql() ) + expected_sql = "SELECT SUM([users].[age]) AS age FROM [users] GROUP BY [users].[age] HAVING [users].[age] > '10'" + self.assertEqual(query_sql, expected_sql) - def test_can_compile_select_raw(self): - to_sql = self.builder.select_raw("COUNT(*)").to_sql() - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + # ------------------------------------------------------------------ + # Locking (MSSQL uses ROWLOCK hints) + # ------------------------------------------------------------------ - def test_can_compile_select_raw_with_select(self): - to_sql = self.builder.select("id").select_raw("COUNT(*)").to_sql() - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) - - def can_compile_first_or_fail(self): - """ - builder = self.get_builder() - 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%'""" - - def where_regexp(self): - """ - builder = self.get_builder() - builder.where("age", "regexp", "Joe") - """ - return """SELECT * FROM [users] WHERE [users].[age] LIKE 'Joe'""" - - def where_not_regexp(self): - """ - builder = self.get_builder() - builder.where("age", "not regexp", "Joe") - """ - return """SELECT * FROM [users] WHERE [users].[age] NOT LIKE 'Joe'""" - - def can_compile_join_clause(self): - """ - builder = self.get_builder() + def test_shared_lock(self): + query_sql = ( + self.builder.where("votes", ">=", 100).shared_lock().to_sql() + ) + expected_sql = "SELECT * FROM [users] WITH(ROWLOCK) WHERE [users].[votes] >= '100'" + self.assertEqual(query_sql, expected_sql) + + def test_update_lock(self): + query_sql = ( + self.builder.where("votes", ">=", 100).lock_for_update().to_sql() + ) + expected_sql = "SELECT * FROM [users] WITH(ROWLOCK) WHERE [users].[votes] >= '100'" + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # Sub-selects + # ------------------------------------------------------------------ + + def test_can_compile_sub_select(self): + query_sql = self.builder.where_in( + "name", self.builder.new().select("age") + ).to_sql() + expected_sql = "SELECT * FROM [users] WHERE [users].[name] IN (SELECT [users].[age] FROM [users])" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_sub_select_where(self): + query_sql = self.builder.where_in( + "age", + self.builder.new() + .select("age") + .where("age", 2) + .where("name", "Joe"), + ).to_sql() + expected_sql = ( + "SELECT * FROM [users] WHERE [users].[age] IN" + " (SELECT [users].[age] FROM [users] WHERE [users].[age] = '2' AND [users].[name] = 'Joe')" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_sub_select_from_lambda(self): + expected = ( + "SELECT * FROM [users] WHERE [users].[age] IN" + " (SELECT [users].[age] FROM [users] WHERE [users].[age] = '2' AND [users].[name] = 'Joe')" + ) + query_sql = ( + self.builder.new() + .where_in( + "age", + lambda q: q.select("age").where("age", 2).where("name", "Joe"), + ) + .to_sql() + ) + expected_sql = expected + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_sub_select_value(self): + query_sql = self.builder.where( + "name", self.builder.new().sum("age") + ).to_sql() + expected_sql = "SELECT * FROM [users] WHERE [users].[name] = (SELECT SUM([users].[age]) AS age FROM [users])" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_complex_sub_select(self): + query_sql = self.builder.where_in( + "name", + self.builder.new() + .select("age") + .where_in("email", self.builder.new().select("email")), + ).to_sql() + expected_sql = ( + "SELECT * FROM [users] WHERE [users].[name] IN" + " (SELECT [users].[age] FROM [users] WHERE [users].[email] IN" + " (SELECT [users].[email] FROM [users]))" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_exists(self): + query_sql = ( + self.builder.select("age") + .where_exists( + self.builder.new().select("username").where("age", 12) + ) + .to_sql() + ) + expected_sql = ( + "SELECT [users].[age] FROM [users]" + " WHERE EXISTS (SELECT [users].[username] FROM [users] WHERE [users].[age] = '12')" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_not_exists(self): + query_sql = ( + self.builder.select("age") + .where_not_exists( + self.builder.new().select("username").where("age", 12) + ) + .to_sql() + ) + expected_sql = ( + "SELECT [users].[age] FROM [users]" + " WHERE NOT EXISTS (SELECT [users].[username] FROM [users] WHERE [users].[age] = '12')" + ) + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # JOINs + # ------------------------------------------------------------------ + + def test_can_compile_join(self): + query_sql = self.builder.join( + "contacts", "users.id", "=", "contacts.user_id" + ).to_sql() + expected_sql = "SELECT * FROM [users] INNER JOIN [contacts] ON [users].[id] = [contacts].[user_id]" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_left_join(self): + query_sql = self.builder.left_join( + "contacts", "users.id", "=", "contacts.user_id" + ).to_sql() + expected_sql = "SELECT * FROM [users] LEFT JOIN [contacts] ON [users].[id] = [contacts].[user_id]" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_multiple_join(self): + query_sql = ( + self.builder.join("contacts", "users.id", "=", "contacts.user_id") + .join("posts", "comments.post_id", "=", "posts.id") + .to_sql() + ) + expected_sql = ( + "SELECT * FROM [users]" + " INNER JOIN [contacts] ON [users].[id] = [contacts].[user_id]" + " INNER JOIN [posts] ON [comments].[post_id] = [posts].[id]" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_join_clause(self): clause = ( JoinClause("report_groups as rg") .on("bgt.fund", "=", "rg.fund") - .on_value("bgt.active", "=", "1") - .or_on_value("bgt.acct", "=", "1234") + .on("bgt.dept", "=", "rg.dept") + .on("bgt.acct", "=", "rg.acct") + .on("bgt.sub", "=", "rg.sub") ) - builder.join(clause).to_sql() - """ - return "SELECT * FROM [users] INNER JOIN [report_groups] AS [rg] ON [bgt].[fund] = [rg].[fund] AND [bgt].[dept] = [rg].[dept] AND [bgt].[acct] = [rg].[acct] AND [bgt].[sub] = [rg].[sub]" + query_sql = self.builder.join(clause).to_sql() + expected_sql = ( + "SELECT * FROM [users] INNER JOIN [report_groups] AS [rg]" + " ON [bgt].[fund] = [rg].[fund] AND [bgt].[dept] = [rg].[dept]" + " AND [bgt].[acct] = [rg].[acct] AND [bgt].[sub] = [rg].[sub]" + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_join_clause_with_value(self): - """ - builder = self.get_builder() + def test_can_compile_join_clause_with_value(self): clause = ( JoinClause("report_groups as rg") .on_value("bgt.active", "=", "1") .or_on_value("bgt.acct", "=", "1234") ) - builder.join(clause).to_sql() - """ - return "SELECT * FROM [users] INNER JOIN [report_groups] AS [rg] ON [bgt].[active] = '1' OR [bgt].[acct] = '1234'" + query_sql = self.builder.join(clause).to_sql() + expected_sql = ( + "SELECT * FROM [users] INNER JOIN [report_groups] AS [rg]" + " ON [bgt].[active] = '1' OR [bgt].[acct] = '1234'" + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_join_clause_with_null(self): - """ - builder = self.get_builder() + def test_can_compile_join_clause_with_null(self): clause = ( JoinClause("report_groups as rg") .on_null("bgt.acct") .or_on_null("bgt.dept") .on_value("rg.abc", 10) ) - builder.join(clause).to_sql() - """ - return "SELECT * FROM [users] INNER JOIN [report_groups] AS [rg] ON [acct] IS NULL OR [dept] IS NULL AND [rg].[abc] = '10'" + query_sql = self.builder.join(clause).to_sql() + expected_sql = ( + "SELECT * FROM [users] INNER JOIN [report_groups] AS [rg]" + " ON [acct] IS NULL OR [dept] IS NULL AND [rg].[abc] = '10'" + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_join_clause_with_not_null(self): - """ - builder = self.get_builder() + def test_can_compile_join_clause_with_not_null(self): clause = ( JoinClause("report_groups as rg") .on_not_null("bgt.acct") .or_on_not_null("bgt.dept") .on_value("rg.abc", 10) ) - builder.join(clause).to_sql() - """ - return "SELECT * FROM [users] INNER JOIN [report_groups] AS [rg] ON [acct] IS NOT NULL OR [dept] IS NOT NULL AND [rg].[abc] = '10'" + query_sql = self.builder.join(clause).to_sql() + expected_sql = ( + "SELECT * FROM [users] INNER JOIN [report_groups] AS [rg]" + " ON [acct] IS NOT NULL OR [dept] IS NOT NULL AND [rg].[abc] = '10'" + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_join_clause_with_lambda(self): - """ - builder = self.get_builder() - builder.join( + def test_can_compile_join_clause_with_lambda(self): + query_sql = self.builder.join( "report_groups as rg", - lambda clause: ( - clause.on("bgt.fund", "=", "rg.fund") - .on_null("bgt") + lambda clause: clause.on("bgt.fund", "=", "rg.fund").on_null( + "bgt" ), ).to_sql() - """ - return "SELECT * FROM [users] INNER JOIN [report_groups] AS [rg] ON [bgt].[fund] = [rg].[fund] AND [bgt] IS NULL" + expected_sql = ( + "SELECT * FROM [users] INNER JOIN [report_groups] AS [rg]" + " ON [bgt].[fund] = [rg].[fund] AND [bgt] IS NULL" + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_left_join_clause_with_lambda(self): - """ - builder = self.get_builder() - builder.left_join( + def test_can_compile_left_join_clause_with_lambda(self): + query_sql = self.builder.left_join( "report_groups as rg", - lambda clause: ( - clause.on("bgt.fund", "=", "rg.fund") - .or_on_null("bgt") + lambda clause: clause.on("bgt.fund", "=", "rg.fund").or_on_null( + "bgt" ), ).to_sql() - """ - return "SELECT * FROM [users] LEFT JOIN [report_groups] AS [rg] ON [bgt].[fund] = [rg].[fund] OR [bgt] IS NULL" + expected_sql = ( + "SELECT * FROM [users] LEFT JOIN [report_groups] AS [rg]" + " ON [bgt].[fund] = [rg].[fund] OR [bgt] IS NULL" + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_right_join_clause_with_lambda(self): - """ - builder = self.get_builder() - builder.right_join( + def test_can_compile_right_join_clause_with_lambda(self): + query_sql = self.builder.right_join( "report_groups as rg", - lambda clause: ( - clause.on("bgt.fund", "=", "rg.fund") - .or_on_null("bgt") + lambda clause: clause.on("bgt.fund", "=", "rg.fund").or_on_null( + "bgt" ), ).to_sql() - """ - return "SELECT * FROM [users] RIGHT JOIN [report_groups] AS [rg] ON [bgt].[fund] = [rg].[fund] OR [bgt] IS NULL" - - def shared_lock(self): - """ - builder = self.get_builder() - builder.where("age", "not like", "%name%").to_sql() - """ - return "SELECT * FROM [users] WITH(ROWLOCK) WHERE [users].[votes] >= '100'" - - def update_lock(self): - """ - builder = self.get_builder() - builder.where("age", "not like", "%name%").to_sql() - """ - return "SELECT * FROM [users] WITH(ROWLOCK) WHERE [users].[votes] >= '100'" - - def can_user_where_raw_and_where(self): - """ - builder.where_raw("`age` = '18'").where("name", "=", "James").to_sql() - """ - return "SELECT * FROM [users] WHERE age = '18' AND [users].[name] = 'James'" - - def where_exists_with_lambda(self): - return """SELECT * FROM [users] WHERE EXISTS (SELECT * FROM [users] WHERE [users].[age] = '1')""" - - def where_not_exists_with_lambda(self): - return """SELECT * FROM [users] WHERE NOT EXISTS (SELECT * FROM [users] WHERE [users].[age] = '1')""" - - def where_date(self): - return ( - """SELECT * FROM [users] WHERE DATE([users].[created_at]) = '2022-06-01'""" + expected_sql = ( + "SELECT * FROM [users] RIGHT JOIN [report_groups] AS [rg]" + " ON [bgt].[fund] = [rg].[fund] OR [bgt] IS NULL" ) - - def or_where_null(self): - return """SELECT * FROM [users] WHERE [users].[column1] IS NULL OR [users].[column2] IS NULL""" - - def select_distinct(self): - return """SELECT DISTINCT [users].[group] FROM [users]""" + self.assertEqual(query_sql, expected_sql) diff --git a/tests/mssql/grammar/test_mssql_update_grammar.py b/tests/mssql/grammar/test_mssql_update_grammar.py index 49c6e4ab4..643d67db8 100644 --- a/tests/mssql/grammar/test_mssql_update_grammar.py +++ b/tests/mssql/grammar/test_mssql_update_grammar.py @@ -1,8 +1,8 @@ import unittest +from src.masoniteorm.expressions import Raw from src.masoniteorm.query import QueryBuilder from src.masoniteorm.query.grammars import MSSQLGrammar -from src.masoniteorm.expressions import Raw class TestMSSQLUpdateGrammar(unittest.TestCase): @@ -10,26 +10,27 @@ def setUp(self): self.builder = QueryBuilder(MSSQLGrammar, table="users") def test_can_compile_update(self): - to_sql = ( - self.builder.where("name", "bob").update({"name": "Joe"}, dry=True).to_sql() + query_sql = ( + self.builder.where("name", "bob") + .update({"name": "Joe"}, dry=True) + .to_sql() ) - - sql = "UPDATE [users] SET [users].[name] = 'Joe' WHERE [users].[name] = 'bob'" - self.assertEqual(to_sql, sql) + expected_sql = "UPDATE [users] SET [users].[name] = 'Joe' WHERE [users].[name] = 'bob'" + self.assertEqual(query_sql, expected_sql) def test_can_compile_update_with_multiple_where(self): - to_sql = ( + query_sql = ( self.builder.where("name", "bob") .where("age", 20) .update({"name": "Joe"}, dry=True) .to_sql() ) - - sql = "UPDATE [users] SET [users].[name] = 'Joe' WHERE [users].[name] = 'bob' AND [users].[age] = '20'" - self.assertEqual(to_sql, sql) + expected_sql = "UPDATE [users] SET [users].[name] = 'Joe' WHERE [users].[name] = 'bob' AND [users].[age] = '20'" + self.assertEqual(query_sql, expected_sql) def test_raw_expression(self): - to_sql = self.builder.update({"name": Raw("[username]")}, dry=True).to_sql() - - sql = "UPDATE [users] SET [users].[name] = [username]" - self.assertEqual(to_sql, sql) + query_sql = self.builder.update( + {"name": Raw("[username]")}, dry=True + ).to_sql() + expected_sql = "UPDATE [users] SET [users].[name] = [username]" + self.assertEqual(query_sql, expected_sql) diff --git a/tests/mssql/schema/test_mssql_schema_builder.py b/tests/mssql/schema/test_mssql_schema_builder.py index 4205bc7eb..47590efd2 100644 --- a/tests/mssql/schema/test_mssql_schema_builder.py +++ b/tests/mssql/schema/test_mssql_schema_builder.py @@ -1,9 +1,9 @@ import unittest -from tests.integrations.config.database import DATABASES from src.masoniteorm.connections import MSSQLConnection from src.masoniteorm.schema import Schema from src.masoniteorm.schema.platforms import MSSQLPlatform +from tests.integrations.config.database import DATABASES class TestMSSQLSchemaBuilder(unittest.TestCase): @@ -24,30 +24,33 @@ def test_can_add_columns(self): blueprint.integer("age") self.assertEqual(len(blueprint.table.added_columns), 2) - self.assertEqual( - blueprint.to_sql(), - ["CREATE TABLE [users] ([name] VARCHAR(255) NOT NULL, [age] INT NOT NULL)"], - ) + query_sql = blueprint.to_sql() + expected_sql = [ + "CREATE TABLE [users] ([name] VARCHAR(255) NOT NULL, [age] INT NOT NULL)" + ] + self.assertEqual(query_sql, expected_sql) def test_can_add_tiny_text(self): with self.schema.create("users") as blueprint: blueprint.tiny_text("description") self.assertEqual(len(blueprint.table.added_columns), 1) - self.assertEqual( - blueprint.to_sql(), - ["CREATE TABLE [users] ([description] TINYTEXT NOT NULL)"], - ) + query_sql = blueprint.to_sql() + expected_sql = [ + "CREATE TABLE [users] ([description] TINYTEXT NOT NULL)" + ] + self.assertEqual(query_sql, expected_sql) def test_can_add_unsigned_decimal(self): with self.schema.create("users") as blueprint: blueprint.unsigned_decimal("amount", 19, 4) self.assertEqual(len(blueprint.table.added_columns), 1) - self.assertEqual( - blueprint.to_sql(), - ["CREATE TABLE [users] ([amount] DECIMAL(19, 4) NOT NULL)"], - ) + query_sql = blueprint.to_sql() + expected_sql = [ + "CREATE TABLE [users] ([amount] DECIMAL(19, 4) NOT NULL)" + ] + self.assertEqual(query_sql, expected_sql) def test_can_add_columns_with_constaint(self): with self.schema.create("users") as blueprint: @@ -56,21 +59,21 @@ def test_can_add_columns_with_constaint(self): blueprint.unique("name") self.assertEqual(len(blueprint.table.added_columns), 2) - self.assertEqual( - blueprint.to_sql(), - [ - "CREATE TABLE [users] ([name] VARCHAR(255) NOT NULL, [age] INT NOT NULL, CONSTRAINT users_name_unique UNIQUE (name))" - ], - ) + query_sql = blueprint.to_sql() + expected_sql = [ + "CREATE TABLE [users] ([name] VARCHAR(255) NOT NULL, [age] INT NOT NULL, CONSTRAINT users_name_unique UNIQUE (name))" + ] + self.assertEqual(query_sql, expected_sql) def test_can_have_float_type(self): with self.schema.create("users") as blueprint: blueprint.float("amount") - self.assertEqual( - blueprint.to_sql(), - ["""CREATE TABLE [users] (""" """[amount] FLOAT(19, 4) NOT NULL)"""], - ) + query_sql = blueprint.to_sql() + expected_sql = [ + """CREATE TABLE [users] (""" """[amount] FLOAT(19, 4) NOT NULL)""" + ] + self.assertEqual(query_sql, expected_sql) def test_can_have_unsigned_columns(self): with self.schema.create("users") as blueprint: @@ -80,17 +83,16 @@ def test_can_have_unsigned_columns(self): blueprint.small_integer("small_profile_id").unsigned() blueprint.medium_integer("medium_profile_id").unsigned() - self.assertEqual( - blueprint.to_sql(), - [ - "CREATE TABLE [users] (" - "[profile_id] INT NOT NULL, " - "[big_profile_id] BIGINT NOT NULL, " - "[tiny_profile_id] TINYINT NOT NULL, " - "[small_profile_id] SMALLINT NOT NULL, " - "[medium_profile_id] MEDIUMINT NOT NULL)" - ], - ) + query_sql = blueprint.to_sql() + expected_sql = [ + "CREATE TABLE [users] (" + "[profile_id] INT NOT NULL, " + "[big_profile_id] BIGINT NOT NULL, " + "[tiny_profile_id] TINYINT NOT NULL, " + "[small_profile_id] SMALLINT NOT NULL, " + "[medium_profile_id] MEDIUMINT NOT NULL)" + ] + self.assertEqual(query_sql, expected_sql) def test_can_add_columns_with_foreign_key_constaint(self): with self.schema.create("users") as blueprint: @@ -100,17 +102,16 @@ def test_can_add_columns_with_foreign_key_constaint(self): blueprint.foreign("profile_id").references("id").on("profiles") self.assertEqual(len(blueprint.table.added_columns), 3) - self.assertEqual( - blueprint.to_sql(), - [ - "CREATE TABLE [users] " - "([name] VARCHAR(255) NOT NULL, " - "[age] INT NOT NULL, " - "[profile_id] INT NOT NULL, " - "CONSTRAINT users_name_unique UNIQUE (name), " - "CONSTRAINT users_profile_id_foreign FOREIGN KEY ([profile_id]) REFERENCES [profiles]([id]))" - ], - ) + query_sql = blueprint.to_sql() + expected_sql = [ + "CREATE TABLE [users] " + "([name] VARCHAR(255) NOT NULL, " + "[age] INT NOT NULL, " + "[profile_id] INT NOT NULL, " + "CONSTRAINT users_name_unique UNIQUE (name), " + "CONSTRAINT users_profile_id_foreign FOREIGN KEY ([profile_id]) REFERENCES [profiles]([id]))" + ] + self.assertEqual(query_sql, expected_sql) def test_can_add_columns_with_add_foreign_constaint(self): with self.schema.create("users") as blueprint: @@ -120,17 +121,16 @@ def test_can_add_columns_with_add_foreign_constaint(self): blueprint.add_foreign("profile_id.id.profiles") self.assertEqual(len(blueprint.table.added_columns), 3) - self.assertEqual( - blueprint.to_sql(), - [ - "CREATE TABLE [users] " - "([name] VARCHAR(255) NOT NULL, " - "[age] INT NOT NULL, " - "[profile_id] INT NOT NULL, " - "CONSTRAINT users_name_unique UNIQUE (name), " - "CONSTRAINT users_profile_id_foreign FOREIGN KEY ([profile_id]) REFERENCES [profiles]([id]))" - ], - ) + query_sql = blueprint.to_sql() + expected_sql = [ + "CREATE TABLE [users] " + "([name] VARCHAR(255) NOT NULL, " + "[age] INT NOT NULL, " + "[profile_id] INT NOT NULL, " + "CONSTRAINT users_name_unique UNIQUE (name), " + "CONSTRAINT users_profile_id_foreign FOREIGN KEY ([profile_id]) REFERENCES [profiles]([id]))" + ] + self.assertEqual(query_sql, expected_sql) def test_can_advanced_table_creation(self): with self.schema.create("users") as blueprint: @@ -141,19 +141,20 @@ def test_can_advanced_table_creation(self): blueprint.integer("admin").default(0) blueprint.string("remember_token").nullable() blueprint.timestamp("verified_at").nullable() - blueprint.timestamp("registered_at").default_raw("CURRENT_TIMESTAMP") + blueprint.timestamp("registered_at").default_raw( + "CURRENT_TIMESTAMP" + ) blueprint.timestamps() self.assertEqual(len(blueprint.table.added_columns), 10) - self.assertEqual( - blueprint.to_sql(), - [ - "CREATE TABLE [users] ([id] INT IDENTITY NOT NULL, [name] VARCHAR(255) NOT NULL, [email] VARCHAR(255) NOT NULL, " - "[password] VARCHAR(255) NOT NULL, [admin] INT NOT NULL DEFAULT 0, [remember_token] VARCHAR(255) NULL, " - "[verified_at] DATETIME NULL, [registered_at] DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, [created_at] DATETIME NULL DEFAULT CURRENT_TIMESTAMP, " - "[updated_at] DATETIME NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT users_id_primary PRIMARY KEY (id), CONSTRAINT users_email_unique UNIQUE (email))" - ], - ) + query_sql = blueprint.to_sql() + expected_sql = [ + "CREATE TABLE [users] ([id] INT IDENTITY NOT NULL, [name] VARCHAR(255) NOT NULL, [email] VARCHAR(255) NOT NULL, " + "[password] VARCHAR(255) NOT NULL, [admin] INT NOT NULL DEFAULT 0, [remember_token] VARCHAR(255) NULL, " + "[verified_at] DATETIME NULL, [registered_at] DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, [created_at] DATETIME NULL DEFAULT CURRENT_TIMESTAMP, " + "[updated_at] DATETIME NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT users_id_primary PRIMARY KEY (id), CONSTRAINT users_email_unique UNIQUE (email))" + ] + self.assertEqual(query_sql, expected_sql) def test_can_advanced_table_creation2(self): with self.schema.create("users") as blueprint: @@ -169,42 +170,38 @@ def test_can_advanced_table_creation2(self): blueprint.string("thumbnail").nullable() blueprint.integer("premium") blueprint.integer("author_id").unsigned().nullable() - blueprint.foreign("author_id").references("id").on("users").on_delete( - "CASCADE" - ) + blueprint.foreign("author_id").references("id").on( + "users" + ).on_delete("CASCADE") blueprint.text("description") blueprint.timestamps() self.assertEqual(len(blueprint.table.added_columns), 15) - self.assertEqual( - blueprint.to_sql(), - ( - [ - "CREATE TABLE [users] ([id] INT IDENTITY NOT NULL, [gender] VARCHAR(255) NOT NULL CHECK([gender] IN ('male', 'female')), [name] VARCHAR(255) NOT NULL, [duration] VARCHAR(255) NOT NULL, " - "[url] VARCHAR(255) NOT NULL, [last_address] VARCHAR(255) NULL, [route_origin] VARCHAR(255) NULL, [mac_address] VARCHAR(255) NULL, [published_at] DATETIME NOT NULL, [thumbnail] VARCHAR(255) NULL, [premium] INT NOT NULL, " - "[author_id] INT NULL, [description] TEXT NOT NULL, [created_at] DATETIME NULL DEFAULT CURRENT_TIMESTAMP, " - "[updated_at] DATETIME NULL DEFAULT CURRENT_TIMESTAMP, " - "CONSTRAINT users_id_primary PRIMARY KEY (id), CONSTRAINT users_author_id_foreign FOREIGN KEY ([author_id]) REFERENCES [users]([id]) ON DELETE CASCADE)" - ] - ), - ) + query_sql = blueprint.to_sql() + expected_sql = [ + "CREATE TABLE [users] ([id] INT IDENTITY NOT NULL, [gender] VARCHAR(255) NOT NULL CHECK([gender] IN ('male', 'female')), [name] VARCHAR(255) NOT NULL, [duration] VARCHAR(255) NOT NULL, " + "[url] VARCHAR(255) NOT NULL, [last_address] VARCHAR(255) NULL, [route_origin] VARCHAR(255) NULL, [mac_address] VARCHAR(255) NULL, [published_at] DATETIME NOT NULL, [thumbnail] VARCHAR(255) NULL, [premium] INT NOT NULL, " + "[author_id] INT NULL, [description] TEXT NOT NULL, [created_at] DATETIME NULL DEFAULT CURRENT_TIMESTAMP, " + "[updated_at] DATETIME NULL DEFAULT CURRENT_TIMESTAMP, " + "CONSTRAINT users_id_primary PRIMARY KEY (id), CONSTRAINT users_author_id_foreign FOREIGN KEY ([author_id]) REFERENCES [users]([id]) ON DELETE CASCADE)" + ] + self.assertEqual(query_sql, expected_sql) def test_can_add_columns_with_foreign_key_constraint_name(self): with self.schema.create("users") as blueprint: blueprint.integer("profile_id") - blueprint.foreign("profile_id", name="profile_foreign").references("id").on( - "profiles" - ) + blueprint.foreign("profile_id", name="profile_foreign").references( + "id" + ).on("profiles") self.assertEqual(len(blueprint.table.added_columns), 1) - self.assertEqual( - blueprint.to_sql(), - [ - "CREATE TABLE [users] (" - "[profile_id] INT NOT NULL, " - "CONSTRAINT profile_foreign FOREIGN KEY ([profile_id]) REFERENCES [profiles]([id]))" - ], - ) + query_sql = blueprint.to_sql() + expected_sql = [ + "CREATE TABLE [users] (" + "[profile_id] INT NOT NULL, " + "CONSTRAINT profile_foreign FOREIGN KEY ([profile_id]) REFERENCES [profiles]([id]))" + ] + self.assertEqual(query_sql, expected_sql) def test_can_have_composite_keys(self): with self.schema.create("users") as blueprint: @@ -214,17 +211,16 @@ def test_can_have_composite_keys(self): blueprint.primary(["name", "age"]) self.assertEqual(len(blueprint.table.added_columns), 3) - self.assertEqual( - blueprint.to_sql(), - [ - "CREATE TABLE [users] " - "([name] VARCHAR(255) NOT NULL, " - "[age] INT NOT NULL, " - "[profile_id] INT NOT NULL, " - "CONSTRAINT users_name_unique UNIQUE (name), " - "CONSTRAINT users_name_age_primary PRIMARY KEY (name, age))" - ], - ) + query_sql = blueprint.to_sql() + expected_sql = [ + "CREATE TABLE [users] " + "([name] VARCHAR(255) NOT NULL, " + "[age] INT NOT NULL, " + "[profile_id] INT NOT NULL, " + "CONSTRAINT users_name_unique UNIQUE (name), " + "CONSTRAINT users_name_age_primary PRIMARY KEY (name, age))" + ] + self.assertEqual(query_sql, expected_sql) def test_can_have_column_primary_key(self): with self.schema.create("users") as blueprint: @@ -233,67 +229,66 @@ def test_can_have_column_primary_key(self): blueprint.integer("profile_id") self.assertEqual(len(blueprint.table.added_columns), 3) - self.assertEqual( - blueprint.to_sql(), - [ - "CREATE TABLE [users] " - "([name] VARCHAR(255) NOT NULL, " - "[age] INT NOT NULL, " - "[profile_id] INT NOT NULL, " - "CONSTRAINT users_name_primary PRIMARY KEY (name))" - ], - ) + query_sql = blueprint.to_sql() + expected_sql = [ + "CREATE TABLE [users] " + "([name] VARCHAR(255) NOT NULL, " + "[age] INT NOT NULL, " + "[profile_id] INT NOT NULL, " + "CONSTRAINT users_name_primary PRIMARY KEY (name))" + ] + self.assertEqual(query_sql, expected_sql) def test_has_table(self): - schema_sql = self.schema.has_table("users") + query_sql = self.schema.has_table("users") - sql = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'users'" + expected_sql = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'users'" - self.assertEqual(schema_sql, sql) + self.assertEqual(query_sql, expected_sql) def test_can_truncate(self): - sql = self.schema.truncate("users") + query_sql = self.schema.truncate("users") - self.assertEqual(sql, "TRUNCATE TABLE [users]") + self.assertEqual(query_sql, "TRUNCATE TABLE [users]") def test_can_rename_table(self): - sql = self.schema.rename("users", "clients") + query_sql = self.schema.rename("users", "clients") - self.assertEqual(sql, "EXEC sp_rename [users], [clients]") + self.assertEqual(query_sql, "EXEC sp_rename [users], [clients]") def test_can_drop_table_if_exists(self): - sql = self.schema.drop_table_if_exists("users", "clients") + query_sql = self.schema.drop_table_if_exists("users", "clients") - self.assertEqual(sql, "DROP TABLE IF EXISTS [users]") + self.assertEqual(query_sql, "DROP TABLE IF EXISTS [users]") def test_can_drop_table(self): - sql = self.schema.drop_table("users", "clients") + query_sql = self.schema.drop_table("users", "clients") - self.assertEqual(sql, "DROP TABLE [users]") + self.assertEqual(query_sql, "DROP TABLE [users]") def test_has_column(self): - sql = self.schema.has_column("users", "name") + query_sql = self.schema.has_column("users", "name") self.assertEqual( - sql, + query_sql, "SELECT 1 FROM sys.columns WHERE Name = N'name' AND Object_ID = Object_ID(N'users')", ) def test_can_enable_foreign_keys(self): - sql = self.schema.enable_foreign_key_constraints() + query_sql = self.schema.enable_foreign_key_constraints() - self.assertEqual(sql, "") + self.assertEqual(query_sql, "") def test_can_disable_foreign_keys(self): - sql = self.schema.disable_foreign_key_constraints() + query_sql = self.schema.disable_foreign_key_constraints() - self.assertEqual(sql, "") + self.assertEqual(query_sql, "") def test_can_truncate_without_foreign_keys(self): - sql = self.schema.truncate("users", foreign_keys=True) + query_sql = self.schema.truncate("users", foreign_keys=True) self.assertEqual( - sql, + query_sql, [ "ALTER TABLE [users] NOCHECK CONSTRAINT ALL", "TRUNCATE TABLE [users]", @@ -306,21 +301,21 @@ def test_can_add_enum(self): blueprint.enum("status", ["active", "inactive"]).default("active") self.assertEqual(len(blueprint.table.added_columns), 1) - self.assertEqual( - blueprint.to_sql(), - [ - "CREATE TABLE [users] ([status] VARCHAR(255) NOT NULL DEFAULT 'active' CHECK([status] IN ('active', 'inactive')))" - ], - ) + query_sql = blueprint.to_sql() + expected_sql = [ + "CREATE TABLE [users] ([status] VARCHAR(255) NOT NULL DEFAULT 'active' CHECK([status] IN ('active', 'inactive')))" + ] + self.assertEqual(query_sql, expected_sql) def test_can_change_column_enum(self): with self.schema.table("users") as blueprint: - blueprint.enum("status", ["active", "inactive"]).default("active").change() + blueprint.enum("status", ["active", "inactive"]).default( + "active" + ).change() self.assertEqual(len(blueprint.table.changed_columns), 1) - self.assertEqual( - blueprint.to_sql(), - [ - "ALTER TABLE [users] ALTER COLUMN [status] VARCHAR(255) NOT NULL DEFAULT 'active' CHECK([status] IN ('active', 'inactive'))" - ], - ) + query_sql = blueprint.to_sql() + expected_sql = [ + "ALTER TABLE [users] ALTER COLUMN [status] VARCHAR(255) NOT NULL DEFAULT 'active' CHECK([status] IN ('active', 'inactive'))" + ] + self.assertEqual(query_sql, expected_sql) diff --git a/tests/mssql/schema/test_mssql_schema_builder_alter.py b/tests/mssql/schema/test_mssql_schema_builder_alter.py index f1b323e27..d6b39c8cf 100644 --- a/tests/mssql/schema/test_mssql_schema_builder_alter.py +++ b/tests/mssql/schema/test_mssql_schema_builder_alter.py @@ -1,10 +1,10 @@ import unittest -from tests.integrations.config.database import DATABASES from src.masoniteorm.connections import MSSQLConnection from src.masoniteorm.schema import Schema from src.masoniteorm.schema.platforms import MSSQLPlatform from src.masoniteorm.schema.Table import Table +from tests.integrations.config.database import DATABASES class TestMySQLSchemaBuilderAlter(unittest.TestCase): @@ -26,11 +26,12 @@ def test_can_add_columns(self): self.assertEqual(len(blueprint.table.added_columns), 2) - sql = [ + expected_sql = [ "ALTER TABLE [users] ADD [name] VARCHAR(255) NOT NULL, [age] INT NOT NULL" ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_can_adds_column_with_default(self): with self.schema.table("users") as blueprint: @@ -38,9 +39,12 @@ def test_can_adds_column_with_default(self): self.assertEqual(len(blueprint.table.added_columns), 1) - sql = ["ALTER TABLE [users] ADD [name] VARCHAR(255) NOT NULL DEFAULT 0"] + expected_sql = [ + "ALTER TABLE [users] ADD [name] VARCHAR(255) NOT NULL DEFAULT 0" + ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_rename(self): with self.schema.table("users") as blueprint: @@ -50,9 +54,10 @@ def test_alter_rename(self): table.add_column("post", "integer") blueprint.table.from_table = table - sql = ["EXEC sp_rename 'users.post', 'comment', 'COLUMN'"] + expected_sql = ["EXEC sp_rename 'users.post', 'comment', 'COLUMN'"] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_add_and_rename(self): with self.schema.table("users") as blueprint: @@ -63,134 +68,155 @@ def test_alter_add_and_rename(self): table.add_column("post", "integer") blueprint.table.from_table = table - sql = [ + expected_sql = [ "ALTER TABLE [users] ADD [name] VARCHAR(255) NOT NULL", "EXEC sp_rename 'users.post', 'comment', 'COLUMN'", ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop1(self): with self.schema.table("users") as blueprint: blueprint.drop_column("post") - sql = ["ALTER TABLE [users] DROP COLUMN post"] + expected_sql = ["ALTER TABLE [users] DROP COLUMN post"] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_add_column_and_foreign_key(self): with self.schema.table("users") as blueprint: blueprint.unsigned_integer("playlist_id").nullable() - blueprint.foreign("playlist_id").references("id").on("playlists").on_delete( - "cascade" - ) + blueprint.foreign("playlist_id").references("id").on( + "playlists" + ).on_delete("cascade") - sql = [ + expected_sql = [ "ALTER TABLE [users] ADD [playlist_id] INT NULL", "ALTER TABLE [users] ADD CONSTRAINT users_playlist_id_foreign FOREIGN KEY ([playlist_id]) REFERENCES [playlists]([id]) ON DELETE CASCADE", ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_add_column_and_add_foreign(self): with self.schema.table("users") as blueprint: blueprint.unsigned_integer("playlist_id").nullable() - blueprint.add_foreign("playlist_id.id.playlists").on_delete("cascade") + blueprint.add_foreign("playlist_id.id.playlists").on_delete( + "cascade" + ) - sql = [ + expected_sql = [ "ALTER TABLE [users] ADD [playlist_id] INT NULL", "ALTER TABLE [users] ADD CONSTRAINT users_playlist_id_foreign FOREIGN KEY ([playlist_id]) REFERENCES [playlists]([id]) ON DELETE CASCADE", ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_foreign_key(self): with self.schema.table("users") as blueprint: blueprint.drop_foreign("users_playlist_id_foreign") - sql = ["ALTER TABLE [users] DROP CONSTRAINT users_playlist_id_foreign"] + expected_sql = [ + "ALTER TABLE [users] DROP CONSTRAINT users_playlist_id_foreign" + ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_foreign_key_shortcut(self): with self.schema.table("users") as blueprint: blueprint.drop_foreign(["playlist_id"]) - sql = ["ALTER TABLE [users] DROP CONSTRAINT users_playlist_id_foreign"] + expected_sql = [ + "ALTER TABLE [users] DROP CONSTRAINT users_playlist_id_foreign" + ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_unique_constraint(self): with self.schema.table("users") as blueprint: blueprint.drop_unique("users_playlist_id_unique") - sql = ["DROP INDEX [users].[users_playlist_id_unique]"] + expected_sql = ["DROP INDEX [users].[users_playlist_id_unique]"] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_add_primary(self): with self.schema.table("users") as blueprint: blueprint.primary("playlist_id") - sql = [ + expected_sql = [ "ALTER TABLE [users] ADD CONSTRAINT users_playlist_id_primary PRIMARY KEY (playlist_id)" ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_add_index(self): with self.schema.table("users") as blueprint: blueprint.index("playlist_id") - sql = ["CREATE INDEX users_playlist_id_index ON [users](playlist_id)"] + expected_sql = [ + "CREATE INDEX users_playlist_id_index ON [users](playlist_id)" + ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_index(self): with self.schema.table("users") as blueprint: blueprint.drop_index("users_playlist_id_index") - sql = ["DROP INDEX [users].[users_playlist_id_index]"] + expected_sql = ["DROP INDEX [users].[users_playlist_id_index]"] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_index_shortcut(self): with self.schema.table("users") as blueprint: blueprint.drop_index(["playlist_id"]) - sql = ["DROP INDEX [users].[users_playlist_id_index]"] + expected_sql = ["DROP INDEX [users].[users_playlist_id_index]"] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_unique_constraint_shortcut(self): with self.schema.table("users") as blueprint: blueprint.drop_unique(["playlist_id"]) - sql = ["DROP INDEX [users].[users_playlist_id_unique]"] + expected_sql = ["DROP INDEX [users].[users_playlist_id_unique]"] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_primary(self): with self.schema.table("users") as blueprint: blueprint.drop_primary(["id"]) - sql = ["DROP INDEX [users].[users_id_primary]"] + expected_sql = ["DROP INDEX [users].[users_id_primary]"] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_has_table(self): - schema_sql = self.schema.has_table("users") + query_sql = self.schema.has_table("users") - sql = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'users'" + expected_sql = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'users'" - self.assertEqual(schema_sql, sql) + self.assertEqual(query_sql, expected_sql) def test_drop_table(self): - schema_sql = self.schema.has_table("users") + query_sql = self.schema.has_table("users") - sql = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'users'" + expected_sql = "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'users'" - self.assertEqual(schema_sql, sql) + self.assertEqual(query_sql, expected_sql) def test_change(self): with self.schema.table("users") as blueprint: @@ -205,12 +231,13 @@ def test_change(self): blueprint.table.from_table = table - sql = [ + expected_sql = [ "ALTER TABLE [users] ADD [name] VARCHAR(255) NOT NULL, [external_type] VARCHAR(255) NOT NULL DEFAULT 'external'", "ALTER TABLE [users] ALTER COLUMN [age] INT NOT NULL", ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_drop_add_and_change(self): with self.schema.table("users") as blueprint: @@ -226,13 +253,14 @@ def test_drop_add_and_change(self): blueprint.table.from_table = table - sql = [ + expected_sql = [ "ALTER TABLE [users] ADD [name] VARCHAR(255) NOT NULL", "ALTER TABLE [users] ALTER COLUMN [age] INT NOT NULL DEFAULT 0", "ALTER TABLE [users] DROP COLUMN email", ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_can_create_indexes(self): with self.schema.table("users") as blueprint: @@ -244,15 +272,14 @@ def test_can_create_indexes(self): self.assertEqual(len(blueprint.table.added_columns), 0) print(blueprint.to_sql()) - self.assertEqual( - blueprint.to_sql(), - [ - "CREATE INDEX users_name_index ON [users](name)", - "CREATE INDEX users_name_email_index ON [users](name,email)", - "ALTER TABLE [users] ADD CONSTRAINT users_name_unique UNIQUE(name)", - "ALTER TABLE [users] ADD CONSTRAINT users_name_email_unique UNIQUE(name,email)", - ], - ) + query_sql = blueprint.to_sql() + expected_sql = [ + "CREATE INDEX users_name_index ON [users](name)", + "CREATE INDEX users_name_email_index ON [users](name,email)", + "ALTER TABLE [users] ADD CONSTRAINT users_name_unique UNIQUE(name)", + "ALTER TABLE [users] ADD CONSTRAINT users_name_email_unique UNIQUE(name,email)", + ] + self.assertEqual(query_sql, expected_sql) def test_timestamp_alter_add_nullable_column(self): with self.schema.table("users") as blueprint: @@ -265,9 +292,10 @@ def test_timestamp_alter_add_nullable_column(self): blueprint.table.from_table = table - sql = ["ALTER TABLE [users] ADD [due_date] DATETIME NULL"] + expected_sql = ["ALTER TABLE [users] ADD [due_date] DATETIME NULL"] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_can_add_column_enum(self): with self.schema.table("users") as blueprint: @@ -275,8 +303,9 @@ def test_can_add_column_enum(self): self.assertEqual(len(blueprint.table.added_columns), 1) - sql = [ + expected_sql = [ "ALTER TABLE [users] ADD [status] VARCHAR(255) NOT NULL DEFAULT 'active' CHECK([status] IN ('active', 'inactive'))" ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) diff --git a/tests/mysql/builder/test_query_builder.py b/tests/mysql/builder/test_query_builder.py index 85252f6a2..da7779794 100644 --- a/tests/mysql/builder/test_query_builder.py +++ b/tests/mysql/builder/test_query_builder.py @@ -1,4 +1,3 @@ -import inspect import unittest from src.masoniteorm.exceptions import InvalidArgument @@ -22,13 +21,18 @@ def articles(self): return Articles -class BaseTestQueryBuilder: +class MySQLQueryBuilderTest(unittest.TestCase): + """Tests for the QueryBuilder using the MySQL grammar. + + Each test builds a query and asserts the expected SQL inline. + """ + maxDiff = None def get_builder(self, table="users", dry=True): connection = MockConnectionFactory().make("default") return QueryBuilder( - grammar=self.grammar, + grammar=MySQLGrammar, connection_class=connection, connection="t", table=table, @@ -37,133 +41,121 @@ def get_builder(self, table="users", dry=True): connection_details=DATABASES, ) + # ------------------------------------------------------------------ + # Aggregates + # ------------------------------------------------------------------ + def test_sum(self): builder = self.get_builder() builder.sum("age") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT SUM(`users`.`age`) AS age FROM `users`" + self.assertEqual(query_sql, expected_sql) def test_sum_chained(self): builder = self.get_builder() builder.sum("age").max("salary") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT SUM(`users`.`age`) AS age, MAX(`users`.`salary`) AS salary FROM `users`" + self.assertEqual(query_sql, expected_sql) def test_with_(self): builder = self.get_builder() builder.with_("articles").sum("age") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - 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) + query_sql = builder.to_sql() + expected_sql = "SELECT SUM(`users`.`age`) AS age FROM `users`" + self.assertEqual(query_sql, expected_sql) def test_max(self): builder = self.get_builder() builder.max("age") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT MAX(`users`.`age`) AS age FROM `users`" + self.assertEqual(query_sql, expected_sql) def test_min(self): builder = self.get_builder() builder.min("age") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT MIN(`users`.`age`) AS age FROM `users`" + self.assertEqual(query_sql, expected_sql) def test_avg(self): builder = self.get_builder() builder.avg("age") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT AVG(`users`.`age`) AS age FROM `users`" + self.assertEqual(query_sql, expected_sql) + + def test_count(self): + builder = self.get_builder() + builder.count("id") + query_sql = builder.to_sql() + expected_sql = "SELECT COUNT(`users`.`id`) AS id FROM `users`" + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # Fetch operations + # ------------------------------------------------------------------ def test_all(self): builder = self.get_builder() builder.all() - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users`" + self.assertEqual(query_sql, expected_sql) def test_get(self): builder = self.get_builder() builder.get() - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users`" + self.assertEqual(query_sql, expected_sql) def test_first(self): builder = self.get_builder().first(query=True) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` LIMIT 1" + self.assertEqual(query_sql, expected_sql) def test_find_with_model(self): builder = self.get_builder() builder.find(1000, query=True) - sql = """SELECT * FROM `users` WHERE `users`.`id` = '1000\'""" - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`id` = '1000'" + self.assertEqual(query_sql, expected_sql) def test_find_with_model_and_list(self): builder = self.get_builder() builder.find([1000, 2000, 3000], query=True) - sql = """SELECT * FROM `users` WHERE `users`.`id` IN ('1000','2000','3000')""" - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`id` IN ('1000','2000','3000')" + self.assertEqual(query_sql, expected_sql) def test_find_with_model_custom_column(self): builder = self.get_builder() builder.find(10, column="age", query=True) - sql = """SELECT * FROM `users` WHERE `users`.`age` = '10\'""" - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`age` = '10'" + self.assertEqual(query_sql, expected_sql) def test_find_with_builder(self): builder = self.get_builder() builder._model = None builder.find(10, column="age", query=True) - sql = """SELECT * FROM `users` WHERE `users`.`age` = '10\'""" - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`age` = '10'" + self.assertEqual(query_sql, expected_sql) def test_find_with_builder_and_list(self): builder = self.get_builder() builder._model = None builder.find([10, 20, 30], column="age", query=True) - sql = ( - """SELECT * FROM `users` WHERE `users`.`age` IN ('10','20','30')""" + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`age` IN ('10','20','30')" ) - self.assertEqual(builder.to_sql(), sql) + self.assertEqual(query_sql, expected_sql) def test_find_with_builder_without_column(self): builder = self.get_builder() @@ -171,814 +163,431 @@ def test_find_with_builder_without_column(self): with self.assertRaises(InvalidArgument): builder.find(10, query=True) + # ------------------------------------------------------------------ + # SELECT columns + # ------------------------------------------------------------------ + def test_select(self): builder = self.get_builder() builder.select("name", "email") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT `users`.`name`, `users`.`email` FROM `users`" + self.assertEqual(query_sql, expected_sql) def test_select_with_table(self): builder = self.get_builder() builder.select("users.*") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT `users`.* FROM `users`" + self.assertEqual(query_sql, expected_sql) def test_select_with_table_raw(self): builder = self.get_builder() builder.select("users.*").from_raw("orders, customers") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT `users`.* FROM orders, customers" + self.assertEqual(query_sql, expected_sql) def test_select_with_alias(self): builder = self.get_builder() builder.select("users.username as name") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT `users`.`username` AS name FROM `users`" + self.assertEqual(query_sql, expected_sql) def test_select_raw(self): builder = self.get_builder() builder.select_raw("count(email) as email_count") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT count(email) as email_count FROM `users`" + self.assertEqual(query_sql, expected_sql) def test_add_select(self): builder = self.get_builder() - sql = ( - builder.select("name") - .add_select("phone_count", lambda q: q.count("*").table("phones")) - .add_select("salary", lambda q: q.count("*").table("salary")) - .to_sql() + builder.select("name").add_select( + "phone_count", lambda q: q.count("*").table("phones") + ).add_select("salary", lambda q: q.count("*").table("salary")) + query_sql = builder.to_sql() + expected_sql = ( + "SELECT `users`.`name`," + " (SELECT COUNT(*) AS m_count_reserved FROM `phones`) AS phone_count," + " (SELECT COUNT(*) AS m_count_reserved FROM `salary`) AS salary" + " FROM `users`" ) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + self.assertEqual(query_sql, expected_sql) def test_add_select_no_table(self): builder = self.get_builder(table=None) - sql = ( - builder.add_select( - "other_test", - lambda q: q.max("updated_at").table("different_table"), - ) - .add_select( - "some_alias", - lambda q: q.max("updated_at").table("another_table"), - ) - .to_sql() + builder.add_select( + "other_test", + lambda q: q.max("updated_at").table("different_table"), + ).add_select( + "some_alias", lambda q: q.max("updated_at").table("another_table") ) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_create(self): - builder = self.get_builder().without_global_scopes() - builder.create( - {"name": "Corentin All", "email": "corentin@yopmail.com"}, - query=True, + query_sql = builder.to_sql() + expected_sql = ( + "SELECT " + "(SELECT MAX(`different_table`.`updated_at`) AS updated_at FROM `different_table`) AS other_test, " + "(SELECT MAX(`another_table`.`updated_at`) AS updated_at FROM `another_table`) AS some_alias" ) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + self.assertEqual(query_sql, expected_sql) - def test_delete(self): - builder = self.get_builder() - builder.delete("name", "Joe", query=True) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + # ------------------------------------------------------------------ + # WHERE + # ------------------------------------------------------------------ def test_where(self): builder = self.get_builder() builder.where("name", "Joe") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`name` = 'Joe'" + self.assertEqual(query_sql, expected_sql) def test_where_exists(self): builder = self.get_builder() builder.where_exists("name") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` WHERE EXISTS 'name'" + self.assertEqual(query_sql, expected_sql) - def test_limit(self): - builder = self.get_builder() - builder.limit(5) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_offset(self): - builder = self.get_builder() - builder.offset(5) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_join(self): - builder = self.get_builder() - builder.join("profiles", "users.id", "=", "profiles.user_id") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_left_join(self): + def test_where_like_as_operator(self): builder = self.get_builder() - builder.left_join("profiles", "users.id", "=", "profiles.user_id") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + builder.where("age", "like", "%name%") + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`age` LIKE '%name%'" + ) + self.assertEqual(query_sql, expected_sql) - def test_right_join(self): + def test_where_like(self): builder = self.get_builder() - builder.right_join("profiles", "users.id", "=", "profiles.user_id") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_update(self): - builder = self.get_builder().update( - {"name": "Joe", "email": "joe@yopmail.com"}, dry=True + builder.where_like("age", "%name%") + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`age` LIKE '%name%'" ) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - # def test_increment(self): - # builder = self.get_builder() - # builder.increment("age", 1) - # sql = getattr( - # self, inspect.currentframe().f_code.co_name.replace("test_", "") - # )() - # self.assertEqual(builder.to_sql(), sql) - - # def test_decrement(self): - # builder = self.get_builder() - # builder.decrement("age", 1) - # sql = getattr( - # self, inspect.currentframe().f_code.co_name.replace("test_", "") - # )() - # self.assertEqual(builder.to_sql(), sql) + self.assertEqual(query_sql, expected_sql) - def test_count(self): + def test_where_not_like_as_operator(self): builder = self.get_builder() - builder.count("id") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + builder.where("age", "not like", "%name%") + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`age` NOT LIKE '%name%'" + ) + self.assertEqual(query_sql, expected_sql) - def test_order_by_asc(self): + def test_where_not_like(self): builder = self.get_builder() - builder.order_by("email", "asc") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + builder.where_not_like("age", "%name%") + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`age` NOT LIKE '%name%'" + ) + self.assertEqual(query_sql, expected_sql) - def test_order_by_desc(self): + def test_where_null(self): builder = self.get_builder() - builder.order_by("email", "desc") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + builder.where_null("name") + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`name` IS NULL" + self.assertEqual(query_sql, expected_sql) - def test_where_column(self): + def test_where_not_null(self): builder = self.get_builder() - builder.where_column("name", "username") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + builder.where_not_null("name") + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`name` IS NOT NULL" + self.assertEqual(query_sql, expected_sql) def test_where_not_in(self): builder = self.get_builder() builder.where_not_in("id", [1, 2, 3]) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_between(self): - builder = self.get_builder() - builder.between("id", 2, 5) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_not_between(self): - builder = self.get_builder() - builder.not_between("id", 2, 5) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`id` NOT IN ('1','2','3')" + ) + self.assertEqual(query_sql, expected_sql) def test_where_in(self): builder = self.get_builder() builder.where_in("id", [1, 2, 3]) - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_where_null(self): - builder = self.get_builder() - builder.where_null("name") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_where_not_null(self): - builder = self.get_builder() - builder.where_not_null("name") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_having(self): - builder = self.get_builder(table="payments") - builder.select("user_id").avg("salary").group_by("user_id").having( - "salary", ">=", "1000" - ) - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_group_by(self): - builder = self.get_builder(table="payments") - builder.select("user_id").min("salary").group_by("user_id") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_builder_alone(self): - self.assertTrue( - QueryBuilder( - dry=True, - connection_details={ - "default": "mysql", - "mysql": { - "driver": "mysql", - "host": "localhost", - "username": "root", - "password": "", - "database": "orm", - "port": "3306", - "prefix": "", - "grammar": "mysql", - "options": {"charset": "utf8mb4"}, - }, - }, - ).table("users") + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`id` IN ('1','2','3')" ) + self.assertEqual(query_sql, expected_sql) def test_where_lt(self): builder = self.get_builder() builder.where("age", "<", "20") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`age` < '20'" + self.assertEqual(query_sql, expected_sql) def test_where_lte(self): builder = self.get_builder() builder.where("age", "<=", "20") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`age` <= '20'" + self.assertEqual(query_sql, expected_sql) def test_where_gt(self): builder = self.get_builder() builder.where("age", ">", "20") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`age` > '20'" + self.assertEqual(query_sql, expected_sql) def test_where_gte(self): builder = self.get_builder() builder.where("age", ">=", "20") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`age` >= '20'" + self.assertEqual(query_sql, expected_sql) def test_where_ne(self): builder = self.get_builder() builder.where("age", "!=", "20") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_or_where(self): - builder = self.get_builder() - builder.where("age", "20").or_where("age", "<", 20) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`age` != '20'" + self.assertEqual(query_sql, expected_sql) def test_or_where(self): builder = self.get_builder() builder.where("age", "20").or_where("age", "<", 20) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_where_like_as_operator(self): - builder = self.get_builder() - builder.where("age", "like", "%name%") - sql = getattr(self, "where_like")() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`age` = '20' OR `users`.`age` < '20'" + self.assertEqual(query_sql, expected_sql) - def test_where_like(self): + def test_where_column(self): builder = self.get_builder() - builder.where_like("age", "%name%") - sql = getattr(self, "where_like")() - self.assertEqual(builder.to_sql(), sql) + builder.where_column("name", "username") + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`name` = `users`.`username`" + ) + self.assertEqual(query_sql, expected_sql) - def test_where_not_like_as_operator(self): + def test_between(self): builder = self.get_builder() - builder.where("age", "not like", "%name%") - sql = getattr(self, "where_not_like")() - self.assertEqual(builder.to_sql(), sql) + builder.between("id", 2, 5) + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`id` BETWEEN '2' AND '5'" + ) + self.assertEqual(query_sql, expected_sql) - def test_where_not_like(self): + def test_not_between(self): builder = self.get_builder() - builder.where_not_like("age", "%name%") - sql = getattr(self, "where_not_like")() - self.assertEqual(builder.to_sql(), sql) + builder.not_between("id", 2, 5) + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`id` NOT BETWEEN '2' AND '5'" + ) + self.assertEqual(query_sql, expected_sql) - def test_can_call_with_multi_tables(self): - builder = self.get_builder() - sql = ( - builder.table("information_schema.columns") - .select("table_name") - .where("table_name", "users") - .to_sql() + def test_having(self): + builder = self.get_builder(table="payments") + builder.select("user_id").avg("salary").group_by("user_id").having( + "salary", ">=", "1000" ) - self.assertEqual( - sql, - """SELECT `information_schema`.`columns`.`table_name` FROM `information_schema`.`columns` WHERE `information_schema`.`columns`.`table_name` = 'users'""", + query_sql = builder.to_sql() + expected_sql = ( + "SELECT `payments`.`user_id`, AVG(`payments`.`salary`) AS salary" + " FROM `payments` GROUP BY `payments`.`user_id` HAVING `payments`.`salary` >= '1000'" ) + self.assertEqual(query_sql, expected_sql) - def test_truncate(self): - builder = self.get_builder(dry=True) - sql = builder.truncate() - sql_ref = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(sql, sql_ref) - - def test_truncate_without_foreign_keys(self): - builder = self.get_builder(dry=True) - sql = builder.truncate(foreign_keys=True) - sql_ref = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(sql, sql_ref) + # ------------------------------------------------------------------ + # LIMIT / OFFSET + # ------------------------------------------------------------------ - def test_shared_lock(self): - builder = self.get_builder(dry=True) - sql = builder.where("votes", ">=", 100).shared_lock().to_sql() - sql_ref = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(sql, sql_ref) - - def test_update_lock(self): - builder = self.get_builder(dry=True) - sql = builder.where("votes", ">=", 100).lock_for_update().to_sql() - sql_ref = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(sql, sql_ref) - - -class MySQLQueryBuilderTest(BaseTestQueryBuilder, unittest.TestCase): - grammar = MySQLGrammar - - def sum(self): - """ - builder = self.get_builder() - builder.sum('age') - """ - return "SELECT SUM(`users`.`age`) AS age FROM `users`" - - def sum_chained(self): - """ - builder = self.get_builder() - builder.sum('age') - """ - return "SELECT SUM(`users`.`age`) AS age, MAX(`users`.`salary`) AS salary FROM `users`" - - def with_(self): - """ - builder = self.get_builder() - builder.with_('articles').sum('age') - """ - return "SELECT SUM(`users`.`age`) AS age FROM `users`" - - def max(self): - """ - builder = self.get_builder() - builder.max('age') - """ - return "SELECT MAX(`users`.`age`) AS age FROM `users`" - - def min(self): - """ - builder = self.get_builder() - builder.min('age') - """ - return "SELECT MIN(`users`.`age`) AS age FROM `users`" - - def avg(self): - """ - builder = self.get_builder() - builder.avg('age') - """ - return "SELECT AVG(`users`.`age`) AS age FROM `users`" - - def first(self): - """ - builder = self.get_builder() - builder.first() - """ - return "SELECT * FROM `users` LIMIT 1" - - def all(self): - """ - builder = self.get_builder() - builder.all() - """ - return "SELECT * FROM `users`" - - def get(self): - """ - builder = self.get_builder() - builder.get() - """ - return "SELECT * FROM `users`" - - def select(self): - """ + def test_limit(self): builder = self.get_builder() - builder.select('name', 'email') - """ - return "SELECT `users`.`name`, `users`.`email` FROM `users`" + builder.limit(5) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` LIMIT 5" + self.assertEqual(query_sql, expected_sql) - def select_with_table(self): - """ + def test_offset(self): builder = self.get_builder() - builder.select('users.*') - """ - return "SELECT `users`.* FROM `users`" + builder.offset(5) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` OFFSET 5" + self.assertEqual(query_sql, expected_sql) - def select_with_table_raw(self): - """ - builder = self.get_builder() - builder.select('users.*') - """ - return "SELECT `users`.* FROM orders, customers" + # ------------------------------------------------------------------ + # ORDER BY / GROUP BY + # ------------------------------------------------------------------ - def select_with_alias(self): - """ + def test_order_by_asc(self): builder = self.get_builder() - builder.select('users.name as name') - """ - return "SELECT `users`.`username` AS name FROM `users`" + builder.order_by("email", "asc") + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` ORDER BY `email` ASC" + self.assertEqual(query_sql, expected_sql) - def select_raw(self): - """ + def test_order_by_desc(self): builder = self.get_builder() - builder.select_raw('count(email) as email_count') - """ - return "SELECT count(email) as email_count FROM `users`" + builder.order_by("email", "desc") + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` ORDER BY `email` DESC" + self.assertEqual(query_sql, expected_sql) - def add_select(self): - """ + def test_latest(self): builder = self.get_builder() - builder.select('name', 'email') - """ - return "SELECT `users`.`name`, (SELECT COUNT(*) AS m_count_reserved FROM `phones`) AS phone_count, (SELECT COUNT(*) AS m_count_reserved FROM `salary`) AS salary FROM `users`" + builder.latest("email") + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` ORDER BY `email` DESC" + self.assertEqual(query_sql, expected_sql) - def add_select_no_table(self): - """ + def test_oldest(self): builder = self.get_builder() - builder.select('name', 'email') - """ - return ( - "SELECT " - "(SELECT MAX(`different_table`.`updated_at`) AS updated_at FROM `different_table`) AS other_test, " - "(SELECT MAX(`another_table`.`updated_at`) AS updated_at FROM `another_table`) AS some_alias" - ) - - def create(self): - """ - builder = get_builder() - builder.create({"name": "Corentin All", 'email': 'corentin@yopmail.com'}) - """ - return "INSERT INTO `users` (`users`.`name`, `users`.`email`) VALUES ('Corentin All', 'corentin@yopmail.com')" - - def delete(self): - """ - builder = get_builder() - builder.delete("name', 'Joe') - """ - return "DELETE FROM `users` WHERE `users`.`name` = 'Joe'" - - def where(self): - """ - builder = get_builder() - builder.where('name', 'Joe') - """ - return "SELECT * FROM `users` WHERE `users`.`name` = 'Joe'" - - def where_exists(self): - """ - builder = get_builder() - builder.where_exists('name') - """ - return "SELECT * FROM `users` WHERE EXISTS 'name'" - - def limit(self): - """ - builder = get_builder() - builder.limit(5) - """ - return "SELECT * FROM `users` LIMIT 5" - - def offset(self): - """ - builder = get_builder() - builder.offset(5) - """ - return "SELECT * FROM `users` OFFSET 5" - - def join(self): - """ - builder.join("profiles", "users.id", "=", "profiles.user_id") - """ - return "SELECT * FROM `users` INNER JOIN `profiles` ON `users`.`id` = `profiles`.`user_id`" - - def left_join(self): - """ - builder.left_join("profiles", "users.id", "=", "profiles.user_id") - """ - return "SELECT * FROM `users` LEFT JOIN `profiles` ON `users`.`id` = `profiles`.`user_id`" - - def right_join(self): - """ - builder.right_join("profiles", "users.id", "=", "profiles.user_id") - """ - return "SELECT * FROM `users` RIGHT JOIN `profiles` ON `users`.`id` = `profiles`.`user_id`" - - def update(self): - """ - builder.update({"name": "Joe", "email": "joe@yopmail.com"}) - """ - return "UPDATE `users` SET `users`.`name` = 'Joe', `users`.`email` = 'joe@yopmail.com'" - - def increment(self): - """ - builder.increment('age', 1) - """ - return "UPDATE `users` SET `users`.`age` = `users`.`age` + '1'" - - def decrement(self): - """ - builder.decrement('age', 1) - """ - return "UPDATE `users` SET `users`.`age` = `users`.`age` - '1'" - - def count(self): - """ - builder.count(id) - """ - return "SELECT COUNT(`users`.`id`) AS id FROM `users`" - - def order_by_asc(self): - """ - builder.order_by('email', 'asc') - """ - return "SELECT * FROM `users` ORDER BY `email` ASC" - - def order_by_desc(self): - """ - builder.order_by('email', 'des') - """ - return "SELECT * FROM `users` ORDER BY `email` DESC" - - def where_column(self): - """ - builder.where_column('name', 'username') - """ - return ( - "SELECT * FROM `users` WHERE `users`.`name` = `users`.`username`" - ) + builder.oldest("email") + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` ORDER BY `email` ASC" + self.assertEqual(query_sql, expected_sql) - def where_null(self): - """ - builder.where_null('name') - """ - return "SELECT * FROM `users` WHERE `users`.`name` IS NULL" - - def where_not_null(self): - """ - builder.where_null('name') - """ - return "SELECT * FROM `users` WHERE `users`.`name` IS NOT NULL" - - def where_not_in(self): - """ - builder.where_not_in('id', [1, 2, 3]) - """ - return "SELECT * FROM `users` WHERE `users`.`id` NOT IN ('1','2','3')" - - def where_in(self): - """ - builder.where_in('id', [1, 2, 3]) - """ - return "SELECT * FROM `users` WHERE `users`.`id` IN ('1','2','3')" - - def between(self): - """ - builder.between('id', 2, 5) - """ - return "SELECT * FROM `users` WHERE `users`.`id` BETWEEN '2' AND '5'" - - def not_between(self): - """ - builder.not_between('id', 2, 5) - """ - return ( - "SELECT * FROM `users` WHERE `users`.`id` NOT BETWEEN '2' AND '5'" + def test_group_by(self): + builder = self.get_builder(table="payments") + builder.select("user_id").min("salary").group_by("user_id") + query_sql = builder.to_sql() + expected_sql = ( + "SELECT `payments`.`user_id`, MIN(`payments`.`salary`) AS salary" + " FROM `payments` GROUP BY `payments`.`user_id`" ) + self.assertEqual(query_sql, expected_sql) - def having(self): - """ - builder.select('user_id').avg('salary').group_by('user_id').having('salary', '>=', '1000') - """ - return "SELECT `payments`.`user_id`, AVG(`payments`.`salary`) AS salary FROM `payments` GROUP BY `payments`.`user_id` HAVING `payments`.`salary` >= '1000'" - - def group_by(self): - """ - builder.select('user_id').min('salary').group_by('user_id') - """ - return "SELECT `payments`.`user_id`, MIN(`payments`.`salary`) AS salary FROM `payments` GROUP BY `payments`.`user_id`" + # ------------------------------------------------------------------ + # JOINs + # ------------------------------------------------------------------ - def where_lt(self): - """ + def test_join(self): builder = self.get_builder() - builder.where('age', '<', '20') - """ - return "SELECT * FROM `users` WHERE `users`.`age` < '20'" + builder.join("profiles", "users.id", "=", "profiles.user_id") + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` INNER JOIN `profiles` ON `users`.`id` = `profiles`.`user_id`" + self.assertEqual(query_sql, expected_sql) - def where_lte(self): - """ + def test_left_join(self): builder = self.get_builder() - builder.where('age', '<=', '20') - """ - return "SELECT * FROM `users` WHERE `users`.`age` <= '20'" + builder.left_join("profiles", "users.id", "=", "profiles.user_id") + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` LEFT JOIN `profiles` ON `users`.`id` = `profiles`.`user_id`" + self.assertEqual(query_sql, expected_sql) - def where_gt(self): - """ + def test_right_join(self): builder = self.get_builder() - builder.where('age', '>', '20') - """ - return "SELECT * FROM `users` WHERE `users`.`age` > '20'" + builder.right_join("profiles", "users.id", "=", "profiles.user_id") + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM `users` RIGHT JOIN `profiles` ON `users`.`id` = `profiles`.`user_id`" + self.assertEqual(query_sql, expected_sql) - def where_gte(self): - """ - builder = self.get_builder() - builder.where('age', '>=', '20') - """ - return "SELECT * FROM `users` WHERE `users`.`age` >= '20'" + # ------------------------------------------------------------------ + # DML + # ------------------------------------------------------------------ - def where_ne(self): - """ - builder = self.get_builder() - builder.where('age', '!=', '20') - """ - return "SELECT * FROM `users` WHERE `users`.`age` != '20'" + def test_create(self): + builder = self.get_builder().without_global_scopes() + builder.create( + {"name": "Corentin All", "email": "corentin@yopmail.com"}, + query=True, + ) + query_sql = builder.to_sql() + expected_sql = "INSERT INTO `users` (`users`.`name`, `users`.`email`) VALUES ('Corentin All', 'corentin@yopmail.com')" + self.assertEqual(query_sql, expected_sql) - def or_where(self): - """ + def test_delete(self): builder = self.get_builder() - builder.where('age', '20').or_where('age','<', 20) - """ - return "SELECT * FROM `users` WHERE `users`.`age` = '20' OR `users`.`age` < '20'" + builder.delete("name", "Joe", query=True) + query_sql = builder.to_sql() + expected_sql = "DELETE FROM `users` WHERE `users`.`name` = 'Joe'" + self.assertEqual(query_sql, expected_sql) - def where_like(self): - """ - builder = self.get_builder() - builder.where("age", "like", "%name%") - """ - return "SELECT * FROM `users` WHERE `users`.`age` LIKE '%name%'" + def test_update(self): + builder = self.get_builder().update( + {"name": "Joe", "email": "joe@yopmail.com"}, dry=True + ) + query_sql = builder.to_sql() + expected_sql = "UPDATE `users` SET `users`.`name` = 'Joe', `users`.`email` = 'joe@yopmail.com'" + self.assertEqual(query_sql, expected_sql) - 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%'" + # ------------------------------------------------------------------ + # TRUNCATE + # ------------------------------------------------------------------ - def truncate(self): - """ - builder = self.get_builder() - builder.truncate() - """ - return """TRUNCATE TABLE `users`""" + def test_truncate(self): + builder = self.get_builder(dry=True) + query_sql = builder.truncate() + expected_sql = "TRUNCATE TABLE `users`" + self.assertEqual(query_sql, expected_sql) - def truncate_without_foreign_keys(self): - """ - builder = self.get_builder() - builder.truncate() - """ - return [ + def test_truncate_without_foreign_keys(self): + builder = self.get_builder(dry=True) + query_sql = builder.truncate(foreign_keys=True) + expected_sql = [ "SET FOREIGN_KEY_CHECKS=0", "TRUNCATE TABLE `users`", "SET FOREIGN_KEY_CHECKS=1", ] + self.assertEqual(query_sql, expected_sql) - def shared_lock(self): - """ - builder = self.get_builder() - builder.truncate() - """ - return "SELECT * FROM `users` WHERE `users`.`votes` >= '100' LOCK IN SHARE MODE" + # ------------------------------------------------------------------ + # Locking + # ------------------------------------------------------------------ - def update_lock(self): - """ - builder = self.get_builder() - builder.truncate() - """ - return ( + def test_shared_lock(self): + builder = self.get_builder(dry=True) + query_sql = builder.where("votes", ">=", 100).shared_lock().to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`votes` >= '100' LOCK IN SHARE MODE" + self.assertEqual(query_sql, expected_sql) + + def test_update_lock(self): + builder = self.get_builder(dry=True) + query_sql = ( + builder.where("votes", ">=", 100).lock_for_update().to_sql() + ) + expected_sql = ( "SELECT * FROM `users` WHERE `users`.`votes` >= '100' FOR UPDATE" ) + self.assertEqual(query_sql, expected_sql) - 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) + # ------------------------------------------------------------------ + # Misc + # ------------------------------------------------------------------ - def test_oldest(self): + def test_builder_alone(self): + self.assertTrue( + QueryBuilder( + dry=True, + connection_details={ + "default": "mysql", + "mysql": { + "driver": "mysql", + "host": "localhost", + "username": "root", + "password": "", + "database": "orm", + "port": "3306", + "prefix": "", + "grammar": "mysql", + "options": {"charset": "utf8mb4"}, + }, + }, + ).table("users") + ) + + def test_can_call_with_multi_tables(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" + query_sql = ( + builder.table("information_schema.columns") + .select("table_name") + .where("table_name", "users") + .to_sql() + ) + expected_sql = ( + "SELECT `information_schema`.`columns`.`table_name` FROM `information_schema`.`columns`" + " WHERE `information_schema`.`columns`.`table_name` = 'users'" + ) + self.assertEqual(query_sql, expected_sql) diff --git a/tests/mysql/builder/test_query_builder_scopes.py b/tests/mysql/builder/test_query_builder_scopes.py index 100cc6a33..f98bd103a 100644 --- a/tests/mysql/builder/test_query_builder_scopes.py +++ b/tests/mysql/builder/test_query_builder_scopes.py @@ -25,10 +25,9 @@ def test_scopes(self): "gender", lambda model, q: q.where("gender", "w") ) - self.assertEqual( - builder.gender().where("id", 1).to_sql(), - "SELECT * FROM `users` WHERE `users`.`gender` = 'w' AND `users`.`id` = '1'", - ) + query_sql = builder.gender().where("id", 1).to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`gender` = 'w' AND `users`.`id` = '1'" + self.assertEqual(query_sql, expected_sql) def test_global_scopes(self): builder = self.get_builder().set_global_scope( @@ -37,18 +36,16 @@ def test_global_scopes(self): action="select", ) - self.assertEqual( - builder.where("id", 1).to_sql(), - "SELECT * FROM `users` WHERE `users`.`id` = '1' AND `users`.`deleted_at` IS NOT NULL", - ) + query_sql = builder.where("id", 1).to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`id` = '1' AND `users`.`deleted_at` IS NOT NULL" + self.assertEqual(query_sql, expected_sql) def test_global_scope_from_class(self): builder = self.get_builder().set_global_scope(SoftDeleteScope()) - self.assertEqual( - builder.where("id", 1).to_sql(), - "SELECT * FROM `users` WHERE `users`.`id` = '1' AND `users`.`deleted_at` IS NULL", - ) + query_sql = builder.where("id", 1).to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`id` = '1' AND `users`.`deleted_at` IS NULL" + self.assertEqual(query_sql, expected_sql) def test_global_scope_remove_from_class(self): builder = ( @@ -57,14 +54,13 @@ def test_global_scope_remove_from_class(self): .remove_global_scope(SoftDeleteScope()) ) - self.assertEqual( - builder.where("id", 1).to_sql(), - "SELECT * FROM `users` WHERE `users`.`id` = '1'", - ) + query_sql = builder.where("id", 1).to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`id` = '1'" + self.assertEqual(query_sql, expected_sql) def test_global_scope_adds_method(self): builder = self.get_builder().set_global_scope(SoftDeleteScope()) - self.assertEqual( - builder.with_trashed().to_sql(), "SELECT * FROM `users`" - ) + query_sql = builder.with_trashed().to_sql() + expected_sql = "SELECT * FROM `users`" + self.assertEqual(query_sql, expected_sql) diff --git a/tests/mysql/connections/test_mysql_connection_selects.py b/tests/mysql/connections/test_mysql_connection_selects.py index acb09e50e..3ab3a081f 100644 --- a/tests/mysql/connections/test_mysql_connection_selects.py +++ b/tests/mysql/connections/test_mysql_connection_selects.py @@ -17,10 +17,10 @@ def setUp(self): self.builder = QueryBuilder(MySQLGrammar, table="users") def test_can_compile_select(self): - to_sql = MockUser.where("id", 1).to_sql() + query_sql = MockUser.where("id", 1).to_sql() - sql = "SELECT * FROM `users` WHERE `users`.`id` = '1'" - self.assertEqual(to_sql, sql) + expected_sql = "SELECT * FROM `users` WHERE `users`.`id` = '1'" + self.assertEqual(query_sql, expected_sql) def test_can_get_first_record(self): user = MockUser.where("id", 1).first() diff --git a/tests/mysql/grammar/test_mysql_delete_grammar.py b/tests/mysql/grammar/test_mysql_delete_grammar.py index c17acee73..37806d174 100644 --- a/tests/mysql/grammar/test_mysql_delete_grammar.py +++ b/tests/mysql/grammar/test_mysql_delete_grammar.py @@ -1,79 +1,32 @@ -import inspect import unittest from src.masoniteorm.query import QueryBuilder from src.masoniteorm.query.grammars import MySQLGrammar -class BaseDeleteGrammarTest: +class TestMySQLDeleteGrammar(unittest.TestCase): def setUp(self): self.builder = QueryBuilder(MySQLGrammar, table="users") def test_can_compile_delete(self): - to_sql = self.builder.delete("id", 1, query=True).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + query_sql = self.builder.delete("id", 1, query=True).to_sql() + expected_sql = "DELETE FROM `users` WHERE `users`.`id` = '1'" + self.assertEqual(query_sql, expected_sql) def test_can_compile_delete_in(self): - to_sql = self.builder.delete("id", [1, 2, 3], query=True).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + query_sql = self.builder.delete("id", [1, 2, 3], query=True).to_sql() + expected_sql = ( + "DELETE FROM `users` WHERE `users`.`id` IN ('1','2','3')" + ) + self.assertEqual(query_sql, expected_sql) def test_can_compile_delete_with_where(self): - to_sql = ( + query_sql = ( self.builder.where("age", 20) .where("profile", 1) .set_action("delete") .delete(query=True) .to_sql() ) - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) - - -class TestMySQLDeleteGrammar(BaseDeleteGrammarTest, unittest.TestCase): - grammar = "mysql" - - def can_compile_delete(self): - """ - ( - self.builder - .delete('id', 1) - .to_sql() - ) - """ - return "DELETE FROM `users` WHERE `users`.`id` = '1'" - - def can_compile_delete_in(self): - """ - ( - self.builder - .delete('id', 1) - .to_sql() - ) - """ - return "DELETE FROM `users` WHERE `users`.`id` IN ('1','2','3')" - - def can_compile_delete_with_where(self): - """ - ( - self.builder - .where('age', 20) - .where('profile', 1) - .set_action('delete') - .delete() - .to_sql() - ) - """ - return ( - "DELETE FROM `users` WHERE `users`.`age` = '20' AND `users`.`profile` = '1'" - ) + expected_sql = "DELETE FROM `users` WHERE `users`.`age` = '20' AND `users`.`profile` = '1'" + self.assertEqual(query_sql, expected_sql) diff --git a/tests/mysql/grammar/test_mysql_insert_grammar.py b/tests/mysql/grammar/test_mysql_insert_grammar.py index 0089ba2c2..49311a03c 100644 --- a/tests/mysql/grammar/test_mysql_insert_grammar.py +++ b/tests/mysql/grammar/test_mysql_insert_grammar.py @@ -1,33 +1,26 @@ -import inspect import unittest from src.masoniteorm.query import QueryBuilder from src.masoniteorm.query.grammars import MySQLGrammar -class BaseInsertGrammarTest: +class TestMySQLInsertGrammar(unittest.TestCase): def setUp(self): self.builder = QueryBuilder(MySQLGrammar, table="users") def test_can_compile_insert(self): - to_sql = self.builder.create({"name": "Joe"}, query=True).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + query_sql = self.builder.create({"name": "Joe"}, query=True).to_sql() + expected_sql = "INSERT INTO `users` (`users`.`name`) VALUES ('Joe')" + self.assertEqual(query_sql, expected_sql) def test_can_compile_insert_with_keywords(self): - to_sql = self.builder.create(name="Joe", query=True).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + query_sql = self.builder.create(name="Joe", query=True).to_sql() + expected_sql = "INSERT INTO `users` (`users`.`name`) VALUES ('Joe')" + self.assertEqual(query_sql, expected_sql) def test_can_compile_bulk_create(self): - to_sql = self.builder.bulk_create( - # These keys are intentionally out of order to show column to value alignment works + # Keys are intentionally out of order to verify column-to-value alignment + query_sql = self.builder.bulk_create( [ {"name": "Joe", "age": 5}, {"age": 35, "name": "Bill"}, @@ -35,24 +28,11 @@ def test_can_compile_bulk_create(self): ], query=True, ).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) - - def test_can_compile_bulk_create_qmark(self): - to_sql = self.builder.bulk_create( - [{"name": "Joe"}, {"name": "Bill"}, {"name": "John"}], query=True - ).to_qmark() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + expected_sql = "INSERT INTO `users` (`age`, `name`) VALUES ('5', 'Joe'), ('35', 'Bill'), ('10', 'John')" + self.assertEqual(query_sql, expected_sql) def test_can_compile_bulk_create_multiple(self): - to_sql = self.builder.bulk_create( + query_sql = self.builder.bulk_create( [ {"name": "Joe", "active": "1"}, {"name": "Bill", "active": "1"}, @@ -60,44 +40,12 @@ def test_can_compile_bulk_create_multiple(self): ], query=True, ).to_sql() + expected_sql = "INSERT INTO `users` (`active`, `name`) VALUES ('1', 'Joe'), ('1', 'Bill'), ('1', 'John')" + self.assertEqual(query_sql, expected_sql) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) - - -class TestMySQLUpdateGrammar(BaseInsertGrammarTest, unittest.TestCase): - grammar = "mysql" - - def can_compile_insert(self): - """ - self.builder.create({ - 'name': 'Joe' - }).to_sql() - """ - return "INSERT INTO `users` (`users`.`name`) VALUES ('Joe')" - - def can_compile_insert_with_keywords(self): - """ - self.builder.create(name="Joe").to_sql() - """ - return "INSERT INTO `users` (`users`.`name`) VALUES ('Joe')" - - def can_compile_bulk_create(self): - """ - self.builder.create(name="Joe").to_sql() - """ - return """INSERT INTO `users` (`age`, `name`) VALUES ('5', 'Joe'), ('35', 'Bill'), ('10', 'John')""" - - def can_compile_bulk_create_multiple(self): - """ - self.builder.create(name="Joe").to_sql() - """ - return """INSERT INTO `users` (`active`, `name`) VALUES ('1', 'Joe'), ('1', 'Bill'), ('1', 'John')""" - - def can_compile_bulk_create_qmark(self): - """ - self.builder.create(name="Joe").to_sql() - """ - return """INSERT INTO `users` (`name`) VALUES (?), (?), (?)""" + def test_can_compile_bulk_create_qmark(self): + query_sql = self.builder.bulk_create( + [{"name": "Joe"}, {"name": "Bill"}, {"name": "John"}], query=True + ).to_qmark() + expected_sql = "INSERT INTO `users` (`name`) VALUES (?), (?), (?)" + self.assertEqual(query_sql, expected_sql) diff --git a/tests/mysql/grammar/test_mysql_qmark.py b/tests/mysql/grammar/test_mysql_qmark.py index f276101d0..d12591ef2 100644 --- a/tests/mysql/grammar/test_mysql_qmark.py +++ b/tests/mysql/grammar/test_mysql_qmark.py @@ -1,203 +1,96 @@ -import inspect import unittest from src.masoniteorm.query import QueryBuilder from src.masoniteorm.query.grammars import MySQLGrammar -class BaseQMarkTest: +class TestMySQLQmark(unittest.TestCase): def setUp(self): self.builder = QueryBuilder(grammar=MySQLGrammar, table="users") def test_can_compile_select(self): mark = self.builder.select("username").where("name", "Joe") - - sql, bindings = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(mark.to_qmark(), sql) - self.assertEqual(mark._bindings, bindings) + query_sql = mark.to_qmark() + expected_sql = ( + "SELECT `users`.`username` FROM `users` WHERE `users`.`name` = ?" + ) + self.assertEqual(query_sql, expected_sql) + self.assertEqual(mark._bindings, ["Joe"]) def test_can_compile_delete(self): mark = self.builder.where("name", "Joe").delete(query=True) - - sql, bindings = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(mark.to_qmark(), sql) - self.assertEqual(mark._bindings, bindings) + query_sql = mark.to_qmark() + expected_sql = "DELETE FROM `users` WHERE `users`.`name` = ?" + self.assertEqual(query_sql, expected_sql) + self.assertEqual(mark._bindings, ["Joe"]) def test_can_compile_update(self): - mark = self.builder.update({"name": "Bob"}, dry=True).where("name", "Joe") - - sql, bindings = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(mark.to_qmark(), sql) - self.assertEqual(mark._bindings, bindings) + mark = self.builder.update({"name": "Bob"}, dry=True).where( + "name", "Joe" + ) + query_sql = mark.to_qmark() + expected_sql = ( + "UPDATE `users` SET `users`.`name` = ? WHERE `users`.`name` = ?" + ) + self.assertEqual(query_sql, expected_sql) + self.assertEqual(mark._bindings, ["Bob", "Joe"]) def test_can_compile_where_in(self): mark = self.builder.where_in("id", [1, 2, 3]) - - sql, bindings = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(mark.to_qmark(), sql) - self.assertEqual(mark._bindings, bindings) + query_sql = mark.to_qmark() + expected_sql = "SELECT * FROM `users` WHERE `users`.`id` IN (?, ?, ?)" + self.assertEqual(query_sql, expected_sql) + self.assertEqual(mark._bindings, [1, 2, 3]) def test_can_compile_where_not_null(self): mark = self.builder.where_not_null("id") - - sql, bindings = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(mark.to_qmark(), sql) + query_sql = mark.to_qmark() + expected_sql = "SELECT * FROM `users` WHERE `users`.`id` IS NOT NULL" + self.assertEqual(query_sql, expected_sql) self.assertEqual(mark._bindings, []) def test_can_compile_where_with_falsy_values(self): mark = self.builder.where("name", 0) - - sql, bindings = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(mark.to_qmark(), sql) - self.assertEqual(mark._bindings, bindings) + query_sql = mark.to_qmark() + expected_sql = "SELECT * FROM `users` WHERE `users`.`name` = ?" + self.assertEqual(query_sql, expected_sql) + self.assertEqual(mark._bindings, [0]) def test_can_compile_where_with_true_value(self): mark = self.builder.where("is_admin", True) - - sql, bindings = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(mark.to_qmark(), sql) - self.assertEqual(mark._bindings, bindings) + query_sql = mark.to_qmark() + expected_sql = "SELECT * FROM `users` WHERE `users`.`is_admin` = '1'" + self.assertEqual(query_sql, expected_sql) + self.assertEqual(mark._bindings, []) def test_can_compile_where_with_false_value(self): mark = self.builder.where("is_admin", False) - - sql, bindings = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(mark.to_qmark(), sql) - self.assertEqual(mark._bindings, bindings) + query_sql = mark.to_qmark() + expected_sql = "SELECT * FROM `users` WHERE `users`.`is_admin` = '0'" + self.assertEqual(query_sql, expected_sql) + self.assertEqual(mark._bindings, []) def test_can_compile_sub_group_bindings(self): mark = self.builder.where( - lambda query: ( - query.where("challenger", 1) - .or_where("proposer", 1) - .or_where("referee", 1) - ) + lambda query: query.where("challenger", 1) + .or_where("proposer", 1) + .or_where("referee", 1) ) - - sql, bindings = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(mark.to_qmark(), sql) - self.assertEqual(mark._bindings, bindings) + query_sql = mark.to_qmark() + expected_sql = "SELECT * FROM `users` WHERE (`users`.`challenger` = ? OR `users`.`proposer` = ? OR `users`.`referee` = ?)" + self.assertEqual(query_sql, expected_sql) + self.assertEqual(mark._bindings, [1, 1, 1]) def test_can_increment(self): builder = self.builder.increment("age", dry=True) - sql, bindings = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - - self.assertEqual(builder.to_qmark(), sql) - self.assertEqual(builder._bindings, bindings) + query_sql = builder.to_qmark() + expected_sql = "UPDATE `users` SET `users`.`age` = `users`.`age` + ?" + self.assertEqual(query_sql, expected_sql) + self.assertEqual(builder._bindings, [1]) def test_can_decrement(self): builder = self.builder.decrement("age", dry=True) - sql, bindings = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - - self.assertEqual(builder.to_qmark(), sql) - self.assertEqual(builder._bindings, bindings) - - -class TestMySQLQmark(BaseQMarkTest, unittest.TestCase): - def can_compile_select(self): - """ - self.builder.select('username').where('name', 'Joe') - """ - return ( - "SELECT `users`.`username` FROM `users` WHERE `users`.`name` = ?", - ["Joe"], - ) - - def can_compile_delete(self): - """ - self.builder.where('name', 'Joe').delete() - """ - return "DELETE FROM `users` WHERE `users`.`name` = ?", ["Joe"] - - def can_compile_update(self): - """ - self.builder.update({ - 'name': 'Bob' - }).where('name', 'Joe') - """ - return ( - "UPDATE `users` SET `users`.`name` = ? WHERE `users`.`name` = ?", - ["Bob", "Joe"], - ) - - def can_compile_where_in(self): - """ - self.builder.where_in('id', [1,2,3]).to_qmark() - """ - return ( - "SELECT * FROM `users` WHERE `users`.`id` IN (?, ?, ?)", - [1, 2, 3], - ) - - def can_compile_where_not_null(self): - """ - self.builder.where_not_null("id").to_qmark() - """ - return ("SELECT * FROM `users` WHERE `users`.`id` IS NOT NULL", ()) - - def can_compile_where_with_falsy_values(self): - """ - self.builder.where_not_null("id").to_qmark() - """ - return ("SELECT * FROM `users` WHERE `users`.`name` = ?", [0]) - - def can_compile_where_with_true_value(self): - """ - self.builder.where("is_admin", True).to_qmark() - """ - return ("SELECT * FROM `users` WHERE `users`.`is_admin` = '1'", []) - - def can_compile_where_with_false_value(self): - """ - self.builder.where("is_admin", True).to_qmark() - """ - return ("SELECT * FROM `users` WHERE `users`.`is_admin` = '0'", []) - - def can_compile_sub_group_bindings(self): - """ - self.builder.where("is_admin", True).to_qmark() - """ - return ( - "SELECT * FROM `users` WHERE (`users`.`challenger` = ? OR `users`.`proposer` = ? OR `users`.`referee` = ?)", - [1, 1, 1], - ) - - def can_increment(self): - """ - self.builder.increment("age", dry=True) - """ - return ( - "UPDATE `users` SET `users`.`age` = `users`.`age` + ?", - [1], - ) - - def can_decrement(self): - """ - self.builder.decrement("age", dry=True) - """ - return ( - "UPDATE `users` SET `users`.`age` = `users`.`age` - ?", - [1], - ) + query_sql = builder.to_qmark() + expected_sql = "UPDATE `users` SET `users`.`age` = `users`.`age` - ?" + self.assertEqual(query_sql, expected_sql) + self.assertEqual(builder._bindings, [1]) diff --git a/tests/mysql/grammar/test_mysql_select_grammar.py b/tests/mysql/grammar/test_mysql_select_grammar.py index aa4d6b40e..276fc24db 100644 --- a/tests/mysql/grammar/test_mysql_select_grammar.py +++ b/tests/mysql/grammar/test_mysql_select_grammar.py @@ -1,497 +1,617 @@ import unittest +from src.masoniteorm.expressions import JoinClause +from src.masoniteorm.models import Model +from src.masoniteorm.query import QueryBuilder from src.masoniteorm.query.grammars import MySQLGrammar -from src.masoniteorm.testing import BaseTestCaseSelectGrammar - - -class TestMySQLGrammar(BaseTestCaseSelectGrammar, unittest.TestCase): - grammar = MySQLGrammar - - def can_compile_select(self): - """ - self.builder.to_sql() - """ - return "SELECT * FROM `users`" - - def can_compile_with_columns(self): - """ - self.builder.select('username', 'password').to_sql() - """ - return "SELECT `users`.`username`, `users`.`password` FROM `users`" - - def can_compile_order_by_and_first(self): - """ - self.builder.order_by('id', 'asc').first() - """ - return """SELECT * FROM `users` ORDER BY `id` ASC LIMIT 1""" - - def can_compile_with_where(self): - """ - self.builder.select('username', 'password').where('id', 1).to_sql() - """ - return "SELECT `users`.`username`, `users`.`password` FROM `users` WHERE `users`.`id` = '1'" - - def can_compile_with_several_where(self): - """ - self.builder.select('username', 'password').where('id', 1).where('username', 'joe').to_sql() - """ - return "SELECT `users`.`username`, `users`.`password` FROM `users` WHERE `users`.`id` = '1' AND `users`.`username` = 'joe'" - - def can_compile_with_several_where_and_limit(self): - """ - self.builder.select('username', 'password').where('id', 1).where('username', 'joe').limit(10).to_sql() - """ - return "SELECT `users`.`username`, `users`.`password` FROM `users` WHERE `users`.`id` = '1' AND `users`.`username` = 'joe' LIMIT 10" - - def can_compile_with_sum(self): - """ - self.builder.sum('age').to_sql() - """ - return "SELECT SUM(`users`.`age`) AS age FROM `users`" - - def can_compile_with_max(self): - """ - self.builder.max('age').to_sql() - """ - return "SELECT MAX(`users`.`age`) AS age FROM `users`" - - def can_compile_with_max_and_columns(self): - """ - self.builder.select('username').max('age').to_sql() - """ - return ( + + +class MockConnection: + connection_details = {} + + def make_connection(self): + return self + + +class TestMySQLSelectGrammar(unittest.TestCase): + """Tests for SQL SELECT compilation with the MySQL grammar. + + Each test is self-contained: it builds a query and asserts the expected + SQL string inline, with no separate data-provider class. + """ + + maxDiff = None + + def setUp(self): + self.builder = QueryBuilder( + MySQLGrammar, + table="users", + connection_class=MockConnection, + model=Model(), + dry=True, + ) + + # ------------------------------------------------------------------ + # Basic SELECT + # ------------------------------------------------------------------ + + def test_can_compile_select(self): + query_sql = self.builder.to_sql() + expected_sql = "SELECT * FROM `users`" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_columns(self): + query_sql = self.builder.select("username", "password").to_sql() + expected_sql = ( + "SELECT `users`.`username`, `users`.`password` FROM `users`" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_select_raw(self): + query_sql = self.builder.select_raw("COUNT(*)").to_sql() + expected_sql = "SELECT COUNT(*) FROM `users`" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_select_raw_with_select(self): + query_sql = self.builder.select("id").select_raw("COUNT(*)").to_sql() + expected_sql = "SELECT `users`.`id`, COUNT(*) FROM `users`" + self.assertEqual(query_sql, expected_sql) + + def test_select_distinct(self): + query_sql = self.builder.select("group").distinct().to_sql() + expected_sql = "SELECT DISTINCT `users`.`group` FROM `users`" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_count(self): + query_sql = self.builder.count("*").to_sql() + expected_sql = "SELECT COUNT(*) AS m_count_reserved FROM `users`" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_count_column(self): + query_sql = self.builder.count("money").to_sql() + expected_sql = "SELECT COUNT(`users`.`money`) AS money FROM `users`" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_sum(self): + query_sql = self.builder.sum("age").to_sql() + expected_sql = "SELECT SUM(`users`.`age`) AS age FROM `users`" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_max(self): + query_sql = self.builder.max("age").to_sql() + expected_sql = "SELECT MAX(`users`.`age`) AS age FROM `users`" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_max_and_columns(self): + query_sql = self.builder.select("username").max("age").to_sql() + expected_sql = ( "SELECT `users`.`username`, MAX(`users`.`age`) AS age FROM `users`" ) + self.assertEqual(query_sql, expected_sql) - def can_compile_with_max_and_columns_different_order(self): - """ - self.builder.max('age').select('username').to_sql() - """ - return ( + def test_can_compile_with_max_and_columns_different_order(self): + query_sql = self.builder.max("age").select("username").to_sql() + expected_sql = ( "SELECT `users`.`username`, MAX(`users`.`age`) AS age FROM `users`" ) + self.assertEqual(query_sql, expected_sql) - def can_compile_with_order_by(self): - """ - self.builder.select('username').order_by('age', 'desc').to_sql() - """ - return "SELECT `users`.`username` FROM `users` ORDER BY `age` DESC" - - def can_compile_with_multiple_order_by(self): - """ - self.builder.select('username').order_by('age', 'desc').order_by('name').to_sql() - """ - return "SELECT `users`.`username` FROM `users` ORDER BY `age` DESC, `name` ASC" - - def can_compile_with_group_by(self): - """ - self.builder.select('username').group_by('age').to_sql() - """ - return "SELECT `users`.`username` FROM `users` GROUP BY `users`.`age`" - - def can_compile_where_in(self): - """ - self.builder.select('username').where_in('age', [1,2,3]).to_sql() - """ - return "SELECT `users`.`username` FROM `users` WHERE `users`.`age` IN ('1','2','3')" - - def can_compile_where_in_empty(self): - """ - self.builder.where_in('age', []).to_sql() - """ - return """SELECT * FROM `users` WHERE 0 = 1""" - - def can_compile_where_not_in(self): - """ - self.builder.select('username').where_not_in('age', [1,2,3]).to_sql() - """ - return "SELECT `users`.`username` FROM `users` WHERE `users`.`age` NOT IN ('1','2','3')" - - def can_compile_where_null(self): - """ - self.builder.select('username').where_null('age').to_sql() - """ - return "SELECT `users`.`username` FROM `users` WHERE `users`.`age` IS NULL" - - def can_compile_where_not_null(self): - """ - self.builder.select('username').where_not_null('age').to_sql() - """ - return "SELECT `users`.`username` FROM `users` WHERE `users`.`age` IS NOT NULL" - - def can_compile_where_raw(self): - """ - self.builder.where_raw("`age` = '18'").to_sql() - """ - return "SELECT * FROM `users` WHERE `users`.`age` = '18'" - - def can_compile_where_raw_and_where_with_multiple_bindings(self): - """ - self.builder.where_raw("`age` = ? AND `is_admin` = ?", [18, True]).where("email", "test@example.com") - """ - return "SELECT * FROM `users` WHERE `age` = ? AND `is_admin` = ? AND `users`.`email` = ?" - - def can_compile_having_raw(self): - """ - self.builder.select_raw("COUNT(*) as counts").having_raw("counts > 18").to_sql() - """ - return "SELECT COUNT(*) as counts FROM `users` HAVING counts > 18" - - def can_compile_select_raw(self): - """ - self.builder.select_raw("COUNT(*)").to_sql() - """ - return "SELECT COUNT(*) FROM `users`" - - def can_compile_limit_and_offset(self): - """ - self.builder.limit(10).offset(10).to_sql() - """ - return "SELECT * FROM `users` LIMIT 10 OFFSET 10" - - def can_compile_select_raw_with_select(self): - """ - self.builder.select('id').select_raw("COUNT(*)").to_sql() - """ - return "SELECT `users`.`id`, COUNT(*) FROM `users`" - - def can_compile_count(self): - """ - self.builder.count().to_sql() - """ - - return "SELECT COUNT(*) AS m_count_reserved FROM `users`" - - def can_compile_count_column(self): - """ - self.builder.count().to_sql() - """ - - return "SELECT COUNT(`users`.`money`) AS money FROM `users`" - - def can_compile_where_column(self): - """ - self.builder.where_column('name', 'email').to_sql() - """ - - return "SELECT * FROM `users` WHERE `users`.`name` = `users`.`email`" - - def can_compile_or_where(self): - """ - self.builder.where('name', 2).or_where('name', 3).to_sql() - """ - return "SELECT * FROM `users` WHERE `users`.`name` = '2' OR `users`.`name` = '3'" - - def can_grouped_where(self): - """ - self.builder.where(lambda query: query.where('age', 2).where('name', 'Joe')).to_sql() - """ - return "SELECT * FROM `users` WHERE (`users`.`age` = '2' AND `users`.`name` = 'Joe')" - - def can_compile_sub_select(self): - """ - self.builder.where_in('name', - QueryBuilder(GrammarFactory.make(self.grammar), table='users').select('age') - ).to_sql() - """ + # ------------------------------------------------------------------ + # ORDER BY / GROUP BY / LIMIT / OFFSET + # ------------------------------------------------------------------ - return "SELECT * FROM `users` WHERE `users`.`name` IN (SELECT `users`.`age` FROM `users`)" + def test_can_compile_order_by_and_first(self): + query_sql = ( + self.builder.order_by("id", "asc").first(query=True).to_sql() + ) + expected_sql = "SELECT * FROM `users` ORDER BY `id` ASC LIMIT 1" + self.assertEqual(query_sql, expected_sql) - def can_compile_sub_select_where(self): - """ - self.builder.where_in('age', - QueryBuilder(GrammarFactory.make(self.grammar), table='users').select('age').where('age', 2).where('name', 'Joe') - ).to_sql() - """ + def test_can_compile_with_order_by(self): + query_sql = ( + self.builder.select("username").order_by("age", "desc").to_sql() + ) + expected_sql = ( + "SELECT `users`.`username` FROM `users` ORDER BY `age` DESC" + ) + self.assertEqual(query_sql, expected_sql) - return "SELECT * FROM `users` WHERE `users`.`age` IN (SELECT `users`.`age` FROM `users` WHERE `users`.`age` = '2' AND `users`.`name` = 'Joe')" + def test_can_compile_with_multiple_order_by(self): + query_sql = ( + self.builder.select("username") + .order_by("age", "desc") + .order_by("name") + .to_sql() + ) + expected_sql = "SELECT `users`.`username` FROM `users` ORDER BY `age` DESC, `name` ASC" + self.assertEqual(query_sql, expected_sql) - def can_compile_sub_select_value(self): - """ - self.builder.where('name', - self.builder.new().sum('age') + def test_can_compile_with_group_by(self): + query_sql = self.builder.select("username").group_by("age").to_sql() + expected_sql = ( + "SELECT `users`.`username` FROM `users` GROUP BY `users`.`age`" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_limit_and_offset(self): + query_sql = self.builder.limit(10).offset(10).to_sql() + expected_sql = "SELECT * FROM `users` LIMIT 10 OFFSET 10" + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # WHERE clauses + # ------------------------------------------------------------------ + + def test_can_compile_with_where(self): + query_sql = ( + self.builder.select("username", "password").where("id", 1).to_sql() + ) + expected_sql = "SELECT `users`.`username`, `users`.`password` FROM `users` WHERE `users`.`id` = '1'" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_several_where(self): + query_sql = ( + self.builder.select("username", "password") + .where("id", 1) + .where("username", "joe") + .to_sql() + ) + expected_sql = ( + "SELECT `users`.`username`, `users`.`password` FROM `users`" + " WHERE `users`.`id` = '1' AND `users`.`username` = 'joe'" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_several_where_and_limit(self): + query_sql = ( + self.builder.select("username", "password") + .where("id", 1) + .where("username", "joe") + .limit(10) + .to_sql() + ) + expected_sql = ( + "SELECT `users`.`username`, `users`.`password` FROM `users`" + " WHERE `users`.`id` = '1' AND `users`.`username` = 'joe' LIMIT 10" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_or_where(self): + query_sql = self.builder.where("name", 2).or_where("name", 3).to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`name` = '2' OR `users`.`name` = '3'" + self.assertEqual(query_sql, expected_sql) + + def test_can_grouped_where(self): + query_sql = self.builder.where( + lambda q: q.where("age", 2).where("name", "Joe") ).to_sql() - """ + expected_sql = "SELECT * FROM `users` WHERE (`users`.`age` = '2' AND `users`.`name` = 'Joe')" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_in(self): + query_sql = ( + self.builder.select("username").where_in("age", [1, 2, 3]).to_sql() + ) + expected_sql = "SELECT `users`.`username` FROM `users` WHERE `users`.`age` IN ('1','2','3')" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_in_empty(self): + query_sql = self.builder.where_in("age", []).to_sql() + expected_sql = "SELECT * FROM `users` WHERE 0 = 1" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_not_in(self): + query_sql = ( + self.builder.select("username") + .where_not_in("age", [1, 2, 3]) + .to_sql() + ) + expected_sql = "SELECT `users`.`username` FROM `users` WHERE `users`.`age` NOT IN ('1','2','3')" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_null(self): + query_sql = self.builder.select("username").where_null("age").to_sql() + expected_sql = "SELECT `users`.`username` FROM `users` WHERE `users`.`age` IS NULL" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_not_null(self): + query_sql = ( + self.builder.select("username").where_not_null("age").to_sql() + ) + expected_sql = "SELECT `users`.`username` FROM `users` WHERE `users`.`age` IS NOT NULL" + self.assertEqual(query_sql, expected_sql) + + def test_or_where_null(self): + query_sql = ( + self.builder.where_null("column1") + .or_where_null("column2") + .to_sql() + ) + expected_sql = "SELECT * FROM `users` WHERE `users`.`column1` IS NULL OR `users`.`column2` IS NULL" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_column(self): + query_sql = self.builder.where_column("name", "email").to_sql() + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`name` = `users`.`email`" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_raw(self): + query_sql = self.builder.where_raw("`age` = '18'").to_sql() + expected_sql = "SELECT * FROM `users` WHERE `age` = '18'" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_raw_and_where_with_multiple_bindings(self): + query = self.builder.where_raw( + "`age` = ? AND `is_admin` = ?", [18, True] + ).where("email", "test@example.com") + query_sql = query.to_qmark() + expected_sql = "SELECT * FROM `users` WHERE `age` = ? AND `is_admin` = ? AND `users`.`email` = ?" + self.assertEqual(query_sql, expected_sql) + self.assertEqual(query._bindings, [18, True, "test@example.com"]) + + def test_can_user_where_raw_and_where(self): + query_sql = ( + self.builder.where_raw("age = '18'") + .where("name", "=", "James") + .to_sql() + ) + expected_sql = "SELECT * FROM `users` WHERE age = '18' AND `users`.`name` = 'James'" + self.assertEqual(query_sql, expected_sql) - return "SELECT * FROM `users` WHERE `users`.`name` = (SELECT SUM(`users`.`age`) AS age FROM `users`)" + def test_where_like(self): + query_sql = self.builder.where("age", "like", "%name%").to_sql() + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`age` LIKE '%name%'" + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_complex_sub_select(self): - """ - self.builder.where_in('name', - (QueryBuilder(GrammarFactory.make(self.grammar), table='users') - .select('age').where_in('email', - QueryBuilder(GrammarFactory.make(self.grammar), table='users').select('email') - )) + def test_where_not_like(self): + query_sql = self.builder.where("age", "not like", "%name%").to_sql() + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`age` NOT LIKE '%name%'" + ) + self.assertEqual(query_sql, expected_sql) + + def test_where_regexp(self): + query_sql = self.builder.where("age", "regexp", "Joe").to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`age` REGEXP 'Joe'" + self.assertEqual(query_sql, expected_sql) + + def test_where_not_regexp(self): + query_sql = self.builder.where("age", "not regexp", "Joe").to_sql() + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`age` NOT REGEXP 'Joe'" + ) + self.assertEqual(query_sql, expected_sql) + + def test_where_date(self): + query_sql = self.builder.where_date( + "created_at", "2022-06-01" ).to_sql() - """ - return "SELECT * FROM `users` WHERE `users`.`name` IN (SELECT `users`.`age` FROM `users` WHERE `users`.`email` IN (SELECT `users`.`email` FROM `users`))" + expected_sql = "SELECT * FROM `users` WHERE DATE(`users`.`created_at`) = '2022-06-01'" + self.assertEqual(query_sql, expected_sql) - def can_compile_exists(self): - """ - self.builder.select('age').where_exists( - self.builder.new().select('username').where('age', 12) + def test_where_exists_with_lambda(self): + query_sql = self.builder.where_exists( + lambda q: q.where("age", 1) ).to_sql() - """ - return "SELECT `users`.`age` FROM `users` WHERE EXISTS (SELECT `users`.`username` FROM `users` WHERE `users`.`age` = '12')" + expected_sql = "SELECT * FROM `users` WHERE EXISTS (SELECT * FROM `users` WHERE `users`.`age` = '1')" + self.assertEqual(query_sql, expected_sql) - def can_compile_not_exists(self): - """ - self.builder.select('age').where_not_exists( - self.builder.new().select('username').where('age', 12) + def test_where_not_exists_with_lambda(self): + query_sql = self.builder.where_not_exists( + lambda q: q.where("age", 1) ).to_sql() - """ - return "SELECT `users`.`age` FROM `users` WHERE NOT EXISTS (SELECT `users`.`username` FROM `users` WHERE `users`.`age` = '12')" - - def can_compile_having(self): - """ - builder.sum('age').group_by('age').having('age').to_sql() - """ - return "SELECT SUM(`users`.`age`) AS age FROM `users` GROUP BY `users`.`age` HAVING `users`.`age`" - - def can_compile_having_order(self): - """ - builder.sum('age').group_by('age').having('age').order_by('age', 'desc').to_sql() - """ - return "SELECT SUM(`users`.`age`) AS age FROM `users` GROUP BY `users`.`age` HAVING `users`.`age` ORDER `users`.`age` DESC" - - def can_compile_having_with_expression(self): - """ - builder.sum('age').group_by('age').having('age', 10).to_sql() - """ - return "SELECT SUM(`users`.`age`) AS age FROM `users` GROUP BY `users`.`age` HAVING `users`.`age` = '10'" - - def can_compile_having_with_greater_than_expression(self): - """ - builder.sum('age').group_by('age').having('age', '>', 10).to_sql() - """ - return "SELECT SUM(`users`.`age`) AS age FROM `users` GROUP BY `users`.`age` HAVING `users`.`age` > '10'" - - def can_compile_join(self): - """ - builder.join('contacts', 'users.id', '=', 'contacts.user_id').to_sql() - """ - return "SELECT * FROM `users` INNER JOIN `contacts` ON `users`.`id` = `contacts`.`user_id`" - - def can_compile_left_join(self): - """ - builder.join('contacts', 'users.id', '=', 'contacts.user_id').to_sql() - """ - return "SELECT * FROM `users` LEFT JOIN `contacts` ON `users`.`id` = `contacts`.`user_id`" - - def can_compile_multiple_join(self): - """ - builder.join('contacts', 'users.id', '=', 'contacts.user_id').to_sql() - """ - return "SELECT * FROM `users` INNER JOIN `contacts` ON `users`.`id` = `contacts`.`user_id` INNER JOIN `posts` ON `comments`.`post_id` = `posts`.`id`" - - def can_compile_between(self): - """ - builder.between('age', 18, 21).to_sql() - """ - return ( + expected_sql = "SELECT * FROM `users` WHERE NOT EXISTS (SELECT * FROM `users` WHERE `users`.`age` = '1')" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_between(self): + query_sql = self.builder.between("age", 18, 21).to_sql() + expected_sql = ( "SELECT * FROM `users` WHERE `users`.`age` BETWEEN '18' AND '21'" ) + self.assertEqual(query_sql, expected_sql) - def can_compile_not_between(self): - """ - builder.not_between('age', 18, 21).to_sql() - """ - return "SELECT * FROM `users` WHERE `users`.`age` NOT BETWEEN '18' AND '21'" + def test_can_compile_not_between(self): + query_sql = self.builder.not_between("age", 18, 21).to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`age` NOT BETWEEN '18' AND '21'" + self.assertEqual(query_sql, expected_sql) - def test_can_compile_where_raw(self): - to_sql = self.builder.where_raw("`age` = '18'").to_sql() - self.assertEqual(to_sql, "SELECT * FROM `users` WHERE `age` = '18'") + def test_can_compile_first_or_fail(self): + query_sql = ( + self.builder.where("is_admin", "=", True) + .first_or_fail(query=True) + .to_sql() + ) + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`is_admin` = '1' LIMIT 1" + ) + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # HAVING + # ------------------------------------------------------------------ + + def test_can_compile_having(self): + query_sql = ( + self.builder.sum("age").group_by("age").having("age").to_sql() + ) + expected_sql = "SELECT SUM(`users`.`age`) AS age FROM `users` GROUP BY `users`.`age` HAVING `users`.`age`" + self.assertEqual(query_sql, expected_sql) def test_can_compile_having_raw(self): - to_sql = ( + query_sql = ( self.builder.select_raw("COUNT(*) as counts") - .having_raw("counts > 10") + .having_raw("counts > 18") .to_sql() ) - self.assertEqual( - to_sql, "SELECT COUNT(*) as counts FROM `users` HAVING counts > 10" + expected_sql = ( + "SELECT COUNT(*) as counts FROM `users` HAVING counts > 18" ) + self.assertEqual(query_sql, expected_sql) - def test_can_compile_having_raw_order(self): - to_sql = ( + def test_can_compile_having_raw_with_order(self): + query_sql = ( self.builder.select_raw("COUNT(*) as counts") .having_raw("counts > 10") .order_by_raw("counts DESC") .to_sql() ) - self.assertEqual( - to_sql, - "SELECT COUNT(*) as counts FROM `users` HAVING counts > 10 ORDER BY counts DESC", + expected_sql = "SELECT COUNT(*) as counts FROM `users` HAVING counts > 10 ORDER BY counts DESC" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_having_with_expression(self): + query_sql = ( + self.builder.sum("age").group_by("age").having("age", 10).to_sql() + ) + expected_sql = "SELECT SUM(`users`.`age`) AS age FROM `users` GROUP BY `users`.`age` HAVING `users`.`age` = '10'" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_having_with_greater_than_expression(self): + query_sql = ( + self.builder.sum("age") + .group_by("age") + .having("age", ">", 10) + .to_sql() ) + expected_sql = "SELECT SUM(`users`.`age`) AS age FROM `users` GROUP BY `users`.`age` HAVING `users`.`age` > '10'" + self.assertEqual(query_sql, expected_sql) - def test_can_compile_select_raw(self): - to_sql = self.builder.select_raw("COUNT(*)").to_sql() - self.assertEqual(to_sql, "SELECT COUNT(*) FROM `users`") + # ------------------------------------------------------------------ + # Locking + # ------------------------------------------------------------------ - def test_can_compile_select_raw_with_select(self): - to_sql = self.builder.select("id").select_raw("COUNT(*)").to_sql() - self.assertEqual(to_sql, "SELECT `users`.`id`, COUNT(*) FROM `users`") - - def can_compile_first_or_fail(self): - """ - builder = self.get_builder() - 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_regexp(self): - """ - builder = self.get_builder() - builder.where("age", "regexp", "Joe").to_sql() - """ - return "SELECT * FROM `users` WHERE `users`.`age` REGEXP 'Joe'" - - def where_not_regexp(self): - """ - builder = self.get_builder() - builder.where("age", "not regexp", "Joe").to_sql() - """ - return "SELECT * FROM `users` WHERE `users`.`age` NOT REGEXP 'Joe'" - - def where_like(self): - """ - builder = self.get_builder() - builder.where("age", "like", "%name%").to_sql() - """ - return "SELECT * FROM `users` WHERE `users`.`age` LIKE '%name%'" - - def can_compile_join_clause(self): - """ - builder = self.get_builder() + def test_shared_lock(self): + query_sql = ( + self.builder.where("votes", ">=", 100).shared_lock().to_sql() + ) + expected_sql = "SELECT * FROM `users` WHERE `users`.`votes` >= '100' LOCK IN SHARE MODE" + self.assertEqual(query_sql, expected_sql) + + def test_update_lock(self): + query_sql = ( + self.builder.where("votes", ">=", 100).lock_for_update().to_sql() + ) + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`votes` >= '100' FOR UPDATE" + ) + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # Sub-selects + # ------------------------------------------------------------------ + + def test_can_compile_sub_select(self): + query_sql = self.builder.where_in( + "name", self.builder.new().select("age") + ).to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`name` IN (SELECT `users`.`age` FROM `users`)" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_sub_select_where(self): + query_sql = self.builder.where_in( + "age", + self.builder.new() + .select("age") + .where("age", 2) + .where("name", "Joe"), + ).to_sql() + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`age` IN" + " (SELECT `users`.`age` FROM `users` WHERE `users`.`age` = '2' AND `users`.`name` = 'Joe')" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_sub_select_from_lambda(self): + expected = ( + "SELECT * FROM `users` WHERE `users`.`age` IN" + " (SELECT `users`.`age` FROM `users` WHERE `users`.`age` = '2' AND `users`.`name` = 'Joe')" + ) + query_sql = ( + self.builder.new() + .where_in( + "age", + lambda q: q.select("age").where("age", 2).where("name", "Joe"), + ) + .to_sql() + ) + expected_sql = expected + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_sub_select_value(self): + query_sql = self.builder.where( + "name", self.builder.new().sum("age") + ).to_sql() + expected_sql = "SELECT * FROM `users` WHERE `users`.`name` = (SELECT SUM(`users`.`age`) AS age FROM `users`)" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_complex_sub_select(self): + query_sql = self.builder.where_in( + "name", + self.builder.new() + .select("age") + .where_in("email", self.builder.new().select("email")), + ).to_sql() + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`name` IN" + " (SELECT `users`.`age` FROM `users` WHERE `users`.`email` IN" + " (SELECT `users`.`email` FROM `users`))" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_exists(self): + query_sql = ( + self.builder.select("age") + .where_exists( + self.builder.new().select("username").where("age", 12) + ) + .to_sql() + ) + expected_sql = ( + "SELECT `users`.`age` FROM `users`" + " WHERE EXISTS (SELECT `users`.`username` FROM `users` WHERE `users`.`age` = '12')" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_not_exists(self): + query_sql = ( + self.builder.select("age") + .where_not_exists( + self.builder.new().select("username").where("age", 12) + ) + .to_sql() + ) + expected_sql = ( + "SELECT `users`.`age` FROM `users`" + " WHERE NOT EXISTS (SELECT `users`.`username` FROM `users` WHERE `users`.`age` = '12')" + ) + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # JOINs + # ------------------------------------------------------------------ + + def test_can_compile_join(self): + query_sql = self.builder.join( + "contacts", "users.id", "=", "contacts.user_id" + ).to_sql() + expected_sql = "SELECT * FROM `users` INNER JOIN `contacts` ON `users`.`id` = `contacts`.`user_id`" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_left_join(self): + query_sql = self.builder.left_join( + "contacts", "users.id", "=", "contacts.user_id" + ).to_sql() + expected_sql = "SELECT * FROM `users` LEFT JOIN `contacts` ON `users`.`id` = `contacts`.`user_id`" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_multiple_join(self): + query_sql = ( + self.builder.join("contacts", "users.id", "=", "contacts.user_id") + .join("posts", "comments.post_id", "=", "posts.id") + .to_sql() + ) + expected_sql = ( + "SELECT * FROM `users`" + " INNER JOIN `contacts` ON `users`.`id` = `contacts`.`user_id`" + " INNER JOIN `posts` ON `comments`.`post_id` = `posts`.`id`" + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_join_clause(self): clause = ( JoinClause("report_groups as rg") .on("bgt.fund", "=", "rg.fund") - .on_value("bgt.active", "=", "1") - .or_on_value("bgt.acct", "=", "1234") + .on("bgt.dept", "=", "rg.dept") + .on("bgt.acct", "=", "rg.acct") + .on("bgt.sub", "=", "rg.sub") ) - builder.join(clause).to_sql() - """ - return "SELECT * FROM `users` INNER JOIN `report_groups` AS `rg` ON `bgt`.`fund` = `rg`.`fund` AND `bgt`.`dept` = `rg`.`dept` AND `bgt`.`acct` = `rg`.`acct` AND `bgt`.`sub` = `rg`.`sub`" + query_sql = self.builder.join(clause).to_sql() + expected_sql = ( + "SELECT * FROM `users` INNER JOIN `report_groups` AS `rg`" + " ON `bgt`.`fund` = `rg`.`fund` AND `bgt`.`dept` = `rg`.`dept`" + " AND `bgt`.`acct` = `rg`.`acct` AND `bgt`.`sub` = `rg`.`sub`" + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_join_clause_with_value(self): - """ - builder = self.get_builder() + def test_can_compile_join_clause_with_value(self): clause = ( JoinClause("report_groups as rg") .on_value("bgt.active", "=", "1") .or_on_value("bgt.acct", "=", "1234") ) - builder.join(clause).to_sql() - """ - return "SELECT * FROM `users` INNER JOIN `report_groups` AS `rg` ON `bgt`.`active` = '1' OR `bgt`.`acct` = '1234'" + query_sql = self.builder.join(clause).to_sql() + expected_sql = ( + "SELECT * FROM `users` INNER JOIN `report_groups` AS `rg`" + " ON `bgt`.`active` = '1' OR `bgt`.`acct` = '1234'" + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_join_clause_with_null(self): - """ - builder = self.get_builder() + def test_can_compile_join_clause_with_null(self): clause = ( JoinClause("report_groups as rg") .on_null("bgt.acct") .or_on_null("bgt.dept") .on_value("rg.abc", 10) ) - builder.join(clause).to_sql() - """ - return "SELECT * FROM `users` INNER JOIN `report_groups` AS `rg` ON `acct` IS NULL OR `dept` IS NULL AND `rg`.`abc` = '10'" + query_sql = self.builder.join(clause).to_sql() + expected_sql = ( + "SELECT * FROM `users` INNER JOIN `report_groups` AS `rg`" + " ON `acct` IS NULL OR `dept` IS NULL AND `rg`.`abc` = '10'" + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_join_clause_with_not_null(self): - """ - builder = self.get_builder() + def test_can_compile_join_clause_with_not_null(self): clause = ( JoinClause("report_groups as rg") .on_not_null("bgt.acct") .or_on_not_null("bgt.dept") .on_value("rg.abc", 10) ) - builder.join(clause).to_sql() - """ - return "SELECT * FROM `users` INNER JOIN `report_groups` AS `rg` ON `acct` IS NOT NULL OR `dept` IS NOT NULL AND `rg`.`abc` = '10'" + query_sql = self.builder.join(clause).to_sql() + expected_sql = ( + "SELECT * FROM `users` INNER JOIN `report_groups` AS `rg`" + " ON `acct` IS NOT NULL OR `dept` IS NOT NULL AND `rg`.`abc` = '10'" + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_join_clause_with_lambda(self): - """ - builder = self.get_builder() - builder.join( + def test_can_compile_join_clause_with_lambda(self): + query_sql = self.builder.join( "report_groups as rg", - lambda clause: ( - clause.on("bgt.fund", "=", "rg.fund") - .on_null("bgt") + lambda clause: clause.on("bgt.fund", "=", "rg.fund").on_null( + "bgt" ), ).to_sql() - """ - return "SELECT * FROM `users` INNER JOIN `report_groups` AS `rg` ON `bgt`.`fund` = `rg`.`fund` AND `bgt` IS NULL" + expected_sql = ( + "SELECT * FROM `users` INNER JOIN `report_groups` AS `rg`" + " ON `bgt`.`fund` = `rg`.`fund` AND `bgt` IS NULL" + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_left_join_clause_with_lambda(self): - """ - builder = self.get_builder() - builder.left_join( + def test_can_compile_left_join_clause_with_lambda(self): + query_sql = self.builder.left_join( "report_groups as rg", - lambda clause: ( - clause.on("bgt.fund", "=", "rg.fund") - .or_on_null("bgt") + lambda clause: clause.on("bgt.fund", "=", "rg.fund").or_on_null( + "bgt" ), ).to_sql() - """ - return "SELECT * FROM `users` LEFT JOIN `report_groups` AS `rg` ON `bgt`.`fund` = `rg`.`fund` OR `bgt` IS NULL" + expected_sql = ( + "SELECT * FROM `users` LEFT JOIN `report_groups` AS `rg`" + " ON `bgt`.`fund` = `rg`.`fund` OR `bgt` IS NULL" + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_right_join_clause_with_lambda(self): - """ - builder = self.get_builder() - builder.right_join( + def test_can_compile_right_join_clause_with_lambda(self): + query_sql = self.builder.right_join( "report_groups as rg", - lambda clause: ( - clause.on("bgt.fund", "=", "rg.fund") - .or_on_null("bgt") + lambda clause: clause.on("bgt.fund", "=", "rg.fund").or_on_null( + "bgt" ), ).to_sql() - """ - return "SELECT * FROM `users` RIGHT JOIN `report_groups` AS `rg` ON `bgt`.`fund` = `rg`.`fund` OR `bgt` IS NULL" - - def shared_lock(self): - """ - builder = self.get_builder() - builder.where("age", "not like", "%name%").to_sql() - """ - return "SELECT * FROM `users` WHERE `users`.`votes` >= '100' LOCK IN SHARE MODE" - - def update_lock(self): - """ - builder = self.get_builder() - builder.where("age", "not like", "%name%").to_sql() - """ - return ( - "SELECT * FROM `users` WHERE `users`.`votes` >= '100' FOR UPDATE" + expected_sql = ( + "SELECT * FROM `users` RIGHT JOIN `report_groups` AS `rg`" + " ON `bgt`.`fund` = `rg`.`fund` OR `bgt` IS NULL" ) - - def can_user_where_raw_and_where(self): - """ - builder.where_raw("`age` = '18'").where("name", "=", "James").to_sql() - """ - return "SELECT * FROM `users` WHERE age = '18' AND `users`.`name` = 'James'" - - def where_exists_with_lambda(self): - return """SELECT * FROM `users` WHERE EXISTS (SELECT * FROM `users` WHERE `users`.`age` = '1')""" - - def where_not_exists_with_lambda(self): - return """SELECT * FROM `users` WHERE NOT EXISTS (SELECT * FROM `users` WHERE `users`.`age` = '1')""" - - def where_date(self): - return """SELECT * FROM `users` WHERE DATE(`users`.`created_at`) = '2022-06-01'""" - - def or_where_null(self): - return """SELECT * FROM `users` WHERE `users`.`column1` IS NULL OR `users`.`column2` IS NULL""" - - def select_distinct(self): - return """SELECT DISTINCT `users`.`group` FROM `users`""" + self.assertEqual(query_sql, expected_sql) diff --git a/tests/mysql/grammar/test_mysql_update_grammar.py b/tests/mysql/grammar/test_mysql_update_grammar.py index 0212ec8fe..1580b63b6 100644 --- a/tests/mysql/grammar/test_mysql_update_grammar.py +++ b/tests/mysql/grammar/test_mysql_update_grammar.py @@ -1,115 +1,43 @@ -import inspect import unittest +from src.masoniteorm.expressions import Raw from src.masoniteorm.query import QueryBuilder from src.masoniteorm.query.grammars import MySQLGrammar -from src.masoniteorm.expressions import Raw -class BaseTestCaseUpdateGrammar: +class TestMySQLUpdateGrammar(unittest.TestCase): def setUp(self): - self.builder = QueryBuilder(self.grammar, table="users") + self.builder = QueryBuilder(MySQLGrammar, table="users") def test_can_compile_update(self): - to_sql = ( - self.builder.where("name", "bob").update({"name": "Joe"}, dry=True).to_sql() + query_sql = ( + self.builder.where("name", "bob") + .update({"name": "Joe"}, dry=True) + .to_sql() ) + expected_sql = "UPDATE `users` SET `users`.`name` = 'Joe' WHERE `users`.`name` = 'bob'" + self.assertEqual(query_sql, expected_sql) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + def test_raw_expression(self): + query_sql = self.builder.update( + {"name": Raw("`username`")}, dry=True + ).to_sql() + expected_sql = "UPDATE `users` SET `users`.`name` = `username`" + self.assertEqual(query_sql, expected_sql) def test_can_compile_multiple_update(self): - to_sql = self.builder.update( + query_sql = self.builder.update( {"name": "Joe", "email": "user@email.com"}, dry=True ).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + expected_sql = "UPDATE `users` SET `users`.`name` = 'Joe', `users`.`email` = 'user@email.com'" + self.assertEqual(query_sql, expected_sql) def test_can_compile_update_with_multiple_where(self): - to_sql = ( + query_sql = ( self.builder.where("name", "bob") .where("age", 20) .update({"name": "Joe"}, dry=True) .to_sql() ) - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) - - # def test_can_compile_increment(self): - # to_sql = self.builder.increment("age") - - # sql = getattr( - # self, inspect.currentframe().f_code.co_name.replace("test_", "") - # )() - # self.assertEqual(to_sql, sql) - - # def test_can_compile_decrement(self): - # to_sql = self.builder.decrement("age", 20).to_sql() - - # sql = getattr( - # self, inspect.currentframe().f_code.co_name.replace("test_", "") - # )() - # self.assertEqual(to_sql, sql) - - def test_raw_expression(self): - to_sql = self.builder.update({"name": Raw("`username`")}, dry=True).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - - self.assertEqual(to_sql, sql) - - -class TestMySQLUpdateGrammar(BaseTestCaseUpdateGrammar, unittest.TestCase): - grammar = MySQLGrammar - - def can_compile_update(self): - """ - builder.where('name', 'bob').update({ - 'name': 'Joe' - }).to_sql() - """ - return "UPDATE `users` SET `users`.`name` = 'Joe' WHERE `users`.`name` = 'bob'" - - def raw_expression(self): - """ - builder.where('name', 'bob').update({ - 'name': 'Joe' - }).to_sql() - """ - return "UPDATE `users` SET `users`.`name` = `username`" - - def can_compile_multiple_update(self): - """ - self.builder.update({"name": "Joe", "email": "user@email.com"}, dry=True).to_sql() - """ - return "UPDATE `users` SET `users`.`name` = 'Joe', `users`.`email` = 'user@email.com'" - - def can_compile_update_with_multiple_where(self): - """ - builder.where('name', 'bob').where('age', 20).update({ - 'name': 'Joe' - }).to_sql() - """ - return "UPDATE `users` SET `users`.`name` = 'Joe' WHERE `users`.`name` = 'bob' AND `users`.`age` = '20'" - - def can_compile_increment(self): - """ - builder.increment('age').to_sql() - """ - return "UPDATE `users` SET `users`.`age` = `users`.`age` + '1'" - - def can_compile_decrement(self): - """ - builder.decrement('age', 20).to_sql() - """ - return "UPDATE `users` SET `users`.`age` = `users`.`age` - '20'" + expected_sql = "UPDATE `users` SET `users`.`name` = 'Joe' WHERE `users`.`name` = 'bob' AND `users`.`age` = '20'" + self.assertEqual(query_sql, expected_sql) diff --git a/tests/mysql/model/test_model.py b/tests/mysql/model/test_model.py index 152949dfc..63ae0bbfb 100644 --- a/tests/mysql/model/test_model.py +++ b/tests/mysql/model/test_model.py @@ -79,41 +79,38 @@ class ProductNames(Model): class TestModel(unittest.TestCase): def test_create_can_use_fillable(self): - sql = ProfileFillable.create( + query_sql = ProfileFillable.create( {"name": "Joe", "email": "user@example.com"}, query=True ).to_sql() - - self.assertEqual( - sql, "INSERT INTO `profiles` (`profiles`.`name`) VALUES ('Joe')" + expected_sql = ( + "INSERT INTO `profiles` (`profiles`.`name`) VALUES ('Joe')" ) + self.assertEqual(query_sql, expected_sql) def test_create_can_use_fillable_asterisk(self): - sql = ProfileFillAsterisk.create( + query_sql = ProfileFillAsterisk.create( {"name": "Joe", "email": "user@example.com"}, query=True ).to_sql() - - self.assertEqual( - sql, - "INSERT INTO `profiles` (`profiles`.`name`, `profiles`.`email`) VALUES ('Joe', 'user@example.com')", - ) + expected_sql = "INSERT INTO `profiles` (`profiles`.`name`, `profiles`.`email`) VALUES ('Joe', 'user@example.com')" + self.assertEqual(query_sql, expected_sql) def test_create_can_use_guarded(self): - sql = ProfileGuarded.create( + query_sql = ProfileGuarded.create( {"name": "Joe", "email": "user@example.com"}, query=True ).to_sql() - - self.assertEqual( - sql, "INSERT INTO `profiles` (`profiles`.`name`) VALUES ('Joe')" + expected_sql = ( + "INSERT INTO `profiles` (`profiles`.`name`) VALUES ('Joe')" ) + self.assertEqual(query_sql, expected_sql) def test_create_can_use_guarded_asterisk(self): - sql = ProfileGuardedAsterisk.create( + query_sql = ProfileGuardedAsterisk.create( {"name": "Joe", "email": "user@example.com"}, query=True ).to_sql() - # An asterisk guarded attribute excludes all fields from mass-assignment. # This would raise a DB error if there are any required fields. - self.assertEqual(sql, "INSERT INTO `profiles` (*) VALUES ()") + expected_sql = "INSERT INTO `profiles` (*) VALUES ()" + self.assertEqual(query_sql, expected_sql) def test_bulk_create_can_use_fillable(self): query_builder = ProfileFillable.bulk_create( @@ -124,10 +121,11 @@ def test_bulk_create_can_use_fillable(self): query=True, ) - self.assertEqual( - query_builder.to_sql(), - "INSERT INTO `profiles` (`name`) VALUES ('Joe'), ('Joe II')", + query_sql = query_builder.to_sql() + expected_sql = ( + "INSERT INTO `profiles` (`name`) VALUES ('Joe'), ('Joe II')" ) + self.assertEqual(query_sql, expected_sql) def test_bulk_create_can_use_fillable_asterisk(self): query_builder = ProfileFillAsterisk.bulk_create( @@ -138,10 +136,9 @@ def test_bulk_create_can_use_fillable_asterisk(self): query=True, ) - self.assertEqual( - query_builder.to_sql(), - "INSERT INTO `profiles` (`email`, `name`) VALUES ('user@example.com', 'Joe'), ('userII@example.com', 'Joe II')", - ) + query_sql = query_builder.to_sql() + expected_sql = "INSERT INTO `profiles` (`email`, `name`) VALUES ('user@example.com', 'Joe'), ('userII@example.com', 'Joe II')" + self.assertEqual(query_sql, expected_sql) def test_bulk_create_can_use_guarded(self): query_builder = ProfileGuarded.bulk_create( @@ -152,10 +149,11 @@ def test_bulk_create_can_use_guarded(self): query=True, ) - self.assertEqual( - query_builder.to_sql(), - "INSERT INTO `profiles` (`name`) VALUES ('Joe'), ('Joe II')", + query_sql = query_builder.to_sql() + expected_sql = ( + "INSERT INTO `profiles` (`name`) VALUES ('Joe'), ('Joe II')" ) + self.assertEqual(query_sql, expected_sql) def test_bulk_create_can_use_guarded_asterisk(self): query_builder = ProfileGuardedAsterisk.bulk_create( @@ -169,39 +167,36 @@ def test_bulk_create_can_use_guarded_asterisk(self): # An asterisk guarded attribute excludes all fields from mass-assignment. # This would obviously raise an invalid SQL syntax error. # TODO: Raise a clearer error? - self.assertEqual( - query_builder.to_sql(), "INSERT INTO `profiles` () VALUES (), ()" - ) + query_sql = query_builder.to_sql() + expected_sql = "INSERT INTO `profiles` () VALUES (), ()" + self.assertEqual(query_sql, expected_sql) def test_update_can_use_fillable(self): query_builder = ProfileFillable().update( {"name": "Joe", "email": "user@example.com"}, dry=True ) - self.assertEqual( - query_builder.to_sql(), - "UPDATE `profiles` SET `profiles`.`name` = 'Joe'", - ) + query_sql = query_builder.to_sql() + expected_sql = "UPDATE `profiles` SET `profiles`.`name` = 'Joe'" + self.assertEqual(query_sql, expected_sql) def test_update_can_use_fillable_asterisk(self): query_builder = ProfileFillAsterisk().update( {"name": "Joe", "email": "user@example.com"}, dry=True ) - self.assertEqual( - query_builder.to_sql(), - "UPDATE `profiles` SET `profiles`.`name` = 'Joe', `profiles`.`email` = 'user@example.com'", - ) + query_sql = query_builder.to_sql() + expected_sql = "UPDATE `profiles` SET `profiles`.`name` = 'Joe', `profiles`.`email` = 'user@example.com'" + self.assertEqual(query_sql, expected_sql) def test_update_can_use_guarded(self): query_builder = ProfileGuarded().update( {"name": "Joe", "email": "user@example.com"}, dry=True ) - self.assertEqual( - query_builder.to_sql(), - "UPDATE `profiles` SET `profiles`.`name` = 'Joe'", - ) + query_sql = query_builder.to_sql() + expected_sql = "UPDATE `profiles` SET `profiles`.`name` = 'Joe'" + self.assertEqual(query_sql, expected_sql) def test_update_can_use_guarded_asterisk(self): profile = ProfileGuardedAsterisk() @@ -212,7 +207,9 @@ def test_update_can_use_guarded_asterisk(self): # An asterisk guarded attribute excludes all fields from mass-assignment. # The query builder's sql should not have been altered in any way. - self.assertEqual(query_builder.to_sql(), initial_sql) + query_sql = query_builder.to_sql() + expected_sql = initial_sql + self.assertEqual(query_sql, expected_sql) def test_table_name(self): table_name = Profile.get_table_name() @@ -342,12 +339,9 @@ def test_can_find_first(self): def test_can_touch(self): profile = ProfileFillTimeStamped.hydrate({"name": "Joe", "id": 1}) - sql = profile.touch("now", query=True).to_sql() - - self.assertEqual( - sql, - "UPDATE `profiles` SET `profiles`.`updated_at` = 'now' WHERE `profiles`.`id` = '1'", - ) + query_sql = profile.touch("now", query=True).to_sql() + expected_sql = "UPDATE `profiles` SET `profiles`.`updated_at` = 'now' WHERE `profiles`.`id` = '1'" + self.assertEqual(query_sql, expected_sql) def test_find_or_fail_raise_an_exception_if_not_exists(self): with self.assertRaises(ModelNotFound): diff --git a/tests/mysql/relationships/test_belongs_to_many.py b/tests/mysql/relationships/test_belongs_to_many.py index 118f7cca0..9b4d3ca74 100644 --- a/tests/mysql/relationships/test_belongs_to_many.py +++ b/tests/mysql/relationships/test_belongs_to_many.py @@ -47,57 +47,59 @@ class MySQLRelationships(unittest.TestCase): maxDiff = None def test_belongs_to_many(self): - sql = Permission.where_has( + query_sql = Permission.where_has( "role", lambda query: (query.where("slug", "users")) ).to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `permissions` WHERE EXISTS (SELECT * FROM `roles` INNER JOIN `permission_role` ON `roles`.`id` = `permission_role`.`role_id` WHERE `permission_role`.`permission_id` = `permissions`.`id` AND `roles`.`id` IN (SELECT `roles`.`id` FROM `roles` WHERE `roles`.`slug` = 'users'))""", ) def test_belongs_to_many_has(self): - sql = Role.has("permissions").to_sql() + query_sql = Role.has("permissions").to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `roles` WHERE EXISTS (SELECT * FROM `permissions` INNER JOIN `permission_role` ON `permissions`.`id` = `permission_role`.`permission_id` WHERE `permission_role`.`role_id` = `roles`.`id`)""", ) def test_belongs_to_many_or_has(self): - sql = Role.where("name", "role_name").or_has("permissions").to_sql() + query_sql = ( + Role.where("name", "role_name").or_has("permissions").to_sql() + ) self.assertEqual( - sql, + query_sql, """SELECT * FROM `roles` WHERE `roles`.`name` = 'role_name' OR EXISTS (SELECT * FROM `permissions` INNER JOIN `permission_role` ON `permissions`.`id` = `permission_role`.`permission_id` WHERE `permission_role`.`role_id` = `roles`.`id`)""", ) def test_belongs_to_many_or_where_has(self): - sql = ( + query_sql = ( Role.where("name", "role_name") .or_where_has("permissions", lambda q: q.where("permission_id", 1)) .to_sql() ) self.assertEqual( - sql, + query_sql, """SELECT * FROM `roles` WHERE `roles`.`name` = 'role_name' OR EXISTS (SELECT * FROM `permissions` INNER JOIN `permission_role` ON `permissions`.`id` = `permission_role`.`permission_id` WHERE `permission_role`.`role_id` = `roles`.`id` AND `permissions`.`id` IN (SELECT `permissions`.`id` FROM `permissions` WHERE `permissions`.`permission_id` = '1'))""", ) def test_belongs_to_many_or_doesnt_have(self): - sql = ( + query_sql = ( Role.where("name", "role_name") .or_doesnt_have("permissions") .to_sql() ) self.assertEqual( - sql, + query_sql, """SELECT * FROM `roles` WHERE `roles`.`name` = 'role_name' OR NOT EXISTS (SELECT * FROM `permissions` INNER JOIN `permission_role` ON `permissions`.`id` = `permission_role`.`permission_id` WHERE `permission_role`.`role_id` = `roles`.`id`)""", ) def test_where_doesnt_have(self): - sql = ( + query_sql = ( Role.where("name", "role_name") .where_doesnt_have( "permissions", lambda q: q.where("name", "Creates Users") @@ -106,12 +108,12 @@ def test_where_doesnt_have(self): ) self.assertEqual( - sql, + query_sql, """SELECT * FROM `roles` WHERE `roles`.`name` = 'role_name' AND NOT EXISTS (SELECT * FROM `permissions` INNER JOIN `permission_role` ON `permissions`.`id` = `permission_role`.`permission_id` WHERE `permission_role`.`role_id` = `roles`.`id` AND `permissions`.`id` IN (SELECT `permissions`.`id` FROM `permissions` WHERE `permissions`.`name` = 'Creates Users'))""", ) def test_or_where_doesnt_have(self): - sql = ( + query_sql = ( Role.where("name", "role_name") .or_where_doesnt_have( "permissions", lambda q: q.where("name", "Creates Users") @@ -120,57 +122,57 @@ def test_or_where_doesnt_have(self): ) self.assertEqual( - sql, + query_sql, """SELECT * FROM `roles` WHERE `roles`.`name` = 'role_name' OR NOT EXISTS (SELECT * FROM `permissions` INNER JOIN `permission_role` ON `permissions`.`id` = `permission_role`.`permission_id` WHERE `permission_role`.`role_id` = `roles`.`id` AND `permissions`.`id` IN (SELECT `permissions`.`id` FROM `permissions` WHERE `permissions`.`name` = 'Creates Users'))""", ) def test_belongs_to_many_where_has(self): - sql = Role.where_has( + query_sql = Role.where_has( "permissions", lambda q: q.where("name", "Creates Users") ).to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `roles` WHERE EXISTS (SELECT * FROM `permissions` INNER JOIN `permission_role` ON `permissions`.`id` = `permission_role`.`permission_id` WHERE `permission_role`.`role_id` = `roles`.`id` AND `permissions`.`id` IN (SELECT `permissions`.`id` FROM `permissions` WHERE `permissions`.`name` = 'Creates Users'))""", ) def test_belongs_to_many_relate_method(self): permission = Permission.hydrate({"id": 1, "name": "Create Users"}) - sql = permission.related("role").to_sql() + query_sql = permission.related("role").to_sql() self.assertEqual( - sql, + query_sql, """SELECT `roles`.*, `permission_role`.`permission_id` AS permission_role_id, `permission_role`.`role_id` AS m_reserved2, `permission_role`.`id` AS m_reserved3 FROM `permissions` INNER JOIN `permission_role` ON `permission_role`.`permission_id` = `permissions`.`id` INNER JOIN `roles` ON `permission_role`.`role_id` = `roles`.`id`""", ) def test_belongs_to_many_relate_method_reversed(self): role = Role.hydrate({"id": 1, "name": "Create Users"}) - sql = role.related("permissions").to_sql() + query_sql = role.related("permissions").to_sql() self.assertEqual( - sql, + query_sql, """SELECT `permissions`.*, `permission_role`.`role_id` AS permission_role_id, `permission_role`.`permission_id` AS m_reserved2, `permission_role`.`id` AS m_reserved3 FROM `roles` INNER JOIN `permission_role` ON `permission_role`.`role_id` = `roles`.`id` INNER JOIN `permissions` ON `permission_role`.`permission_id` = `permissions`.`id`""", ) def test_belongs_to_many_joins(self): - sql = Role.joins("permissions").to_sql() + query_sql = Role.joins("permissions").to_sql() self.assertEqual( - sql, + query_sql, """SELECT `roles`.*, `permission_role`.`role_id` AS permission_role_id, `permission_role`.`permission_id` AS m_reserved2, `permission_role`.`id` AS m_reserved3 FROM `roles` INNER JOIN `permission_role` ON `permission_role`.`role_id` = `roles`.`id` INNER JOIN `permissions` ON `permission_role`.`id` = `permissions`.`id`""", ) def test_with_count(self): - sql = Permission.with_count("role").to_sql() + query_sql = Permission.with_count("role").to_sql() self.assertEqual( - sql, + query_sql, """SELECT `permissions`.*, (SELECT COUNT(*) AS m_count_reserved FROM `permission_role` WHERE `permissions`.`id` = `permission_role`.`permission_id`) AS roles_count FROM `permissions`""", ) def test_with_count_with_selects(self): - sql = PermissionSelect.with_count("role").to_sql() + query_sql = PermissionSelect.with_count("role").to_sql() self.assertEqual( - sql, + query_sql, """SELECT `permissions`.`permission_id`, (SELECT COUNT(*) AS m_count_reserved FROM `permission_role` WHERE `permissions`.`id` = `permission_role`.`permission_id`) AS roles_count FROM `permissions`""", ) diff --git a/tests/mysql/relationships/test_has_many_through.py b/tests/mysql/relationships/test_has_many_through.py index 3c6d5b7ef..94a13fb1c 100644 --- a/tests/mysql/relationships/test_has_many_through.py +++ b/tests/mysql/relationships/test_has_many_through.py @@ -1,10 +1,11 @@ import unittest +from dotenv import load_dotenv + from src.masoniteorm.models import Model from src.masoniteorm.relationships import ( has_many_through, ) -from dotenv import load_dotenv load_dotenv(".env") @@ -27,53 +28,59 @@ class MySQLRelationships(unittest.TestCase): maxDiff = None def test_has_query(self): - sql = InboundShipment.has("from_country").to_sql() + query_sql = InboundShipment.has("from_country").to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `inbound_shipments` WHERE EXISTS (SELECT * FROM `countries` INNER JOIN `ports` ON `ports`.`country_id` = `countries`.`country_id` WHERE `ports`.`port_id` = `inbound_shipments`.`from_port_id`)""", ) def test_or_has(self): - sql = InboundShipment.where("name", "Joe").or_has("from_country").to_sql() + query_sql = ( + InboundShipment.where("name", "Joe") + .or_has("from_country") + .to_sql() + ) self.assertEqual( - sql, + query_sql, """SELECT * FROM `inbound_shipments` WHERE `inbound_shipments`.`name` = 'Joe' OR EXISTS (SELECT * FROM `countries` INNER JOIN `ports` ON `ports`.`country_id` = `countries`.`country_id` WHERE `ports`.`port_id` = `inbound_shipments`.`from_port_id`)""", ) def test_where_has_query(self): - sql = InboundShipment.where_has( + query_sql = InboundShipment.where_has( "from_country", lambda query: query.where("name", "USA") ).to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `inbound_shipments` WHERE EXISTS (SELECT * FROM `countries` INNER JOIN `ports` ON `ports`.`country_id` = `countries`.`country_id` WHERE `ports`.`port_id` = `inbound_shipments`.`from_port_id` AND `countries`.`name` = 'USA')""", ) def test_or_where_has(self): - sql = ( + query_sql = ( InboundShipment.where("name", "Joe") - .or_where_has("from_country", lambda query: query.where("name", "USA")) + .or_where_has( + "from_country", lambda query: query.where("name", "USA") + ) .to_sql() ) self.assertEqual( - sql, + query_sql, """SELECT * FROM `inbound_shipments` WHERE `inbound_shipments`.`name` = 'Joe' OR EXISTS (SELECT * FROM `countries` INNER JOIN `ports` ON `ports`.`country_id` = `countries`.`country_id` WHERE `ports`.`port_id` = `inbound_shipments`.`from_port_id` AND `countries`.`name` = 'USA')""", ) def test_doesnt_have(self): - sql = InboundShipment.doesnt_have("from_country").to_sql() + query_sql = InboundShipment.doesnt_have("from_country").to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `inbound_shipments` WHERE NOT EXISTS (SELECT * FROM `countries` INNER JOIN `ports` ON `ports`.`country_id` = `countries`.`country_id` WHERE `ports`.`port_id` = `inbound_shipments`.`from_port_id`)""", ) def test_or_where_doesnt_have(self): - sql = ( + query_sql = ( InboundShipment.where("name", "Joe") .or_where_doesnt_have( "from_country", lambda query: query.where("name", "USA") @@ -82,6 +89,6 @@ def test_or_where_doesnt_have(self): ) self.assertEqual( - sql, + query_sql, """SELECT * FROM `inbound_shipments` WHERE `inbound_shipments`.`name` = 'Joe' OR NOT EXISTS (SELECT * FROM `countries` INNER JOIN `ports` ON `ports`.`country_id` = `countries`.`country_id` WHERE `ports`.`port_id` = `inbound_shipments`.`from_port_id` AND `countries`.`name` = 'USA')""", ) diff --git a/tests/mysql/relationships/test_has_one_through.py b/tests/mysql/relationships/test_has_one_through.py index 4337dc837..f6abff952 100644 --- a/tests/mysql/relationships/test_has_one_through.py +++ b/tests/mysql/relationships/test_has_one_through.py @@ -1,16 +1,19 @@ import unittest +from dotenv import load_dotenv + from src.masoniteorm.models import Model from src.masoniteorm.relationships import ( has_one_through, ) -from dotenv import load_dotenv load_dotenv(".env") class InboundShipment(Model): - @has_one_through(None, "from_port_id", "country_id", "port_id", "country_id") + @has_one_through( + None, "from_port_id", "country_id", "port_id", "country_id" + ) def from_country(self): return Country, Port @@ -27,53 +30,59 @@ class MySQLHasOneThroughRelationship(unittest.TestCase): maxDiff = None def test_has_query(self): - sql = InboundShipment.has("from_country").to_sql() + query_sql = InboundShipment.has("from_country").to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `inbound_shipments` WHERE EXISTS (SELECT * FROM `countries` INNER JOIN `ports` ON `ports`.`country_id` = `countries`.`country_id` WHERE `ports`.`port_id` = `inbound_shipments`.`from_port_id`)""", ) def test_or_has(self): - sql = InboundShipment.where("name", "Joe").or_has("from_country").to_sql() + query_sql = ( + InboundShipment.where("name", "Joe") + .or_has("from_country") + .to_sql() + ) self.assertEqual( - sql, + query_sql, """SELECT * FROM `inbound_shipments` WHERE `inbound_shipments`.`name` = 'Joe' OR EXISTS (SELECT * FROM `countries` INNER JOIN `ports` ON `ports`.`country_id` = `countries`.`country_id` WHERE `ports`.`port_id` = `inbound_shipments`.`from_port_id`)""", ) def test_where_has_query(self): - sql = InboundShipment.where_has( + query_sql = InboundShipment.where_has( "from_country", lambda query: query.where("name", "USA") ).to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `inbound_shipments` WHERE EXISTS (SELECT * FROM `countries` INNER JOIN `ports` ON `ports`.`country_id` = `countries`.`country_id` WHERE `ports`.`port_id` = `inbound_shipments`.`from_port_id` AND `countries`.`name` = 'USA')""", ) def test_or_where_has(self): - sql = ( + query_sql = ( InboundShipment.where("name", "Joe") - .or_where_has("from_country", lambda query: query.where("name", "USA")) + .or_where_has( + "from_country", lambda query: query.where("name", "USA") + ) .to_sql() ) self.assertEqual( - sql, + query_sql, """SELECT * FROM `inbound_shipments` WHERE `inbound_shipments`.`name` = 'Joe' OR EXISTS (SELECT * FROM `countries` INNER JOIN `ports` ON `ports`.`country_id` = `countries`.`country_id` WHERE `ports`.`port_id` = `inbound_shipments`.`from_port_id` AND `countries`.`name` = 'USA')""", ) def test_doesnt_have(self): - sql = InboundShipment.doesnt_have("from_country").to_sql() + query_sql = InboundShipment.doesnt_have("from_country").to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `inbound_shipments` WHERE NOT EXISTS (SELECT * FROM `countries` INNER JOIN `ports` ON `ports`.`country_id` = `countries`.`country_id` WHERE `ports`.`port_id` = `inbound_shipments`.`from_port_id`)""", ) def test_or_where_doesnt_have(self): - sql = ( + query_sql = ( InboundShipment.where("name", "Joe") .or_where_doesnt_have( "from_country", lambda query: query.where("name", "USA") @@ -82,14 +91,14 @@ def test_or_where_doesnt_have(self): ) self.assertEqual( - sql, + query_sql, """SELECT * FROM `inbound_shipments` WHERE `inbound_shipments`.`name` = 'Joe' OR NOT EXISTS (SELECT * FROM `countries` INNER JOIN `ports` ON `ports`.`country_id` = `countries`.`country_id` WHERE `ports`.`port_id` = `inbound_shipments`.`from_port_id` AND `countries`.`name` = 'USA')""", ) def test_has_one_through_with_count(self): - sql = InboundShipment.with_count("from_country").to_sql() + query_sql = InboundShipment.with_count("from_country").to_sql() self.assertEqual( - sql, + query_sql, """SELECT `inbound_shipments`.*, (SELECT COUNT(*) AS m_count_reserved FROM `countries` INNER JOIN `ports` ON `ports`.`country_id` = `countries`.`country_id` WHERE `ports`.`port_id` = `inbound_shipments`.`from_port_id`) AS from_country_count FROM `inbound_shipments`""", ) diff --git a/tests/mysql/relationships/test_relationships.py b/tests/mysql/relationships/test_relationships.py index 0829b439e..cb3df043e 100644 --- a/tests/mysql/relationships/test_relationships.py +++ b/tests/mysql/relationships/test_relationships.py @@ -30,51 +30,51 @@ class MySQLRelationships(unittest.TestCase): maxDiff = None def test_has(self): - sql = User.has("profile").to_sql() + query_sql = User.has("profile").to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `users` WHERE EXISTS (SELECT * FROM `profiles` WHERE `profiles`.`profile_id` = `users`.`id`)""", ) def test_has_nested(self): - sql = User.has("profile.identification").to_sql() + query_sql = User.has("profile.identification").to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `users` WHERE EXISTS (SELECT * FROM `profiles` WHERE `profiles`.`profile_id` = `users`.`id` AND EXISTS (SELECT * FROM `identifications` WHERE `identifications`.`identification_id` = `profiles`.`id`))""", ) def test_or_has(self): - sql = User.where("name", "Joe").or_has("profile").to_sql() + query_sql = User.where("name", "Joe").or_has("profile").to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `users` WHERE `users`.`name` = 'Joe' OR EXISTS (SELECT * FROM `profiles` WHERE `profiles`.`profile_id` = `users`.`id`)""", ) def test_or_has_nested(self): - sql = ( + query_sql = ( User.where("name", "Joe").or_has("profile.identification").to_sql() ) self.assertEqual( - sql, + query_sql, """SELECT * FROM `users` WHERE `users`.`name` = 'Joe' OR EXISTS (SELECT * FROM `profiles` WHERE `profiles`.`profile_id` = `users`.`id` AND EXISTS (SELECT * FROM `identifications` WHERE `identifications`.`identification_id` = `profiles`.`id`))""", ) def test_relationship_where_has(self): - sql = ( + query_sql = ( User.where("name", "Joe") .where_has("profile", lambda q: q.where("profile_id", 1)) .to_sql() ) self.assertEqual( - sql, + query_sql, """SELECT * FROM `users` WHERE `users`.`name` = 'Joe' AND EXISTS (SELECT * FROM `profiles` WHERE `profiles`.`profile_id` = `users`.`id` AND `profiles`.`profile_id` = '1')""", ) def test_relationship_where_has_nested(self): - sql = ( + query_sql = ( User.where("name", "Joe") .where_has( "profile.identification", @@ -84,24 +84,24 @@ def test_relationship_where_has_nested(self): ) self.assertEqual( - sql, + query_sql, """SELECT * FROM `users` WHERE `users`.`name` = 'Joe' AND EXISTS (SELECT * FROM `profiles` WHERE `profiles`.`profile_id` = `users`.`id` AND EXISTS (SELECT * FROM `identifications` WHERE `identifications`.`identification_id` = `profiles`.`id` AND `identifications`.`identification_id` = '1'))""", ) def test_relationship_or_where_has(self): - sql = ( + query_sql = ( User.where("name", "Joe") .or_where_has("profile", lambda q: q.where("profile_id", 1)) .to_sql() ) self.assertEqual( - sql, + query_sql, """SELECT * FROM `users` WHERE `users`.`name` = 'Joe' OR EXISTS (SELECT * FROM `profiles` WHERE `profiles`.`profile_id` = `users`.`id` AND `profiles`.`profile_id` = '1')""", ) def test_relationship_or_where_has_nested(self): - sql = ( + query_sql = ( User.where("name", "Joe") .or_where_has( "profile.identification", @@ -111,79 +111,79 @@ def test_relationship_or_where_has_nested(self): ) self.assertEqual( - sql, + query_sql, """SELECT * FROM `users` WHERE `users`.`name` = 'Joe' OR EXISTS (SELECT * FROM `profiles` WHERE `profiles`.`profile_id` = `users`.`id` AND EXISTS (SELECT * FROM `identifications` WHERE `identifications`.`identification_id` = `profiles`.`id` AND `identifications`.`identification_id` = '1'))""", ) def test_relationship_doesnt_have(self): - sql = User.doesnt_have("profile").to_sql() + query_sql = User.doesnt_have("profile").to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `users` WHERE NOT EXISTS (SELECT * FROM `profiles` WHERE `profiles`.`profile_id` = `users`.`id`)""", ) def test_relationship_doesnt_have_nested(self): - sql = User.doesnt_have("profile.identification").to_sql() + query_sql = User.doesnt_have("profile.identification").to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `users` WHERE NOT EXISTS (SELECT * FROM `profiles` WHERE `profiles`.`profile_id` = `users`.`id` AND EXISTS (SELECT * FROM `identifications` WHERE `identifications`.`identification_id` = `profiles`.`id`))""", ) def test_relationship_where_doesnt_have(self): - sql = User.where_doesnt_have( + query_sql = User.where_doesnt_have( "profile", lambda q: q.where("profile_id", 1) ).to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `users` WHERE NOT EXISTS (SELECT * FROM `profiles` WHERE `profiles`.`profile_id` = `users`.`id` AND `profiles`.`profile_id` = '1')""", ) def test_relationship_where_doesnt_have_nested(self): - sql = User.where_doesnt_have( + query_sql = User.where_doesnt_have( "profile.identification", lambda q: q.where("identification_id", 1) ).to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `users` WHERE NOT EXISTS (SELECT * FROM `profiles` WHERE `profiles`.`profile_id` = `users`.`id`) AND EXISTS (SELECT * FROM `identifications` WHERE `identifications`.`identification_id` = `users`.`id` AND `identifications`.`identification_id` = '1')""", ) def test_relationship_or_where_doesnt_have(self): - sql = User.or_where_doesnt_have( + query_sql = User.or_where_doesnt_have( "profile", lambda q: q.where("profile_id", 1) ).to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `users` WHERE NOT EXISTS (SELECT * FROM `profiles` WHERE `profiles`.`profile_id` = `users`.`id` AND `profiles`.`profile_id` = '1')""", ) def test_relationship_or_where_doesnt_have_nested(self): - sql = User.or_where_doesnt_have( + query_sql = User.or_where_doesnt_have( "profile.identification", lambda q: q.where("identification_id", 1) ).to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `users` WHERE NOT EXISTS (SELECT * FROM `profiles` WHERE `profiles`.`profile_id` = `users`.`id`) AND EXISTS (SELECT * FROM `identifications` WHERE `identifications`.`identification_id` = `users`.`id` AND `identifications`.`identification_id` = '1')""", ) def test_joins(self): - sql = User.joins("profile").to_sql() + query_sql = User.joins("profile").to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `users` INNER JOIN `profiles` ON `users`.`id` = `profiles`.`profile_id`""", ) def test_join_on(self): - sql = User.join_on( + query_sql = User.join_on( "profile", lambda q: (q.where("active", 1)) ).to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM `users` INNER JOIN `profiles` ON `users`.`id` = `profiles`.`profile_id` WHERE (`profiles`.`active` = '1')""", ) diff --git a/tests/mysql/schema/test_mysql_schema_builder.py b/tests/mysql/schema/test_mysql_schema_builder.py index b3aefc033..18006e11d 100644 --- a/tests/mysql/schema/test_mysql_schema_builder.py +++ b/tests/mysql/schema/test_mysql_schema_builder.py @@ -2,11 +2,9 @@ import unittest from src.masoniteorm import Model -from tests.integrations.config.database import DATABASES from src.masoniteorm.connections import MySQLConnection from src.masoniteorm.schema import Schema from src.masoniteorm.schema.platforms import MySQLPlatform - from tests.integrations.config.database import DATABASES @@ -56,7 +54,9 @@ def test_can_add_unsigned_decimal(self): self.assertEqual(len(blueprint.table.added_columns), 1) self.assertEqual( blueprint.to_sql(), - ["CREATE TABLE `users` (`amount` DECIMAL(19, 4) UNSIGNED NOT NULL)"], + [ + "CREATE TABLE `users` (`amount` DECIMAL(19, 4) UNSIGNED NOT NULL)" + ], ) def test_can_create_table_if_not_exists(self): @@ -119,7 +119,9 @@ def test_can_add_columns_with_foreign_key_constaint(self): blueprint.integer("profile_id") blueprint.foreign("profile_id").references("id").on("profiles") blueprint.foreign_id("post_id").references("id").on("posts") - blueprint.foreign_id_for(Discussion).references("id").on("discussions") + blueprint.foreign_id_for(Discussion).references("id").on( + "discussions" + ) self.assertEqual(len(blueprint.table.added_columns), 3) self.assertEqual( @@ -212,9 +214,9 @@ def test_can_advanced_table_creation2(self): blueprint.string("thumbnail").nullable() blueprint.integer("premium") blueprint.integer("author_id").unsigned().nullable() - blueprint.foreign("author_id").references("id").on("users").on_delete( - "CASCADE" - ) + blueprint.foreign("author_id").references("id").on( + "users" + ).on_delete("CASCADE") blueprint.text("description") blueprint.timestamps() @@ -233,9 +235,9 @@ def test_can_advanced_table_creation2(self): def test_can_add_columns_with_foreign_key_constraint_name(self): with self.schema.create("users") as blueprint: blueprint.integer("profile_id") - blueprint.foreign("profile_id", name="profile_foreign").references("id").on( - "profiles" - ) + blueprint.foreign("profile_id", name="profile_foreign").references( + "id" + ).on("profiles") self.assertEqual(len(blueprint.table.added_columns), 1) self.assertEqual( @@ -316,7 +318,10 @@ def test_can_have_default_blank_string(self): self.assertEqual( blueprint.to_sql(), - ["CREATE TABLE `users` (" "`profile_id` VARCHAR(255) NOT NULL DEFAULT '')"], + [ + "CREATE TABLE `users` (" + "`profile_id` VARCHAR(255) NOT NULL DEFAULT '')" + ], ) def test_can_have_float_type(self): @@ -329,55 +334,55 @@ def test_can_have_float_type(self): ) def test_has_table(self): - schema_sql = self.schema.has_table("users") + query_sql = self.schema.has_table("users") - sql = f"SELECT * from information_schema.tables where table_name='users' AND table_schema = '{os.getenv('MYSQL_DATABASE_DATABASE')}'" + expected_sql = f"SELECT * from information_schema.tables where table_name='users' AND table_schema = '{os.getenv('MYSQL_DATABASE_DATABASE')}'" - self.assertEqual(schema_sql, sql) + self.assertEqual(query_sql, expected_sql) def test_can_truncate(self): - sql = self.schema.truncate("users") + query_sql = self.schema.truncate("users") - self.assertEqual(sql, "TRUNCATE `users`") + self.assertEqual(query_sql, "TRUNCATE `users`") def test_can_rename_table(self): - sql = self.schema.rename("users", "clients") + query_sql = self.schema.rename("users", "clients") - self.assertEqual(sql, "ALTER TABLE `users` RENAME TO `clients`") + self.assertEqual(query_sql, "ALTER TABLE `users` RENAME TO `clients`") def test_can_drop_table_if_exists(self): - sql = self.schema.drop_table_if_exists("users", "clients") + query_sql = self.schema.drop_table_if_exists("users", "clients") - self.assertEqual(sql, "DROP TABLE IF EXISTS `users`") + self.assertEqual(query_sql, "DROP TABLE IF EXISTS `users`") def test_can_drop_table(self): - sql = self.schema.drop_table("users", "clients") + query_sql = self.schema.drop_table("users", "clients") - self.assertEqual(sql, "DROP TABLE `users`") + self.assertEqual(query_sql, "DROP TABLE `users`") def test_has_column(self): - sql = self.schema.has_column("users", "name") + query_sql = self.schema.has_column("users", "name") self.assertEqual( - sql, + query_sql, "SELECT column_name FROM information_schema.columns WHERE table_name='users' and column_name='name'", ) def test_can_enable_foreign_keys(self): - sql = self.schema.enable_foreign_key_constraints() + query_sql = self.schema.enable_foreign_key_constraints() - self.assertEqual(sql, "SET FOREIGN_KEY_CHECKS=1") + self.assertEqual(query_sql, "SET FOREIGN_KEY_CHECKS=1") def test_can_disable_foreign_keys(self): - sql = self.schema.disable_foreign_key_constraints() + query_sql = self.schema.disable_foreign_key_constraints() - self.assertEqual(sql, "SET FOREIGN_KEY_CHECKS=0") + self.assertEqual(query_sql, "SET FOREIGN_KEY_CHECKS=0") def test_can_truncate_without_foreign_keys(self): - sql = self.schema.truncate("users", foreign_keys=True) + query_sql = self.schema.truncate("users", foreign_keys=True) self.assertEqual( - sql, + query_sql, [ "SET FOREIGN_KEY_CHECKS=0", "TRUNCATE `users`", diff --git a/tests/mysql/schema/test_mysql_schema_builder_alter.py b/tests/mysql/schema/test_mysql_schema_builder_alter.py index 0bd4a6b00..7a92ad66c 100644 --- a/tests/mysql/schema/test_mysql_schema_builder_alter.py +++ b/tests/mysql/schema/test_mysql_schema_builder_alter.py @@ -26,11 +26,12 @@ def test_can_add_columns(self): self.assertEqual(len(blueprint.table.added_columns), 2) - sql = [ + expected_sql = [ "ALTER TABLE `users` ADD `name` VARCHAR(255) NOT NULL, ADD `age` INT(11) NOT NULL" ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_can_add_column_comments(self): with self.schema.table("users") as blueprint: @@ -59,9 +60,10 @@ def test_can_add_table_comment_with_no_columns(self): self.assertEqual(len(blueprint.table.added_columns), 0) - sql = ["ALTER TABLE `users` COMMENT 'A users username'"] + expected_sql = ["ALTER TABLE `users` COMMENT 'A users username'"] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_can_add_column_after(self): with self.schema.table("users") as blueprint: @@ -69,11 +71,12 @@ def test_can_add_column_after(self): self.assertEqual(len(blueprint.table.added_columns), 1) - sql = [ + expected_sql = [ "ALTER TABLE `users` ADD `name` VARCHAR(255) NOT NULL AFTER `age`" ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_rename(self): with self.schema.table("users") as blueprint: @@ -83,9 +86,12 @@ def test_alter_rename(self): table.add_column("post", "integer") blueprint.table.from_table = table - sql = ["ALTER TABLE `users` CHANGE `post` `comment` INT NOT NULL"] + expected_sql = [ + "ALTER TABLE `users` CHANGE `post` `comment` INT NOT NULL" + ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_add_and_rename(self): with self.schema.table("users") as blueprint: @@ -96,12 +102,13 @@ def test_alter_add_and_rename(self): table.add_column("post", "string") blueprint.table.from_table = table - sql = [ + expected_sql = [ "ALTER TABLE `users` ADD `name` VARCHAR(255) NOT NULL", "ALTER TABLE `users` CHANGE `post` `comment` VARCHAR NOT NULL", ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_add_and_rename_to_string(self): with self.schema.table("users") as blueprint: @@ -112,20 +119,22 @@ def test_alter_add_and_rename_to_string(self): table.add_column("post", "integer") blueprint.table.from_table = table - sql = [ + expected_sql = [ "ALTER TABLE `users` ADD `name` VARCHAR(255) NOT NULL", "ALTER TABLE `users` CHANGE `post` `comment` VARCHAR(200) NOT NULL", ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop1(self): with self.schema.table("users") as blueprint: blueprint.drop_column("post") - sql = ["ALTER TABLE `users` DROP COLUMN `post`"] + expected_sql = ["ALTER TABLE `users` DROP COLUMN `post`"] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_add_column_and_foreign_key(self): with self.schema.table("users") as blueprint: @@ -134,90 +143,110 @@ def test_alter_add_column_and_foreign_key(self): "playlists" ).on_delete("cascade") - sql = [ + expected_sql = [ "ALTER TABLE `users` ADD `playlist_id` INT UNSIGNED NULL", "ALTER TABLE `users` ADD CONSTRAINT users_playlist_id_foreign FOREIGN KEY (playlist_id) REFERENCES playlists(id) ON DELETE CASCADE", ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_foreign_key(self): with self.schema.table("users") as blueprint: blueprint.drop_foreign("users_playlist_id_foreign") - sql = [ + expected_sql = [ "ALTER TABLE `users` DROP FOREIGN KEY users_playlist_id_foreign" ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_foreign_key_shortcut(self): with self.schema.table("users") as blueprint: blueprint.drop_foreign(["playlist_id"]) - sql = [ + expected_sql = [ "ALTER TABLE `users` DROP FOREIGN KEY users_playlist_id_foreign" ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_unique_constraint(self): with self.schema.table("users") as blueprint: blueprint.drop_unique("users_playlist_id_unique") - sql = ["ALTER TABLE `users` DROP INDEX users_playlist_id_unique"] + expected_sql = [ + "ALTER TABLE `users` DROP INDEX users_playlist_id_unique" + ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_add_index(self): with self.schema.table("users") as blueprint: blueprint.index("playlist_id") - sql = ["CREATE INDEX users_playlist_id_index ON `users`(playlist_id)"] + expected_sql = [ + "CREATE INDEX users_playlist_id_index ON `users`(playlist_id)" + ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_index(self): with self.schema.table("users") as blueprint: blueprint.drop_index("users_playlist_id_index") - sql = ["ALTER TABLE `users` DROP INDEX users_playlist_id_index"] + expected_sql = [ + "ALTER TABLE `users` DROP INDEX users_playlist_id_index" + ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_add_primary(self): with self.schema.table("users") as blueprint: blueprint.primary("playlist_id") - sql = [ + expected_sql = [ "ALTER TABLE `users` ADD CONSTRAINT users_playlist_id_primary PRIMARY KEY (playlist_id)" ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_index_shortcut(self): with self.schema.table("users") as blueprint: blueprint.drop_index(["playlist_id"]) - sql = ["ALTER TABLE `users` DROP INDEX users_playlist_id_index"] + expected_sql = [ + "ALTER TABLE `users` DROP INDEX users_playlist_id_index" + ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_unique_constraint_shortcut(self): with self.schema.table("users") as blueprint: blueprint.drop_unique(["playlist_id"]) - sql = ["ALTER TABLE `users` DROP INDEX users_playlist_id_unique"] + expected_sql = [ + "ALTER TABLE `users` DROP INDEX users_playlist_id_unique" + ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_primary(self): with self.schema.table("users") as blueprint: blueprint.drop_primary("users_id_primary") - sql = ["ALTER TABLE `users` DROP INDEX users_id_primary"] + expected_sql = ["ALTER TABLE `users` DROP INDEX users_id_primary"] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_change(self): with self.schema.table("users") as blueprint: @@ -233,12 +262,13 @@ def test_change(self): blueprint.table.from_table = table - sql = [ + expected_sql = [ "ALTER TABLE `users` ADD `external_type` VARCHAR(255) NOT NULL DEFAULT 'external', ADD `name` VARCHAR(255) NOT NULL", "ALTER TABLE `users` MODIFY `age` INT(11) NOT NULL, MODIFY `gender` INT(11) NULL", ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_timestamp_alter_add_nullable_column(self): with self.schema.table("users") as blueprint: @@ -251,9 +281,10 @@ def test_timestamp_alter_add_nullable_column(self): blueprint.table.from_table = table - sql = ["ALTER TABLE `users` ADD `due_date` TIMESTAMP NULL"] + expected_sql = ["ALTER TABLE `users` ADD `due_date` TIMESTAMP NULL"] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_drop_add_and_change(self): with self.schema.table("users") as blueprint: @@ -269,13 +300,14 @@ def test_drop_add_and_change(self): blueprint.table.from_table = table - sql = [ + expected_sql = [ "ALTER TABLE `users` ADD `name` VARCHAR(255) NOT NULL", "ALTER TABLE `users` MODIFY `age` INT(11) NOT NULL DEFAULT 0", "ALTER TABLE `users` DROP COLUMN `email`", ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_can_create_indexes(self): with self.schema.table("users") as blueprint: @@ -288,17 +320,16 @@ def test_can_create_indexes(self): self.assertEqual(len(blueprint.table.added_columns), 0) print(blueprint.to_sql()) - self.assertEqual( - blueprint.to_sql(), - [ - "CREATE INDEX users_name_index ON `users`(name)", - "CREATE INDEX users_name_email_index ON `users`(name,email)", - "ALTER TABLE `users` ADD CONSTRAINT UNIQUE INDEX users_name_unique(name)", - "ALTER TABLE `users` ADD CONSTRAINT UNIQUE INDEX table_unique(name)", - "ALTER TABLE `users` ADD CONSTRAINT UNIQUE INDEX users_name_email_unique(name,email)", - "ALTER TABLE `users` ADD FULLTEXT description_fulltext(description)", - ], - ) + query_sql = blueprint.to_sql() + expected_sql = [ + "CREATE INDEX users_name_index ON `users`(name)", + "CREATE INDEX users_name_email_index ON `users`(name,email)", + "ALTER TABLE `users` ADD CONSTRAINT UNIQUE INDEX users_name_unique(name)", + "ALTER TABLE `users` ADD CONSTRAINT UNIQUE INDEX table_unique(name)", + "ALTER TABLE `users` ADD CONSTRAINT UNIQUE INDEX users_name_email_unique(name,email)", + "ALTER TABLE `users` ADD FULLTEXT description_fulltext(description)", + ] + self.assertEqual(query_sql, expected_sql) def test_can_add_column_enum(self): with self.schema.table("users") as blueprint: @@ -306,11 +337,12 @@ def test_can_add_column_enum(self): self.assertEqual(len(blueprint.table.added_columns), 1) - sql = [ + expected_sql = [ "ALTER TABLE `users` ADD `status` ENUM('active', 'inactive') NOT NULL DEFAULT 'active'" ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_can_change_column_enum(self): with self.schema.table("users") as blueprint: @@ -320,8 +352,9 @@ def test_can_change_column_enum(self): self.assertEqual(len(blueprint.table.changed_columns), 1) - sql = [ + expected_sql = [ "ALTER TABLE `users` MODIFY `status` ENUM('active', 'inactive') NOT NULL DEFAULT 'active'" ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) diff --git a/tests/mysql/scopes/test_can_use_global_scopes.py b/tests/mysql/scopes/test_can_use_global_scopes.py index 89b94d194..f259f6d69 100644 --- a/tests/mysql/scopes/test_can_use_global_scopes.py +++ b/tests/mysql/scopes/test_can_use_global_scopes.py @@ -16,13 +16,14 @@ class User(Model): class TestMySQLGlobalScopes(unittest.TestCase): def test_can_use_global_scopes_on_select(self): - sql = "SELECT * FROM `user_softs` WHERE `user_softs`.`name` = 'joe' AND `user_softs`.`deleted_at` IS NULL" - self.assertEqual(sql, UserSoft.where("name", "joe").to_sql()) + expected_sql = "SELECT * FROM `user_softs` WHERE `user_softs`.`name` = 'joe' AND `user_softs`.`deleted_at` IS NULL" + query_sql = UserSoft.where("name", "joe").to_sql() + self.assertEqual(query_sql, expected_sql) # def test_can_use_global_scopes_on_delete(self): - # sql = "UPDATE `users` SET `users`.`deleted_at` = 'now' WHERE `users`.`name` = 'joe'" + # expected_sql = "UPDATE `users` SET `users`.`deleted_at` = 'now' WHERE `users`.`name` = 'joe'" # self.assertEqual( - # sql, + # expected_sql, # User.apply_scope(SoftDeletes) # .where("name", "joe") # .delete(query=True) @@ -30,9 +31,11 @@ def test_can_use_global_scopes_on_select(self): # ) def test_can_use_global_scopes_on_time(self): - sql = "INSERT INTO `users` (`users`.`name`, `users`.`updated_at`, `users`.`created_at`) VALUES ('Joe'" + expected_sql = "INSERT INTO `users` (`users`.`name`, `users`.`updated_at`, `users`.`created_at`) VALUES ('Joe'" self.assertTrue( - User.create({"name": "Joe"}, query=True).to_sql().startswith(sql) + User.create({"name": "Joe"}, query=True) + .to_sql() + .startswith(expected_sql) ) # def test_can_use_global_scopes_on_inherit(self): diff --git a/tests/mysql/scopes/test_can_use_scopes.py b/tests/mysql/scopes/test_can_use_scopes.py index 354fd0d43..9f73c899d 100644 --- a/tests/mysql/scopes/test_can_use_scopes.py +++ b/tests/mysql/scopes/test_can_use_scopes.py @@ -23,19 +23,21 @@ class UserSoft(Model, SoftDeletesMixin): class TestMySQLScopes(unittest.TestCase): def test_can_get_sql(self): - sql = "SELECT * FROM `users` WHERE `users`.`name` = 'joe'" - self.assertEqual(sql, User.where("name", "joe").to_sql()) + expected_sql = "SELECT * FROM `users` WHERE `users`.`name` = 'joe'" + query_sql = User.where("name", "joe").to_sql() + self.assertEqual(query_sql, expected_sql) def test_active_scope(self): - sql = "SELECT * FROM `users` WHERE `users`.`name` = 'joe' AND `users`.`active` = '1'" - self.assertEqual(sql, User.where("name", "joe").active(1).to_sql()) + expected_sql = "SELECT * FROM `users` WHERE `users`.`name` = 'joe' AND `users`.`active` = '1'" + query_sql = User.where("name", "joe").active(1).to_sql() + self.assertEqual(query_sql, expected_sql) def test_active_scope_with_params(self): - sql = "SELECT * FROM `users` WHERE `users`.`active` = '2' AND `users`.`name` = 'joe'" - self.assertEqual(sql, User.active(2).where("name", "joe").to_sql()) + expected_sql = "SELECT * FROM `users` WHERE `users`.`active` = '2' AND `users`.`name` = 'joe'" + query_sql = User.active(2).where("name", "joe").to_sql() + self.assertEqual(query_sql, expected_sql) def test_can_chain_scopes(self): - sql = "SELECT * FROM `users` WHERE `users`.`active` = '2' AND `users`.`gender` = 'W' AND `users`.`name` = 'joe'" - self.assertEqual( - sql, User.active(2).gender("W").where("name", "joe").to_sql() - ) + expected_sql = "SELECT * FROM `users` WHERE `users`.`active` = '2' AND `users`.`gender` = 'W' AND `users`.`name` = 'joe'" + query_sql = User.active(2).gender("W").where("name", "joe").to_sql() + self.assertEqual(query_sql, expected_sql) diff --git a/tests/mysql/scopes/test_soft_delete.py b/tests/mysql/scopes/test_soft_delete.py index 7d6689b45..7605651c4 100644 --- a/tests/mysql/scopes/test_soft_delete.py +++ b/tests/mysql/scopes/test_soft_delete.py @@ -32,55 +32,71 @@ def get_builder(self, table="users"): ) def test_with_trashed(self): - sql = "SELECT * FROM `users`" + expected_sql = "SELECT * FROM `users`" builder = self.get_builder().set_global_scope(SoftDeleteScope()) - self.assertEqual(sql, builder.with_trashed().to_sql()) + query_sql = builder.with_trashed().to_sql() + self.assertEqual(query_sql, expected_sql) def test_force_delete(self): - sql = "DELETE FROM `users`" + expected_sql = "DELETE FROM `users`" builder = self.get_builder().set_global_scope(SoftDeleteScope()) - self.assertEqual(sql, builder.force_delete(query=True).to_sql()) + query_sql = builder.force_delete(query=True).to_sql() + self.assertEqual(query_sql, expected_sql) def test_restore(self): - sql = "UPDATE `users` SET `users`.`deleted_at` = 'None'" + expected_sql = "UPDATE `users` SET `users`.`deleted_at` = 'None'" builder = self.get_builder().set_global_scope(SoftDeleteScope()) - self.assertEqual(sql, builder.restore().to_sql()) + query_sql = builder.restore().to_sql() + self.assertEqual(query_sql, expected_sql) def test_force_delete_with_wheres(self): - sql = "DELETE FROM `users` WHERE `users`.`active` = '1'" - self.assertEqual( - sql, UserSoft.where("active", 1).force_delete(query=True).to_sql() + expected_sql = "DELETE FROM `users` WHERE `users`.`active` = '1'" + query_sql = ( + UserSoft.where("active", 1).force_delete(query=True).to_sql() ) + self.assertEqual(query_sql, expected_sql) def test_that_trashed_users_are_not_returned_by_default(self): - sql = "SELECT * FROM `users` WHERE `users`.`deleted_at` IS NULL" + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`deleted_at` IS NULL" + ) builder = self.get_builder().set_global_scope(SoftDeleteScope()) - self.assertEqual(sql, builder.to_sql()) + query_sql = builder.to_sql() + self.assertEqual(query_sql, expected_sql) def test_only_trashed(self): - sql = "SELECT * FROM `users` WHERE `users`.`deleted_at` IS NOT NULL" + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`deleted_at` IS NOT NULL" + ) builder = self.get_builder().set_global_scope(SoftDeleteScope()) - self.assertEqual(sql, builder.only_trashed().to_sql()) + query_sql = builder.only_trashed().to_sql() + self.assertEqual(query_sql, expected_sql) def test_only_trashed_on_model(self): - sql = "SELECT * FROM `users` WHERE `users`.`deleted_at` IS NOT NULL" - self.assertEqual(sql, UserSoft.only_trashed().to_sql()) + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`deleted_at` IS NOT NULL" + ) + query_sql = UserSoft.only_trashed().to_sql() + self.assertEqual(query_sql, expected_sql) def test_can_change_column(self): - sql = "SELECT * FROM `users` WHERE `users`.`archived_at` IS NOT NULL" - self.assertEqual(sql, UserSoftArchived.only_trashed().to_sql()) + expected_sql = ( + "SELECT * FROM `users` WHERE `users`.`archived_at` IS NOT NULL" + ) + query_sql = UserSoftArchived.only_trashed().to_sql() + self.assertEqual(query_sql, expected_sql) def test_find_with_global_scope(self): - find_sql = UserSoft.find("1", query=True).to_sql() - raw_sql = """SELECT * FROM `users` WHERE `users`.`id` = '1' AND `users`.`deleted_at` IS NULL""" - self.assertEqual(find_sql, raw_sql) + query_sql = UserSoft.find("1", query=True).to_sql() + expected_sql = """SELECT * FROM `users` WHERE `users`.`id` = '1' AND `users`.`deleted_at` IS NULL""" + self.assertEqual(query_sql, expected_sql) def test_find_with_trashed_scope(self): - find_sql = UserSoft.with_trashed().find("1", query=True).to_sql() - raw_sql = """SELECT * FROM `users` WHERE `users`.`id` = '1'""" - self.assertEqual(find_sql, raw_sql) + query_sql = UserSoft.with_trashed().find("1", query=True).to_sql() + expected_sql = """SELECT * FROM `users` WHERE `users`.`id` = '1'""" + self.assertEqual(query_sql, expected_sql) def test_find_with_only_trashed_scope(self): - find_sql = UserSoft.only_trashed().find("1", query=True).to_sql() - raw_sql = """SELECT * FROM `users` WHERE `users`.`deleted_at` IS NOT NULL AND `users`.`id` = '1'""" - self.assertEqual(find_sql, raw_sql) + query_sql = UserSoft.only_trashed().find("1", query=True).to_sql() + expected_sql = """SELECT * FROM `users` WHERE `users`.`deleted_at` IS NOT NULL AND `users`.`id` = '1'""" + self.assertEqual(query_sql, expected_sql) diff --git a/tests/postgres/builder/test_postgres_query_builder.py b/tests/postgres/builder/test_postgres_query_builder.py index 1431b9f91..52fb2c0b2 100644 --- a/tests/postgres/builder/test_postgres_query_builder.py +++ b/tests/postgres/builder/test_postgres_query_builder.py @@ -1,4 +1,3 @@ -import inspect import unittest from src.masoniteorm.models import Model @@ -22,11 +21,18 @@ class ModelTest(Model): __timestamps__ = False -class BaseTestQueryBuilder: +class PostgresQueryBuilderTest(unittest.TestCase): + """Tests for the QueryBuilder using the Postgres grammar. + + Each test builds a query and asserts the expected SQL inline. + """ + + maxDiff = None + def get_builder(self, table="users", dry=True): connection = MockConnectionFactory().make("postgres") return QueryBuilder( - self.grammar, + PostgresGrammar, connection_class=connection, connection="postgres", table=table, @@ -34,775 +40,436 @@ def get_builder(self, table="users", dry=True): dry=dry, ) + # ------------------------------------------------------------------ + # Aggregates + # ------------------------------------------------------------------ + def test_sum(self): builder = self.get_builder() builder.sum("age") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - 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) + query_sql = builder.to_sql() + expected_sql = 'SELECT SUM("users"."age") AS age FROM "users"' + self.assertEqual(query_sql, expected_sql) def test_max(self): builder = self.get_builder() builder.max("age") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT MAX("users"."age") AS age FROM "users"' + self.assertEqual(query_sql, expected_sql) def test_min(self): builder = self.get_builder() builder.min("age") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT MIN("users"."age") AS age FROM "users"' + self.assertEqual(query_sql, expected_sql) def test_avg(self): builder = self.get_builder() builder.avg("age") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT AVG("users"."age") AS age FROM "users"' + self.assertEqual(query_sql, expected_sql) + + def test_count(self): + builder = self.get_builder() + builder.count("id") + query_sql = builder.to_sql() + expected_sql = 'SELECT COUNT("users"."id") AS id FROM "users"' + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # Fetch operations + # ------------------------------------------------------------------ def test_all(self): builder = self.get_builder() builder.all() - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users"' + self.assertEqual(query_sql, expected_sql) def test_get(self): builder = self.get_builder() builder.get() - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users"' + self.assertEqual(query_sql, expected_sql) def test_first(self): builder = self.get_builder().first(query=True) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" LIMIT 1' + self.assertEqual(query_sql, expected_sql) + + def test_latest(self): + builder = self.get_builder() + builder.latest("email") + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" ORDER BY "email" DESC' + self.assertEqual(query_sql, expected_sql) + + def test_oldest(self): + builder = self.get_builder() + builder.oldest("email") + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" ORDER BY "email" ASC' + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # SELECT columns + # ------------------------------------------------------------------ def test_select(self): builder = self.get_builder() builder.select("name", "email") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT "users"."name", "users"."email" FROM "users"' + self.assertEqual(query_sql, expected_sql) def test_add_select_no_table(self): builder = self.get_builder(table=None) - sql = ( - builder.add_select( - "other_test", - lambda q: q.max("updated_at").table("different_table"), - ) - .add_select( - "some_alias", - lambda q: q.max("updated_at").table("another_table"), - ) - .to_sql() + builder.add_select( + "other_test", + lambda q: q.max("updated_at").table("different_table"), + ).add_select( + "some_alias", lambda q: q.max("updated_at").table("another_table") ) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = ( + "SELECT " + '(SELECT MAX("different_table"."updated_at") AS updated_at FROM "different_table") AS other_test, ' + '(SELECT MAX("another_table"."updated_at") AS updated_at FROM "another_table") AS some_alias' + ) + self.assertEqual(query_sql, expected_sql) def test_select_raw(self): builder = self.get_builder() builder.select_raw("count(email) as email_count") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT count(email) as email_count FROM "users"' + self.assertEqual(query_sql, expected_sql) - def test_create(self): - builder = self.get_builder().without_global_scopes() - builder.create( - {"name": "Corentin All", "email": "corentin@yopmail.com"}, - query=True, - ) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_delete(self): - builder = self.get_builder() - builder.delete("name", "Joe", query=True) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + # ------------------------------------------------------------------ + # WHERE + # ------------------------------------------------------------------ def test_where(self): builder = self.get_builder() builder.where("name", "Joe") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."name" = \'Joe\'' + self.assertEqual(query_sql, expected_sql) def test_where_exists(self): builder = self.get_builder() builder.where_exists("name") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_limit(self): - builder = self.get_builder() - builder.limit(5) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_offset(self): - builder = self.get_builder() - builder.offset(5) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM \"users\" WHERE EXISTS 'name'" + self.assertEqual(query_sql, expected_sql) - def test_join(self): - builder = self.get_builder() - builder.join("profiles", "users.id", "=", "profiles.user_id") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_left_join(self): - builder = self.get_builder() - builder.left_join("profiles", "users.id", "=", "profiles.user_id") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_right_join(self): + def test_where_like(self): builder = self.get_builder() - builder.right_join("profiles", "users.id", "=", "profiles.user_id") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_update(self): - builder = self.get_builder().update( - {"name": "Joe", "email": "joe@yopmail.com"}, dry=True + builder.where("age", "like", "%name%") + query_sql = builder.to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."age" ILIKE \'%name%\'' ) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - # def test_increment(self): - # builder = self.get_builder() - # builder.increment("age", 1) - # sql = getattr( - # self, inspect.currentframe().f_code.co_name.replace("test_", "") - # )() - # self.assertEqual(builder.to_sql(), sql) - - # def test_decrement(self): - # builder = self.get_builder() - # builder.decrement("age", 1) - # sql = getattr( - # self, inspect.currentframe().f_code.co_name.replace("test_", "") - # )() - # self.assertEqual(builder.to_sql(), sql) - - def test_count(self): - builder = self.get_builder() - builder.count("id") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + self.assertEqual(query_sql, expected_sql) - def test_order_by_asc(self): + def test_where_not_like(self): builder = self.get_builder() - builder.order_by("email", "asc") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + builder.where("age", "not like", "%name%") + query_sql = builder.to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."age" NOT ILIKE \'%name%\'' + ) + self.assertEqual(query_sql, expected_sql) - def test_order_by_desc(self): + def test_where_null(self): builder = self.get_builder() - builder.order_by("email", "desc") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + builder.where_null("name") + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."name" IS NULL' + self.assertEqual(query_sql, expected_sql) - def test_where_column(self): + def test_where_not_null(self): builder = self.get_builder() - builder.where_column("name", "username") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + builder.where_not_null("name") + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."name" IS NOT NULL' + self.assertEqual(query_sql, expected_sql) def test_where_not_in(self): builder = self.get_builder() builder.where_not_in("id", [1, 2, 3]) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_between(self): - builder = self.get_builder() - builder.between("id", 2, 5) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_not_between(self): - builder = self.get_builder() - builder.not_between("id", 2, 5) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM \"users\" WHERE \"users\".\"id\" NOT IN ('1','2','3')" + self.assertEqual(query_sql, expected_sql) def test_where_in(self): builder = self.get_builder() builder.where_in("id", [1, 2, 3]) - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_where_null(self): - builder = self.get_builder() - builder.where_null("name") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_where_not_null(self): - builder = self.get_builder() - builder.where_not_null("name") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_having(self): - builder = self.get_builder(table="payments") - builder.select("user_id").avg("salary").group_by("user_id").having( - "salary", ">=", "1000" - ) - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_group_by(self): - builder = self.get_builder(table="payments") - builder.select("user_id").min("salary").group_by("user_id") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_builder_alone(self): - self.assertTrue( - QueryBuilder( - connection_class=MockConnection, - connection="postgres", - connection_details={ - "default": "postgres", - "postgres": { - "driver": "postgres", - "host": "localhost", - "user": "postgres", - "password": "postgres", - "database": "orm", - "port": "5432", - "prefix": "", - "grammar": "postgres", - }, - }, - ).table("users") + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM \"users\" WHERE \"users\".\"id\" IN ('1','2','3')" ) + self.assertEqual(query_sql, expected_sql) def test_where_lt(self): builder = self.get_builder() builder.where("age", "<", "20") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."age" < \'20\'' + self.assertEqual(query_sql, expected_sql) def test_where_lte(self): builder = self.get_builder() builder.where("age", "<=", "20") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."age" <= \'20\'' + self.assertEqual(query_sql, expected_sql) def test_where_gt(self): builder = self.get_builder() builder.where("age", ">", "20") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."age" > \'20\'' + self.assertEqual(query_sql, expected_sql) def test_where_gte(self): builder = self.get_builder() builder.where("age", ">=", "20") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."age" >= \'20\'' + self.assertEqual(query_sql, expected_sql) def test_where_ne(self): builder = self.get_builder() builder.where("age", "!=", "20") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."age" != \'20\'' + self.assertEqual(query_sql, expected_sql) def test_or_where(self): builder = self.get_builder() builder.where("age", "20").or_where("age", "<", 20) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."age" = \'20\' OR "users"."age" < \'20\'' + self.assertEqual(query_sql, expected_sql) - def test_can_call_with_schema(self): + def test_where_column(self): builder = self.get_builder() - sql = ( - builder.table("information_schema.columns") - .select("table_name") - .where("table_name", "users") - .to_sql() - ) - self.assertEqual( - sql, - """SELECT "information_schema"."columns"."table_name" FROM "information_schema"."columns" WHERE "information_schema"."columns"."table_name" = 'users'""", + builder.where_column("name", "username") + query_sql = builder.to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."name" = "users"."username"' ) + self.assertEqual(query_sql, expected_sql) - def test_truncate(self): - builder = self.get_builder(dry=True) - sql = builder.truncate() - sql_ref = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(sql, sql_ref) - - def test_truncate_without_foreign_keys(self): - builder = self.get_builder(dry=True) - sql = builder.truncate(foreign_keys=True) - sql_ref = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(sql, sql_ref) - - def test_shared_lock(self): - builder = self.get_builder(dry=True) - sql = builder.where("votes", ">=", 100).shared_lock().to_sql() - sql_ref = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(sql, sql_ref) - - def test_update_lock(self): - builder = self.get_builder(dry=True) - sql = builder.where("votes", ">=", 100).lock_for_update().to_sql() - sql_ref = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(sql, sql_ref) - - -class PostgresQueryBuilderTest(BaseTestQueryBuilder, unittest.TestCase): - grammar = PostgresGrammar - - def sum(self): - """ + def test_between(self): builder = self.get_builder() - builder.sum('age') - """ - return """SELECT SUM("users"."age") AS age FROM "users\"""" + builder.between("id", 2, 5) + query_sql = builder.to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."id" BETWEEN \'2\' AND \'5\'' + ) + self.assertEqual(query_sql, expected_sql) - def max(self): - """ + def test_not_between(self): builder = self.get_builder() - builder.max('age') - """ - return """SELECT MAX("users"."age") AS age FROM "users\"""" + builder.not_between("id", 2, 5) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."id" NOT BETWEEN \'2\' AND \'5\'' + self.assertEqual(query_sql, expected_sql) - def min(self): - """ - builder = self.get_builder() - builder.min('age') - """ - return """SELECT MIN("users"."age") AS age FROM "users\"""" + def test_having(self): + builder = self.get_builder(table="payments") + builder.select("user_id").avg("salary").group_by("user_id").having( + "salary", ">=", "1000" + ) + query_sql = builder.to_sql() + expected_sql = ( + 'SELECT "payments"."user_id", AVG("payments"."salary") AS salary' + ' FROM "payments" GROUP BY "payments"."user_id" HAVING "payments"."salary" >= \'1000\'' + ) + self.assertEqual(query_sql, expected_sql) - def avg(self): - """ - builder = self.get_builder() - builder.avg('age') - """ - return """SELECT AVG("users"."age") AS age FROM "users\"""" + # ------------------------------------------------------------------ + # LIMIT / OFFSET + # ------------------------------------------------------------------ - def first(self): - """ + def test_limit(self): builder = self.get_builder() - builder.first() - """ - return """SELECT * FROM "users" LIMIT 1""" + builder.limit(5) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" LIMIT 5' + self.assertEqual(query_sql, expected_sql) - def all(self): - """ + def test_offset(self): builder = self.get_builder() - builder.all() - """ - return """SELECT * FROM "users\"""" + builder.offset(5) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" OFFSET 5' + self.assertEqual(query_sql, expected_sql) - def get(self): - """ - builder = self.get_builder() - builder.get() - """ - return """SELECT * FROM "users\"""" + # ------------------------------------------------------------------ + # ORDER BY / GROUP BY + # ------------------------------------------------------------------ - def select(self): - """ + def test_order_by_asc(self): builder = self.get_builder() - builder.select('name', 'email') - """ - return """SELECT "users"."name", "users"."email" FROM "users\"""" + builder.order_by("email", "asc") + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" ORDER BY "email" ASC' + self.assertEqual(query_sql, expected_sql) - def add_select_no_table(self): - """ + def test_order_by_desc(self): builder = self.get_builder() - builder.select('name', 'email') - """ - return ( - "SELECT " - '(SELECT MAX("different_table"."updated_at") AS updated_at FROM "different_table") AS other_test, ' - '(SELECT MAX("another_table"."updated_at") AS updated_at FROM "another_table") AS some_alias' - ) + builder.order_by("email", "desc") + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" ORDER BY "email" DESC' + self.assertEqual(query_sql, expected_sql) - def select_raw(self): - """ - builder = self.get_builder() - builder.select_raw('count(email) as email_count') - """ - return """SELECT count(email) as email_count FROM "users\"""" - - def create(self): - """ - builder = get_builder() - builder.create({"name": "Corentin All", 'email': 'corentin@yopmail.com'}) - """ - return """INSERT INTO "users" ("name", "email") VALUES ('Corentin All', 'corentin@yopmail.com') RETURNING *""" - - def delete(self): - """ - builder = get_builder() - builder.delete("name', 'Joe') - """ - return """DELETE FROM "users" WHERE "users"."name" = 'Joe'""" - - def where(self): - """ - builder = get_builder() - builder.where('name', 'Joe') - """ - return """SELECT * FROM "users" WHERE "users"."name" = 'Joe'""" - - def where_exists(self): - """ - builder = get_builder() - builder.where_exists('name') - """ - return """SELECT * FROM "users" WHERE EXISTS 'name'""" - - def limit(self): - """ - builder = get_builder() - builder.limit(5) - """ - return """SELECT * FROM "users" LIMIT 5""" + def test_group_by(self): + builder = self.get_builder(table="payments") + builder.select("user_id").min("salary").group_by("user_id") + query_sql = builder.to_sql() + expected_sql = ( + 'SELECT "payments"."user_id", MIN("payments"."salary") AS salary' + ' FROM "payments" GROUP BY "payments"."user_id"' + ) + self.assertEqual(query_sql, expected_sql) - def offset(self): - """ - builder = get_builder() - builder.offset(5) - """ - return """SELECT * FROM "users" OFFSET 5""" + # ------------------------------------------------------------------ + # JOINs + # ------------------------------------------------------------------ - def join(self): - """ + def test_join(self): + builder = self.get_builder() builder.join("profiles", "users.id", "=", "profiles.user_id") - """ - return """SELECT * FROM "users" INNER JOIN "profiles" ON "users"."id" = "profiles"."user_id\"""" + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" INNER JOIN "profiles" ON "users"."id" = "profiles"."user_id"' + self.assertEqual(query_sql, expected_sql) - def left_join(self): - """ + def test_left_join(self): + builder = self.get_builder() builder.left_join("profiles", "users.id", "=", "profiles.user_id") - """ - return """SELECT * FROM "users" LEFT JOIN "profiles" ON "users"."id" = "profiles"."user_id\"""" + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" LEFT JOIN "profiles" ON "users"."id" = "profiles"."user_id"' + self.assertEqual(query_sql, expected_sql) - def right_join(self): - """ + def test_right_join(self): + builder = self.get_builder() builder.right_join("profiles", "users.id", "=", "profiles.user_id") - """ - return """SELECT * FROM "users" RIGHT JOIN "profiles" ON "users"."id" = "profiles"."user_id\"""" - - def update(self): - """ - builder.update({"name": "Joe", "email": "joe@yopmail.com"}) - """ - return """UPDATE "users" SET "name" = 'Joe', "email" = 'joe@yopmail.com'""" - - def increment(self): - """ - builder.increment('age', 1) - """ - return """UPDATE "users" SET "age" = "age" + '1'""" - - def decrement(self): - """ - builder.decrement('age', 1) - """ - return """UPDATE "users" SET "age" = "age" - '1'""" - - def count(self): - """ - builder.count(id) - """ - return """SELECT COUNT("users"."id") AS id FROM "users\"""" - - def order_by_asc(self): - """ - builder.order_by('email', 'asc') - """ - return """SELECT * FROM "users" ORDER BY "email" ASC""" - - def order_by_desc(self): - """ - builder.order_by('email', 'des') - """ - return """SELECT * FROM "users" ORDER BY "email" DESC""" - - def where_column(self): - """ - builder.where_column('name', 'username') - """ - return """SELECT * FROM "users" WHERE "users"."name" = "users"."username\"""" - - def where_null(self): - """ - builder.where_null('name') - """ - return """SELECT * FROM "users" WHERE "users"."name" IS NULL""" - - def where_not_null(self): - """ - builder.where_null('name') - """ - return """SELECT * FROM "users" WHERE "users"."name" IS NOT NULL""" - - def where_not_in(self): - """ - builder.where_not_in('id', [1, 2, 3]) - """ - return ( - """SELECT * FROM "users" WHERE "users"."id" NOT IN ('1','2','3')""" - ) - - def where_in(self): - """ - builder.where_in('id', [1, 2, 3]) - """ - return """SELECT * FROM "users" WHERE "users"."id" IN ('1','2','3')""" - - def between(self): - """ - builder.between('id', 2, 5) - """ - return ( - """SELECT * FROM "users" WHERE "users"."id" BETWEEN '2' AND '5'""" - ) - - def not_between(self): - """ - builder.not_between('id', 2, 5) - """ - return """SELECT * FROM "users" WHERE "users"."id" NOT BETWEEN '2' AND '5'""" + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" RIGHT JOIN "profiles" ON "users"."id" = "profiles"."user_id"' + self.assertEqual(query_sql, expected_sql) - def having(self): - """ - builder.select('user_id').avg('salary').group_by('user_id').having('salary', '>=', '1000') - """ - return """SELECT "payments"."user_id", AVG("payments"."salary") AS salary FROM "payments" GROUP BY "payments"."user_id" HAVING "payments"."salary" >= '1000'""" + # ------------------------------------------------------------------ + # DML + # ------------------------------------------------------------------ - def group_by(self): - """ - builder.select('user_id').min('salary').group_by('user_id') - """ - return """SELECT "payments"."user_id", MIN("payments"."salary") AS salary FROM "payments" GROUP BY "payments"."user_id\"""" - - def where_lt(self): - """ - builder = self.get_builder() - builder.where('age', '<', '20') - """ - return """SELECT * FROM "users" WHERE "users"."age" < '20'""" + def test_create(self): + builder = self.get_builder().without_global_scopes() + builder.create( + {"name": "Corentin All", "email": "corentin@yopmail.com"}, + query=True, + ) + query_sql = builder.to_sql() + expected_sql = 'INSERT INTO "users" ("name", "email") VALUES (\'Corentin All\', \'corentin@yopmail.com\') RETURNING *' + self.assertEqual(query_sql, expected_sql) - def where_lte(self): - """ + def test_delete(self): builder = self.get_builder() - builder.where('age', '<=', '20') - """ - return """SELECT * FROM "users" WHERE "users"."age" <= '20'""" + builder.delete("name", "Joe", query=True) + query_sql = builder.to_sql() + expected_sql = 'DELETE FROM "users" WHERE "users"."name" = \'Joe\'' + self.assertEqual(query_sql, expected_sql) - def where_gt(self): - """ - builder = self.get_builder() - builder.where('age', '>', '20') - """ - return """SELECT * FROM "users" WHERE "users"."age" > '20'""" + def test_update(self): + builder = self.get_builder().update( + {"name": "Joe", "email": "joe@yopmail.com"}, dry=True + ) + query_sql = builder.to_sql() + expected_sql = 'UPDATE "users" SET "name" = \'Joe\', "email" = \'joe@yopmail.com\'' + self.assertEqual(query_sql, expected_sql) - def where_gte(self): - """ - builder = self.get_builder() - builder.where('age', '>=', '20') - """ - return """SELECT * FROM "users" WHERE "users"."age" >= '20'""" + # ------------------------------------------------------------------ + # TRUNCATE + # ------------------------------------------------------------------ - def where_ne(self): - """ - builder = self.get_builder() - builder.where('age', '!=', '20') - """ - return """SELECT * FROM "users" WHERE "users"."age" != '20'""" + def test_truncate(self): + builder = self.get_builder(dry=True) + query_sql = builder.truncate() + expected_sql = 'TRUNCATE TABLE "users"' + self.assertEqual(query_sql, expected_sql) - def or_where(self): - """ - builder = self.get_builder() - builder.where('age', '20').or_where('age','<', 20) - """ - return """SELECT * FROM "users" WHERE "users"."age" = '20' OR "users"."age" < '20'""" + def test_truncate_without_foreign_keys(self): + # Postgres TRUNCATE ignores the foreign_keys flag and always issues TRUNCATE TABLE + builder = self.get_builder(dry=True) + query_sql = builder.truncate(foreign_keys=True) + expected_sql = 'TRUNCATE TABLE "users"' + self.assertEqual(query_sql, expected_sql) - def where_like(self): - """ - builder = self.get_builder() - builder.where("age", "like", "%name%") - """ - return """SELECT * FROM "users" WHERE "users"."age" ILIKE '%name%'""" + # ------------------------------------------------------------------ + # Locking + # ------------------------------------------------------------------ - def where_not_like(self): - """ - builder = self.get_builder() - builder.where("age", "not like", "%name%") - """ - return ( - """SELECT * FROM "users" WHERE "users"."age" NOT ILIKE '%name%'""" + def test_shared_lock(self): + builder = self.get_builder(dry=True) + query_sql = builder.where("votes", ">=", 100).shared_lock().to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."votes" >= \'100\' FOR SHARE' ) + self.assertEqual(query_sql, expected_sql) - def truncate(self): - """ - builder = self.get_builder() - builder.truncate() - """ - return """TRUNCATE TABLE "users\"""" - - def truncate_without_foreign_keys(self): - """ - builder = self.get_builder() - builder.truncate() - """ - return """TRUNCATE TABLE "users\"""" - - def update_lock(self): - """ - builder = self.get_builder() - builder.truncate() - """ - return """SELECT * FROM "users" WHERE "users"."votes" >= '100' FOR UPDATE""" + def test_update_lock(self): + builder = self.get_builder(dry=True) + query_sql = ( + builder.where("votes", ">=", 100).lock_for_update().to_sql() + ) + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."votes" >= \'100\' FOR UPDATE' + ) + self.assertEqual(query_sql, expected_sql) - def shared_lock(self): - """ - builder = self.get_builder() - builder.truncate() - """ - return """SELECT * FROM "users" WHERE "users"."votes" >= '100' FOR SHARE""" + # ------------------------------------------------------------------ + # Misc + # ------------------------------------------------------------------ - 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_builder_alone(self): + self.assertTrue( + QueryBuilder( + connection_class=MockConnection, + connection="postgres", + connection_details={ + "default": "postgres", + "postgres": { + "driver": "postgres", + "host": "localhost", + "user": "postgres", + "password": "postgres", + "database": "orm", + "port": "5432", + "prefix": "", + "grammar": "postgres", + }, + }, + ).table("users") + ) - def test_oldest(self): + def test_can_call_with_schema(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""" + query_sql = ( + builder.table("information_schema.columns") + .select("table_name") + .where("table_name", "users") + .to_sql() + ) + expected_sql = ( + 'SELECT "information_schema"."columns"."table_name" FROM "information_schema"."columns"' + ' WHERE "information_schema"."columns"."table_name" = \'users\'' + ) + self.assertEqual(query_sql, expected_sql) diff --git a/tests/postgres/grammar/test_delete_grammar.py b/tests/postgres/grammar/test_delete_grammar.py index 690e72537..904b347af 100644 --- a/tests/postgres/grammar/test_delete_grammar.py +++ b/tests/postgres/grammar/test_delete_grammar.py @@ -1,77 +1,32 @@ -import inspect import unittest from src.masoniteorm.query import QueryBuilder from src.masoniteorm.query.grammars import PostgresGrammar -class BaseDeleteGrammarTest: +class TestPostgresDeleteGrammar(unittest.TestCase): def setUp(self): self.builder = QueryBuilder(PostgresGrammar, table="users") def test_can_compile_delete(self): - to_sql = self.builder.delete("id", 1, query=True).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + query_sql = self.builder.delete("id", 1, query=True).to_sql() + expected_sql = """DELETE FROM "users" WHERE "users"."id" = '1'""" + self.assertEqual(query_sql, expected_sql) def test_can_compile_delete_in(self): - to_sql = self.builder.delete("id", [1, 2, 3], query=True).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + query_sql = self.builder.delete("id", [1, 2, 3], query=True).to_sql() + expected_sql = ( + """DELETE FROM "users" WHERE "users"."id" IN ('1','2','3')""" + ) + self.assertEqual(query_sql, expected_sql) def test_can_compile_delete_with_where(self): - to_sql = ( + query_sql = ( self.builder.where("age", 20) .where("profile", 1) .set_action("delete") .delete(query=True) .to_sql() ) - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) - - -class TestPostgresDeleteGrammar(BaseDeleteGrammarTest, unittest.TestCase): - grammar = "postgres" - - def can_compile_delete(self): - """ - ( - self.builder - .delete('id', 1) - .to_sql() - ) - """ - return """DELETE FROM "users" WHERE "users"."id" = '1'""" - - def can_compile_delete_in(self): - """ - ( - self.builder - .delete('id', 1) - .to_sql() - ) - """ - return """DELETE FROM "users" WHERE "users"."id" IN ('1','2','3')""" - - def can_compile_delete_with_where(self): - """ - ( - self.builder - .where('age', 20) - .where('profile', 1) - .set_action('delete') - .delete() - .to_sql() - ) - """ - return """DELETE FROM "users" WHERE "users"."age" = '20' AND "users"."profile" = '1'""" + expected_sql = """DELETE FROM "users" WHERE "users"."age" = '20' AND "users"."profile" = '1'""" + self.assertEqual(query_sql, expected_sql) diff --git a/tests/postgres/grammar/test_insert_grammar.py b/tests/postgres/grammar/test_insert_grammar.py index 6404d2e34..182a7295d 100644 --- a/tests/postgres/grammar/test_insert_grammar.py +++ b/tests/postgres/grammar/test_insert_grammar.py @@ -1,33 +1,30 @@ -import inspect import unittest from src.masoniteorm.query import QueryBuilder from src.masoniteorm.query.grammars import PostgresGrammar -class BaseInsertGrammarTest: +class TestPostgresInsertGrammar(unittest.TestCase): def setUp(self): self.builder = QueryBuilder(PostgresGrammar, table="users") def test_can_compile_insert(self): - to_sql = self.builder.create({"name": "Joe"}, query=True).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + query_sql = self.builder.create({"name": "Joe"}, query=True).to_sql() + expected_sql = ( + """INSERT INTO "users" ("name") VALUES ('Joe') RETURNING *""" + ) + self.assertEqual(query_sql, expected_sql) def test_can_compile_insert_with_keywords(self): - to_sql = self.builder.create(name="Joe", query=True).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + query_sql = self.builder.create(name="Joe", query=True).to_sql() + expected_sql = ( + """INSERT INTO "users" ("name") VALUES ('Joe') RETURNING *""" + ) + self.assertEqual(query_sql, expected_sql) def test_can_compile_bulk_create(self): - to_sql = self.builder.bulk_create( - # These keys are intentionally out of order to show column to value alignment works + # Keys are intentionally out of order to verify column-to-value alignment + query_sql = self.builder.bulk_create( [ {"name": "Joe", "age": 5}, {"age": 35, "name": "Bill"}, @@ -35,48 +32,14 @@ def test_can_compile_bulk_create(self): ], query=True, ).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + expected_sql = """INSERT INTO "users" ("age", "name") VALUES ('5', 'Joe'), ('35', 'Bill'), ('10', 'John') RETURNING *""" + self.assertEqual(query_sql, expected_sql) def test_can_compile_bulk_create_qmark(self): - to_sql = self.builder.bulk_create( + query_sql = self.builder.bulk_create( [{"name": "Joe"}, {"name": "Bill"}, {"name": "John"}], query=True ).to_qmark() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) - - -class TestPostgresUpdateGrammar(BaseInsertGrammarTest, unittest.TestCase): - grammar = "postgres" - - def can_compile_insert(self): - """ - self.builder.create({ - 'name': 'Joe' - }).to_sql() - """ - return """INSERT INTO "users" ("name") VALUES ('Joe') RETURNING *""" - - def can_compile_insert_with_keywords(self): - """ - self.builder.create(name="Joe").to_sql() - """ - return """INSERT INTO "users" ("name") VALUES ('Joe') RETURNING *""" - - def can_compile_bulk_create(self): - """ - self.builder.create(name="Joe").to_sql() - """ - return """INSERT INTO "users" ("age", "name") VALUES ('5', 'Joe'), ('35', 'Bill'), ('10', 'John') RETURNING *""" - - def can_compile_bulk_create_qmark(self): - """ - self.builder.create(name="Joe").to_sql() - """ - return """INSERT INTO "users" ("name") VALUES (?), (?), (?) RETURNING *""" + expected_sql = ( + """INSERT INTO "users" ("name") VALUES (?), (?), (?) RETURNING *""" + ) + self.assertEqual(query_sql, expected_sql) diff --git a/tests/postgres/grammar/test_select_grammar.py b/tests/postgres/grammar/test_select_grammar.py index f55d06a42..29acb7466 100644 --- a/tests/postgres/grammar/test_select_grammar.py +++ b/tests/postgres/grammar/test_select_grammar.py @@ -1,511 +1,609 @@ import unittest +from src.masoniteorm.expressions import JoinClause +from src.masoniteorm.models import Model +from src.masoniteorm.query import QueryBuilder from src.masoniteorm.query.grammars import PostgresGrammar -from src.masoniteorm.testing import BaseTestCaseSelectGrammar - - -class TestPostgresGrammar(BaseTestCaseSelectGrammar, unittest.TestCase): - grammar = PostgresGrammar - - def can_compile_select(self): - """ - self.builder.to_sql() - """ - return """SELECT * FROM "users\"""" - - def can_compile_with_columns(self): - """ - self.builder.select('username', 'password').to_sql() - """ - return ( - """SELECT "users"."username", "users"."password" FROM "users\"""" - ) - - def can_compile_with_where(self): - """ - self.builder.select('username', 'password').where('id', 1).to_sql() - """ - return """SELECT "users"."username", "users"."password" FROM "users" WHERE "users"."id" = '1'""" - - def can_compile_with_several_where(self): - """ - self.builder.select('username', 'password').where('id', 1).where('username', 'joe').to_sql() - """ - return """SELECT "users"."username", "users"."password" FROM "users" WHERE "users"."id" = '1' AND "users"."username" = 'joe'""" - - def can_compile_with_several_where_and_limit(self): - """ - self.builder.select('username', 'password').where('id', 1).where('username', 'joe').limit(10).to_sql() - """ - return """SELECT "users"."username", "users"."password" FROM "users" WHERE "users"."id" = '1' AND "users"."username" = 'joe' LIMIT 10""" - - def can_compile_with_sum(self): - """ - self.builder.sum('age').to_sql() - """ - return """SELECT SUM("users"."age") AS age FROM "users\"""" - - def can_compile_with_max(self): - """ - self.builder.max('age').to_sql() - """ - return """SELECT MAX("users"."age") AS age FROM "users\"""" - - def can_compile_with_max_and_columns(self): - """ - self.builder.select('username').max('age').to_sql() - """ - return """SELECT "users"."username", MAX("users"."age") AS age FROM "users\"""" - - def can_compile_with_max_and_columns_different_order(self): - """ - self.builder.max('age').select('username').to_sql() - """ - return """SELECT "users"."username", MAX("users"."age") AS age FROM "users\"""" - - def can_compile_with_order_by(self): - """ - self.builder.select('username').order_by('age', 'desc').to_sql() - """ - return """SELECT "users"."username" FROM "users" ORDER BY "age" DESC""" - - def can_compile_with_multiple_order_by(self): - """ - self.builder.select('username').order_by('age', 'desc').order_by('name').to_sql() - """ - return """SELECT "users"."username" FROM "users" ORDER BY "age" DESC, "name" ASC""" - - def can_compile_with_group_by(self): - """ - self.builder.select('username').group_by('age').to_sql() - """ - return """SELECT "users"."username" FROM "users" GROUP BY "users"."age\"""" - - def can_compile_where_in(self): - """ - self.builder.select('username').where_in('age', [1,2,3]).to_sql() - """ - return """SELECT "users"."username" FROM "users" WHERE "users"."age" IN ('1','2','3')""" - - def can_compile_where_in_empty(self): - """ - self.builder.where_in('age', []).to_sql() - """ - return """SELECT * FROM "users" WHERE 0 = 1""" - - def can_compile_where_not_in(self): - """ - self.builder.select('username').where_not_in('age', [1,2,3]).to_sql() - """ - return """SELECT "users"."username" FROM "users" WHERE "users"."age" NOT IN ('1','2','3')""" - - def can_compile_where_null(self): - """ - self.builder.select('username').where_null('age').to_sql() - """ - return """SELECT "users"."username" FROM "users" WHERE "users"."age" IS NULL""" - - def can_compile_where_not_null(self): - """ - self.builder.select('username').where_not_null('age').to_sql() - """ - return """SELECT "users"."username" FROM "users" WHERE "users"."age" IS NOT NULL""" - - def can_compile_where_raw(self): - """ - self.builder.where_raw(""age" = '18'").to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."age" = '18'""" - - def can_compile_having_raw(self): - """ - self.builder.select_raw("COUNT(*) as counts").having_raw("counts > 18").to_sql() - """ - return """SELECT COUNT(*) as counts FROM "users" HAVING counts > 18""" - - def can_compile_select_raw(self): - """ - self.builder.select_raw("COUNT(*)").to_sql() - """ - return """SELECT COUNT(*) FROM "users\"""" - - def can_compile_limit_and_offset(self): - """ - self.builder.limit(10).offset(10).to_sql() - """ - return """SELECT * FROM "users" LIMIT 10 OFFSET 10""" - - def can_compile_select_raw_with_select(self): - """ - self.builder.select('id').select_raw("COUNT(*)").to_sql() - """ - return """SELECT "users"."id", COUNT(*) FROM "users\"""" - - def can_compile_count(self): - """ - self.builder.count().to_sql() - """ - - return """SELECT COUNT(*) AS m_count_reserved FROM "users\"""" - - def can_compile_count_column(self): - """ - self.builder.count().to_sql() - """ - - return """SELECT COUNT("users"."money") AS money FROM "users\"""" - - def can_compile_where_column(self): - """ - self.builder.where_column('name', 'email').to_sql() - """ - - return ( - """SELECT * FROM "users" WHERE "users"."name" = "users"."email\"""" - ) - - def can_compile_or_where(self): - """ - self.builder.where('name', 2).or_where('name', 3).to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."name" = '2' OR "users"."name" = '3'""" - - def can_grouped_where(self): - """ - self.builder.where(lambda query: query.where('age', 2).where('name', 'Joe')).to_sql() - """ - return """SELECT * FROM "users" WHERE ("users"."age" = '2' AND "users"."name" = 'Joe')""" - - def can_compile_sub_select(self): - """ - self.builder.where_in('name', - QueryBuilder(GrammarFactory.make(self.grammar), table='users').select('age') - ).to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."name" IN (SELECT "users"."age" FROM "users")""" - def can_compile_sub_select_from_lambda(self): - """ - self.builder.where_in('name', - QueryBuilder(GrammarFactory.make(self.grammar), table='users').select('age') - ).to_sql() - """ +class MockConnection: + connection_details = {} - return """SELECT * FROM "users" WHERE "users"."name" IN (SELECT "users"."age" FROM "users")""" + def make_connection(self): + return self - def can_compile_sub_select_where(self): - """ - self.builder.where_in('age', - QueryBuilder(GrammarFactory.make(self.grammar), table='users').select('age').where('age', 2).where('name', 'Joe') - ).to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."age" IN (SELECT "users"."age" FROM "users" WHERE "users"."age" = '2' AND "users"."name" = 'Joe')""" +class TestPostgresSelectGrammar(unittest.TestCase): + """Tests for SQL SELECT compilation with the Postgres grammar. + + Each test is self-contained: it builds a query and asserts the expected + SQL string inline, with no separate data-provider class. + """ + + maxDiff = None + + def setUp(self): + self.builder = QueryBuilder( + PostgresGrammar, + table="users", + connection_class=MockConnection, + model=Model(), + dry=True, + ) + + # ------------------------------------------------------------------ + # Basic SELECT + # ------------------------------------------------------------------ + + def test_can_compile_select(self): + query_sql = self.builder.to_sql() + expected_sql = 'SELECT * FROM "users"' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_columns(self): + query_sql = self.builder.select("username", "password").to_sql() + expected_sql = ( + 'SELECT "users"."username", "users"."password" FROM "users"' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_select_raw(self): + query_sql = self.builder.select_raw("COUNT(*)").to_sql() + expected_sql = 'SELECT COUNT(*) FROM "users"' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_select_raw_with_select(self): + query_sql = self.builder.select("id").select_raw("COUNT(*)").to_sql() + expected_sql = 'SELECT "users"."id", COUNT(*) FROM "users"' + self.assertEqual(query_sql, expected_sql) + + def test_select_distinct(self): + query_sql = self.builder.select("group").distinct().to_sql() + expected_sql = 'SELECT DISTINCT "users"."group" FROM "users"' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_count(self): + query_sql = self.builder.count("*").to_sql() + expected_sql = 'SELECT COUNT(*) AS m_count_reserved FROM "users"' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_count_column(self): + query_sql = self.builder.count("money").to_sql() + expected_sql = 'SELECT COUNT("users"."money") AS money FROM "users"' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_sum(self): + query_sql = self.builder.sum("age").to_sql() + expected_sql = 'SELECT SUM("users"."age") AS age FROM "users"' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_max(self): + query_sql = self.builder.max("age").to_sql() + expected_sql = 'SELECT MAX("users"."age") AS age FROM "users"' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_max_and_columns(self): + query_sql = self.builder.select("username").max("age").to_sql() + expected_sql = ( + 'SELECT "users"."username", MAX("users"."age") AS age FROM "users"' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_max_and_columns_different_order(self): + query_sql = self.builder.max("age").select("username").to_sql() + expected_sql = ( + 'SELECT "users"."username", MAX("users"."age") AS age FROM "users"' + ) + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # ORDER BY / GROUP BY / LIMIT / OFFSET + # ------------------------------------------------------------------ + + def test_can_compile_order_by_and_first(self): + query_sql = ( + self.builder.order_by("id", "asc").first(query=True).to_sql() + ) + expected_sql = 'SELECT * FROM "users" ORDER BY "id" ASC LIMIT 1' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_order_by(self): + query_sql = ( + self.builder.select("username").order_by("age", "desc").to_sql() + ) + expected_sql = ( + 'SELECT "users"."username" FROM "users" ORDER BY "age" DESC' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_multiple_order_by(self): + query_sql = ( + self.builder.select("username") + .order_by("age", "desc") + .order_by("name") + .to_sql() + ) + expected_sql = 'SELECT "users"."username" FROM "users" ORDER BY "age" DESC, "name" ASC' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_group_by(self): + query_sql = self.builder.select("username").group_by("age").to_sql() + expected_sql = ( + 'SELECT "users"."username" FROM "users" GROUP BY "users"."age"' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_limit_and_offset(self): + query_sql = self.builder.limit(10).offset(10).to_sql() + expected_sql = 'SELECT * FROM "users" LIMIT 10 OFFSET 10' + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # WHERE clauses + # ------------------------------------------------------------------ - def can_compile_sub_select_value(self): - """ - self.builder.where('name', - self.builder.new().sum('age') + def test_can_compile_with_where(self): + query_sql = ( + self.builder.select("username", "password").where("id", 1).to_sql() + ) + expected_sql = 'SELECT "users"."username", "users"."password" FROM "users" WHERE "users"."id" = \'1\'' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_several_where(self): + query_sql = ( + self.builder.select("username", "password") + .where("id", 1) + .where("username", "joe") + .to_sql() + ) + expected_sql = ( + 'SELECT "users"."username", "users"."password" FROM "users"' + ' WHERE "users"."id" = \'1\' AND "users"."username" = \'joe\'' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_several_where_and_limit(self): + query_sql = ( + self.builder.select("username", "password") + .where("id", 1) + .where("username", "joe") + .limit(10) + .to_sql() + ) + expected_sql = ( + 'SELECT "users"."username", "users"."password" FROM "users"' + ' WHERE "users"."id" = \'1\' AND "users"."username" = \'joe\' LIMIT 10' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_or_where(self): + query_sql = self.builder.where("name", 2).or_where("name", 3).to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."name" = \'2\' OR "users"."name" = \'3\'' + self.assertEqual(query_sql, expected_sql) + + def test_can_grouped_where(self): + query_sql = self.builder.where( + lambda q: q.where("age", 2).where("name", "Joe") ).to_sql() - """ + expected_sql = 'SELECT * FROM "users" WHERE ("users"."age" = \'2\' AND "users"."name" = \'Joe\')' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_in(self): + query_sql = ( + self.builder.select("username").where_in("age", [1, 2, 3]).to_sql() + ) + expected_sql = 'SELECT "users"."username" FROM "users" WHERE "users"."age" IN (\'1\',\'2\',\'3\')' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_in_empty(self): + query_sql = self.builder.where_in("age", []).to_sql() + expected_sql = 'SELECT * FROM "users" WHERE 0 = 1' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_not_in(self): + query_sql = ( + self.builder.select("username") + .where_not_in("age", [1, 2, 3]) + .to_sql() + ) + expected_sql = 'SELECT "users"."username" FROM "users" WHERE "users"."age" NOT IN (\'1\',\'2\',\'3\')' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_null(self): + query_sql = self.builder.select("username").where_null("age").to_sql() + expected_sql = 'SELECT "users"."username" FROM "users" WHERE "users"."age" IS NULL' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_not_null(self): + query_sql = ( + self.builder.select("username").where_not_null("age").to_sql() + ) + expected_sql = 'SELECT "users"."username" FROM "users" WHERE "users"."age" IS NOT NULL' + self.assertEqual(query_sql, expected_sql) + + def test_or_where_null(self): + query_sql = ( + self.builder.where_null("column1") + .or_where_null("column2") + .to_sql() + ) + expected_sql = 'SELECT * FROM "users" WHERE "users"."column1" IS NULL OR "users"."column2" IS NULL' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_column(self): + query_sql = self.builder.where_column("name", "email").to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."name" = "users"."email"' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_raw(self): + query_sql = self.builder.where_raw("""`age` = '18'""").to_sql() + expected_sql = "SELECT * FROM \"users\" WHERE `age` = '18'" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_raw_and_where_with_multiple_bindings(self): + query = self.builder.where_raw( + "`age` = ? AND `is_admin` = ?", [18, True] + ).where("email", "test@example.com") + query_sql = query.to_qmark() + expected_sql = 'SELECT * FROM "users" WHERE `age` = ? AND `is_admin` = ? AND "users"."email" = ?' + self.assertEqual(query_sql, expected_sql) + self.assertEqual(query._bindings, [18, True, "test@example.com"]) + + def test_can_user_where_raw_and_where(self): + query_sql = ( + self.builder.where_raw("age = '18'") + .where("name", "=", "James") + .to_sql() + ) + expected_sql = 'SELECT * FROM "users" WHERE age = \'18\' AND "users"."name" = \'James\'' + self.assertEqual(query_sql, expected_sql) + + def test_where_like(self): + query_sql = self.builder.where("age", "like", "%name%").to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."age" ILIKE \'%name%\'' + ) + self.assertEqual(query_sql, expected_sql) + + def test_where_not_like(self): + query_sql = self.builder.where("age", "not like", "%name%").to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."age" NOT ILIKE \'%name%\'' + ) + self.assertEqual(query_sql, expected_sql) + + def test_where_regexp(self): + query_sql = self.builder.where("age", "regexp", "Joe").to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."age" REGEXP \'Joe\'' + ) + self.assertEqual(query_sql, expected_sql) - return """SELECT * FROM "users" WHERE "users"."name" = (SELECT SUM("users"."age") AS age FROM "users")""" + def test_where_not_regexp(self): + query_sql = self.builder.where("age", "not regexp", "Joe").to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."age" NOT REGEXP \'Joe\'' + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_complex_sub_select(self): - """ - self.builder.where_in('name', - (QueryBuilder(GrammarFactory.make(self.grammar), table='users') - .select('age').where_in('email', - QueryBuilder(GrammarFactory.make(self.grammar), table='users').select('email') - )) + def test_where_date(self): + query_sql = self.builder.where_date( + "created_at", "2022-06-01" ).to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."name" IN (SELECT "users"."age" FROM "users" WHERE "users"."email" IN (SELECT "users"."email" FROM "users"))""" + expected_sql = 'SELECT * FROM "users" WHERE DATE("users"."created_at") = \'2022-06-01\'' + self.assertEqual(query_sql, expected_sql) - def can_compile_exists(self): - """ - self.builder.select('age').where_exists( - self.builder.new().select('username').where('age', 12) + def test_where_exists_with_lambda(self): + query_sql = self.builder.where_exists( + lambda q: q.where("age", 1) ).to_sql() - """ - return """SELECT "users"."age" FROM "users" WHERE EXISTS (SELECT "users"."username" FROM "users" WHERE "users"."age" = '12')""" + expected_sql = 'SELECT * FROM "users" WHERE EXISTS (SELECT * FROM "users" WHERE "users"."age" = \'1\')' + self.assertEqual(query_sql, expected_sql) - def can_compile_not_exists(self): - """ - self.builder.select('age').where_not_exists( - self.builder.new().select('username').where('age', 12) + def test_where_not_exists_with_lambda(self): + query_sql = self.builder.where_not_exists( + lambda q: q.where("age", 1) ).to_sql() - """ - return """SELECT "users"."age" FROM "users" WHERE NOT EXISTS (SELECT "users"."username" FROM "users" WHERE "users"."age" = '12')""" - - def can_compile_having(self): - """ - builder.sum('age').group_by('age').having('age').to_sql() - """ - return """SELECT SUM("users"."age") AS age FROM "users" GROUP BY "users"."age" HAVING "users"."age\"""" - - def can_compile_having_order(self): - """ - builder.sum('age').group_by('age').having('age').order_by('age', 'desc').to_sql() - """ - return """SELECT SUM("users"."age") AS age FROM "users" GROUP BY "users"."age" HAVING "users"."age" ORDER "users"."age" DESC""" - - def can_compile_having_with_expression(self): - """ - builder.sum('age').group_by('age').having('age', 10).to_sql() - """ - return """SELECT SUM("users"."age") AS age FROM "users" GROUP BY "users"."age" HAVING "users"."age" = '10'""" - - def can_compile_order_by_and_first(self): - """ - self.builder.order_by('id', 'asc').first() - """ - return """SELECT * FROM "users" ORDER BY "id" ASC LIMIT 1""" - - def can_compile_having_with_greater_than_expression(self): - """ - builder.sum('age').group_by('age').having('age', '>', 10).to_sql() - """ - return """SELECT SUM("users"."age") AS age FROM "users" GROUP BY "users"."age" HAVING "users"."age" > '10'""" - - def can_compile_join(self): - """ - builder.join('contacts', 'users.id', '=', 'contacts.user_id').to_sql() - """ - return """SELECT * FROM "users" INNER JOIN "contacts" ON "users"."id" = "contacts"."user_id\"""" - - def can_compile_left_join(self): - """ - builder.join('contacts', 'users.id', '=', 'contacts.user_id').to_sql() - """ - return """SELECT * FROM "users" LEFT JOIN "contacts" ON "users"."id" = "contacts"."user_id\"""" - - def can_compile_multiple_join(self): - """ - builder.join('contacts', 'users.id', '=', 'contacts.user_id').to_sql() - """ - return """SELECT * FROM "users" INNER JOIN "contacts" ON "users"."id" = "contacts"."user_id" INNER JOIN "posts" ON "comments"."post_id" = "posts"."id\"""" - - def can_compile_between(self): - """ - builder.between('age', 18, 21).to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."age" BETWEEN '18' AND '21'""" - - def can_compile_not_between(self): - """ - builder.not_between('age', 18, 21).to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."age" NOT BETWEEN '18' AND '21'""" + expected_sql = 'SELECT * FROM "users" WHERE NOT EXISTS (SELECT * FROM "users" WHERE "users"."age" = \'1\')' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_between(self): + query_sql = self.builder.between("age", 18, 21).to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."age" BETWEEN \'18\' AND \'21\'' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_not_between(self): + query_sql = self.builder.not_between("age", 18, 21).to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."age" NOT BETWEEN \'18\' AND \'21\'' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_first_or_fail(self): + query_sql = ( + self.builder.where("is_admin", "=", True) + .first_or_fail(query=True) + .to_sql() + ) + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."is_admin" IS True LIMIT 1' + ) + self.assertEqual(query_sql, expected_sql) - def test_can_compile_where_raw(self): - to_sql = self.builder.where_raw(""" "age" = '18'""").to_sql() - self.assertEqual( - to_sql, """SELECT * FROM "users" WHERE "age" = '18'""" + # ------------------------------------------------------------------ + # HAVING + # ------------------------------------------------------------------ + + def test_can_compile_having(self): + query_sql = ( + self.builder.sum("age").group_by("age").having("age").to_sql() ) + expected_sql = 'SELECT SUM("users"."age") AS age FROM "users" GROUP BY "users"."age" HAVING "users"."age"' + self.assertEqual(query_sql, expected_sql) def test_can_compile_having_raw(self): - to_sql = ( + query_sql = ( self.builder.select_raw("COUNT(*) as counts") - .having_raw("counts > 10") + .having_raw("counts > 18") .to_sql() ) - self.assertEqual( - to_sql, - """SELECT COUNT(*) as counts FROM "users" HAVING counts > 10""", + expected_sql = ( + 'SELECT COUNT(*) as counts FROM "users" HAVING counts > 18' ) + self.assertEqual(query_sql, expected_sql) - def test_can_compile_having_raw_order(self): - to_sql = ( - self.builder.select_raw("COUNT(*) as counts") - .having_raw("counts > 10") - .order_by_raw("counts DESC") + def test_can_compile_having_with_expression(self): + query_sql = ( + self.builder.sum("age").group_by("age").having("age", 10).to_sql() + ) + expected_sql = 'SELECT SUM("users"."age") AS age FROM "users" GROUP BY "users"."age" HAVING "users"."age" = \'10\'' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_having_with_greater_than_expression(self): + query_sql = ( + self.builder.sum("age") + .group_by("age") + .having("age", ">", 10) .to_sql() ) - self.assertEqual( - to_sql, - """SELECT COUNT(*) as counts FROM "users" HAVING counts > 10 ORDER BY counts DESC""", + expected_sql = 'SELECT SUM("users"."age") AS age FROM "users" GROUP BY "users"."age" HAVING "users"."age" > \'10\'' + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # Locking + # ------------------------------------------------------------------ + + def test_shared_lock(self): + query_sql = ( + self.builder.where("votes", ">=", 100).shared_lock().to_sql() + ) + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."votes" >= \'100\' FOR SHARE' ) + self.assertEqual(query_sql, expected_sql) - def test_can_compile_where_raw_and_where_with_multiple_bindings(self): - query = self.builder.where_raw( - """ "age" = ? AND "is_admin" = ?""", [18, True] - ).where("email", "test@example.com") - self.assertEqual( - query.to_qmark(), - """SELECT * FROM "users" WHERE "age" = ? AND "is_admin" = ? AND "users"."email" = ?""", + def test_update_lock(self): + query_sql = ( + self.builder.where("votes", ">=", 100).lock_for_update().to_sql() ) - self.assertEqual(query._bindings, [18, True, "test@example.com"]) + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."votes" >= \'100\' FOR UPDATE' + ) + self.assertEqual(query_sql, expected_sql) - def test_can_compile_select_raw(self): - to_sql = self.builder.select_raw("COUNT(*)").to_sql() - self.assertEqual(to_sql, """SELECT COUNT(*) FROM "users\"""") + # ------------------------------------------------------------------ + # Sub-selects + # ------------------------------------------------------------------ - def test_can_compile_select_raw_with_select(self): - to_sql = self.builder.select("id").select_raw("COUNT(*)").to_sql() - self.assertEqual( - to_sql, """SELECT "users"."id", COUNT(*) FROM "users\"""" - ) - - def can_compile_first_or_fail(self): - """ - builder = self.get_builder() - builder.where("is_admin", "=", True).first_or_fail() - """ - return """SELECT * FROM "users" WHERE "users"."is_admin" IS True 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 ILIKE '%name%'""" - ) - - def where_like(self): - """ - builder = self.get_builder() - builder.where("age", "like", "%name%").to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."age" ILIKE '%name%'""" - - def where_regexp(self): - """ - builder = self.get_builder() - builder.where("age", "regexp", "Joe").to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."age" REGEXP 'Joe'""" - - def where_not_regexp(self): - """ - builder = self.get_builder() - builder.where("age", "regexp", "Joe").to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."age" NOT REGEXP 'Joe'""" - - def can_compile_join_clause(self): - """ - builder = self.get_builder() + def test_can_compile_sub_select(self): + query_sql = self.builder.where_in( + "name", self.builder.new().select("age") + ).to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."name" IN (SELECT "users"."age" FROM "users")' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_sub_select_where(self): + query_sql = self.builder.where_in( + "age", + self.builder.new() + .select("age") + .where("age", 2) + .where("name", "Joe"), + ).to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."age" IN' + ' (SELECT "users"."age" FROM "users" WHERE "users"."age" = \'2\' AND "users"."name" = \'Joe\')' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_sub_select_from_lambda(self): + expected = ( + 'SELECT * FROM "users" WHERE "users"."age" IN' + ' (SELECT "users"."age" FROM "users" WHERE "users"."age" = \'2\' AND "users"."name" = \'Joe\')' + ) + query_sql = ( + self.builder.new() + .where_in( + "age", + lambda q: q.select("age").where("age", 2).where("name", "Joe"), + ) + .to_sql() + ) + expected_sql = expected + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_sub_select_value(self): + query_sql = self.builder.where( + "name", self.builder.new().sum("age") + ).to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."name" = (SELECT SUM("users"."age") AS age FROM "users")' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_complex_sub_select(self): + query_sql = self.builder.where_in( + "name", + self.builder.new() + .select("age") + .where_in("email", self.builder.new().select("email")), + ).to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."name" IN' + ' (SELECT "users"."age" FROM "users" WHERE "users"."email" IN' + ' (SELECT "users"."email" FROM "users"))' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_exists(self): + query_sql = ( + self.builder.select("age") + .where_exists( + self.builder.new().select("username").where("age", 12) + ) + .to_sql() + ) + expected_sql = ( + 'SELECT "users"."age" FROM "users"' + ' WHERE EXISTS (SELECT "users"."username" FROM "users" WHERE "users"."age" = \'12\')' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_not_exists(self): + query_sql = ( + self.builder.select("age") + .where_not_exists( + self.builder.new().select("username").where("age", 12) + ) + .to_sql() + ) + expected_sql = ( + 'SELECT "users"."age" FROM "users"' + ' WHERE NOT EXISTS (SELECT "users"."username" FROM "users" WHERE "users"."age" = \'12\')' + ) + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # JOINs + # ------------------------------------------------------------------ + + def test_can_compile_join(self): + query_sql = self.builder.join( + "contacts", "users.id", "=", "contacts.user_id" + ).to_sql() + expected_sql = 'SELECT * FROM "users" INNER JOIN "contacts" ON "users"."id" = "contacts"."user_id"' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_left_join(self): + query_sql = self.builder.left_join( + "contacts", "users.id", "=", "contacts.user_id" + ).to_sql() + expected_sql = 'SELECT * FROM "users" LEFT JOIN "contacts" ON "users"."id" = "contacts"."user_id"' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_multiple_join(self): + query_sql = ( + self.builder.join("contacts", "users.id", "=", "contacts.user_id") + .join("posts", "comments.post_id", "=", "posts.id") + .to_sql() + ) + expected_sql = ( + 'SELECT * FROM "users"' + ' INNER JOIN "contacts" ON "users"."id" = "contacts"."user_id"' + ' INNER JOIN "posts" ON "comments"."post_id" = "posts"."id"' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_join_clause(self): clause = ( JoinClause("report_groups as rg") .on("bgt.fund", "=", "rg.fund") - .on_value("bgt.active", "=", "1") - .or_on_value("bgt.acct", "=", "1234") + .on("bgt.dept", "=", "rg.dept") + .on("bgt.acct", "=", "rg.acct") + .on("bgt.sub", "=", "rg.sub") ) - builder.join(clause).to_sql() - """ - return """SELECT * FROM "users" INNER JOIN "report_groups" AS "rg" ON "bgt"."fund" = "rg"."fund" AND "bgt"."dept" = "rg"."dept" AND "bgt"."acct" = "rg"."acct" AND "bgt"."sub" = "rg"."sub\"""" + query_sql = self.builder.join(clause).to_sql() + expected_sql = ( + 'SELECT * FROM "users" INNER JOIN "report_groups" AS "rg"' + ' ON "bgt"."fund" = "rg"."fund" AND "bgt"."dept" = "rg"."dept"' + ' AND "bgt"."acct" = "rg"."acct" AND "bgt"."sub" = "rg"."sub"' + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_join_clause_with_value(self): - """ - builder = self.get_builder() + def test_can_compile_join_clause_with_value(self): clause = ( JoinClause("report_groups as rg") .on_value("bgt.active", "=", "1") .or_on_value("bgt.acct", "=", "1234") ) - builder.join(clause).to_sql() - """ - return """SELECT * FROM "users" INNER JOIN "report_groups" AS "rg" ON "bgt"."active" = '1' OR "bgt"."acct" = '1234'""" + query_sql = self.builder.join(clause).to_sql() + expected_sql = ( + 'SELECT * FROM "users" INNER JOIN "report_groups" AS "rg"' + ' ON "bgt"."active" = \'1\' OR "bgt"."acct" = \'1234\'' + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_join_clause_with_null(self): - """ - builder = self.get_builder() + def test_can_compile_join_clause_with_null(self): clause = ( JoinClause("report_groups as rg") .on_null("bgt.acct") .or_on_null("bgt.dept") .on_value("rg.abc", 10) ) - builder.join(clause).to_sql() - """ - return """SELECT * FROM "users" INNER JOIN "report_groups" AS "rg" ON "acct" IS NULL OR "dept" IS NULL AND "rg"."abc" = '10'""" + query_sql = self.builder.join(clause).to_sql() + expected_sql = ( + 'SELECT * FROM "users" INNER JOIN "report_groups" AS "rg"' + ' ON "acct" IS NULL OR "dept" IS NULL AND "rg"."abc" = \'10\'' + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_join_clause_with_not_null(self): - """ - builder = self.get_builder() + def test_can_compile_join_clause_with_not_null(self): clause = ( JoinClause("report_groups as rg") .on_not_null("bgt.acct") .or_on_not_null("bgt.dept") .on_value("rg.abc", 10) ) - builder.join(clause).to_sql() - """ - return """SELECT * FROM "users" INNER JOIN "report_groups" AS "rg" ON "acct" IS NOT NULL OR "dept" IS NOT NULL AND "rg"."abc" = '10'""" + query_sql = self.builder.join(clause).to_sql() + expected_sql = ( + 'SELECT * FROM "users" INNER JOIN "report_groups" AS "rg"' + ' ON "acct" IS NOT NULL OR "dept" IS NOT NULL AND "rg"."abc" = \'10\'' + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_join_clause_with_lambda(self): - """ - builder = self.get_builder() - builder.join( + def test_can_compile_join_clause_with_lambda(self): + query_sql = self.builder.join( "report_groups as rg", - lambda clause: ( - clause.on("bgt.fund", "=", "rg.fund") - .on_null("bgt") + lambda clause: clause.on("bgt.fund", "=", "rg.fund").on_null( + "bgt" ), ).to_sql() - """ - return """SELECT * FROM "users" INNER JOIN "report_groups" AS "rg" ON "bgt"."fund" = "rg"."fund" AND "bgt" IS NULL""" + expected_sql = ( + 'SELECT * FROM "users" INNER JOIN "report_groups" AS "rg"' + ' ON "bgt"."fund" = "rg"."fund" AND "bgt" IS NULL' + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_left_join_clause_with_lambda(self): - """ - builder = self.get_builder() - builder.left_join( + def test_can_compile_left_join_clause_with_lambda(self): + query_sql = self.builder.left_join( "report_groups as rg", - lambda clause: ( - clause.on("bgt.fund", "=", "rg.fund") - .or_on_null("bgt") + lambda clause: clause.on("bgt.fund", "=", "rg.fund").or_on_null( + "bgt" ), ).to_sql() - """ - return """SELECT * FROM "users" LEFT JOIN "report_groups" AS "rg" ON "bgt"."fund" = "rg"."fund" OR "bgt" IS NULL""" + expected_sql = ( + 'SELECT * FROM "users" LEFT JOIN "report_groups" AS "rg"' + ' ON "bgt"."fund" = "rg"."fund" OR "bgt" IS NULL' + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_right_join_clause_with_lambda(self): - """ - builder = self.get_builder() - builder.right_join( + def test_can_compile_right_join_clause_with_lambda(self): + query_sql = self.builder.right_join( "report_groups as rg", - lambda clause: ( - clause.on("bgt.fund", "=", "rg.fund") - .or_on_null("bgt") + lambda clause: clause.on("bgt.fund", "=", "rg.fund").or_on_null( + "bgt" ), ).to_sql() - """ - return """SELECT * FROM "users" RIGHT JOIN "report_groups" AS "rg" ON "bgt"."fund" = "rg"."fund" OR "bgt" IS NULL""" - - def shared_lock(self): - """ - builder = self.get_builder() - builder.where("age", "not like", "%name%").to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."votes" >= '100' FOR SHARE""" - - def update_lock(self): - """ - builder = self.get_builder() - builder.where("age", "not like", "%name%").to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."votes" >= '100' FOR UPDATE""" - - def can_user_where_raw_and_where(self): - """ - builder.where_raw("`age` = '18'").where("name", "=", "James").to_sql() - """ - return """SELECT * FROM "users" WHERE age = '18' AND "users"."name" = 'James'""" - - def where_exists_with_lambda(self): - return """SELECT * FROM "users" WHERE EXISTS (SELECT * FROM "users" WHERE "users"."age" = '1')""" - - def where_not_exists_with_lambda(self): - return """SELECT * FROM "users" WHERE NOT EXISTS (SELECT * FROM "users" WHERE "users"."age" = '1')""" - - def where_date(self): - return """SELECT * FROM "users" WHERE DATE("users"."created_at") = '2022-06-01'""" - - def or_where_null(self): - return """SELECT * FROM "users" WHERE "users"."column1" IS NULL OR "users"."column2" IS NULL""" - - def select_distinct(self): - return """SELECT DISTINCT "users"."group" FROM "users\"""" + expected_sql = ( + 'SELECT * FROM "users" RIGHT JOIN "report_groups" AS "rg"' + ' ON "bgt"."fund" = "rg"."fund" OR "bgt" IS NULL' + ) + self.assertEqual(query_sql, expected_sql) diff --git a/tests/postgres/grammar/test_update_grammar.py b/tests/postgres/grammar/test_update_grammar.py index 76d19f7f0..6b4ecbe3a 100644 --- a/tests/postgres/grammar/test_update_grammar.py +++ b/tests/postgres/grammar/test_update_grammar.py @@ -1,126 +1,55 @@ -import inspect import unittest from src.masoniteorm.connections import PostgresConnection +from src.masoniteorm.expressions import Raw from src.masoniteorm.query import QueryBuilder from src.masoniteorm.query.grammars import PostgresGrammar -from src.masoniteorm.expressions import Raw -class BaseTestCaseUpdateGrammar: +class TestPostgresUpdateGrammar(unittest.TestCase): def setUp(self): self.builder = QueryBuilder( PostgresGrammar, connection_class=PostgresConnection, table="users" ) def test_can_compile_update(self): - to_sql = ( - self.builder.where("name", "bob").update({"name": "Joe"}, dry=True).to_sql() + query_sql = ( + self.builder.where("name", "bob") + .update({"name": "Joe"}, dry=True) + .to_sql() + ) + expected_sql = ( + """UPDATE "users" SET "name" = 'Joe' WHERE "name" = 'bob'""" ) + self.assertEqual(query_sql, expected_sql) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + def test_raw_expression(self): + query_sql = self.builder.update( + {"name": Raw('"username"')}, dry=True + ).to_sql() + expected_sql = """UPDATE "users" SET "name" = "username\"""" + self.assertEqual(query_sql, expected_sql) def test_can_compile_multiple_update(self): - to_sql = self.builder.update( + query_sql = self.builder.update( {"name": "Joe", "email": "user@email.com"}, dry=True ).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + expected_sql = ( + """UPDATE "users" SET "name" = 'Joe', "email" = 'user@email.com'""" + ) + self.assertEqual(query_sql, expected_sql) def test_can_compile_update_with_multiple_where(self): - to_sql = ( + query_sql = ( self.builder.where("name", "bob") .where("age", 20) .update({"name": "Joe"}, dry=True) .to_sql() ) - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) - - # def test_can_compile_increment(self): - # to_sql = self.builder.increment("age").to_sql() - - # sql = getattr( - # self, inspect.currentframe().f_code.co_name.replace("test_", "") - # )() - # self.assertEqual(to_sql, sql) - - # def test_can_compile_decrement(self): - # to_sql = self.builder.decrement("age", 20).to_sql() - - # sql = getattr( - # self, inspect.currentframe().f_code.co_name.replace("test_", "") - # )() - # self.assertEqual(to_sql, sql) - - def test_raw_expression(self): - to_sql = self.builder.update({"name": Raw('"username"')}, dry=True).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - - self.assertEqual(to_sql, sql) + expected_sql = """UPDATE "users" SET "name" = 'Joe' WHERE "name" = 'bob' AND "age" = '20'""" + self.assertEqual(query_sql, expected_sql) def test_update_null(self): - to_sql = self.builder.update({"name": None}, dry=True).to_sql() - print(to_sql) - - sql = """UPDATE "users" SET "name" = \'None\'""" - - self.assertEqual(to_sql, sql) - - -class TestPostgresUpdateGrammar(BaseTestCaseUpdateGrammar, unittest.TestCase): - grammar = "postgres" - - def can_compile_update(self): - """ - builder.where('name', 'bob').update({ - 'name': 'Joe' - }).to_sql() - """ - return """UPDATE "users" SET "name" = 'Joe' WHERE "name" = 'bob'""" - - def raw_expression(self): - """ - builder.where('name', 'bob').update({ - 'name': 'Joe' - }).to_sql() - """ - return """UPDATE "users" SET "name" = "username\"""" - - def can_compile_multiple_update(self): - """ - self.builder.update({"name": "Joe", "email": "user@email.com"}, dry=True).to_sql() - """ - return """UPDATE "users" SET "name" = 'Joe', "email" = 'user@email.com'""" - - def can_compile_update_with_multiple_where(self): - """ - builder.where('name', 'bob').where('age', 20).update({ - 'name': 'Joe' - }).to_sql() - """ - return """UPDATE "users" SET "name" = 'Joe' WHERE "name" = 'bob' AND "age" = '20'""" - - def can_compile_increment(self): - """ - builder.increment('age').to_sql() - """ - return """UPDATE "users" SET "age" = "age" + '1'""" - - def can_compile_decrement(self): - """ - builder.decrement('age', 20).to_sql() - """ - return """UPDATE "users" SET "age" = "age" - '20'""" + query_sql = self.builder.update({"name": None}, dry=True).to_sql() + expected_sql = """UPDATE "users" SET "name" = 'None'""" + self.assertEqual(query_sql, expected_sql) diff --git a/tests/postgres/relationships/test_postgres_relationships.py b/tests/postgres/relationships/test_postgres_relationships.py index 023fd536d..950584682 100644 --- a/tests/postgres/relationships/test_postgres_relationships.py +++ b/tests/postgres/relationships/test_postgres_relationships.py @@ -44,10 +44,11 @@ class TestRelationships(unittest.TestCase): maxDiff = None def test_relationship_can_be_callable(self): - self.assertEqual( - User.profile().where("name", "Joe").to_sql(), - """SELECT * FROM "profiles" WHERE "profiles"."name" = 'Joe'""", + query_sql = User.profile().where("name", "Joe").to_sql() + expected_sql = ( + """SELECT * FROM "profiles" WHERE "profiles"."name" = 'Joe'""" ) + self.assertEqual(query_sql, expected_sql) def test_can_access_relationship(self): for user in User.where("id", 1).get(): @@ -65,12 +66,14 @@ def test_can_access_relationship_multiple_times(self): def test_loading(self): users = User.with_("articles").get() for user in users: - user + self.assertTrue(hasattr(user, "articles")) + self.assertGreater(len(user.articles), 0) def test_casting(self): users = User.with_("articles").where("is_admin", True).get() for user in users: - user + self.assertIsInstance(user.is_admin, bool) + self.assertTrue(user.is_admin) def test_setting(self): users = User.with_("articles").where("is_admin", True).get() @@ -78,29 +81,31 @@ def test_setting(self): user.name = "Joe" user.is_admin = 1 user.save() + fresh_user = User.find(user.id) + self.assertEqual(fresh_user.name, "Joe") def test_relationship_has(self): - to_sql = User.has("articles").to_sql() + query_sql = User.has("articles").to_sql() self.assertEqual( - to_sql, + query_sql, """SELECT * FROM "users" WHERE EXISTS (""" """SELECT * FROM "articles" WHERE "articles"."user_id" = "users"."id\"""" """)""", ) def test_relationship_has_off_builder(self): - to_sql = User.where("active", 1).has("articles").to_sql() + query_sql = User.where("active", 1).has("articles").to_sql() self.assertEqual( - to_sql, + query_sql, """SELECT * FROM "users" WHERE "users"."active" = '1' AND EXISTS (""" """SELECT * FROM "articles" WHERE "articles"."user_id" = "users"."id\"""" """)""", ) def test_relationship_multiple_has(self): - to_sql = User.has("articles", "profile").to_sql() + query_sql = User.has("articles", "profile").to_sql() self.assertEqual( - to_sql, + query_sql, """SELECT * FROM "users" WHERE EXISTS (""" """SELECT * FROM "articles" WHERE "articles"."user_id" = "users"."id\"""" """) AND EXISTS (""" @@ -112,9 +117,9 @@ def test_relationship_multiple_has(self): self.assertEqual(count, 2) def test_nested_has(self): - to_sql = User.has("articles.logo").to_sql() + query_sql = User.has("articles.logo").to_sql() self.assertEqual( - to_sql, + query_sql, """SELECT * FROM "users" WHERE EXISTS (SELECT * FROM "articles" WHERE "articles"."user_id" = "users"."id" AND EXISTS (SELECT * FROM "logos" WHERE "logos"."article_id" = "articles"."id"))""", ) @@ -122,9 +127,11 @@ def test_nested_has(self): self.assertEqual(count, 2) def test_relationship_where_has(self): - to_sql = User.where_has("articles", lambda q: q.where("status", 1)).to_sql() + query_sql = User.where_has( + "articles", lambda q: q.where("status", 1) + ).to_sql() self.assertEqual( - to_sql, + query_sql, """SELECT * FROM "users" WHERE EXISTS (""" """SELECT * FROM "articles" WHERE "articles"."user_id" = "users"."id" AND "articles"."status" = '1'""" """)""", diff --git a/tests/postgres/schema/test_postgres_schema_builder.py b/tests/postgres/schema/test_postgres_schema_builder.py index 9e04b3dd5..675f43816 100644 --- a/tests/postgres/schema/test_postgres_schema_builder.py +++ b/tests/postgres/schema/test_postgres_schema_builder.py @@ -1,9 +1,9 @@ import unittest -from tests.integrations.config.database import DATABASES from src.masoniteorm.connections import PostgresConnection from src.masoniteorm.schema import Schema from src.masoniteorm.schema.platforms import PostgresPlatform +from tests.integrations.config.database import DATABASES class TestPostgresSchemaBuilder(unittest.TestCase): @@ -37,7 +37,8 @@ def test_can_add_tiny_text(self): self.assertEqual(len(blueprint.table.added_columns), 1) self.assertEqual( - blueprint.to_sql(), ['CREATE TABLE "users" ("description" TEXT NOT NULL)'] + blueprint.to_sql(), + ['CREATE TABLE "users" ("description" TEXT NOT NULL)'], ) def test_can_add_unsigned_decimal(self): @@ -91,30 +92,30 @@ def test_can_add_table_comment(self): ) def test_can_truncate(self): - sql = self.schema.truncate("users") + query_sql = self.schema.truncate("users") - self.assertEqual(sql, 'TRUNCATE "users"') + self.assertEqual(query_sql, 'TRUNCATE "users"') def test_can_rename_table(self): - sql = self.schema.rename("users", "clients") + query_sql = self.schema.rename("users", "clients") - self.assertEqual(sql, 'ALTER TABLE "users" RENAME TO "clients"') + self.assertEqual(query_sql, 'ALTER TABLE "users" RENAME TO "clients"') def test_can_drop_table_if_exists(self): - sql = self.schema.drop_table_if_exists("users", "clients") + query_sql = self.schema.drop_table_if_exists("users", "clients") - self.assertEqual(sql, 'DROP TABLE IF EXISTS "users"') + self.assertEqual(query_sql, 'DROP TABLE IF EXISTS "users"') def test_can_drop_table(self): - sql = self.schema.drop_table("users", "clients") + query_sql = self.schema.drop_table("users", "clients") - self.assertEqual(sql, 'DROP TABLE "users"') + self.assertEqual(query_sql, 'DROP TABLE "users"') def test_has_column(self): - sql = self.schema.has_column("users", "name") + query_sql = self.schema.has_column("users", "name") self.assertEqual( - sql, + query_sql, "SELECT column_name FROM information_schema.columns WHERE table_name='users' and column_name='name'", ) @@ -138,7 +139,8 @@ def test_can_add_columns_with_long_text(self): self.assertEqual(len(blueprint.table.added_columns), 1) self.assertEqual( - blueprint.to_sql(), ['CREATE TABLE "users" ("description" TEXT NOT NULL)'] + blueprint.to_sql(), + ['CREATE TABLE "users" ("description" TEXT NOT NULL)'], ) def test_can_have_unsigned_columns(self): @@ -219,9 +221,9 @@ def test_can_advanced_table_creation2(self): blueprint.integer("premium") blueprint.double("amount").default(0.0) blueprint.integer("author_id").unsigned().nullable() - blueprint.foreign("author_id").references("id").on("authors").on_delete( - "CASCADE" - ) + blueprint.foreign("author_id").references("id").on( + "authors" + ).on_delete("CASCADE") blueprint.text("description") blueprint.timestamps() @@ -261,9 +263,9 @@ def test_can_add_uuid_column(self): def test_can_add_columns_with_foreign_key_constraint_name(self): with self.schema.create("users") as blueprint: blueprint.integer("profile_id") - blueprint.foreign("profile_id", name="profile_foreign").references("id").on( - "profiles" - ) + blueprint.foreign("profile_id", name="profile_foreign").references( + "id" + ).on("profiles") self.assertEqual(len(blueprint.table.added_columns), 1) self.assertEqual( @@ -344,24 +346,27 @@ def test_can_have_float_type(self): self.assertEqual( blueprint.to_sql(), - ["""CREATE TABLE "users" (""" """\"amount" FLOAT(19, 4) NOT NULL)"""], + [ + """CREATE TABLE "users" (""" + """\"amount" FLOAT(19, 4) NOT NULL)""" + ], ) def test_can_enable_foreign_keys(self): - sql = self.schema.enable_foreign_key_constraints() + query_sql = self.schema.enable_foreign_key_constraints() - self.assertEqual(sql, "") + self.assertEqual(query_sql, "") def test_can_disable_foreign_keys(self): - sql = self.schema.disable_foreign_key_constraints() + query_sql = self.schema.disable_foreign_key_constraints() - self.assertEqual(sql, "") + self.assertEqual(query_sql, "") def test_can_truncate_without_foreign_keys(self): - sql = self.schema.truncate("users", foreign_keys=True) + query_sql = self.schema.truncate("users", foreign_keys=True) self.assertEqual( - sql, + query_sql, [ 'ALTER TABLE "users" DISABLE TRIGGER ALL', 'TRUNCATE "users"', @@ -377,6 +382,7 @@ def test_can_add_enum(self): self.assertEqual( blueprint.to_sql(), [ - 'CREATE TABLE "users" ("status" VARCHAR(255) CHECK(status IN (\'active\', \'inactive\')) NOT NULL ' 'DEFAULT \'active\')' + "CREATE TABLE \"users\" (\"status\" VARCHAR(255) CHECK(status IN ('active', 'inactive')) NOT NULL " + "DEFAULT 'active')" ], ) diff --git a/tests/postgres/schema/test_postgres_schema_builder_alter.py b/tests/postgres/schema/test_postgres_schema_builder_alter.py index d77d632b6..908c63146 100644 --- a/tests/postgres/schema/test_postgres_schema_builder_alter.py +++ b/tests/postgres/schema/test_postgres_schema_builder_alter.py @@ -1,10 +1,10 @@ import unittest -from tests.integrations.config.database import DATABASES from src.masoniteorm.connections import PostgresConnection from src.masoniteorm.schema import Schema from src.masoniteorm.schema.platforms import PostgresPlatform from src.masoniteorm.schema.Table import Table +from tests.integrations.config.database import DATABASES class TestPostgresSchemaBuilderAlter(unittest.TestCase): @@ -26,11 +26,12 @@ def test_can_add_columns(self): self.assertEqual(len(blueprint.table.added_columns), 2) - sql = [ + expected_sql = [ 'ALTER TABLE "users" ADD COLUMN "name" VARCHAR(255) NOT NULL, ADD COLUMN "age" INTEGER NOT NULL' ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_can_add_column_comments(self): with self.schema.table("users") as blueprint: @@ -38,12 +39,13 @@ def test_can_add_column_comments(self): self.assertEqual(len(blueprint.table.added_columns), 1) - sql = [ + expected_sql = [ 'ALTER TABLE "users" ADD COLUMN "name" VARCHAR(255) NOT NULL', """COMMENT ON COLUMN "users"."name" is 'A users username'""", ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_can_add_table_comment(self): with self.schema.table("users") as blueprint: @@ -52,12 +54,13 @@ def test_can_add_table_comment(self): self.assertEqual(len(blueprint.table.added_columns), 1) - sql = [ + expected_sql = [ 'ALTER TABLE "users" ADD COLUMN "name" VARCHAR(255) NOT NULL', """COMMENT ON TABLE "users" is 'A users table'""", ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_rename(self): with self.schema.table("users") as blueprint: @@ -67,9 +70,12 @@ def test_alter_rename(self): table.add_column("post", "integer") blueprint.table.from_table = table - sql = ['ALTER TABLE "users" RENAME COLUMN "post" TO "comment"'] + expected_sql = [ + 'ALTER TABLE "users" RENAME COLUMN "post" TO "comment"' + ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_add_and_rename(self): with self.schema.table("users") as blueprint: @@ -80,34 +86,37 @@ def test_alter_add_and_rename(self): table.add_column("post", "integer") blueprint.table.from_table = table - sql = [ + expected_sql = [ 'ALTER TABLE "users" ADD COLUMN "name" VARCHAR(255) NOT NULL', 'ALTER TABLE "users" RENAME COLUMN "post" TO "comment"', ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop(self): with self.schema.table("users") as blueprint: blueprint.drop_column("post") - sql = ['ALTER TABLE "users" DROP COLUMN "post"'] + expected_sql = ['ALTER TABLE "users" DROP COLUMN "post"'] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_add_column_and_foreign_key(self): with self.schema.table("users") as blueprint: blueprint.unsigned_integer("playlist_id").nullable() - blueprint.foreign("playlist_id").references("id").on("playlists").on_delete( - "cascade" - ) + blueprint.foreign("playlist_id").references("id").on( + "playlists" + ).on_delete("cascade") - sql = [ + expected_sql = [ 'ALTER TABLE "users" ADD COLUMN "playlist_id" INTEGER NULL', 'ALTER TABLE "users" ADD CONSTRAINT users_playlist_id_foreign FOREIGN KEY ("playlist_id") REFERENCES "playlists"("id") ON DELETE CASCADE', ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_can_create_indexes(self): with self.schema.table("users") as blueprint: @@ -118,103 +127,121 @@ def test_can_create_indexes(self): blueprint.fulltext("description") self.assertEqual(len(blueprint.table.added_columns), 0) - self.assertEqual( - blueprint.to_sql(), - [ - 'CREATE INDEX users_name_index ON "users"(name)', - 'CREATE INDEX users_name_email_index ON "users"(name,email)', - 'ALTER TABLE "users" ADD CONSTRAINT users_name_unique UNIQUE(name)', - 'ALTER TABLE "users" ADD CONSTRAINT users_name_email_unique UNIQUE(name,email)', - ], - ) + query_sql = blueprint.to_sql() + expected_sql = [ + 'CREATE INDEX users_name_index ON "users"(name)', + 'CREATE INDEX users_name_email_index ON "users"(name,email)', + 'ALTER TABLE "users" ADD CONSTRAINT users_name_unique UNIQUE(name)', + 'ALTER TABLE "users" ADD CONSTRAINT users_name_email_unique UNIQUE(name,email)', + ] + self.assertEqual(query_sql, expected_sql) def test_alter_drop_foreign_key(self): with self.schema.table("users") as blueprint: blueprint.drop_foreign("users_playlist_id_foreign") - sql = ['ALTER TABLE "users" DROP CONSTRAINT users_playlist_id_foreign'] + expected_sql = [ + 'ALTER TABLE "users" DROP CONSTRAINT users_playlist_id_foreign' + ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_foreign_key_shortcut(self): with self.schema.table("users") as blueprint: blueprint.drop_foreign(["playlist_id"]) - sql = ['ALTER TABLE "users" DROP CONSTRAINT users_playlist_id_foreign'] + expected_sql = [ + 'ALTER TABLE "users" DROP CONSTRAINT users_playlist_id_foreign' + ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_unique_constraint(self): with self.schema.table("users") as blueprint: blueprint.drop_unique("users_playlist_id_unique") - sql = ['ALTER TABLE "users" DROP CONSTRAINT users_playlist_id_unique'] + expected_sql = [ + 'ALTER TABLE "users" DROP CONSTRAINT users_playlist_id_unique' + ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_add_index(self): with self.schema.table("users") as blueprint: blueprint.index("playlist_id") - sql = ['CREATE INDEX users_playlist_id_index ON "users"(playlist_id)'] + expected_sql = [ + 'CREATE INDEX users_playlist_id_index ON "users"(playlist_id)' + ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_add_primary(self): with self.schema.table("users") as blueprint: blueprint.primary("playlist_id") - sql = [ + expected_sql = [ 'ALTER TABLE "users" ADD CONSTRAINT users_playlist_id_primary PRIMARY KEY (playlist_id)' ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_index(self): with self.schema.table("users") as blueprint: blueprint.drop_index("users_playlist_id_index") - sql = ["DROP INDEX users_playlist_id_index"] + expected_sql = ["DROP INDEX users_playlist_id_index"] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_index_shortcut(self): with self.schema.table("users") as blueprint: blueprint.drop_index(["playlist_id"]) - sql = ["DROP INDEX users_playlist_id_index"] + expected_sql = ["DROP INDEX users_playlist_id_index"] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_primary(self): with self.schema.table("users") as blueprint: blueprint.drop_primary("users_id_primary") - sql = ['ALTER TABLE "users" DROP CONSTRAINT users_id_primary'] + expected_sql = ['ALTER TABLE "users" DROP CONSTRAINT users_id_primary'] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_unique_constraint_shortcut(self): with self.schema.table("users") as blueprint: blueprint.drop_unique(["playlist_id"]) - sql = ['ALTER TABLE "users" DROP CONSTRAINT users_playlist_id_unique'] + expected_sql = [ + 'ALTER TABLE "users" DROP CONSTRAINT users_playlist_id_unique' + ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_has_table(self): - schema_sql = self.schema.has_table("users") + query_sql = self.schema.has_table("users") - sql = "SELECT * from information_schema.tables where table_name='users' AND table_schema = 'public'" + expected_sql = "SELECT * from information_schema.tables where table_name='users' AND table_schema = 'public'" - self.assertEqual(schema_sql, sql) + self.assertEqual(query_sql, expected_sql) def test_drop_table(self): - schema_sql = self.schema.has_table("users") + query_sql = self.schema.has_table("users") - sql = "SELECT * from information_schema.tables where table_name='users' AND table_schema = 'public'" + expected_sql = "SELECT * from information_schema.tables where table_name='users' AND table_schema = 'public'" - self.assertEqual(schema_sql, sql) + self.assertEqual(query_sql, expected_sql) def test_change(self): with self.schema.table("users") as blueprint: @@ -228,12 +255,13 @@ def test_change(self): blueprint.table.from_table = table - sql = [ + expected_sql = [ 'ALTER TABLE "users" ADD COLUMN "name" VARCHAR(255) NOT NULL', 'ALTER TABLE "users" ALTER COLUMN "age" TYPE INTEGER, ALTER COLUMN "age" SET NOT NULL', ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_change_string(self): with self.schema.table("users") as blueprint: @@ -245,11 +273,12 @@ def test_change_string(self): blueprint.table.from_table = table - sql = [ + expected_sql = [ 'ALTER TABLE "users" ALTER COLUMN "name" TYPE VARCHAR(93), ALTER COLUMN "name" SET NOT NULL' ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_drop_add_and_change(self): with self.schema.table("users") as blueprint: @@ -266,13 +295,14 @@ def test_drop_add_and_change(self): blueprint.table.from_table = table - sql = [ + expected_sql = [ """ALTER TABLE "users" ADD COLUMN "name" VARCHAR(255) NOT NULL, ADD COLUMN "external_type" VARCHAR(255) NOT NULL DEFAULT 'external'""", 'ALTER TABLE "users" DROP COLUMN "email"', 'ALTER TABLE "users" ALTER COLUMN "age" TYPE INTEGER, ALTER COLUMN "age" DROP NOT NULL, ALTER COLUMN "age" SET DEFAULT 0', ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_timestamp_alter_add_nullable_column(self): with self.schema.table("users") as blueprint: @@ -285,43 +315,61 @@ def test_timestamp_alter_add_nullable_column(self): blueprint.table.from_table = table - sql = ['ALTER TABLE "users" ADD COLUMN "due_date" TIMESTAMP NULL'] + expected_sql = [ + 'ALTER TABLE "users" ADD COLUMN "due_date" TIMESTAMP NULL' + ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_on_table_schema_table(self): schema = Schema( connection_class=PostgresConnection, connection="postgres", connection_details=DATABASES, + dry=True, ).on("postgres") with schema.table("table_schema") as blueprint: blueprint.drop_column("name") + expected_sql_drop = ['ALTER TABLE "table_schema" DROP COLUMN "name"'] + query_sql_drop = blueprint.to_sql() + self.assertEqual(query_sql_drop, expected_sql_drop) + with schema.table("table_schema") as blueprint: blueprint.string("name") + expected_sql_add = [ + 'ALTER TABLE "table_schema" ADD COLUMN "name" VARCHAR(255) NOT NULL' + ] + query_sql_add = blueprint.to_sql() + self.assertEqual(query_sql_add, expected_sql_add) + def test_can_add_column_enum(self): with self.schema.table("users") as blueprint: blueprint.enum("status", ["active", "inactive"]).default("active") self.assertEqual(len(blueprint.table.added_columns), 1) - sql = [ - 'ALTER TABLE "users" ADD COLUMN "status" VARCHAR(255) CHECK(status IN (\'active\', \'inactive\')) NOT NULL DEFAULT \'active\'', + expected_sql = [ + "ALTER TABLE \"users\" ADD COLUMN \"status\" VARCHAR(255) CHECK(status IN ('active', 'inactive')) NOT NULL DEFAULT 'active'", ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_can_change_column_enum(self): with self.schema.table("users") as blueprint: - blueprint.enum("status", ["active", "inactive"]).default("active").change() + blueprint.enum("status", ["active", "inactive"]).default( + "active" + ).change() self.assertEqual(len(blueprint.table.changed_columns), 1) - sql = [ + expected_sql = [ 'ALTER TABLE "users" ALTER COLUMN "status" TYPE VARCHAR(255) CHECK(status IN (\'active\', \'inactive\')), ALTER COLUMN "status" SET NOT NULL, ALTER COLUMN "status" SET DEFAULT active', ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) diff --git a/tests/scopes/test_default_global_scopes.py b/tests/scopes/test_default_global_scopes.py index 0a7b75687..710fe27b5 100644 --- a/tests/scopes/test_default_global_scopes.py +++ b/tests/scopes/test_default_global_scopes.py @@ -93,8 +93,8 @@ class TestSoftDeletesScope(unittest.TestCase): def test_soft_deletes_changes_delete_to_update(self): UserSoft.__timestamps__ = False user = UserSoft.hydrate({"id": 1}) - sql = user.delete(query=True).to_sql() - self.assertTrue(sql.startswith("UPDATE")) + query_sql = user.delete(query=True).to_sql() + self.assertTrue(query_sql.startswith("UPDATE")) class TestTimeStampsScope(unittest.TestCase): @@ -141,5 +141,5 @@ def test_uses_custom_timestamp_columns_on_create(self): def test_uses_custom_updated_column_on_update(self): user = UserWithCustomTimeStamps.hydrate({"id": 1}) - sql = user.update({"id": 2}).to_sql() - self.assertTrue(UserWithCustomTimeStamps.date_updated_at in sql) + query_sql = user.update({"id": 2}).to_sql() + self.assertTrue(UserWithCustomTimeStamps.date_updated_at in query_sql) diff --git a/tests/sqlite/builder/test_sqlite_query_builder.py b/tests/sqlite/builder/test_sqlite_query_builder.py index 341b1e79e..031782d1a 100644 --- a/tests/sqlite/builder/test_sqlite_query_builder.py +++ b/tests/sqlite/builder/test_sqlite_query_builder.py @@ -1,4 +1,3 @@ -import inspect import os import unittest from pathlib import Path @@ -24,7 +23,12 @@ class UserMock(Model): __table__ = "users" -class BaseTestQueryBuilder: +class SQLiteQueryBuilderTest(unittest.TestCase): + """Tests for the QueryBuilder using the SQLite grammar. + + Each test builds a query and asserts the expected SQL inline. + """ + maxDiff = None def get_builder(self, table="users"): @@ -36,10 +40,12 @@ def get_builder(self, table="users"): dry=True, ) + # ------------------------------------------------------------------ + # Connection / config tests + # ------------------------------------------------------------------ + def test_standalone_connection_details(self): - # clear the env config path current_path = os.environ.pop("DB_CONFIG_PATH", None) - # test we fail to load the default config with pytest.raises(ConfigurationNotFound): load_config() @@ -50,127 +56,110 @@ def test_standalone_connection_details(self): "database": "config_test.sqlite3", }, } - resolver = ConnectionResolver(connection_details=custom_details) connection = resolver.connection_factory.make("sqlite") builder = QueryBuilder( - connection_details=custom_details, - connection_class=connection, + connection_details=custom_details, connection_class=connection ) with pytest.raises(QueryException) as query_exc: builder.table("tests").all() self.assertIn("'no such table: tests'", str(query_exc)) - - # remove the test file (Path().cwd() / "config_test.sqlite3").unlink() - - # reset the config path for other tests to use os.environ["DB_CONFIG_PATH"] = current_path + # ------------------------------------------------------------------ + # Aggregates + # ------------------------------------------------------------------ + def test_sum(self): builder = self.get_builder() builder.sum("age") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT SUM("users"."age") AS age FROM "users"' + self.assertEqual(query_sql, expected_sql) def test_sum_aggregate(self): builder = self.get_builder() builder.aggregate("SUM", "age") - - sql = getattr(self, "sum")() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT SUM("users"."age") AS age FROM "users"' + self.assertEqual(query_sql, expected_sql) def test_sum_aggregate_with_alias(self): builder = self.get_builder() builder.aggregate("SUM", "age", alias="number") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT SUM("users"."age") AS number FROM "users"' + self.assertEqual(query_sql, expected_sql) def test_sum_aggregate_with_alias_in_column_name(self): builder = self.get_builder() builder.sum("age as number") - - sql = getattr(self, "sum_aggregate_with_alias")() - 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) + query_sql = builder.to_sql() + expected_sql = 'SELECT SUM("users"."age") AS number FROM "users"' + self.assertEqual(query_sql, expected_sql) def test_max(self): builder = self.get_builder() builder.max("age") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT MAX("users"."age") AS age FROM "users"' + self.assertEqual(query_sql, expected_sql) def test_min(self): builder = self.get_builder() builder.min("age") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT MIN("users"."age") AS age FROM "users"' + self.assertEqual(query_sql, expected_sql) def test_avg(self): builder = self.get_builder() builder.avg("age") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT AVG("users"."age") AS age FROM "users"' + self.assertEqual(query_sql, expected_sql) + + def test_count(self): + builder = self.get_builder() + builder.count("id") + query_sql = builder.to_sql() + expected_sql = 'SELECT COUNT("users"."id") AS id FROM "users"' + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # Fetch operations + # ------------------------------------------------------------------ def test_all(self): builder = self.get_builder() builder.all() - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users"' + self.assertEqual(query_sql, expected_sql) def test_get(self): builder = self.get_builder() builder.get() - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users"' + self.assertEqual(query_sql, expected_sql) def test_first(self): builder = self.get_builder().first(query=True) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" LIMIT 1' + self.assertEqual(query_sql, expected_sql) def test_last(self): - UserMock.order_by("id", "DESC").first().id == UserMock.last("id").id + last_id = UserMock.last("id").id + first_desc_id = UserMock.order_by("id", "DESC").first().id + self.assertEqual(last_id, first_desc_id) def test_last_with_default_primary_key(self): - UserMock.order_by("id", "DESC").first().id == UserMock.last().id + last_id = UserMock.last().id + first_desc_id = UserMock.order_by("id", "DESC").first().id + self.assertEqual(last_id, first_desc_id) def test_first_or_fail_exception(self): with self.assertRaises(ModelNotFound): @@ -182,263 +171,215 @@ def test_find_or_fail_exception(self): def test_find_or_404_exception(self): with self.assertRaises(HTTP404): - UserMock.find_or_404(10000) + UserMock.find_or_404(1000) + + # ------------------------------------------------------------------ + # SELECT columns + # ------------------------------------------------------------------ def test_select(self): builder = self.get_builder() builder.select("name", "email") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT "users"."name", "users"."email" FROM "users"' + self.assertEqual(query_sql, expected_sql) def test_select_multiple(self): builder = self.get_builder() - builder.select("name, email") - sql = getattr(self, "select")() - self.assertEqual(builder.to_sql(), sql) + builder.select("name", "email") + query_sql = builder.to_sql() + expected_sql = 'SELECT "users"."name", "users"."email" FROM "users"' + self.assertEqual(query_sql, expected_sql) def test_add_select(self): builder = self.get_builder() - sql = ( - builder.select("name") - .add_select("phone_count", lambda q: q.count("*").table("phones")) - .add_select("salary", lambda q: q.count("*").table("salary")) - .to_sql() + builder.select("name").add_select( + "phone_count", lambda q: q.count("*").table("phones") + ).add_select("salary", lambda q: q.count("*").table("salary")) + query_sql = builder.to_sql() + expected_sql = ( + 'SELECT "users"."name",' + ' (SELECT COUNT(*) AS m_count_reserved FROM "phones") AS phone_count,' + ' (SELECT COUNT(*) AS m_count_reserved FROM "salary") AS salary' + ' FROM "users"' ) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + self.assertEqual(query_sql, expected_sql) def test_add_select_no_table(self): builder = self.get_builder(table=None) - sql = ( - builder.add_select( - "other_test", - lambda q: q.max("updated_at").table("different_table"), - ) - .add_select( - "some_alias", - lambda q: q.max("updated_at").table("another_table"), - ) - .to_sql() + builder.add_select( + "other_test", + lambda q: q.max("updated_at").table("different_table"), + ).add_select( + "some_alias", lambda q: q.max("updated_at").table("another_table") + ) + query_sql = builder.to_sql() + expected_sql = ( + "SELECT " + '(SELECT MAX("different_table"."updated_at") AS updated_at FROM "different_table") AS other_test, ' + '(SELECT MAX("another_table"."updated_at") AS updated_at FROM "another_table") AS some_alias' ) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + self.assertEqual(query_sql, expected_sql) def test_add_select_with_raw(self): builder = self.get_builder(table=None) - sql = ( - builder.select_raw("max(updated_at) as test") - .from_("some_table") - .add_select( - "other_test", - lambda query: ( - query.max("updated_at") - .from_("different_table") - .where("some_id", "=", "3") - ), - ) + builder.select_raw("max(updated_at) as test").from_( + "some_table" + ).add_select( + "other_test", + lambda query: query.max("updated_at") + .from_("different_table") + .where("some_id", "=", "3"), ) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = ( + "SELECT max(updated_at) as test, " + '(SELECT MAX("different_table"."updated_at") AS updated_at ' + 'FROM "different_table" ' + 'WHERE "different_table"."some_id" = \'3\') AS other_test ' + 'FROM "some_table"' + ) + self.assertEqual(query_sql, expected_sql) def test_select_raw(self): builder = self.get_builder() builder.select_raw("count(email) as email_count") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT count(email) as email_count FROM "users"' + self.assertEqual(query_sql, expected_sql) - def test_create(self): - builder = self.get_builder() - builder.create( - {"name": "Corentin All", "email": "corentin@yopmail.com"}, - query=True, - ) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_delete(self): - builder = self.get_builder() - builder.delete("name", "Joe", query=True) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + # ------------------------------------------------------------------ + # WHERE + # ------------------------------------------------------------------ def test_where(self): builder = self.get_builder() builder.where("name", "Joe") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."name" = \'Joe\'' + self.assertEqual(query_sql, expected_sql) def test_where_dictionary(self): builder = self.get_builder() builder.where({"name": "Joe"}) - sql = getattr(self, "where")() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."name" = \'Joe\'' + self.assertEqual(query_sql, expected_sql) def test_where_exists(self): builder = self.get_builder() builder.where_exists("name") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM \"users\" WHERE EXISTS 'name'" + self.assertEqual(query_sql, expected_sql) - def test_limit(self): + def test_where_like(self): builder = self.get_builder() - builder.limit(5) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + builder.where("age", "like", "%name%") + query_sql = builder.to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."age" LIKE \'%name%\'' + ) + self.assertEqual(query_sql, expected_sql) - def test_offset(self): + def test_where_not_like(self): builder = self.get_builder() - builder.offset(5) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + builder.where("age", "not like", "%name%") + query_sql = builder.to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."age" NOT LIKE \'%name%\'' + ) + self.assertEqual(query_sql, expected_sql) - def test_offset_with_limit(self): + def test_where_null(self): builder = self.get_builder() - builder.limit(2).offset(5) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + builder.where_null("name") + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."name" IS NULL' + self.assertEqual(query_sql, expected_sql) - def test_join(self): + def test_where_not_null(self): builder = self.get_builder() - builder.join("profiles", "users.id", "=", "profiles.user_id") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + builder.where_not_null("name") + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."name" IS NOT NULL' + self.assertEqual(query_sql, expected_sql) - def test_left_join(self): + def test_where_not_in(self): builder = self.get_builder() - builder.left_join("profiles", "users.id", "=", "profiles.user_id") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + builder.where_not_in("id", [1, 2, 3]) + query_sql = builder.to_sql() + expected_sql = "SELECT * FROM \"users\" WHERE \"users\".\"id\" NOT IN ('1','2','3')" + self.assertEqual(query_sql, expected_sql) - def test_right_join(self): + def test_where_in(self): builder = self.get_builder() - builder.right_join("profiles", "users.id", "=", "profiles.user_id") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_update(self): - builder = self.get_builder().update( - {"name": "Joe", "email": "joe@yopmail.com"}, dry=True + builder.where_in("id", [1, 2, 3]) + query_sql = builder.to_sql() + expected_sql = ( + "SELECT * FROM \"users\" WHERE \"users\".\"id\" IN ('1','2','3')" ) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + self.assertEqual(query_sql, expected_sql) - def test_increment(self): - builder = self.get_builder().increment("age", 1, dry=True) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_decrement(self): - builder = self.get_builder().decrement("age", 1, dry=True) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_count(self): + def test_where_lt(self): builder = self.get_builder() - builder.count("id") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + builder.where("age", "<", "20") + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."age" < \'20\'' + self.assertEqual(query_sql, expected_sql) - def test_order_by_asc(self): + def test_where_lte(self): builder = self.get_builder() - builder.order_by("email", "asc") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + builder.where("age", "<=", "20") + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."age" <= \'20\'' + self.assertEqual(query_sql, expected_sql) - def test_order_by_multiple(self): + def test_where_gt(self): builder = self.get_builder() - builder.order_by("email, name, active") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + builder.where("age", ">", "20") + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."age" > \'20\'' + self.assertEqual(query_sql, expected_sql) - def test_order_by_reference_direction(self): + def test_where_gte(self): builder = self.get_builder() - builder.order_by("email, name desc") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + builder.where("age", ">=", "20") + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."age" >= \'20\'' + self.assertEqual(query_sql, expected_sql) - def test_order_by_raw(self): + def test_where_ne(self): builder = self.get_builder() - builder.order_by_raw("col asc") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + builder.where("age", "!=", "20") + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."age" != \'20\'' + self.assertEqual(query_sql, expected_sql) - def test_order_by_desc(self): + def test_or_where(self): builder = self.get_builder() - builder.order_by("email", "desc") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + builder.where("age", "20").or_where("age", "<", 20) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."age" = \'20\' OR "users"."age" < \'20\'' + self.assertEqual(query_sql, expected_sql) def test_where_column(self): builder = self.get_builder() builder.where_column("name", "username") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_where_not_in(self): - builder = self.get_builder() - builder.where_not_in("id", [1, 2, 3]) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."name" = "users"."username"' + ) + self.assertEqual(query_sql, expected_sql) def test_between(self): builder = self.get_builder() builder.between("id", 2, 5) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."id" BETWEEN \'2\' AND \'5\'' + ) + self.assertEqual(query_sql, expected_sql) def test_between_persisted(self): builder = QueryBuilder().table("users").on("dev") @@ -448,616 +389,287 @@ def test_between_persisted(self): def test_not_between(self): builder = self.get_builder() builder.not_between("id", 2, 5) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."id" NOT BETWEEN \'2\' AND \'5\'' + self.assertEqual(query_sql, expected_sql) def test_not_between_persisted(self): builder = QueryBuilder().table("users").on("dev") users = builder.where_not_null("id").not_between("age", 1, 10).count() self.assertEqual(users, 2) - def test_where_in(self): - builder = self.get_builder() - builder.where_in("id", [1, 2, 3]) - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_where_null(self): - builder = self.get_builder() - builder.where_null("name") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_where_not_null(self): - builder = self.get_builder() - builder.where_not_null("name") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - def test_having(self): builder = self.get_builder(table="payments") builder.select("user_id").avg("salary").group_by("user_id").having( "salary", ">=", "1000" ) - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_group_by(self): - builder = self.get_builder(table="payments") - builder.select("user_id").min("salary").group_by("user_id") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_group_by_raw(self): - builder = self.get_builder(table="payments") - builder.select("user_id").min("salary").group_by_raw("count(*)") - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_group_by_multiple(self): - builder = self.get_builder(table="payments") - builder.select("user_id").min("salary").group_by("user_id").group_by( - "salary" + query_sql = builder.to_sql() + expected_sql = ( + 'SELECT "payments"."user_id", AVG("payments"."salary") AS salary' + ' FROM "payments" GROUP BY "payments"."user_id" HAVING "payments"."salary" >= \'1000\'' ) + self.assertEqual(query_sql, expected_sql) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) + # ------------------------------------------------------------------ + # LIMIT / OFFSET + # ------------------------------------------------------------------ - def test_group_by_multiple_in_same_group_by(self): - builder = self.get_builder(table="payments") - builder.select("user_id").min("salary").group_by("user_id, salary") - - sql = getattr(self, "group_by_multiple")() - self.assertEqual(builder.to_sql(), sql) - - def test_builder_alone(self): - self.assertTrue( - QueryBuilder( - connection_details={ - "default": "sqlite", - "sqlite": { - "driver": "sqlite", - "database": "orm.sqlite3", - "prefix": "", - }, - } - ).table("users") - ) - - def test_where_lt(self): - builder = self.get_builder() - builder.where("age", "<", "20") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_where_lte(self): - builder = self.get_builder() - builder.where("age", "<=", "20") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_where_gt(self): - builder = self.get_builder() - builder.where("age", ">", "20") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_where_gte(self): - builder = self.get_builder() - builder.where("age", ">=", "20") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_where_ne(self): - builder = self.get_builder() - builder.where("age", "!=", "20") - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_or_where(self): - builder = self.get_builder() - builder.where("age", "20").or_where("age", "<", 20) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(builder.to_sql(), sql) - - def test_can_call_with_schema(self): - builder = self.get_builder() - sql = ( - builder.table("information_schema.columns") - .select("table_name") - .where("table_name", "users") - .to_sql() - ) - self.assertEqual( - sql, - """SELECT "information_schema"."columns"."table_name" FROM "information_schema"."columns" WHERE "information_schema"."columns"."table_name" = 'users'""", - ) - - def test_can_call_with_raw(self): - builder = self.get_builder() - sql = builder.on("dev").statement("select * from users") - self.assertTrue(sql) - - def test_truncate(self): - builder = self.get_builder() - sql = builder.truncate(dry=True) - sql_ref = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(sql, sql_ref) - - def test_truncate_without_foreign_keys(self): - builder = self.get_builder() - sql = builder.truncate(foreign_keys=True) - sql_ref = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(sql, sql_ref) - - -class SQLiteQueryBuilderTest(BaseTestQueryBuilder, unittest.TestCase): - grammar = SQLiteGrammar - - def sum(self): - """ + def test_limit(self): builder = self.get_builder() - builder.sum('age') - """ - return """SELECT SUM("users"."age") AS age FROM "users\"""" + builder.limit(5) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" LIMIT 5' + self.assertEqual(query_sql, expected_sql) - def sum_aggregate_with_alias(self): - """ + def test_offset(self): builder = self.get_builder() - builder.sum('age') - """ - return """SELECT SUM("users"."age") AS number FROM "users\"""" + builder.offset(5) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" LIMIT -1 OFFSET 5' + self.assertEqual(query_sql, expected_sql) - def max(self): - """ + def test_offset_with_limit(self): builder = self.get_builder() - builder.max('age') - """ - return """SELECT MAX("users"."age") AS age FROM "users\"""" + builder.limit(2).offset(5) + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" LIMIT 2 OFFSET 5' + self.assertEqual(query_sql, expected_sql) - def min(self): - """ - builder = self.get_builder() - builder.min('age') - """ - return """SELECT MIN("users"."age") AS age FROM "users\"""" + # ------------------------------------------------------------------ + # ORDER BY / GROUP BY + # ------------------------------------------------------------------ - def avg(self): - """ + def test_order_by_asc(self): builder = self.get_builder() - builder.avg('age') - """ - return """SELECT AVG("users"."age") AS age FROM "users\"""" + builder.order_by("email", "asc") + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" ORDER BY "email" ASC' + self.assertEqual(query_sql, expected_sql) - def first(self): - """ + def test_order_by_desc(self): builder = self.get_builder() - builder.first() - """ - return """SELECT * FROM "users" LIMIT 1""" + builder.order_by("email", "desc") + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" ORDER BY "email" DESC' + self.assertEqual(query_sql, expected_sql) - def all(self): - """ + def test_order_by_multiple(self): builder = self.get_builder() - builder.all() - """ - return """SELECT * FROM "users\"""" + builder.order_by("email, name, active") + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" ORDER BY "email" ASC, "name" ASC, "active" ASC' + self.assertEqual(query_sql, expected_sql) - def get(self): - """ + def test_order_by_raw(self): builder = self.get_builder() - builder.get() - """ - return """SELECT * FROM "users\"""" + builder.order_by_raw("col asc") + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" ORDER BY col asc' + self.assertEqual(query_sql, expected_sql) - def select(self): - """ + def test_order_by_reference_direction(self): builder = self.get_builder() - builder.select('name', 'email') - """ - return """SELECT "users"."name", "users"."email" FROM "users\"""" + builder.order_by("email, name desc") + query_sql = builder.to_sql() + expected_sql = ( + 'SELECT * FROM "users" ORDER BY "email" ASC, "name" DESC' + ) + self.assertEqual(query_sql, expected_sql) - def select_multiple(self): - """ + def test_latest(self): builder = self.get_builder() - builder.select('name', 'email') - """ - return """SELECT "users"."name", "users"."email" FROM "users\"""" + builder.latest("email") + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" ORDER BY "email" DESC' + self.assertEqual(query_sql, expected_sql) - def add_select(self): - """ + def test_oldest(self): builder = self.get_builder() - builder.select('name', 'email') - """ - return """SELECT "users"."name", (SELECT COUNT(*) AS m_count_reserved FROM "phones") AS phone_count, (SELECT COUNT(*) AS m_count_reserved FROM "salary") AS salary FROM "users\"""" + builder.oldest("email") + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" ORDER BY "email" ASC' + self.assertEqual(query_sql, expected_sql) - def add_select_no_table(self): - """ - builder = self.get_builder() - builder.select('name', 'email') - """ - return ( - "SELECT " - '(SELECT MAX("different_table"."updated_at") AS updated_at FROM "different_table") AS other_test, ' - '(SELECT MAX("another_table"."updated_at") AS updated_at FROM "another_table") AS some_alias' + def test_group_by(self): + builder = self.get_builder(table="payments") + builder.select("user_id").min("salary").group_by("user_id") + query_sql = builder.to_sql() + expected_sql = ( + 'SELECT "payments"."user_id", MIN("payments"."salary") AS salary' + ' FROM "payments" GROUP BY "payments"."user_id"' ) + self.assertEqual(query_sql, expected_sql) - def add_select_with_raw(self): - """ - builder - .select_raw("max(updated_at) as test").from_("some_table") - .add_select( - "other_test", - lambda query: ( - query.max("updated_at") - .from_("different_table") - .where( - "some_id", "=", - "3" - ) - ), + def test_group_by_multiple(self): + builder = self.get_builder(table="payments") + builder.select("user_id").min("salary").group_by("user_id").group_by( + "salary" ) - """ - return ( - "SELECT max(updated_at) as test, " - '(SELECT MAX("different_table"."updated_at") AS updated_at ' - 'FROM "different_table" ' - 'WHERE "different_table"."some_id" = \'3\') AS other_test ' - 'FROM "some_table"' + query_sql = builder.to_sql() + expected_sql = ( + 'SELECT "payments"."user_id", MIN("payments"."salary") AS salary' + ' FROM "payments" GROUP BY "payments"."user_id", "payments"."salary"' ) + self.assertEqual(query_sql, expected_sql) - def select_raw(self): - """ - builder = self.get_builder() - builder.select_raw('count(email) as email_count') - """ - return """SELECT count(email) as email_count FROM "users\"""" - - def create(self): - """ - builder = get_builder() - builder.create({"name": "Corentin All", 'email': 'corentin@yopmail.com'}) - """ - return """INSERT INTO "users" ("name", "email") VALUES ('Corentin All', 'corentin@yopmail.com')""" - - def delete(self): - """ - builder = get_builder() - builder.delete("name', 'Joe') - """ - return """DELETE FROM "users" WHERE "name" = 'Joe'""" - - def where(self): - """ - builder = get_builder() - builder.where('name', 'Joe') - """ - return """SELECT * FROM "users" WHERE "users"."name" = 'Joe'""" - - def where_exists(self): - """ - builder = get_builder() - builder.where_exists('name') - """ - return """SELECT * FROM "users" WHERE EXISTS 'name'""" - - def limit(self): - """ - builder = get_builder() - builder.limit(5) - """ - return """SELECT * FROM "users" LIMIT 5""" + def test_group_by_multiple_in_same_group_by(self): + builder = self.get_builder(table="payments") + builder.select("user_id").min("salary").group_by("user_id, salary") + query_sql = builder.to_sql() + expected_sql = ( + 'SELECT "payments"."user_id", MIN("payments"."salary") AS salary' + ' FROM "payments" GROUP BY "payments"."user_id", "payments"."salary"' + ) + self.assertEqual(query_sql, expected_sql) - def offset(self): - """ - builder = get_builder() - builder.offset(5) - """ - return """SELECT * FROM "users" LIMIT -1 OFFSET 5""" + def test_group_by_raw(self): + builder = self.get_builder(table="payments") + builder.select("user_id").min("salary").group_by_raw("count(*)") + query_sql = builder.to_sql() + expected_sql = ( + 'SELECT "payments"."user_id", MIN("payments"."salary") AS salary' + ' FROM "payments" GROUP BY count(*)' + ) + self.assertEqual(query_sql, expected_sql) - def offset_with_limit(self): - """ - builder = get_builder() - builder.limit(2).offset(5) - """ - return """SELECT * FROM "users" LIMIT 2 OFFSET 5""" + # ------------------------------------------------------------------ + # JOINs + # ------------------------------------------------------------------ - def join(self): - """ + def test_join(self): + builder = self.get_builder() builder.join("profiles", "users.id", "=", "profiles.user_id") - """ - return """SELECT * FROM "users" INNER JOIN "profiles" ON "users"."id" = "profiles"."user_id\"""" + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" INNER JOIN "profiles" ON "users"."id" = "profiles"."user_id"' + self.assertEqual(query_sql, expected_sql) - def left_join(self): - """ + def test_left_join(self): + builder = self.get_builder() builder.left_join("profiles", "users.id", "=", "profiles.user_id") - """ - return """SELECT * FROM "users" LEFT JOIN "profiles" ON "users"."id" = "profiles"."user_id\"""" + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" LEFT JOIN "profiles" ON "users"."id" = "profiles"."user_id"' + self.assertEqual(query_sql, expected_sql) - def right_join(self): - """ + def test_right_join(self): + builder = self.get_builder() builder.right_join("profiles", "users.id", "=", "profiles.user_id") - """ - return """SELECT * FROM "users" LEFT JOIN "profiles" ON "users"."id" = "profiles"."user_id\"""" - - def update(self): - """ - builder.update({"name": "Joe", "email": "joe@yopmail.com"}) - """ - return """UPDATE "users" SET "name" = 'Joe', "email" = 'joe@yopmail.com'""" - - def increment(self): - """ - builder.increment('age', 1) - """ - return """UPDATE "users" SET "age" = "age" + '1'""" - - def decrement(self): - """ - builder.decrement('age', 1) - """ - return """UPDATE "users" SET "age" = "age" - '1'""" - - def count(self): - """ - builder.count(id) - """ - return """SELECT COUNT("users"."id") AS id FROM "users\"""" - - def order_by_asc(self): - """ - builder.order_by('email', 'asc') - """ - return """SELECT * FROM "users" ORDER BY "email" ASC""" - - def order_by_multiple(self): - """ - builder.order_by('email', 'asc') - """ - return """SELECT * FROM "users" ORDER BY "email" ASC, "name" ASC, "active" ASC""" - - def order_by_raw(self): - """ - builder.order_by('email', 'asc') - """ - return """SELECT * FROM "users" ORDER BY col asc""" - - def order_by_reference_direction(self): - """ - builder.order_by('email', 'asc') - """ - return """SELECT * FROM "users" ORDER BY "email" ASC, "name" DESC""" - - def order_by_desc(self): - """ - builder.order_by('email', 'des') - """ - return """SELECT * FROM "users" ORDER BY "email" DESC""" - - def where_column(self): - """ - builder.where_column('name', 'username') - """ - return """SELECT * FROM "users" WHERE "users"."name" = "users"."username\"""" - - def where_null(self): - """ - builder.where_null('name') - """ - return """SELECT * FROM "users" WHERE "users"."name" IS NULL""" - - def where_not_null(self): - """ - builder.where_null('name') - """ - return """SELECT * FROM "users" WHERE "users"."name" IS NOT NULL""" - - def where_not_in(self): - """ - builder.where_not_in('id', [1, 2, 3]) - """ - return ( - """SELECT * FROM "users" WHERE "users"."id" NOT IN ('1','2','3')""" - ) + # SQLite has no RIGHT JOIN; it is emitted as LEFT JOIN + query_sql = builder.to_sql() + expected_sql = 'SELECT * FROM "users" LEFT JOIN "profiles" ON "users"."id" = "profiles"."user_id"' + self.assertEqual(query_sql, expected_sql) - def where_in(self): - """ - builder.where_in('id', [1, 2, 3]) - """ - return """SELECT * FROM "users" WHERE "users"."id" IN ('1','2','3')""" - - def between(self): - """ - builder.between('id', 2, 5) - """ - return ( - """SELECT * FROM "users" WHERE "users"."id" BETWEEN '2' AND '5'""" - ) + # ------------------------------------------------------------------ + # DML + # ------------------------------------------------------------------ - def not_between(self): - """ - builder.not_between('id', 2, 5) - """ - return """SELECT * FROM "users" WHERE "users"."id" NOT BETWEEN '2' AND '5'""" - - def having(self): - """ - builder.select('user_id').avg('salary').group_by('user_id').having('salary', '>=', '1000') - """ - return """SELECT "payments"."user_id", AVG("payments"."salary") AS salary FROM "payments" GROUP BY "payments"."user_id" HAVING "payments"."salary" >= '1000'""" - - def group_by(self): - """ - builder.select('user_id').min('salary').group_by('user_id') - """ - return """SELECT "payments"."user_id", MIN("payments"."salary") AS salary FROM "payments" GROUP BY "payments"."user_id\"""" - - def group_by_multiple(self): - """ - builder.select('user_id').min('salary').group_by('user_id') - """ - return """SELECT "payments"."user_id", MIN("payments"."salary") AS salary FROM "payments" GROUP BY "payments"."user_id", "payments"."salary\"""" - - def group_by_raw(self): - """ - builder.select('user_id').min('salary').group_by('user_id') - """ - return """SELECT "payments"."user_id", MIN("payments"."salary") AS salary FROM "payments" GROUP BY count(*)""" - - def where_lt(self): - """ + def test_create(self): builder = self.get_builder() - builder.where('age', '<', '20') - """ - return """SELECT * FROM "users" WHERE "users"."age" < '20'""" + builder.create( + {"name": "Corentin All", "email": "corentin@yopmail.com"}, + query=True, + ) + query_sql = builder.to_sql() + expected_sql = 'INSERT INTO "users" ("name", "email") VALUES (\'Corentin All\', \'corentin@yopmail.com\')' + self.assertEqual(query_sql, expected_sql) - def where_lte(self): - """ + def test_delete(self): builder = self.get_builder() - builder.where('age', '<=', '20') - """ - return """SELECT * FROM "users" WHERE "users"."age" <= '20'""" + builder.delete("name", "Joe", query=True) + query_sql = builder.to_sql() + expected_sql = 'DELETE FROM "users" WHERE "name" = \'Joe\'' + self.assertEqual(query_sql, expected_sql) - def where_gt(self): - """ - builder = self.get_builder() - builder.where('age', '>', '20') - """ - return """SELECT * FROM "users" WHERE "users"."age" > '20'""" + def test_update(self): + builder = self.get_builder().update( + {"name": "Joe", "email": "joe@yopmail.com"}, dry=True + ) + query_sql = builder.to_sql() + expected_sql = 'UPDATE "users" SET "name" = \'Joe\', "email" = \'joe@yopmail.com\'' + self.assertEqual(query_sql, expected_sql) - def where_gte(self): - """ - builder = self.get_builder() - builder.where('age', '>=', '20') - """ - return """SELECT * FROM "users" WHERE "users"."age" >= '20'""" + def test_increment(self): + builder = self.get_builder().increment("age", 1, dry=True) + query_sql = builder.to_sql() + expected_sql = 'UPDATE "users" SET "age" = "age" + \'1\'' + self.assertEqual(query_sql, expected_sql) - def where_ne(self): - """ - builder = self.get_builder() - builder.where('age', '!=', '20') - """ - return """SELECT * FROM "users" WHERE "users"."age" != '20'""" + def test_decrement(self): + builder = self.get_builder().decrement("age", 1, dry=True) + query_sql = builder.to_sql() + expected_sql = 'UPDATE "users" SET "age" = "age" - \'1\'' + self.assertEqual(query_sql, expected_sql) - def or_where(self): - """ - builder = self.get_builder() - builder.where('age', '20').or_where('age','<', 20) - """ - return """SELECT * FROM "users" WHERE "users"."age" = '20' OR "users"."age" < '20'""" + # ------------------------------------------------------------------ + # TRUNCATE + # ------------------------------------------------------------------ - def where_like(self): - """ + def test_truncate(self): builder = self.get_builder() - builder.where("age", "like", "%name%") - """ - return """SELECT * FROM "users" WHERE "users"."age" LIKE '%name%'""" + query_sql = builder.truncate(dry=True) + expected_sql = 'DELETE FROM "users"' + self.assertEqual(query_sql, expected_sql) - def where_not_like(self): - """ + def test_truncate_without_foreign_keys(self): builder = self.get_builder() - builder.where("age", "like", "%name%") - """ - return ( - """SELECT * FROM "users" WHERE "users"."age" NOT LIKE '%name%'""" - ) + query_sql = builder.truncate(foreign_keys=True) + expected_sql = [ + "PRAGMA foreign_keys = OFF", + 'DELETE FROM "users"', + "PRAGMA foreign_keys = ON", + ] + self.assertEqual(query_sql, expected_sql) - def test_when(self): + # ------------------------------------------------------------------ + # Conditional / misc + # ------------------------------------------------------------------ + + def test_when_condition_true(self): builder = self.get_builder() - sql = builder.when( + query_sql = builder.when( 19 > 18, lambda q: q.where("age_restricted", 1) ).to_sql() - return self.assertEqual( - sql, - """SELECT * FROM "users" WHERE "users"."age_restricted" = '1'""", + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."age_restricted" = \'1\'' ) + self.assertEqual(query_sql, expected_sql) + def test_when_condition_false(self): builder = self.get_builder() - sql = builder.when( + query_sql = builder.when( 17 > 18, lambda q: q.where("age_restricted", 1) ).to_sql() - return self.assertEqual(sql, """SELECT * FROM "users\"""") + expected_sql = 'SELECT * FROM "users"' + self.assertEqual(query_sql, expected_sql) - def truncate(self): - """ - builder = self.get_builder() - builder.truncate() - """ - return """DELETE FROM "users\"""" - - def truncate_without_foreign_keys(self): - """ - builder = self.get_builder() - builder.truncate(foreign_keys=True) - """ - return [ - "PRAGMA foreign_keys = OFF", - 'DELETE FROM "users"', - "PRAGMA foreign_keys = ON", - ] + def test_builder_alone(self): + self.assertTrue( + QueryBuilder( + connection_details={ + "default": "sqlite", + "sqlite": { + "driver": "sqlite", + "database": "orm.sqlite3", + "prefix": "", + }, + } + ).table("users") + ) - def test_latest(self): + def test_can_call_with_schema(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) + query_sql = ( + builder.table("information_schema.columns") + .select("table_name") + .where("table_name", "users") + .to_sql() + ) + expected_sql = ( + 'SELECT "information_schema"."columns"."table_name" FROM "information_schema"."columns"' + ' WHERE "information_schema"."columns"."table_name" = \'users\'' + ) + self.assertEqual(query_sql, expected_sql) - def test_oldest(self): + def test_can_call_with_raw(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""" + query_sql = builder.on("dev").statement("select * from users") + self.assertTrue(query_sql) diff --git a/tests/sqlite/builder/test_sqlite_query_builder_relationships.py b/tests/sqlite/builder/test_sqlite_query_builder_relationships.py index eb1e24b8f..72e7414cc 100644 --- a/tests/sqlite/builder/test_sqlite_query_builder_relationships.py +++ b/tests/sqlite/builder/test_sqlite_query_builder_relationships.py @@ -55,9 +55,9 @@ def get_builder(self, table="users"): def test_has(self): builder = self.get_builder() - sql = builder.has("articles").to_sql() + query_sql = builder.has("articles").to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM "users" WHERE EXISTS (""" """SELECT * FROM "articles" WHERE "articles"."user_id" = "users"."id\"""" """)""", @@ -65,9 +65,9 @@ def test_has(self): def test_doesnt_have(self): builder = self.get_builder() - sql = builder.doesnt_have("articles").to_sql() + query_sql = builder.doesnt_have("articles").to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM "users" WHERE NOT EXISTS (""" """SELECT * FROM "articles" WHERE "articles"."user_id" = "users"."id\"""" """)""", @@ -75,11 +75,11 @@ def test_doesnt_have(self): def test_where_doesnt_have(self): builder = self.get_builder() - sql = builder.where_doesnt_have( + query_sql = builder.where_doesnt_have( "articles", lambda q: q.where("title", "Eggs and Ham") ).to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM "users" WHERE NOT EXISTS (""" """SELECT * FROM "articles" WHERE "articles"."user_id" = "users"."id" AND "articles"."title" = 'Eggs and Ham'""" """)""", @@ -87,20 +87,20 @@ def test_where_doesnt_have(self): def test_where_has_query(self): builder = self.get_builder() - sql = builder.where_has( + query_sql = builder.where_has( "articles", lambda q: q.where("active", 1) ).to_sql() self.assertEqual( - sql, + query_sql, """SELECT * FROM "users" WHERE EXISTS (""" """SELECT * FROM "articles" WHERE "articles"."user_id" = "users"."id" AND "articles"."active" = '1'""" """)""", ) def test_relationship_multiple_has(self): - to_sql = User.has("articles", "profile").to_sql() + query_sql = User.has("articles", "profile").to_sql() self.assertEqual( - to_sql, + query_sql, """SELECT * FROM "users" WHERE EXISTS (""" """SELECT * FROM "articles" WHERE "articles"."user_id" = "users"."id\"""" """) AND EXISTS (""" @@ -109,9 +109,9 @@ def test_relationship_multiple_has(self): ) def test_relationship_multiple_has_calls(self): - to_sql = User.has("articles").has("profile").to_sql() + query_sql = User.has("articles").has("profile").to_sql() self.assertEqual( - to_sql, + query_sql, """SELECT * FROM "users" WHERE EXISTS (""" """SELECT * FROM "articles" WHERE "articles"."user_id" = "users"."id\"""" """) AND EXISTS (""" @@ -120,15 +120,15 @@ def test_relationship_multiple_has_calls(self): ) def test_nested_has(self): - to_sql = User.has("articles.logo").to_sql() + query_sql = User.has("articles.logo").to_sql() self.assertEqual( - to_sql, + query_sql, """SELECT * FROM "users" WHERE EXISTS (SELECT * FROM "articles" WHERE "articles"."user_id" = "users"."id" AND EXISTS (SELECT * FROM "logos" WHERE "logos"."article_id" = "articles"."id"))""", ) def test_joins(self): - to_sql = self.get_builder().joins("articles").to_sql() + query_sql = self.get_builder().joins("articles").to_sql() self.assertEqual( - to_sql, + query_sql, """SELECT * FROM "users" INNER JOIN "articles" ON "users"."id" = "articles"."user_id\"""", ) diff --git a/tests/sqlite/grammar/test_sqlite_delete_grammar.py b/tests/sqlite/grammar/test_sqlite_delete_grammar.py index 3bd36a872..08f74a33b 100644 --- a/tests/sqlite/grammar/test_sqlite_delete_grammar.py +++ b/tests/sqlite/grammar/test_sqlite_delete_grammar.py @@ -1,75 +1,32 @@ -import inspect import unittest from src.masoniteorm.query import QueryBuilder from src.masoniteorm.query.grammars import SQLiteGrammar -class BaseDeleteGrammarTest: +class TestSQLiteDeleteGrammar(unittest.TestCase): def setUp(self): self.builder = QueryBuilder(SQLiteGrammar, table="users") def test_can_compile_delete(self): - to_sql = self.builder.delete("id", 1, query=True).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + query_sql = self.builder.delete("id", 1, query=True).to_sql() + expected_sql = """DELETE FROM "users" WHERE "id" = '1'""" + self.assertEqual(query_sql, expected_sql) def test_can_compile_delete_in(self): - to_sql = self.builder.delete("id", [1, 2, 3], query=True).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + query_sql = self.builder.delete("id", [1, 2, 3], query=True).to_sql() + expected_sql = """DELETE FROM "users" WHERE "id" IN ('1','2','3')""" + self.assertEqual(query_sql, expected_sql) def test_can_compile_delete_with_where(self): - to_sql = ( + query_sql = ( self.builder.where("age", 20) .where("profile", 1) + .set_action("delete") .delete(query=True) .to_sql() ) - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) - - -class TestSqliteDeleteGrammar(BaseDeleteGrammarTest, unittest.TestCase): - grammar = "sqlite" - - def can_compile_delete(self): - """ - ( - self.builder - .delete('id', 1) - .to_sql() - ) - """ - return """DELETE FROM "users" WHERE "id" = '1'""" - - def can_compile_delete_in(self): - """ - ( - self.builder - .delete('id', 1) - .to_sql() - ) - """ - return """DELETE FROM "users" WHERE "id" IN ('1','2','3')""" - - def can_compile_delete_with_where(self): - """ - ( - self.builder - .where('age', 20) - .where('profile', 1) - .delete() - .to_sql() + expected_sql = ( + """DELETE FROM "users" WHERE "age" = '20' AND "profile" = '1'""" ) - """ - return """DELETE FROM "users" WHERE "age" = '20' AND "profile" = '1'""" + self.assertEqual(query_sql, expected_sql) diff --git a/tests/sqlite/grammar/test_sqlite_insert_grammar.py b/tests/sqlite/grammar/test_sqlite_insert_grammar.py index 35ee7eb91..89650f2a4 100644 --- a/tests/sqlite/grammar/test_sqlite_insert_grammar.py +++ b/tests/sqlite/grammar/test_sqlite_insert_grammar.py @@ -1,33 +1,26 @@ -import inspect import unittest from src.masoniteorm.query import QueryBuilder from src.masoniteorm.query.grammars import SQLiteGrammar -class BaseInsertGrammarTest: +class TestSQLiteInsertGrammar(unittest.TestCase): def setUp(self): self.builder = QueryBuilder(SQLiteGrammar, table="users") def test_can_compile_insert(self): - to_sql = self.builder.create({"name": "Joe"}, query=True).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + query_sql = self.builder.create({"name": "Joe"}, query=True).to_sql() + expected_sql = """INSERT INTO "users" ("name") VALUES ('Joe')""" + self.assertEqual(query_sql, expected_sql) def test_can_compile_insert_with_keywords(self): - to_sql = self.builder.create(name="Joe", query=True).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + query_sql = self.builder.create(name="Joe", query=True).to_sql() + expected_sql = """INSERT INTO "users" ("name") VALUES ('Joe')""" + self.assertEqual(query_sql, expected_sql) def test_can_compile_bulk_create(self): - to_sql = self.builder.bulk_create( - # These keys are intentionally out of order to show column to value alignment works + # Keys are intentionally out of order to verify column-to-value alignment + query_sql = self.builder.bulk_create( [ {"name": "Joe", "age": 5}, {"age": 35, "name": "Bill"}, @@ -35,24 +28,11 @@ def test_can_compile_bulk_create(self): ], query=True, ).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) - - def test_can_compile_bulk_create_qmark(self): - to_sql = self.builder.bulk_create( - [{"name": "Joe"}, {"name": "Bill"}, {"name": "John"}], query=True - ).to_qmark() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + expected_sql = """INSERT INTO "users" ("age", "name") VALUES ('5', 'Joe'), ('35', 'Bill'), ('10', 'John')""" + self.assertEqual(query_sql, expected_sql) def test_can_compile_bulk_create_multiple(self): - to_sql = self.builder.bulk_create( + query_sql = self.builder.bulk_create( [ {"name": "Joe", "active": "1"}, {"name": "Bill", "active": "1"}, @@ -60,44 +40,12 @@ def test_can_compile_bulk_create_multiple(self): ], query=True, ).to_sql() + expected_sql = """INSERT INTO "users" ("active", "name") VALUES ('1', 'Joe'), ('1', 'Bill'), ('1', 'John')""" + self.assertEqual(query_sql, expected_sql) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) - - -class TestSqliteUpdateGrammar(BaseInsertGrammarTest, unittest.TestCase): - grammar = "sqlite" - - def can_compile_insert(self): - """ - self.builder.create({ - 'name': 'Joe' - }).to_sql() - """ - return """INSERT INTO "users" ("name") VALUES ('Joe')""" - - def can_compile_insert_with_keywords(self): - """ - self.builder.create(name="Joe").to_sql() - """ - return """INSERT INTO "users" ("name") VALUES ('Joe')""" - - def can_compile_bulk_create(self): - """ - self.builder.create(name="Joe").to_sql() - """ - return """INSERT INTO "users" ("age", "name") VALUES ('5', 'Joe'), ('35', 'Bill'), ('10', 'John')""" - - def can_compile_bulk_create_multiple(self): - """ - self.builder.create(name="Joe").to_sql() - """ - return """INSERT INTO "users" ("active", "name") VALUES ('1', 'Joe'), ('1', 'Bill'), ('1', 'John')""" - - def can_compile_bulk_create_qmark(self): - """ - self.builder.create(name="Joe").to_sql() - """ - return """INSERT INTO "users" ("name") VALUES (?), (?), (?)""" + def test_can_compile_bulk_create_qmark(self): + query_sql = self.builder.bulk_create( + [{"name": "Joe"}, {"name": "Bill"}, {"name": "John"}], query=True + ).to_qmark() + expected_sql = """INSERT INTO "users" ("name") VALUES (?), (?), (?)""" + self.assertEqual(query_sql, expected_sql) diff --git a/tests/sqlite/grammar/test_sqlite_select_grammar.py b/tests/sqlite/grammar/test_sqlite_select_grammar.py index ad88acd66..a916f3683 100644 --- a/tests/sqlite/grammar/test_sqlite_select_grammar.py +++ b/tests/sqlite/grammar/test_sqlite_select_grammar.py @@ -1,482 +1,607 @@ import unittest +from src.masoniteorm.expressions import JoinClause +from src.masoniteorm.models import Model +from src.masoniteorm.query import QueryBuilder from src.masoniteorm.query.grammars import SQLiteGrammar -from src.masoniteorm.testing import BaseTestCaseSelectGrammar -class TestSQLiteGrammar(BaseTestCaseSelectGrammar, unittest.TestCase): - grammar = SQLiteGrammar +class MockConnection: + connection_details = {} + + def make_connection(self): + return self + + +class TestSQLiteSelectGrammar(unittest.TestCase): + """Tests for SQL SELECT compilation with the SQLite grammar. + + Each test is self-contained: it builds a query and asserts the expected + SQL string inline, so no separate data-provider class is needed. + """ + maxDiff = None - def can_compile_select(self): - """ - self.builder.to_sql() - """ - return """SELECT * FROM "users\"""" - - def can_compile_order_by_and_first(self): - """ - self.builder.order_by('id', 'asc').first() - """ - return """SELECT * FROM "users" ORDER BY "id" ASC LIMIT 1""" - - def can_compile_with_columns(self): - """ - self.builder.select('username', 'password').to_sql() - """ - return ( - """SELECT "users"."username", "users"."password" FROM "users\"""" - ) - - def can_compile_with_where(self): - """ - self.builder.select('username', 'password').where('id', 1).to_sql() - """ - return """SELECT "users"."username", "users"."password" FROM "users" WHERE "users"."id" = '1'""" - - def can_compile_with_several_where(self): - """ - self.builder.select('username', 'password').where('id', 1).where('username', 'joe').to_sql() - """ - return """SELECT "users"."username", "users"."password" FROM "users" WHERE "users"."id" = '1' AND "users"."username" = 'joe'""" - - def can_compile_with_several_where_and_limit(self): - """ - self.builder.select('username', 'password').where('id', 1).where('username', 'joe').limit(10).to_sql() - """ - return """SELECT "users"."username", "users"."password" FROM "users" WHERE "users"."id" = '1' AND "users"."username" = 'joe' LIMIT 10""" - - def can_compile_with_sum(self): - """ - self.builder.sum('age').to_sql() - """ - return """SELECT SUM("users"."age") AS age FROM "users\"""" - - def can_compile_with_max(self): - """ - self.builder.max('age').to_sql() - """ - return """SELECT MAX("users"."age") AS age FROM "users\"""" - - def can_compile_with_max_and_columns(self): - """ - self.builder.select('username').max('age').to_sql() - """ - return """SELECT "users"."username", MAX("users"."age") AS age FROM "users\"""" - - def can_compile_with_max_and_columns_different_order(self): - """ - self.builder.max('age').select('username').to_sql() - """ - return """SELECT "users"."username", MAX("users"."age") AS age FROM "users\"""" - - def can_compile_with_order_by(self): - """ - self.builder.select('username').order_by('age', 'desc').to_sql() - """ - return """SELECT "users"."username" FROM "users" ORDER BY "age" DESC""" - - def can_compile_with_multiple_order_by(self): - """ - self.builder.select('username').order_by('age', 'desc').order_by('name').to_sql() - """ - return """SELECT "users"."username" FROM "users" ORDER BY "age" DESC, "name" ASC""" - - def can_compile_with_group_by(self): - """ - self.builder.select('username').group_by('age').to_sql() - """ - return """SELECT "users"."username" FROM "users" GROUP BY "users"."age\"""" - - def can_compile_where_in(self): - """ - self.builder.select('username').where_in('age', [1,2,3]).to_sql() - """ - return """SELECT "users"."username" FROM "users" WHERE "users"."age" IN ('1','2','3')""" - - def can_compile_where_in_empty(self): - """ - self.builder.where_in('age', []).to_sql() - """ - return """SELECT * FROM "users" WHERE 0 = 1""" - - def can_compile_where_not_in(self): - """ - self.builder.select('username').where_not_in('age', [1,2,3]).to_sql() - """ - return """SELECT "users"."username" FROM "users" WHERE "users"."age" NOT IN ('1','2','3')""" - - def can_compile_where_null(self): - """ - self.builder.select('username').where_null('age').to_sql() - """ - return """SELECT "users"."username" FROM "users" WHERE "users"."age" IS NULL""" - - def can_compile_where_not_null(self): - """ - self.builder.select('username').where_not_null('age').to_sql() - """ - return """SELECT "users"."username" FROM "users" WHERE "users"."age" IS NOT NULL""" - - def can_compile_where_raw(self): - """ - self.builder.where_raw(""age" = '18'").to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."age" = '18'""" - - def can_compile_select_raw(self): - """ - self.builder.select_raw("COUNT(*)").to_sql() - """ - return """SELECT COUNT(*) FROM "users\"""" - - def can_compile_limit_and_offset(self): - """ - self.builder.limit(10).offset(10).to_sql() - """ - return """SELECT * FROM "users" LIMIT 10 OFFSET 10""" - - def can_compile_select_raw_with_select(self): - """ - self.builder.select('id').select_raw("COUNT(*)").to_sql() - """ - return """SELECT "users"."id", COUNT(*) FROM "users\"""" - - def can_compile_count(self): - """ - self.builder.count().to_sql() - """ - - return """SELECT COUNT(*) AS m_count_reserved FROM "users\"""" - - def can_compile_count_column(self): - """ - self.builder.count().to_sql() - """ - - return """SELECT COUNT("users"."money") AS money FROM "users\"""" - - def can_compile_where_column(self): - """ - self.builder.where_column('name', 'email').to_sql() - """ - - return ( - """SELECT * FROM "users" WHERE "users"."name" = "users"."email\"""" - ) - - def can_compile_or_where(self): - """ - self.builder.where('name', 2).or_where('name', 3).to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."name" = '2' OR "users"."name" = '3'""" - - def can_grouped_where(self): - """ - self.builder.where(lambda query: query.where('age', 2).where('name', 'Joe')).to_sql() - """ - return """SELECT * FROM "users" WHERE ("users"."age" = '2' AND "users"."name" = 'Joe')""" - - def can_compile_sub_select(self): - """ - self.builder.where_in('name', - QueryBuilder(GrammarFactory.make(self.grammar), table='users').select('age') - ).to_sql() - """ + def setUp(self): + self.builder = QueryBuilder( + SQLiteGrammar, + table="users", + connection_class=MockConnection, + model=Model(), + dry=True, + ) - return """SELECT * FROM "users" WHERE "users"."name" IN (SELECT "users"."age" FROM "users")""" + # ------------------------------------------------------------------ + # Basic SELECT + # ------------------------------------------------------------------ - def can_compile_sub_select_where(self): - """ - self.builder.where_in('age', - QueryBuilder(GrammarFactory.make(self.grammar), table='users').select('age').where('age', 2).where('name', 'Joe') - ).to_sql() - """ + def test_can_compile_select(self): + query_sql = self.builder.to_sql() + expected_sql = 'SELECT * FROM "users"' + self.assertEqual(query_sql, expected_sql) - return """SELECT * FROM "users" WHERE "users"."age" IN (SELECT "users"."age" FROM "users" WHERE "users"."age" = '2' AND "users"."name" = 'Joe')""" + def test_can_compile_with_columns(self): + query_sql = self.builder.select("username", "password").to_sql() + expected_sql = ( + 'SELECT "users"."username", "users"."password" FROM "users"' + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_sub_select_value(self): - """ - self.builder.where('name', - self.builder.new().sum('age') - ).to_sql() - """ + def test_can_compile_select_raw(self): + query_sql = self.builder.select_raw("COUNT(*)").to_sql() + expected_sql = 'SELECT COUNT(*) FROM "users"' + self.assertEqual(query_sql, expected_sql) - return """SELECT * FROM "users" WHERE "users"."name" = (SELECT SUM("users"."age") AS age FROM "users")""" + def test_can_compile_select_raw_with_select(self): + query_sql = self.builder.select("id").select_raw("COUNT(*)").to_sql() + expected_sql = 'SELECT "users"."id", COUNT(*) FROM "users"' + self.assertEqual(query_sql, expected_sql) + + def test_select_distinct(self): + query_sql = self.builder.select("group").distinct().to_sql() + expected_sql = 'SELECT DISTINCT "users"."group" FROM "users"' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_count(self): + query_sql = self.builder.count("*").to_sql() + expected_sql = 'SELECT COUNT(*) AS m_count_reserved FROM "users"' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_count_column(self): + query_sql = self.builder.count("money").to_sql() + expected_sql = 'SELECT COUNT("users"."money") AS money FROM "users"' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_sum(self): + query_sql = self.builder.sum("age").to_sql() + expected_sql = 'SELECT SUM("users"."age") AS age FROM "users"' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_max(self): + query_sql = self.builder.max("age").to_sql() + expected_sql = 'SELECT MAX("users"."age") AS age FROM "users"' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_max_and_columns(self): + query_sql = self.builder.select("username").max("age").to_sql() + expected_sql = ( + 'SELECT "users"."username", MAX("users"."age") AS age FROM "users"' + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_complex_sub_select(self): - """ - self.builder.where_in('name', - (QueryBuilder(GrammarFactory.make(self.grammar), table='users') - .select('age').where_in('email', - QueryBuilder(GrammarFactory.make(self.grammar), table='users').select('email') - )) - ).to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."name" IN (SELECT "users"."age" FROM "users" WHERE "users"."email" IN (SELECT "users"."email" FROM "users"))""" + def test_can_compile_with_max_and_columns_different_order(self): + query_sql = self.builder.max("age").select("username").to_sql() + expected_sql = ( + 'SELECT "users"."username", MAX("users"."age") AS age FROM "users"' + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_exists(self): - """ - self.builder.select('age').where_exists( - self.builder.new().select('username').where('age', 12) - ).to_sql() - """ - return """SELECT "users"."age" FROM "users" WHERE EXISTS (SELECT "users"."username" FROM "users" WHERE "users"."age" = '12')""" + # ------------------------------------------------------------------ + # ORDER BY / GROUP BY / LIMIT / OFFSET + # ------------------------------------------------------------------ + + def test_can_compile_order_by_and_first(self): + query_sql = ( + self.builder.order_by("id", "asc").first(query=True).to_sql() + ) + expected_sql = 'SELECT * FROM "users" ORDER BY "id" ASC LIMIT 1' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_order_by(self): + query_sql = ( + self.builder.select("username").order_by("age", "desc").to_sql() + ) + expected_sql = ( + 'SELECT "users"."username" FROM "users" ORDER BY "age" DESC' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_multiple_order_by(self): + query_sql = ( + self.builder.select("username") + .order_by("age", "desc") + .order_by("name") + .to_sql() + ) + expected_sql = 'SELECT "users"."username" FROM "users" ORDER BY "age" DESC, "name" ASC' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_group_by(self): + query_sql = self.builder.select("username").group_by("age").to_sql() + expected_sql = ( + 'SELECT "users"."username" FROM "users" GROUP BY "users"."age"' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_limit_and_offset(self): + query_sql = self.builder.limit(10).offset(10).to_sql() + expected_sql = 'SELECT * FROM "users" LIMIT 10 OFFSET 10' + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # WHERE clauses + # ------------------------------------------------------------------ + + def test_can_compile_with_where(self): + query_sql = ( + self.builder.select("username", "password").where("id", 1).to_sql() + ) + expected_sql = 'SELECT "users"."username", "users"."password" FROM "users" WHERE "users"."id" = \'1\'' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_several_where(self): + query_sql = ( + self.builder.select("username", "password") + .where("id", 1) + .where("username", "joe") + .to_sql() + ) + expected_sql = ( + 'SELECT "users"."username", "users"."password" FROM "users"' + ' WHERE "users"."id" = \'1\' AND "users"."username" = \'joe\'' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_with_several_where_and_limit(self): + query_sql = ( + self.builder.select("username", "password") + .where("id", 1) + .where("username", "joe") + .limit(10) + .to_sql() + ) + expected_sql = ( + 'SELECT "users"."username", "users"."password" FROM "users"' + ' WHERE "users"."id" = \'1\' AND "users"."username" = \'joe\' LIMIT 10' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_or_where(self): + query_sql = self.builder.where("name", 2).or_where("name", 3).to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."name" = \'2\' OR "users"."name" = \'3\'' + self.assertEqual(query_sql, expected_sql) - def can_compile_not_exists(self): - """ - self.builder.select('age').where_not_exists( - self.builder.new().select('username').where('age', 12) + def test_can_grouped_where(self): + query_sql = self.builder.where( + lambda q: q.where("age", 2).where("name", "Joe") ).to_sql() - """ - return """SELECT "users"."age" FROM "users" WHERE NOT EXISTS (SELECT "users"."username" FROM "users" WHERE "users"."age" = '12')""" - - def can_compile_having(self): - """ - builder.sum('age').group_by('age').having('age').to_sql() - """ - return """SELECT SUM("users"."age") AS age FROM "users" GROUP BY "users"."age" HAVING "users"."age\"""" - - def can_compile_having_order(self): - """ - builder.sum('age').group_by('age').having('age').order_by('age', 'desc').to_sql() - """ - return """SELECT SUM("users"."age") AS age FROM "users" GROUP BY "users"."age" HAVING "users"."age\" ORDER "users"."age" DESC""" - - def can_compile_having_raw(self): - """ - builder.select_raw("COUNT(*) as counts").having_raw("counts > 18").to_sql() - """ - return """SELECT COUNT(*) as counts FROM "users" HAVING counts > 18""" - - def can_compile_having_with_expression(self): - """ - builder.sum('age').group_by('age').having('age', 10).to_sql() - """ - return """SELECT SUM("users"."age") AS age FROM "users" GROUP BY "users"."age" HAVING "users"."age" = '10'""" - - def can_compile_having_with_greater_than_expression(self): - """ - builder.sum('age').group_by('age').having('age', '>', 10).to_sql() - """ - return """SELECT SUM("users"."age") AS age FROM "users" GROUP BY "users"."age" HAVING "users"."age" > '10'""" - - def can_compile_join(self): - """ - builder.join('contacts', 'users.id', '=', 'contacts.user_id').to_sql() - """ - return """SELECT * FROM "users" INNER JOIN "contacts" ON "users"."id" = "contacts"."user_id\"""" - - def can_compile_left_join(self): - """ - builder.join('contacts', 'users.id', '=', 'contacts.user_id').to_sql() - """ - return """SELECT * FROM "users" LEFT JOIN "contacts" ON "users"."id" = "contacts"."user_id\"""" - - def can_compile_multiple_join(self): - """ - builder.join('contacts', 'users.id', '=', 'contacts.user_id').to_sql() - """ - return """SELECT * FROM "users" INNER JOIN "contacts" ON "users"."id" = "contacts"."user_id" INNER JOIN "posts" ON "comments"."post_id" = "posts"."id\"""" - - def can_compile_between(self): - """ - builder.between('age', 18, 21).to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."age" BETWEEN '18' AND '21'""" - - def can_compile_not_between(self): - """ - builder.not_between('age', 18, 21).to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."age" NOT BETWEEN '18' AND '21'""" + expected_sql = 'SELECT * FROM "users" WHERE ("users"."age" = \'2\' AND "users"."name" = \'Joe\')' + self.assertEqual(query_sql, expected_sql) - def test_can_compile_where_raw(self): - to_sql = self.builder.where_raw(""" "age" = '18'""").to_sql() - self.assertEqual( - to_sql, """SELECT * FROM "users" WHERE "age" = '18'""" + def test_can_compile_where_in(self): + query_sql = ( + self.builder.select("username").where_in("age", [1, 2, 3]).to_sql() + ) + expected_sql = 'SELECT "users"."username" FROM "users" WHERE "users"."age" IN (\'1\',\'2\',\'3\')' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_in_empty(self): + query_sql = self.builder.where_in("age", []).to_sql() + expected_sql = 'SELECT * FROM "users" WHERE 0 = 1' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_not_in(self): + query_sql = ( + self.builder.select("username") + .where_not_in("age", [1, 2, 3]) + .to_sql() + ) + expected_sql = 'SELECT "users"."username" FROM "users" WHERE "users"."age" NOT IN (\'1\',\'2\',\'3\')' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_null(self): + query_sql = self.builder.select("username").where_null("age").to_sql() + expected_sql = 'SELECT "users"."username" FROM "users" WHERE "users"."age" IS NULL' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_not_null(self): + query_sql = ( + self.builder.select("username").where_not_null("age").to_sql() + ) + expected_sql = 'SELECT "users"."username" FROM "users" WHERE "users"."age" IS NOT NULL' + self.assertEqual(query_sql, expected_sql) + + def test_or_where_null(self): + query_sql = ( + self.builder.where_null("column1") + .or_where_null("column2") + .to_sql() + ) + expected_sql = 'SELECT * FROM "users" WHERE "users"."column1" IS NULL OR "users"."column2" IS NULL' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_column(self): + query_sql = self.builder.where_column("name", "email").to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."name" = "users"."email"' ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_where_raw(self): + query_sql = self.builder.where_raw(""" "age" = '18'""").to_sql() + expected_sql = """SELECT * FROM "users" WHERE "age" = '18'""" + self.assertEqual(query_sql, expected_sql) def test_can_compile_where_raw_and_where_with_multiple_bindings(self): query = self.builder.where_raw( """ "age" = ? AND "is_admin" = ? """, [18, True] ).where("email", "test@example.com") - self.assertEqual( - query.to_qmark(), - """SELECT * FROM "users" WHERE "age" = ? AND "is_admin" = ? AND "users"."email" = ?""", - ) + query_sql = query.to_qmark() + expected_sql = 'SELECT * FROM "users" WHERE "age" = ? AND "is_admin" = ? AND "users"."email" = ?' + self.assertEqual(query_sql, expected_sql) self.assertEqual(query._bindings, [18, True, "test@example.com"]) - def test_can_compile_select_raw(self): - to_sql = self.builder.select_raw("COUNT(*)").to_sql() - self.assertEqual(to_sql, """SELECT COUNT(*) FROM "users\"""") + def test_can_user_where_raw_and_where(self): + query_sql = ( + self.builder.where_raw("age = '18'") + .where("name", "=", "James") + .to_sql() + ) + expected_sql = 'SELECT * FROM "users" WHERE age = \'18\' AND "users"."name" = \'James\'' + self.assertEqual(query_sql, expected_sql) - def test_can_compile_select_raw_with_select(self): - to_sql = self.builder.select("id").select_raw("COUNT(*)").to_sql() - self.assertEqual( - to_sql, """SELECT "users"."id", COUNT(*) FROM "users\"""" - ) - - def can_compile_first_or_fail(self): - """ - builder = self.get_builder() - 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", "like", "%name%").to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."age" LIKE '%name%'""" - - def where_regexp(self): - """ - builder = self.get_builder() - builder.where("age", "regexp", "Joe").to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."age" REGEXP 'Joe'""" - - def where_not_regexp(self): - """ - builder = self.get_builder() - builder.where("age", "regexp", "Joe").to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."age" NOT REGEXP 'Joe'""" - - def can_compile_join_clause(self): - """ - builder = self.get_builder() + def test_where_like(self): + query_sql = self.builder.where("age", "like", "%name%").to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."age" LIKE \'%name%\'' + ) + self.assertEqual(query_sql, expected_sql) + + def test_where_not_like(self): + query_sql = self.builder.where("age", "not like", "%name%").to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."age" NOT LIKE \'%name%\'' + ) + self.assertEqual(query_sql, expected_sql) + + def test_where_regexp(self): + query_sql = self.builder.where("age", "regexp", "Joe").to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."age" REGEXP \'Joe\'' + ) + self.assertEqual(query_sql, expected_sql) + + def test_where_not_regexp(self): + query_sql = self.builder.where("age", "not regexp", "Joe").to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."age" NOT REGEXP \'Joe\'' + ) + self.assertEqual(query_sql, expected_sql) + + def test_where_date(self): + query_sql = self.builder.where_date( + "created_at", "2022-06-01" + ).to_sql() + expected_sql = 'SELECT * FROM "users" WHERE DATE("users"."created_at") = \'2022-06-01\'' + self.assertEqual(query_sql, expected_sql) + + def test_where_exists_with_lambda(self): + query_sql = self.builder.where_exists( + lambda q: q.where("age", 1) + ).to_sql() + expected_sql = 'SELECT * FROM "users" WHERE EXISTS (SELECT * FROM "users" WHERE "users"."age" = \'1\')' + self.assertEqual(query_sql, expected_sql) + + def test_where_not_exists_with_lambda(self): + query_sql = self.builder.where_not_exists( + lambda q: q.where("age", 1) + ).to_sql() + expected_sql = 'SELECT * FROM "users" WHERE NOT EXISTS (SELECT * FROM "users" WHERE "users"."age" = \'1\')' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_between(self): + query_sql = self.builder.between("age", 18, 21).to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."age" BETWEEN \'18\' AND \'21\'' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_not_between(self): + query_sql = self.builder.not_between("age", 18, 21).to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."age" NOT BETWEEN \'18\' AND \'21\'' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_first_or_fail(self): + query_sql = ( + self.builder.where("is_admin", "=", True) + .first_or_fail(query=True) + .to_sql() + ) + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."is_admin" = \'1\' LIMIT 1' + ) + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # Locking + # ------------------------------------------------------------------ + + def test_shared_lock(self): + # SQLite has no native locking syntax; the query is returned unchanged + query_sql = ( + self.builder.where("votes", ">=", 100).shared_lock().to_sql() + ) + expected_sql = 'SELECT * FROM "users" WHERE "users"."votes" >= \'100\'' + self.assertEqual(query_sql, expected_sql) + + def test_update_lock(self): + query_sql = ( + self.builder.where("votes", ">=", 100).lock_for_update().to_sql() + ) + expected_sql = 'SELECT * FROM "users" WHERE "users"."votes" >= \'100\'' + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # Sub-selects + # ------------------------------------------------------------------ + + def test_can_compile_sub_select(self): + query_sql = self.builder.where_in( + "name", self.builder.new().select("age") + ).to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."name" IN (SELECT "users"."age" FROM "users")' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_sub_select_where(self): + query_sql = self.builder.where_in( + "age", + self.builder.new() + .select("age") + .where("age", 2) + .where("name", "Joe"), + ).to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."age" IN' + ' (SELECT "users"."age" FROM "users" WHERE "users"."age" = \'2\' AND "users"."name" = \'Joe\')' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_sub_select_from_lambda(self): + """Lambda variant of where_in sub-select should produce the same SQL.""" + expected = ( + 'SELECT * FROM "users" WHERE "users"."age" IN' + ' (SELECT "users"."age" FROM "users" WHERE "users"."age" = \'2\' AND "users"."name" = \'Joe\')' + ) + query_sql = ( + self.builder.new() + .where_in( + "age", + lambda q: q.select("age").where("age", 2).where("name", "Joe"), + ) + .to_sql() + ) + expected_sql = expected + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_sub_select_value(self): + query_sql = self.builder.where( + "name", self.builder.new().sum("age") + ).to_sql() + expected_sql = 'SELECT * FROM "users" WHERE "users"."name" = (SELECT SUM("users"."age") AS age FROM "users")' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_complex_sub_select(self): + query_sql = self.builder.where_in( + "name", + self.builder.new() + .select("age") + .where_in("email", self.builder.new().select("email")), + ).to_sql() + expected_sql = ( + 'SELECT * FROM "users" WHERE "users"."name" IN' + ' (SELECT "users"."age" FROM "users" WHERE "users"."email" IN' + ' (SELECT "users"."email" FROM "users"))' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_exists(self): + query_sql = ( + self.builder.select("age") + .where_exists( + self.builder.new().select("username").where("age", 12) + ) + .to_sql() + ) + expected_sql = ( + 'SELECT "users"."age" FROM "users"' + ' WHERE EXISTS (SELECT "users"."username" FROM "users" WHERE "users"."age" = \'12\')' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_not_exists(self): + query_sql = ( + self.builder.select("age") + .where_not_exists( + self.builder.new().select("username").where("age", 12) + ) + .to_sql() + ) + expected_sql = ( + 'SELECT "users"."age" FROM "users"' + ' WHERE NOT EXISTS (SELECT "users"."username" FROM "users" WHERE "users"."age" = \'12\')' + ) + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # HAVING + # ------------------------------------------------------------------ + + def test_can_compile_having(self): + query_sql = ( + self.builder.sum("age").group_by("age").having("age").to_sql() + ) + expected_sql = 'SELECT SUM("users"."age") AS age FROM "users" GROUP BY "users"."age" HAVING "users"."age"' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_having_raw(self): + query_sql = ( + self.builder.select_raw("COUNT(*) as counts") + .having_raw("counts > 18") + .to_sql() + ) + expected_sql = ( + 'SELECT COUNT(*) as counts FROM "users" HAVING counts > 18' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_having_with_expression(self): + query_sql = ( + self.builder.sum("age").group_by("age").having("age", 10).to_sql() + ) + expected_sql = 'SELECT SUM("users"."age") AS age FROM "users" GROUP BY "users"."age" HAVING "users"."age" = \'10\'' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_having_with_greater_than_expression(self): + query_sql = ( + self.builder.sum("age") + .group_by("age") + .having("age", ">", 10) + .to_sql() + ) + expected_sql = 'SELECT SUM("users"."age") AS age FROM "users" GROUP BY "users"."age" HAVING "users"."age" > \'10\'' + self.assertEqual(query_sql, expected_sql) + + # ------------------------------------------------------------------ + # JOINs + # ------------------------------------------------------------------ + + def test_can_compile_join(self): + query_sql = self.builder.join( + "contacts", "users.id", "=", "contacts.user_id" + ).to_sql() + expected_sql = 'SELECT * FROM "users" INNER JOIN "contacts" ON "users"."id" = "contacts"."user_id"' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_left_join(self): + query_sql = self.builder.left_join( + "contacts", "users.id", "=", "contacts.user_id" + ).to_sql() + expected_sql = 'SELECT * FROM "users" LEFT JOIN "contacts" ON "users"."id" = "contacts"."user_id"' + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_multiple_join(self): + query_sql = ( + self.builder.join("contacts", "users.id", "=", "contacts.user_id") + .join("posts", "comments.post_id", "=", "posts.id") + .to_sql() + ) + expected_sql = ( + 'SELECT * FROM "users"' + ' INNER JOIN "contacts" ON "users"."id" = "contacts"."user_id"' + ' INNER JOIN "posts" ON "comments"."post_id" = "posts"."id"' + ) + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_join_clause(self): clause = ( JoinClause("report_groups as rg") .on("bgt.fund", "=", "rg.fund") - .on_value("bgt.active", "=", "1") - .or_on_value("bgt.acct", "=", "1234") + .on("bgt.dept", "=", "rg.dept") + .on("bgt.acct", "=", "rg.acct") + .on("bgt.sub", "=", "rg.sub") + ) + query_sql = self.builder.join(clause).to_sql() + expected_sql = ( + 'SELECT * FROM "users" INNER JOIN "report_groups" AS "rg"' + ' ON "bgt"."fund" = "rg"."fund" AND "bgt"."dept" = "rg"."dept"' + ' AND "bgt"."acct" = "rg"."acct" AND "bgt"."sub" = "rg"."sub"' ) - builder.join(clause).to_sql() - """ - return """SELECT * FROM "users" INNER JOIN "report_groups" AS "rg" ON "bgt"."fund" = "rg"."fund" AND "bgt"."dept" = "rg"."dept" AND "bgt"."acct" = "rg"."acct" AND "bgt"."sub" = "rg"."sub\"""" + self.assertEqual(query_sql, expected_sql) - def can_compile_join_clause_with_value(self): - """ - builder = self.get_builder() + def test_can_compile_join_clause_with_value(self): clause = ( JoinClause("report_groups as rg") .on_value("bgt.active", "=", "1") .or_on_value("bgt.acct", "=", "1234") ) - builder.join(clause).to_sql() - """ - return """SELECT * FROM "users" INNER JOIN "report_groups" AS "rg" ON "bgt"."active" = '1' OR "bgt"."acct" = '1234'""" + query_sql = self.builder.join(clause).to_sql() + expected_sql = ( + 'SELECT * FROM "users" INNER JOIN "report_groups" AS "rg"' + ' ON "bgt"."active" = \'1\' OR "bgt"."acct" = \'1234\'' + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_join_clause_with_null(self): - """ - builder = self.get_builder() + def test_can_compile_join_clause_with_null(self): clause = ( JoinClause("report_groups as rg") .on_null("bgt.acct") .or_on_null("bgt.dept") .on_value("rg.abc", 10) ) - builder.join(clause).to_sql() - """ - return """SELECT * FROM "users" INNER JOIN "report_groups" AS "rg" ON "acct" IS NULL OR "dept" IS NULL AND "rg"."abc" = '10'""" + query_sql = self.builder.join(clause).to_sql() + expected_sql = ( + 'SELECT * FROM "users" INNER JOIN "report_groups" AS "rg"' + ' ON "acct" IS NULL OR "dept" IS NULL AND "rg"."abc" = \'10\'' + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_join_clause_with_not_null(self): - """ - builder = self.get_builder() + def test_can_compile_join_clause_with_not_null(self): clause = ( JoinClause("report_groups as rg") .on_not_null("bgt.acct") .or_on_not_null("bgt.dept") .on_value("rg.abc", 10) ) - builder.join(clause).to_sql() - """ - return """SELECT * FROM "users" INNER JOIN "report_groups" AS "rg" ON "acct" IS NOT NULL OR "dept" IS NOT NULL AND "rg"."abc" = '10'""" + query_sql = self.builder.join(clause).to_sql() + expected_sql = ( + 'SELECT * FROM "users" INNER JOIN "report_groups" AS "rg"' + ' ON "acct" IS NOT NULL OR "dept" IS NOT NULL AND "rg"."abc" = \'10\'' + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_join_clause_with_lambda(self): - """ - builder = self.get_builder() - builder.join( + def test_can_compile_join_clause_with_lambda(self): + query_sql = self.builder.join( "report_groups as rg", - lambda clause: ( - clause.on("bgt.fund", "=", "rg.fund") - .on_null("bgt") + lambda clause: clause.on("bgt.fund", "=", "rg.fund").on_null( + "bgt" ), ).to_sql() - """ - return """SELECT * FROM "users" INNER JOIN "report_groups" AS "rg" ON "bgt"."fund" = "rg"."fund" AND "bgt" IS NULL""" + expected_sql = ( + 'SELECT * FROM "users" INNER JOIN "report_groups" AS "rg"' + ' ON "bgt"."fund" = "rg"."fund" AND "bgt" IS NULL' + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_left_join_clause_with_lambda(self): - """ - builder = self.get_builder() - builder.left_join( + def test_can_compile_left_join_clause_with_lambda(self): + query_sql = self.builder.left_join( "report_groups as rg", - lambda clause: ( - clause.on("bgt.fund", "=", "rg.fund") - .or_on_null("bgt") + lambda clause: clause.on("bgt.fund", "=", "rg.fund").or_on_null( + "bgt" ), ).to_sql() - """ - return """SELECT * FROM "users" LEFT JOIN "report_groups" AS "rg" ON "bgt"."fund" = "rg"."fund" OR "bgt" IS NULL""" + expected_sql = ( + 'SELECT * FROM "users" LEFT JOIN "report_groups" AS "rg"' + ' ON "bgt"."fund" = "rg"."fund" OR "bgt" IS NULL' + ) + self.assertEqual(query_sql, expected_sql) - def can_compile_right_join_clause_with_lambda(self): - """ - builder = self.get_builder() - builder.right_join( + def test_can_compile_right_join_clause_with_lambda(self): + query_sql = self.builder.right_join( "report_groups as rg", - lambda clause: ( - clause.on("bgt.fund", "=", "rg.fund") - .or_on_null("bgt") + lambda clause: clause.on("bgt.fund", "=", "rg.fund").or_on_null( + "bgt" ), ).to_sql() - """ - return """SELECT * FROM "users" LEFT JOIN "report_groups" AS "rg" ON "bgt"."fund" = "rg"."fund" OR "bgt" IS NULL""" - - def update_lock(self): - """ - builder = self.get_builder() - builder.where("age", "not like", "%name%").to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."votes" >= '100'""" - - def shared_lock(self): - """ - builder = self.get_builder() - builder.where("age", "not like", "%name%").to_sql() - """ - return """SELECT * FROM "users" WHERE "users"."votes" >= '100'""" - - def can_user_where_raw_and_where(self): - """ - builder.where_raw("age = '18'").where("name", "=", "James").to_sql() - """ - return """SELECT * FROM "users" WHERE age = '18' AND "users"."name" = 'James'""" - - def where_exists_with_lambda(self): - return """SELECT * FROM "users" WHERE EXISTS (SELECT * FROM "users" WHERE "users"."age" = '1')""" - - def where_not_exists_with_lambda(self): - return """SELECT * FROM "users" WHERE NOT EXISTS (SELECT * FROM "users" WHERE "users"."age" = '1')""" - - def where_date(self): - return """SELECT * FROM "users" WHERE DATE("users"."created_at") = '2022-06-01'""" - - def or_where_null(self): - return """SELECT * FROM "users" WHERE "users"."column1" IS NULL OR "users"."column2" IS NULL""" - - def select_distinct(self): - return """SELECT DISTINCT "users"."group" FROM "users\"""" + expected_sql = ( + 'SELECT * FROM "users" LEFT JOIN "report_groups" AS "rg"' + ' ON "bgt"."fund" = "rg"."fund" OR "bgt" IS NULL' + ) + self.assertEqual(query_sql, expected_sql) diff --git a/tests/sqlite/grammar/test_sqlite_update_grammar.py b/tests/sqlite/grammar/test_sqlite_update_grammar.py index 4ee265432..f53bd30d8 100644 --- a/tests/sqlite/grammar/test_sqlite_update_grammar.py +++ b/tests/sqlite/grammar/test_sqlite_update_grammar.py @@ -1,113 +1,57 @@ -import inspect import unittest +from src.masoniteorm.expressions import Raw from src.masoniteorm.query import QueryBuilder from src.masoniteorm.query.grammars import SQLiteGrammar -from src.masoniteorm.expressions import Raw -class BaseTestCaseUpdateGrammar: +class TestSQLiteUpdateGrammar(unittest.TestCase): def setUp(self): self.builder = QueryBuilder(SQLiteGrammar, table="users") def test_can_compile_update(self): - to_sql = ( - self.builder.where("name", "bob").update({"name": "Joe"}, dry=True).to_sql() + query_sql = ( + self.builder.where("name", "bob") + .update({"name": "Joe"}, dry=True) + .to_sql() + ) + expected_sql = ( + """UPDATE "users" SET "name" = 'Joe' WHERE "name" = 'bob'""" ) + self.assertEqual(query_sql, expected_sql) - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + def test_raw_expression(self): + query_sql = self.builder.update( + {"name": Raw('"username"')}, dry=True + ).to_sql() + expected_sql = """UPDATE "users" SET "name" = "username\"""" + self.assertEqual(query_sql, expected_sql) def test_can_compile_multiple_update(self): - to_sql = self.builder.update( + query_sql = self.builder.update( {"name": "Joe", "email": "user@email.com"}, dry=True ).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) + expected_sql = ( + """UPDATE "users" SET "name" = 'Joe', "email" = 'user@email.com'""" + ) + self.assertEqual(query_sql, expected_sql) def test_can_compile_update_with_multiple_where(self): - to_sql = ( + query_sql = ( self.builder.where("name", "bob") .where("age", 20) .update({"name": "Joe"}, dry=True) .to_sql() ) - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - self.assertEqual(to_sql, sql) - - # def test_can_compile_increment(self): - # to_sql = self.builder.increment("age") - # print(to_sql) - - # self.assertTrue(to_sql.isnumeric()) - - # def test_can_compile_decrement(self): - # to_sql = self.builder.decrement("age", 20).to_sql() - - # sql = getattr( - # self, inspect.currentframe().f_code.co_name.replace("test_", "") - # )() - # self.assertEqual(to_sql, sql) - - def test_raw_expression(self): - to_sql = self.builder.update({"name": Raw('"username"')}, dry=True).to_sql() - - sql = getattr( - self, inspect.currentframe().f_code.co_name.replace("test_", "") - )() - - self.assertEqual(to_sql, sql) - - -class TestSqliteUpdateGrammar(BaseTestCaseUpdateGrammar, unittest.TestCase): - grammar = "sqlite" - - def can_compile_update(self): - """ - builder.where('name', 'bob').update({ - 'name': 'Joe' - }).to_sql() - """ - return """UPDATE "users" SET "name" = 'Joe' WHERE "name" = 'bob'""" - - def raw_expression(self): - """ - builder.where('name', 'bob').update({ - 'name': 'Joe' - }).to_sql() - """ - return 'UPDATE "users" SET "name" = "username"' - - def can_compile_multiple_update(self): - """ - self.builder.update({"name": "Joe", "email": "user@email.com"}, dry=True).to_sql() - """ - return """UPDATE "users" SET "name" = 'Joe', "email" = 'user@email.com'""" - - def can_compile_update_with_multiple_where(self): - """ - builder.where('name', 'bob').where('age', 20).update({ - 'name': 'Joe' - }).to_sql() - """ - return """UPDATE "users" SET "name" = 'Joe' WHERE "name" = 'bob' AND "age" = '20'""" - - def can_compile_increment(self): - """ - builder.increment('age').to_sql() - """ - return """UPDATE "users" SET "age" = "age" + '1'""" - - def can_compile_decrement(self): - """ - builder.decrement('age', 20).to_sql() - """ - return """UPDATE "users" SET "age" = "age" - '20'""" + expected_sql = """UPDATE "users" SET "name" = 'Joe' WHERE "name" = 'bob' AND "age" = '20'""" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_increment(self): + query_sql = self.builder.increment("age", dry=True).to_sql() + expected_sql = """UPDATE "users" SET "age" = "age" + '1'""" + self.assertEqual(query_sql, expected_sql) + + def test_can_compile_decrement(self): + query_sql = self.builder.decrement("age", 20, dry=True).to_sql() + expected_sql = """UPDATE "users" SET "age" = "age" - '20'""" + self.assertEqual(query_sql, expected_sql) diff --git a/tests/sqlite/models/test_sqlite_model.py b/tests/sqlite/models/test_sqlite_model.py index 0fd8703ff..082161459 100644 --- a/tests/sqlite/models/test_sqlite_model.py +++ b/tests/sqlite/models/test_sqlite_model.py @@ -54,31 +54,27 @@ class SqliteTestQueryBuilderModel(unittest.TestCase): def test_update_specific_record(self): user = User.first() - sql = user.update({"name": "joe"}).to_sql() - - self.assertEqual( - sql, - f"""UPDATE "users" SET "name" = 'joe' WHERE "id" = '{user.id}'""", + query_sql = user.update({"name": "joe"}).to_sql() + expected_sql = ( + f"""UPDATE "users" SET "name" = 'joe' WHERE "id" = '{user.id}'""" ) + self.assertEqual(query_sql, expected_sql) def test_update_all_records(self): - sql = User.update({"name": "joe"}).to_sql() - - self.assertEqual(sql, """UPDATE "users" SET "name" = 'joe'""") + query_sql = User.update({"name": "joe"}).to_sql() + expected_sql = """UPDATE "users" SET "name" = 'joe'""" + self.assertEqual(query_sql, expected_sql) def test_can_find_list(self): - sql = User.find(1, query=True).to_sql() + query_sql = User.find(1, query=True).to_sql() + expected_sql = """SELECT * FROM "users" WHERE "users"."id" = '1'""" + self.assertEqual(query_sql, expected_sql) - self.assertEqual( - sql, """SELECT * FROM "users" WHERE "users"."id" = '1'""" - ) - - sql = User.find([1, 2, 3], query=True).to_sql() - - self.assertEqual( - sql, - """SELECT * FROM "users" WHERE "users"."id" IN ('1','2','3')""", + query_sql = User.find([1, 2, 3], query=True).to_sql() + expected_sql = ( + """SELECT * FROM "users" WHERE "users"."id" IN ('1','2','3')""" ) + self.assertEqual(query_sql, expected_sql) def test_find_or_if_record_not_found(self): # Insane record number so record cannot be found @@ -99,56 +95,50 @@ def test_can_set_and_retreive_attribute(self): self.assertEqual(user.customer_id, "CUST1") def test_model_can_use_selects(self): - self.assertEqual( - Select.to_sql(), - 'SELECT "selects"."username", "selects"."rememember_token" AS token FROM "selects"', - ) + query_sql = Select.to_sql() + expected_sql = 'SELECT "selects"."username", "selects"."rememember_token" AS token FROM "selects"' + self.assertEqual(query_sql, expected_sql) def test_model_can_use_selects_from_methods(self): - self.assertEqual( - SelectPass.all(["username"], query=True).to_sql(), - 'SELECT "select_passes"."username" FROM "select_passes"', - ) + query_sql = SelectPass.all(["username"], query=True).to_sql() + expected_sql = 'SELECT "select_passes"."username" FROM "select_passes"' + self.assertEqual(query_sql, expected_sql) def test_update_only_changed_attributes(self): user = User.first() - sql = user.update({"name": user.name, "username": "new"}).to_sql() + query_sql = user.update( + {"name": user.name, "username": "new"} + ).to_sql() # unchanged name attribute is not updated - self.assertEqual( - sql, - f"""UPDATE "users" SET "username" = 'new' WHERE "id" = '{user.id}'""", - ) + expected_sql = f"""UPDATE "users" SET "username" = 'new' WHERE "id" = '{user.id}'""" + self.assertEqual(query_sql, expected_sql) def test_can_force_update_on_method(self): user = User.first() - sql = user.update( + query_sql = user.update( {"name": "Frank", "username": "new"}, force=True ).to_sql() - self.assertEqual( - sql, - f"""UPDATE "users" SET "name" = 'Frank', "username" = 'new' WHERE "id" = '{user.id}'""", - ) + expected_sql = f"""UPDATE "users" SET "name" = 'Frank', "username" = 'new' WHERE "id" = '{user.id}'""" + self.assertEqual(query_sql, expected_sql) def test_can_force_update_on_model(self): user = UserForced.first() - sql = user.update({"name": "Fred", "username": "new"}).to_sql() - self.assertEqual( - sql, - f"""UPDATE "users" SET "name" = 'Fred', "username" = 'new' WHERE "id" = '{user.id}'""", - ) + query_sql = user.update({"name": "Fred", "username": "new"}).to_sql() + expected_sql = f"""UPDATE "users" SET "name" = 'Fred', "username" = 'new' WHERE "id" = '{user.id}'""" + self.assertEqual(query_sql, expected_sql) def test_force_update(self): user = User.first() - sql = user.force_update({"name": "Bill", "username": "new"}).to_sql() - self.assertEqual( - sql, - f"""UPDATE "users" SET "name" = 'Bill', "username" = 'new' WHERE "id" = '{user.id}'""", - ) + query_sql = user.force_update( + {"name": "Bill", "username": "new"} + ).to_sql() + expected_sql = f"""UPDATE "users" SET "name" = 'Bill', "username" = 'new' WHERE "id" = '{user.id}'""" + self.assertEqual(query_sql, expected_sql) def test_update_is_not_done_when_no_changes(self): user = User.first() - sql = user.update({"name": user.name}).to_sql() - self.assertNotIn("UPDATE", sql) + query_sql = user.update({"name": user.name}).to_sql() + self.assertNotIn("UPDATE", query_sql) def test_should_collect_correct_amount_data_using_between(self): class ModelUser(Model): diff --git a/tests/sqlite/relationships/test_sqlite_relationships.py b/tests/sqlite/relationships/test_sqlite_relationships.py index a3be52469..14fd26292 100644 --- a/tests/sqlite/relationships/test_sqlite_relationships.py +++ b/tests/sqlite/relationships/test_sqlite_relationships.py @@ -1,6 +1,12 @@ import unittest + from src.masoniteorm.models import Model -from src.masoniteorm.relationships import belongs_to, has_many, has_one, belongs_to_many +from src.masoniteorm.relationships import ( + belongs_to, + belongs_to_many, + has_many, + has_one, +) from tests.integrations.config.database import DB @@ -49,11 +55,15 @@ def get_is_admin(self): class Store(Model): __connection__ = "dev" - @belongs_to_many("store_id", "product_id", "id", "id", with_timestamps=True) + @belongs_to_many( + "store_id", "product_id", "id", "id", with_timestamps=True + ) def products(self): return Product - @belongs_to_many("store_id", "product_id", "id", "id", table="product_table") + @belongs_to_many( + "store_id", "product_id", "id", "id", table="product_table" + ) def products_table(self): return Product @@ -68,7 +78,6 @@ class Product(Model): class UserHasOne(Model): __table__ = "users" - __connection__ = "dev" @has_one("user_id", "user_id") @@ -80,10 +89,11 @@ class TestRelationships(unittest.TestCase): maxDiff = None def test_relationship_can_be_callable(self): - self.assertEqual( - User.profile().where("name", "Joe").to_sql(), - """SELECT * FROM "profiles" WHERE "profiles"."name" = 'Joe'""", + query_sql = User.profile().where("name", "Joe").to_sql() + expected_sql = ( + """SELECT * FROM "profiles" WHERE "profiles"."name" = 'Joe'""" ) + self.assertEqual(query_sql, expected_sql) def test_can_access_relationship(self): for user in User.where("id", 1).get(): @@ -101,34 +111,42 @@ def test_can_access_relationship_multiple_times(self): def test_can_access_relationship_date(self): user = User.with_("articles").where("id", 1).first() for article in user.articles: - print(article.logo.published_date.is_past()) + result = article.logo.published_date.is_past() + self.assertIsInstance(result, bool) def test_loading(self): users = User.with_("articles").get() + self.assertGreater(len(users), 0) for user in users: - user + self.assertIsInstance(user, User) def test_relationship_has_one_sql(self): - self.assertEqual(UserHasOne.profile().to_sql(), 'SELECT * FROM "profiles"') + query_sql = UserHasOne.profile().to_sql() + expected_sql = 'SELECT * FROM "profiles"' + self.assertEqual(query_sql, expected_sql) def test_loading_with_nested_with(self): users = User.with_("articles", "articles.logo").get() + self.assertGreater(len(users), 0) for user in users: + self.assertIsInstance(user, User) for article in user.articles: - if article.logo: - print("aa", article.logo.url) + # logo may be None if not every article has one; accessing it must not raise + _ = article.logo def test_casting(self): users = User.with_("articles").where("is_admin", True).get() for user in users: - user + self.assertIsInstance(user.is_admin, bool) + self.assertTrue(user.is_admin) def test_setting(self): users = User.with_("articles").where("is_admin", True).get() for user in users: user.name = "Joe" user.is_admin = 1 - user.save() + result = user.save() + self.assertIsNotNone(result) def test_related(self): user = User.first() @@ -141,10 +159,11 @@ def test_related(self): def test_associate_records(self): DB.begin_transaction("dev") user = User.first() - articles = [Articles.hydrate({"id": 1, "title": "associate records"})] - user.save_many("articles", articles) + # Verify the association was written: the article's user_id should now match + updated = Articles.on("dev").find(1) + self.assertEqual(str(updated.user_id), str(user.id)) DB.rollback("dev") def test_belongs_to_many(self): @@ -153,10 +172,12 @@ def test_belongs_to_many(self): self.assertEqual(store.products.serialize()[0]["id"], 4) self.assertEqual(store.products.serialize()[0]["name"], "Handgun") self.assertEqual( - store.products.serialize()[0]["updated_at"], "2020-01-01T00:00:00+00:00" + store.products.serialize()[0]["updated_at"], + "2020-01-01T00:00:00+00:00", ) self.assertEqual( - store.products.serialize()[0]["created_at"], "2020-01-01T00:00:00+00:00" + store.products.serialize()[0]["created_at"], + "2020-01-01T00:00:00+00:00", ) def test_belongs_to_eager_many(self): diff --git a/tests/sqlite/schema/test_sqlite_schema_builder.py b/tests/sqlite/schema/test_sqlite_schema_builder.py index 461abd55e..e8ed9eeb2 100644 --- a/tests/sqlite/schema/test_sqlite_schema_builder.py +++ b/tests/sqlite/schema/test_sqlite_schema_builder.py @@ -135,12 +135,13 @@ def test_can_use_morphs_for_polymorphism_relationships(self): blueprint.morphs("record") self.assertEqual(len(blueprint.table.added_columns), 2) - sql = [ + query_sql = blueprint.to_sql() + expected_sql = [ 'CREATE TABLE "likes" ("record_id" INTEGER UNSIGNED NOT NULL, "record_type" VARCHAR(255) NOT NULL)', 'CREATE INDEX likes_record_id_index ON "likes"(record_id)', 'CREATE INDEX likes_record_type_index ON "likes"(record_type)', ] - self.assertEqual(blueprint.to_sql(), sql) + self.assertEqual(query_sql, expected_sql) def test_can_advanced_table_creation(self): with self.schema.create("users") as blueprint: @@ -281,37 +282,37 @@ def test_can_advanced_table_creation2(self): ) def test_has_table(self): - schema_sql = self.schema.has_table("users") + query_sql = self.schema.has_table("users") - sql = "SELECT name FROM sqlite_master WHERE type='table' AND name='users'" + expected_sql = "SELECT name FROM sqlite_master WHERE type='table' AND name='users'" - self.assertEqual(schema_sql, sql) + self.assertEqual(query_sql, expected_sql) def test_can_truncate(self): - sql = self.schema.truncate("users") + query_sql = self.schema.truncate("users") - self.assertEqual(sql, 'DELETE FROM "users"') + self.assertEqual(query_sql, 'DELETE FROM "users"') def test_can_rename_table(self): - sql = self.schema.rename("users", "clients") + query_sql = self.schema.rename("users", "clients") - self.assertEqual(sql, 'ALTER TABLE "users" RENAME TO "clients"') + self.assertEqual(query_sql, 'ALTER TABLE "users" RENAME TO "clients"') def test_can_drop_table_if_exists(self): - sql = self.schema.drop_table_if_exists("users", "clients") + query_sql = self.schema.drop_table_if_exists("users", "clients") - self.assertEqual(sql, 'DROP TABLE IF EXISTS "users"') + self.assertEqual(query_sql, 'DROP TABLE IF EXISTS "users"') def test_can_drop_table(self): - sql = self.schema.drop_table("users", "clients") + query_sql = self.schema.drop_table("users", "clients") - self.assertEqual(sql, 'DROP TABLE "users"') + self.assertEqual(query_sql, 'DROP TABLE "users"') def test_has_column(self): - sql = self.schema.has_column("users", "name") + query_sql = self.schema.has_column("users", "name") self.assertEqual( - sql, + query_sql, "SELECT column_name FROM information_schema.columns WHERE table_name='users' and column_name='name'", ) @@ -336,20 +337,20 @@ def test_can_have_unsigned_columns(self): ) def test_can_enable_foreign_keys(self): - sql = self.schema.enable_foreign_key_constraints() + query_sql = self.schema.enable_foreign_key_constraints() - self.assertEqual(sql, "PRAGMA foreign_keys = ON") + self.assertEqual(query_sql, "PRAGMA foreign_keys = ON") def test_can_disable_foreign_keys(self): - sql = self.schema.disable_foreign_key_constraints() + query_sql = self.schema.disable_foreign_key_constraints() - self.assertEqual(sql, "PRAGMA foreign_keys = OFF") + self.assertEqual(query_sql, "PRAGMA foreign_keys = OFF") def test_can_truncate_without_foreign_keys(self): - sql = self.schema.truncate("users", foreign_keys=True) + query_sql = self.schema.truncate("users", foreign_keys=True) self.assertEqual( - sql, + query_sql, [ "PRAGMA foreign_keys = OFF", 'DELETE FROM "users"', diff --git a/tests/sqlite/schema/test_sqlite_schema_builder_alter.py b/tests/sqlite/schema/test_sqlite_schema_builder_alter.py index 677b14451..f502d685a 100644 --- a/tests/sqlite/schema/test_sqlite_schema_builder_alter.py +++ b/tests/sqlite/schema/test_sqlite_schema_builder_alter.py @@ -25,13 +25,14 @@ def test_can_add_columns(self): self.assertEqual(len(blueprint.table.added_columns), 3) - sql = [ + expected_sql = [ 'ALTER TABLE "users" ADD COLUMN "name" VARCHAR NOT NULL', """ALTER TABLE "users" ADD COLUMN "external_type" VARCHAR NOT NULL DEFAULT 'external'""", 'ALTER TABLE "users" ADD COLUMN "age" INTEGER NOT NULL', ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_can_add_constraints(self): with self.schema.table("users") as blueprint: @@ -39,9 +40,10 @@ def test_can_add_constraints(self): self.assertEqual(len(blueprint.table.added_columns), 0) - sql = ['CREATE UNIQUE INDEX table_unique ON "users"(name)'] + expected_sql = ['CREATE UNIQUE INDEX table_unique ON "users"(name)'] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_rename(self): with self.schema.table("users") as blueprint: @@ -51,7 +53,7 @@ def test_alter_rename(self): table.add_column("post", "integer") blueprint.table.from_table = table - sql = [ + expected_sql = [ "CREATE TEMPORARY TABLE __temp__users AS SELECT post FROM users", 'DROP TABLE "users"', 'CREATE TABLE "users" ("comment" INTEGER NOT NULL)', @@ -59,7 +61,8 @@ def test_alter_rename(self): "DROP TABLE __temp__users", ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop(self): with self.schema.table("users") as blueprint: @@ -71,7 +74,7 @@ def test_alter_drop(self): table.add_column("email", "string") blueprint.table.from_table = table - sql = [ + expected_sql = [ "CREATE TEMPORARY TABLE __temp__users AS SELECT name, email FROM users", 'DROP TABLE "users"', 'CREATE TABLE "users" ("name" VARCHAR NOT NULL, "email" VARCHAR NOT NULL)', @@ -79,7 +82,8 @@ def test_alter_drop(self): "DROP TABLE __temp__users", ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_change(self): with self.schema.table("users") as blueprint: @@ -93,7 +97,7 @@ def test_change(self): blueprint.table.from_table = table - sql = [ + expected_sql = [ 'ALTER TABLE "users" ADD COLUMN "name" VARCHAR NOT NULL', "CREATE TEMPORARY TABLE __temp__users AS SELECT age FROM users", 'DROP TABLE "users"', @@ -102,7 +106,8 @@ def test_change(self): "DROP TABLE __temp__users", ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_drop_add_and_change(self): with self.schema.table("users") as blueprint: @@ -138,9 +143,12 @@ def test_timestamp_alter_add_nullable_column(self): blueprint.table.from_table = table - sql = ['ALTER TABLE "users" ADD COLUMN "due_date" TIMESTAMP NULL'] + expected_sql = [ + 'ALTER TABLE "users" ADD COLUMN "due_date" TIMESTAMP NULL' + ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_drop_on_table_schema_table(self): schema = Schema(connection="dev", connection_details=DATABASES).on( @@ -150,18 +158,23 @@ def test_alter_drop_on_table_schema_table(self): with schema.table("table_schema") as blueprint: blueprint.drop_column("name") + self.assertEqual(blueprint.table.dropped_columns, ["name"]) + with schema.table("table_schema") as blueprint: blueprint.string("name").nullable() + self.assertIn("name", blueprint.table.added_columns) + def test_alter_add_primary(self): with self.schema.table("users") as blueprint: blueprint.primary("playlist_id") - sql = [ + expected_sql = [ 'ALTER TABLE "users" ADD CONSTRAINT users_playlist_id_primary PRIMARY KEY (playlist_id)' ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_add_column_and_foreign_key(self): with self.schema.table("users") as blueprint: @@ -176,7 +189,7 @@ def test_alter_add_column_and_foreign_key(self): blueprint.table.from_table = table - sql = [ + expected_sql = [ 'ALTER TABLE "users" ADD COLUMN "playlist_id" INTEGER UNSIGNED NULL REFERENCES "playlists"("id")', "CREATE TEMPORARY TABLE __temp__users AS SELECT age, email FROM users", 'DROP TABLE "users"', @@ -186,7 +199,8 @@ def test_alter_add_column_and_foreign_key(self): "DROP TABLE __temp__users", ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_alter_add_foreign_key_only(self): with self.schema.table("users") as blueprint: @@ -200,7 +214,7 @@ def test_alter_add_foreign_key_only(self): blueprint.table.from_table = table - sql = [ + expected_sql = [ "CREATE TEMPORARY TABLE __temp__users AS SELECT age, email FROM users", 'DROP TABLE "users"', 'CREATE TABLE "users" ("age" VARCHAR NOT NULL, "email" VARCHAR NOT NULL, ' @@ -209,7 +223,8 @@ def test_alter_add_foreign_key_only(self): "DROP TABLE __temp__users", ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_can_add_column_enum(self): with self.schema.table("users") as blueprint: @@ -217,11 +232,12 @@ def test_can_add_column_enum(self): self.assertEqual(len(blueprint.table.added_columns), 1) - sql = [ + expected_sql = [ "ALTER TABLE \"users\" ADD COLUMN \"status\" VARCHAR CHECK('status' IN('active', 'inactive')) NOT NULL DEFAULT 'active'" ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) def test_can_change_column_enum(self): with self.schema.table("users") as blueprint: @@ -233,7 +249,7 @@ def test_can_change_column_enum(self): self.assertEqual(len(blueprint.table.changed_columns), 1) - sql = [ + expected_sql = [ "CREATE TEMPORARY TABLE __temp__users AS SELECT FROM users", 'DROP TABLE "users"', "CREATE TABLE \"users\" (\"status\" VARCHAR(255) CHECK(status IN ('active', 'inactive')) NOT NULL DEFAULT 'active')", @@ -241,4 +257,5 @@ def test_can_change_column_enum(self): "DROP TABLE __temp__users", ] - self.assertEqual(blueprint.to_sql(), sql) + query_sql = blueprint.to_sql() + self.assertEqual(query_sql, expected_sql) diff --git a/tests/sqlite/schema/test_table.py b/tests/sqlite/schema/test_table.py index 2e73a4ab4..b171ca821 100644 --- a/tests/sqlite/schema/test_table.py +++ b/tests/sqlite/schema/test_table.py @@ -1,9 +1,9 @@ import unittest -from tests.integrations.config.database import DATABASES from src.masoniteorm.connections import SQLiteConnection from src.masoniteorm.schema import Column, Table from src.masoniteorm.schema.platforms.SQLitePlatform import SQLitePlatform +from tests.integrations.config.database import DATABASES class TestTable(unittest.TestCase): @@ -30,8 +30,10 @@ def test_create_sql(self): table.add_column("id", "integer") table.add_column("name", "string") - sql = 'CREATE TABLE "users" ("id" INTEGER NOT NULL, "name" VARCHAR NOT NULL)' - self.assertEqual([sql], self.platform.compile_create_sql(table)) + expected_sql = 'CREATE TABLE "users" ("id" INTEGER NOT NULL, "name" VARCHAR NOT NULL)' + self.assertEqual( + [expected_sql], self.platform.compile_create_sql(table) + ) def test_create_sql_with_primary_key(self): table = Table("users") @@ -39,8 +41,10 @@ def test_create_sql_with_primary_key(self): table.add_column("name", "string") table.set_primary_key("id") - sql = 'CREATE TABLE "users" ("id" INTEGER NOT NULL, "name" VARCHAR NOT NULL)' - self.assertEqual([sql], self.platform.compile_create_sql(table)) + expected_sql = 'CREATE TABLE "users" ("id" INTEGER NOT NULL, "name" VARCHAR NOT NULL)' + self.assertEqual( + [expected_sql], self.platform.compile_create_sql(table) + ) def test_create_sql_with_unique_constraint(self): table = Table("users") @@ -49,9 +53,11 @@ def test_create_sql_with_unique_constraint(self): table.add_constraint("name", "unique", ["name"]) table.set_primary_key("id") - sql = 'CREATE TABLE "users" ("id" INTEGER NOT NULL, "name" VARCHAR NOT NULL, UNIQUE(name))' + expected_sql = 'CREATE TABLE "users" ("id" INTEGER NOT NULL, "name" VARCHAR NOT NULL, UNIQUE(name))' self.platform.constraintize(table.get_added_constraints()) - self.assertEqual(self.platform.compile_create_sql(table), [sql]) + self.assertEqual( + self.platform.compile_create_sql(table), [expected_sql] + ) def test_create_sql_with_multiple_unique_constraints(self): table = Table("users") @@ -62,9 +68,11 @@ def test_create_sql_with_multiple_unique_constraints(self): table.add_constraint("email", "unique", ["email"]) table.set_primary_key("id") - sql = 'CREATE TABLE "users" ("id" INTEGER NOT NULL, "email" VARCHAR NOT NULL, "name" VARCHAR NOT NULL, UNIQUE(name), UNIQUE(email))' + expected_sql = 'CREATE TABLE "users" ("id" INTEGER NOT NULL, "email" VARCHAR NOT NULL, "name" VARCHAR NOT NULL, UNIQUE(name), UNIQUE(email))' self.platform.constraintize(table.get_added_constraints()) - self.assertEqual(self.platform.compile_create_sql(table), [sql]) + self.assertEqual( + self.platform.compile_create_sql(table), [expected_sql] + ) def test_create_sql_with_multiple_unique_constraint(self): table = Table("users") @@ -74,9 +82,11 @@ def test_create_sql_with_multiple_unique_constraint(self): table.add_constraint("name", "unique", ["name", "email"]) table.set_primary_key("id") - sql = 'CREATE TABLE "users" ("id" INTEGER NOT NULL, "email" VARCHAR NOT NULL, "name" VARCHAR NOT NULL, UNIQUE(name, email))' + expected_sql = 'CREATE TABLE "users" ("id" INTEGER NOT NULL, "email" VARCHAR NOT NULL, "name" VARCHAR NOT NULL, UNIQUE(name, email))' self.platform.constraintize(table.get_added_constraints()) - self.assertEqual(self.platform.compile_create_sql(table), [sql]) + self.assertEqual( + self.platform.compile_create_sql(table), [expected_sql] + ) def test_create_sql_with_foreign_key_constraint(self): table = Table("users") @@ -87,7 +97,7 @@ def test_create_sql_with_foreign_key_constraint(self): table.add_foreign_key("comment_id", "comments", "id") table.set_primary_key("id") - sql = ( + expected_sql = ( 'CREATE TABLE "users" (' '"id" INTEGER NOT NULL, "profile_id" INTEGER NOT NULL, "comment_id" INTEGER NOT NULL, ' 'CONSTRAINT users_profile_id_foreign FOREIGN KEY ("profile_id") REFERENCES "profiles"("id"), ' @@ -95,7 +105,9 @@ def test_create_sql_with_foreign_key_constraint(self): ) self.platform.constraintize(table.get_added_constraints()) - self.assertEqual(self.platform.compile_create_sql(table), [sql]) + self.assertEqual( + self.platform.compile_create_sql(table), [expected_sql] + ) def test_can_build_table_from_connection_call(self): sql_details = DATABASES["dev"] diff --git a/tests/sqlite/schema/test_table_diff.py b/tests/sqlite/schema/test_table_diff.py index e8549f8d2..cc28b7289 100644 --- a/tests/sqlite/schema/test_table_diff.py +++ b/tests/sqlite/schema/test_table_diff.py @@ -17,9 +17,9 @@ def test_rename_table(self): diff.from_table = table diff.new_name = "clients" - sql = ['ALTER TABLE "users" RENAME TO "clients"'] + expected_sql = ['ALTER TABLE "users" RENAME TO "clients"'] - self.assertEqual(sql, self.platform.compile_alter_sql(diff)) + self.assertEqual(expected_sql, self.platform.compile_alter_sql(diff)) def test_drop_index(self): table = Table("users") @@ -29,9 +29,9 @@ def test_drop_index(self): diff.from_table = table diff.remove_index("name") - sql = ["DROP INDEX name"] + expected_sql = ["DROP INDEX name"] - self.assertEqual(sql, self.platform.compile_alter_sql(diff)) + self.assertEqual(expected_sql, self.platform.compile_alter_sql(diff)) def test_drop_index_and_rename_table(self): table = Table("users") @@ -42,12 +42,12 @@ def test_drop_index_and_rename_table(self): diff.new_name = "clients" diff.remove_index("name_unique") - sql = [ + expected_sql = [ "DROP INDEX name_unique", 'ALTER TABLE "users" RENAME TO "clients"', ] - self.assertEqual(sql, self.platform.compile_alter_sql(diff)) + self.assertEqual(expected_sql, self.platform.compile_alter_sql(diff)) def test_alter_add_column(self): table = Table("users") @@ -57,12 +57,12 @@ def test_alter_add_column(self): diff.add_column("name", "string") diff.add_column("email", "string") - sql = [ + expected_sql = [ 'ALTER TABLE "users" ADD COLUMN "name" VARCHAR NOT NULL', 'ALTER TABLE "users" ADD COLUMN "email" VARCHAR NOT NULL', ] - self.assertEqual(sql, self.platform.compile_alter_sql(diff)) + self.assertEqual(expected_sql, self.platform.compile_alter_sql(diff)) def test_alter_rename(self): table = Table("users") @@ -72,7 +72,7 @@ def test_alter_rename(self): diff.from_table = table diff.rename_column("post", "comment", "integer") - sql = [ + expected_sql = [ "CREATE TEMPORARY TABLE __temp__users AS SELECT post FROM users", 'DROP TABLE "users"', 'CREATE TABLE "users" ("comment" INTEGER NOT NULL)', @@ -80,7 +80,7 @@ def test_alter_rename(self): "DROP TABLE __temp__users", ] - self.assertEqual(sql, self.platform.compile_alter_sql(diff)) + self.assertEqual(expected_sql, self.platform.compile_alter_sql(diff)) def test_alter_advanced_rename_columns(self): table = Table("users") @@ -92,7 +92,7 @@ def test_alter_advanced_rename_columns(self): diff.from_table = table diff.rename_column("post", "comment", "integer") - sql = [ + expected_sql = [ "CREATE TEMPORARY TABLE __temp__users AS SELECT post, user, email FROM users", 'DROP TABLE "users"', 'CREATE TABLE "users" ("comment" INTEGER NOT NULL, "user" INTEGER NOT NULL, "email" INTEGER NOT NULL)', @@ -100,7 +100,7 @@ def test_alter_advanced_rename_columns(self): "DROP TABLE __temp__users", ] - self.assertEqual(sql, self.platform.compile_alter_sql(diff)) + self.assertEqual(expected_sql, self.platform.compile_alter_sql(diff)) def test_alter_rename_column_and_rename_table(self): table = Table("users") @@ -111,7 +111,7 @@ def test_alter_rename_column_and_rename_table(self): diff.new_name = "clients" diff.rename_column("post", "comment", "integer") - sql = [ + expected_sql = [ "CREATE TEMPORARY TABLE __temp__users AS SELECT post FROM users", 'DROP TABLE "users"', 'CREATE TABLE "users" ("comment" INTEGER NOT NULL)', @@ -120,7 +120,7 @@ def test_alter_rename_column_and_rename_table(self): 'ALTER TABLE "users" RENAME TO "clients"', ] - self.assertEqual(sql, self.platform.compile_alter_sql(diff)) + self.assertEqual(expected_sql, self.platform.compile_alter_sql(diff)) def test_alter_rename_column_and_rename_table_and_drop_index(self): table = Table("users") @@ -133,7 +133,7 @@ def test_alter_rename_column_and_rename_table_and_drop_index(self): diff.rename_column("post", "comment", "integer") diff.remove_index("name") - sql = [ + expected_sql = [ "DROP INDEX name", "CREATE TEMPORARY TABLE __temp__users AS SELECT post FROM users", 'DROP TABLE "users"', @@ -143,7 +143,7 @@ def test_alter_rename_column_and_rename_table_and_drop_index(self): 'ALTER TABLE "users" RENAME TO "clients"', ] - self.assertEqual(sql, self.platform.compile_alter_sql(diff)) + self.assertEqual(expected_sql, self.platform.compile_alter_sql(diff)) def test_alter_can_drop_column(self): table = Table("users") @@ -155,7 +155,7 @@ def test_alter_can_drop_column(self): diff.from_table = table diff.drop_column("post") - sql = [ + expected_sql = [ "CREATE TEMPORARY TABLE __temp__users AS SELECT name, email FROM users", 'DROP TABLE "users"', 'CREATE TABLE "users" ("name" VARCHAR NOT NULL, "email" VARCHAR NOT NULL)', @@ -163,4 +163,4 @@ def test_alter_can_drop_column(self): "DROP TABLE __temp__users", ] - self.assertEqual(sql, self.platform.compile_alter_sql(diff)) + self.assertEqual(expected_sql, self.platform.compile_alter_sql(diff)) From d1869c31365be41918e9699cbb419c089369fe3c Mon Sep 17 00:00:00 2001 From: Kieren Eaton <499977+circulon@users.noreply.github.com> Date: Sun, 17 May 2026 13:21:04 +0800 Subject: [PATCH 10/10] added extra test checks --- .../test_postgres_schema_builder_alter.py | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/tests/postgres/schema/test_postgres_schema_builder_alter.py b/tests/postgres/schema/test_postgres_schema_builder_alter.py index 908c63146..7bfb71afb 100644 --- a/tests/postgres/schema/test_postgres_schema_builder_alter.py +++ b/tests/postgres/schema/test_postgres_schema_builder_alter.py @@ -323,27 +323,22 @@ def test_timestamp_alter_add_nullable_column(self): self.assertEqual(query_sql, expected_sql) def test_alter_drop_on_table_schema_table(self): - schema = Schema( - connection_class=PostgresConnection, - connection="postgres", - connection_details=DATABASES, - dry=True, - ).on("postgres") - - with schema.table("table_schema") as blueprint: + with self.schema.table("table_schema") as blueprint: blueprint.drop_column("name") - expected_sql_drop = ['ALTER TABLE "table_schema" DROP COLUMN "name"'] + self.assertEqual(len(blueprint.table.dropped_columns), 1) query_sql_drop = blueprint.to_sql() + expected_sql_drop = ['ALTER TABLE "table_schema" DROP COLUMN "name"'] self.assertEqual(query_sql_drop, expected_sql_drop) - with schema.table("table_schema") as blueprint: - blueprint.string("name") + with self.schema.table("table_schema") as blueprint: + blueprint.text("name").nullable() + self.assertEqual(len(blueprint.table.added_columns), 1) + query_sql_add = blueprint.to_sql() expected_sql_add = [ - 'ALTER TABLE "table_schema" ADD COLUMN "name" VARCHAR(255) NOT NULL' + 'ALTER TABLE "table_schema" ADD COLUMN "name" TEXT NULL' ] - query_sql_add = blueprint.to_sql() self.assertEqual(query_sql_add, expected_sql_add) def test_can_add_column_enum(self):