diff --git a/src/masoniteorm/schema/Blueprint.py b/src/masoniteorm/schema/Blueprint.py index 3c9c0b1b..b2865c54 100644 --- a/src/masoniteorm/schema/Blueprint.py +++ b/src/masoniteorm/schema/Blueprint.py @@ -396,6 +396,7 @@ def decimal(self, column, length=17, precision=6, nullable=False): Returns: self """ + self._last_column = self.table.add_column( column, "decimal", @@ -483,6 +484,46 @@ def text(self, column, length=None, nullable=False): ) return self + def tiny_text(self, column, length=None, nullable=False): + """Sets a column to be the text representation for the table. + + Arguments: + column {string} -- The column name. + + Keyword Arguments: + length {int} -- The length of the column if any. (default: {False}) + nullable {bool} -- Whether the column is nullable. (default: {False}) + + Returns: + self + """ + self._last_column = self.table.add_column( + column, "tiny_text", length=length, nullable=nullable + ) + return self + + def unsigned_decimal(self, column, length=17, precision=6, nullable=False): + """Sets a column to be the text representation for the table. + + Arguments: + column {string} -- The column name. + + Keyword Arguments: + length {int} -- The length of the column if any. (default: {False}) + nullable {bool} -- Whether the column is nullable. (default: {False}) + + Returns: + self + """ + self._last_column = self.table.add_column( + column, + "decimal", + length="{length}, {precision}".format(length=length, precision=precision), + nullable=nullable, + ).unsigned() + return self + return self + def long_text(self, column, length=None, nullable=False): """Sets a column to be the long_text representation for the table. @@ -643,13 +684,12 @@ def unsigned(self, column=None, length=None, nullable=False): self """ if not column: - self._last_column.column_type += "_unsigned" - self._last_column.length = None + self._last_column.unsigned() return self self._last_column = self.table.add_column( column, "unsigned", length=length, nullable=nullable - ) + ).unsigned() return self def unsigned_integer(self, column, nullable=False): @@ -665,8 +705,8 @@ def unsigned_integer(self, column, nullable=False): self """ self._last_column = self.table.add_column( - column, "integer_unsigned", nullable=nullable - ) + column, "integer", nullable=nullable + ).unsigned() return self def morphs(self, column, nullable=False, indexes=True): @@ -684,8 +724,8 @@ def morphs(self, column, nullable=False, indexes=True): _columns = [] _columns.append( self.table.add_column( - "{}_id".format(column), "integer_unsigned", nullable=nullable - ) + "{}_id".format(column), "integer", nullable=nullable + ).unsigned() ) _columns.append( self.table.add_column( diff --git a/src/masoniteorm/schema/Column.py b/src/masoniteorm/schema/Column.py index 63783a2c..8f1a6c07 100644 --- a/src/masoniteorm/schema/Column.py +++ b/src/masoniteorm/schema/Column.py @@ -9,6 +9,7 @@ def __init__( values=None, nullable=False, default=None, + signed=None, default_is_raw=False, column_python_type=str, ): @@ -21,6 +22,7 @@ def __init__( self._after = None self.old_column = "" self.default = default + self._signed = signed self.default_is_raw = default_is_raw self.primary = False self.comment = None @@ -34,6 +36,24 @@ def nullable(self): self.is_null = True return self + def signed(self): + """Sets this column to be nullable + + Returns: + self + """ + self._signed = "signed" + return self + + def unsigned(self): + """Sets this column to be nullable + + Returns: + self + """ + self._signed = "unsigned" + return self + def not_nullable(self): """Sets this column to be not nullable diff --git a/src/masoniteorm/schema/Table.py b/src/masoniteorm/schema/Table.py index 75d0d413..b64f33d1 100644 --- a/src/masoniteorm/schema/Table.py +++ b/src/masoniteorm/schema/Table.py @@ -25,6 +25,7 @@ def add_column( values=None, nullable=False, default=None, + signed=None, default_is_raw=False, primary=False, column_python_type=str, @@ -36,6 +37,7 @@ def add_column( nullable=nullable, values=values or [], default=default, + signed=signed, default_is_raw=default_is_raw, column_python_type=column_python_type, ) diff --git a/src/masoniteorm/schema/platforms/MSSQLPlatform.py b/src/masoniteorm/schema/platforms/MSSQLPlatform.py index 9b3b3132..bf9386b6 100644 --- a/src/masoniteorm/schema/platforms/MSSQLPlatform.py +++ b/src/masoniteorm/schema/platforms/MSSQLPlatform.py @@ -33,6 +33,7 @@ class MSSQLPlatform(Platform): "double": "DOUBLE", "enum": "VARCHAR", "text": "TEXT", + "tiny_text": "TINYTEXT", "float": "FLOAT", "geometry": "GEOMETRY", "json": "JSON", diff --git a/src/masoniteorm/schema/platforms/MySQLPlatform.py b/src/masoniteorm/schema/platforms/MySQLPlatform.py index b37c7ac8..a39d9a77 100644 --- a/src/masoniteorm/schema/platforms/MySQLPlatform.py +++ b/src/masoniteorm/schema/platforms/MySQLPlatform.py @@ -29,6 +29,7 @@ class MySQLPlatform(Platform): "double": "DOUBLE", "enum": "ENUM", "text": "TEXT", + "tiny_text": "TINYTEXT", "float": "FLOAT", "geometry": "GEOMETRY", "json": "JSON", @@ -55,6 +56,8 @@ class MySQLPlatform(Platform): "null": " DEFAULT NULL", } + signed = {"unsigned": "UNSIGNED", "signed": "SIGNED"} + def columnize(self, columns): sql = [] for name, column in columns.items(): @@ -87,7 +90,6 @@ def columnize(self, columns): if column.column_type == "enum": values = ", ".join(f"'{x}'" for x in column.values) column_constraint = f"({values})" - sql.append( self.columnize_string() .format( @@ -98,6 +100,9 @@ def columnize(self, columns): constraint=constraint, nullable=self.premapped_nulls.get(column.is_null) or "", default=default, + signed=" " + self.signed.get(column._signed) + if column._signed + else "", comment="COMMENT '" + column.comment + "'" if column.comment else "", @@ -180,6 +185,9 @@ def compile_alter_sql(self, table): constraint="PRIMARY KEY" if column.primary else "", nullable="NULL" if column.is_null else "NOT NULL", default=default, + signed=" " + self.signed.get(column._signed) + if column._signed + else "", after=(" AFTER " + self.wrap_column(column._after)) if column._after else "", @@ -324,7 +332,9 @@ def compile_alter_sql(self, table): return sql def add_column_string(self): - return "ADD {name} {data_type}{length} {nullable}{default}{after}{comment}" + return ( + "ADD {name} {data_type}{length}{signed} {nullable}{default}{after}{comment}" + ) def drop_column_string(self): return "DROP COLUMN {name}" @@ -336,7 +346,7 @@ def rename_column_string(self): return "CHANGE {old} {to}" def columnize_string(self): - return "{name} {data_type}{length}{column_constraint} {nullable}{default} {constraint}{comment}" + return "{name} {data_type}{length}{column_constraint}{signed} {nullable}{default} {constraint}{comment}" def constraintize(self, constraints, table): sql = [] diff --git a/src/masoniteorm/schema/platforms/Platform.py b/src/masoniteorm/schema/platforms/Platform.py index 4d69187e..cbda6814 100644 --- a/src/masoniteorm/schema/platforms/Platform.py +++ b/src/masoniteorm/schema/platforms/Platform.py @@ -8,6 +8,8 @@ class Platform: "default": "SET DEFAULT", } + signed = {"signed": "SIGNED", "unsigned": "UNSIGNED"} + def columnize(self, columns): sql = [] for name, column in columns.items(): diff --git a/src/masoniteorm/schema/platforms/PostgresPlatform.py b/src/masoniteorm/schema/platforms/PostgresPlatform.py index 6aeb67cb..2f9f3e65 100644 --- a/src/masoniteorm/schema/platforms/PostgresPlatform.py +++ b/src/masoniteorm/schema/platforms/PostgresPlatform.py @@ -40,6 +40,7 @@ class PostgresPlatform(Platform): "double": "DOUBLE PRECISION", "enum": "VARCHAR", "text": "TEXT", + "tiny_text": "TEXT", "float": "FLOAT", "geometry": "GEOMETRY", "json": "JSON", diff --git a/src/masoniteorm/schema/platforms/SQLitePlatform.py b/src/masoniteorm/schema/platforms/SQLitePlatform.py index 5e1ca632..f4ca6b6d 100644 --- a/src/masoniteorm/schema/platforms/SQLitePlatform.py +++ b/src/masoniteorm/schema/platforms/SQLitePlatform.py @@ -12,6 +12,8 @@ class SQLitePlatform(Platform): "medium_integer", ] + types_without_signs = ["decimal"] + type_map = { "string": "VARCHAR", "char": "CHAR", @@ -34,6 +36,7 @@ class SQLitePlatform(Platform): "double": "DOUBLE", "enum": "VARCHAR", "text": "TEXT", + "tiny_text": "TEXT", "float": "FLOAT", "geometry": "GEOMETRY", "json": "JSON", @@ -132,6 +135,10 @@ def columnize(self, columns): data_type=self.type_map.get(column.column_type, ""), column_constraint=column_constraint, length=length, + signed=" " + self.signed.get(column._signed) + if column.column_type not in self.types_without_signs + and column._signed + else "", constraint=constraint, nullable=self.premapped_nulls.get(column.is_null) or "", default=default, @@ -169,12 +176,16 @@ def compile_alter_sql(self, diff): constraint = f" REFERENCES {self.wrap_table(foreign_key.foreign_table)}({self.wrap_column(foreign_key.foreign_column)})" sql.append( - "ALTER TABLE {table} ADD COLUMN {name} {data_type} {nullable}{default}{constraint}".format( + "ALTER TABLE {table} ADD COLUMN {name} {data_type}{signed} {nullable}{default}{constraint}".format( table=self.wrap_table(diff.name), name=self.wrap_column(column.name), data_type=self.type_map.get(column.column_type, ""), nullable="NULL" if column.is_null else "NOT NULL", default=default, + signed=" " + self.signed.get(column._signed) + if column.column_type not in self.types_without_signs + and column._signed + else "", constraint=constraint, ).strip() ) @@ -286,7 +297,7 @@ def create_column_length(self, column_type): return "({length})" def columnize_string(self): - return "{name} {data_type}{length}{column_constraint} {nullable}{default} {constraint}" + return "{name} {data_type}{length}{column_constraint}{signed} {nullable}{default} {constraint}" def get_unique_constraint_string(self): return "UNIQUE({columns})" diff --git a/tests/mssql/schema/test_mssql_schema_builder.py b/tests/mssql/schema/test_mssql_schema_builder.py index e46c6efb..16813a3a 100644 --- a/tests/mssql/schema/test_mssql_schema_builder.py +++ b/tests/mssql/schema/test_mssql_schema_builder.py @@ -29,6 +29,26 @@ def test_can_add_columns(self): ["CREATE TABLE [users] ([name] VARCHAR(255) NOT NULL, [age] INT NOT NULL)"], ) + 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)"], + ) + + 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)"], + ) + def test_can_add_columns_with_constaint(self): with self.schema.create("users") as blueprint: blueprint.string("name") diff --git a/tests/mysql/schema/test_mysql_schema_builder.py b/tests/mysql/schema/test_mysql_schema_builder.py index d4f460e6..8d7c751c 100644 --- a/tests/mysql/schema/test_mysql_schema_builder.py +++ b/tests/mysql/schema/test_mysql_schema_builder.py @@ -1,7 +1,8 @@ import os import unittest -from src.masoniteorm.models import Model +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 @@ -38,6 +39,26 @@ def test_can_add_columns1(self): ], ) + 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)"], + ) + + 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) UNSIGNED NOT NULL)"], + ) + def test_can_create_table_if_not_exists(self): with self.schema.create_table_if_not_exists("users") as blueprint: blueprint.string("name") @@ -204,7 +225,7 @@ def test_can_advanced_table_creation2(self): "CREATE TABLE `users` (`id` BIGINT UNSIGNED AUTO_INCREMENT NOT NULL, `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(11) NOT NULL, `author_id` INT UNSIGNED NULL, `description` TEXT NOT NULL, `created_at` DATETIME NULL DEFAULT CURRENT_TIMESTAMP, " + "`premium` INT(11) NOT NULL, `author_id` INT(11) UNSIGNED 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)" ], ) @@ -279,13 +300,13 @@ def test_can_have_unsigned_columns(self): blueprint.to_sql(), [ "CREATE TABLE `users` (" - "`profile_id` INT UNSIGNED NOT NULL, " - "`big_profile_id` BIGINT UNSIGNED NOT NULL, " - "`tiny_profile_id` TINYINT UNSIGNED NOT NULL, " - "`small_profile_id` SMALLINT UNSIGNED NOT NULL, " - "`medium_profile_id` MEDIUMINT UNSIGNED NOT NULL, " + "`profile_id` INT(11) UNSIGNED NOT NULL, " + "`big_profile_id` BIGINT(32) UNSIGNED NOT NULL, " + "`tiny_profile_id` TINYINT(1) UNSIGNED NOT NULL, " + "`small_profile_id` SMALLINT(5) UNSIGNED NOT NULL, " + "`medium_profile_id` MEDIUMINT(7) UNSIGNED NOT NULL, " "`unsigned_profile_id` INT UNSIGNED NOT NULL, " - "`unsigned_big_profile_id` BIGINT UNSIGNED NOT NULL)" + "`unsigned_big_profile_id` BIGINT(32) UNSIGNED NOT NULL)" ], ) diff --git a/tests/postgres/schema/test_postgres_schema_builder.py b/tests/postgres/schema/test_postgres_schema_builder.py index 9c7751b7..d5804e81 100644 --- a/tests/postgres/schema/test_postgres_schema_builder.py +++ b/tests/postgres/schema/test_postgres_schema_builder.py @@ -31,6 +31,25 @@ def test_can_add_columns(self): ], ) + 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" TEXT NOT NULL)'] + ) + + 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)'], + ) + def test_can_create_table_if_not_exists(self): with self.schema.create_table_if_not_exists("users") as blueprint: blueprint.string("name") diff --git a/tests/sqlite/schema/test_sqlite_schema_builder.py b/tests/sqlite/schema/test_sqlite_schema_builder.py index 6b37303d..acaf1bc7 100644 --- a/tests/sqlite/schema/test_sqlite_schema_builder.py +++ b/tests/sqlite/schema/test_sqlite_schema_builder.py @@ -30,6 +30,25 @@ def test_can_add_columns(self): ], ) + 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" TEXT NOT NULL)'] + ) + + 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)'], + ) + def test_can_create_table_if_not_exists(self): with self.schema.create_table_if_not_exists("users") as blueprint: blueprint.string("name") @@ -114,7 +133,7 @@ def test_can_use_morphs_for_polymorphism_relationships(self): self.assertEqual(len(blueprint.table.added_columns), 2) sql = [ - 'CREATE TABLE "likes" ("record_id" INT UNSIGNED NOT NULL, "record_type" VARCHAR(255) NOT NULL)', + '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)', ] @@ -251,7 +270,7 @@ def test_can_advanced_table_creation2(self): [ 'CREATE TABLE "users" ("id" BIGINT NOT NULL, "name" VARCHAR(255) NOT NULL, "duration" VARCHAR(255) NOT NULL, ' '"url" VARCHAR(255) NOT NULL, "payload" JSON NOT NULL, "birth" VARCHAR(4) NOT NULL, "last_address" VARCHAR(255) NULL, "route_origin" VARCHAR(255) NULL, "mac_address" VARCHAR(255) NULL, ' - '"published_at" DATETIME NOT NULL, "wakeup_at" TIME NOT NULL, "thumbnail" VARCHAR(255) NULL, "premium" INTEGER NOT NULL, "author_id" INT UNSIGNED NULL, "description" TEXT NOT NULL, ' + '"published_at" DATETIME NOT NULL, "wakeup_at" TIME NOT NULL, "thumbnail" VARCHAR(255) NULL, "premium" INTEGER NOT NULL, "author_id" INTEGER UNSIGNED 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 SET NULL)' ] @@ -301,13 +320,11 @@ def test_can_have_unsigned_columns(self): blueprint.small_integer("small_profile_id").unsigned() blueprint.medium_integer("medium_profile_id").unsigned() - print(blueprint.to_sql()) - self.assertEqual( blueprint.to_sql(), [ """CREATE TABLE "users" (""" - """"profile_id" INT UNSIGNED NOT NULL, """ + """"profile_id" INTEGER UNSIGNED NOT NULL, """ """"big_profile_id" BIGINT UNSIGNED NOT NULL, """ """"tiny_profile_id" TINYINT UNSIGNED NOT NULL, """ """"small_profile_id" SMALLINT UNSIGNED NOT NULL, """ diff --git a/tests/sqlite/schema/test_sqlite_schema_builder_alter.py b/tests/sqlite/schema/test_sqlite_schema_builder_alter.py index fde74e94..91c5c43d 100644 --- a/tests/sqlite/schema/test_sqlite_schema_builder_alter.py +++ b/tests/sqlite/schema/test_sqlite_schema_builder_alter.py @@ -176,10 +176,10 @@ def test_alter_add_column_and_foreign_key(self): blueprint.table.from_table = table sql = [ - 'ALTER TABLE "users" ADD COLUMN "playlist_id" INT UNSIGNED NULL REFERENCES "playlists"("id")', + '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"', - 'CREATE TABLE "users" ("age" VARCHAR NOT NULL, "email" VARCHAR NOT NULL, "playlist_id" INT UNSIGNED NULL, ' + 'CREATE TABLE "users" ("age" VARCHAR NOT NULL, "email" VARCHAR NOT NULL, "playlist_id" INTEGER UNSIGNED NULL, ' 'CONSTRAINT users_playlist_id_foreign FOREIGN KEY ("playlist_id") REFERENCES "playlists"("id") ON DELETE CASCADE ON UPDATE SET NULL)', 'INSERT INTO "users" ("age", "email") SELECT age, email FROM __temp__users', "DROP TABLE __temp__users",