diff --git a/Guide/authentication.markdown b/Guide/authentication.markdown index 3d74a754a..716e27032 100644 --- a/Guide/authentication.markdown +++ b/Guide/authentication.markdown @@ -31,7 +31,7 @@ To use the authentication module, your `users` table needs to have at least an ` ```sql CREATE TABLE users ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, email TEXT NOT NULL, password_hash TEXT NOT NULL, locked_at TIMESTAMP WITH TIME ZONE DEFAULT NULL, diff --git a/Guide/database-migrations.markdown b/Guide/database-migrations.markdown index eebda3764..993fa5f89 100644 --- a/Guide/database-migrations.markdown +++ b/Guide/database-migrations.markdown @@ -35,7 +35,7 @@ To generate our new posts table we copy the DDL statement from `Schema.sql` into ```sql CREATE TABLE posts ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, title TEXT NOT NULL, body TEXT NOT NULL ); diff --git a/Guide/database.markdown b/Guide/database.markdown index f12ed6ebc..c35ca2102 100644 --- a/Guide/database.markdown +++ b/Guide/database.markdown @@ -32,13 +32,13 @@ Database name: `app`. Once you have created your project, the first step is to define a database schema. The database schema is a SQL file with a lot of `CREATE TABLE ...` statements. You can find it at `Application/Schema.sql`. -In a new project, this file will be empty. The [`uuid-ossp`](https://www.postgresql.org/docs/current/uuid-ossp.html) extension is automatically enabled for the database by IHP. +In a new project, this file will be empty. PostgreSQL 18+ provides native `uuidv7()` and `uuidv4()` functions for generating UUIDs without requiring any extensions. To define your database schema add your `CREATE TABLE ...` statements to the `Schema.sql`. For a users table this can look like this: ```sql CREATE TABLE users ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, firstname TEXT NOT NULL, lastname TEXT NOT NULL ); @@ -120,7 +120,7 @@ For every table in the `Schema.sql` a corresponding data structure will be gener ```sql CREATE TABLE users ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, firstname TEXT NOT NULL, lastname TEXT NOT NULL ); @@ -190,7 +190,7 @@ Sometimes you have an optional id field, like e.g. when having a database schema ```sql CREATE TABLE tasks ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, description TEXT, assigned_user_id UUID ); @@ -690,7 +690,7 @@ You can use the enum as a field type for another record. E.g. we can have `posts ```sql CREATE TABLE posts ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, body TEXT NOT NULL, color colors ); @@ -847,7 +847,7 @@ It's possible to use the UI to set the unique constraint on a column. However, s ```sql CREATE TABLE users ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, email TEXT NOT NULL, username TEXT NOT NULL, UNIQUE (email, username) diff --git a/Guide/file-storage.markdown b/Guide/file-storage.markdown index 9701132a2..8107c296f 100644 --- a/Guide/file-storage.markdown +++ b/Guide/file-storage.markdown @@ -197,7 +197,7 @@ In this example we assume the following data schema: ```sql CREATE TABLE companies ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, name TEXT NOT NULL, logo_url TEXT DEFAULT NULL ); @@ -498,7 +498,7 @@ To solve both problems we can introduce a new model `UploadedFile`: ```sql CREATE TABLE uploaded_files ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, signed_url TEXT NOT NULL, signed_url_expired_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, path TEXT NOT NULL, @@ -513,7 +513,7 @@ Companies will now reference this new record ```sql CREATE TABLE companies ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, name TEXT NOT NULL, uploaded_file_id UUID NOT NULL ); diff --git a/Guide/oauth.markdown b/Guide/oauth.markdown index 6ef616a37..68b897116 100644 --- a/Guide/oauth.markdown +++ b/Guide/oauth.markdown @@ -51,7 +51,7 @@ For Google OAuth Login to work, we need to add a `google_user_id TEXT` column to Open `Application/Schema.sql` and add `google_user_id TEXT` to the `CREATE TABLE users` statement: ```sql CREATE TABLE users ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, -- ... , google_user_id TEXT ); @@ -296,7 +296,7 @@ For GitHub OAuth Login to work, we need to add a `github_user_id INT` column to Open `Application/Schema.sql` and add `github_iser_id INT` to the `CREATE TABLE users` statement: ```sql CREATE TABLE users ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, -- ... , github_user_id INT DEFAULT NULL UNIQUE, ); diff --git a/Guide/realtime-spas.markdown b/Guide/realtime-spas.markdown index 814047683..145936415 100644 --- a/Guide/realtime-spas.markdown +++ b/Guide/realtime-spas.markdown @@ -179,7 +179,7 @@ In this example we're going to build a simple todo list. ```sql CREATE TABLE todos ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, title TEXT NOT NULL, is_completed BOOLEAN DEFAULT false NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, diff --git a/Guide/relationships.markdown b/Guide/relationships.markdown index 7654cf3a9..cfce7961b 100644 --- a/Guide/relationships.markdown +++ b/Guide/relationships.markdown @@ -10,14 +10,14 @@ The following sections assume the following database schema being given. It's th ```sql CREATE TABLE posts ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, title TEXT NOT NULL, body TEXT NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL ); CREATE TABLE comments ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, post_id UUID NOT NULL, author TEXT NOT NULL, body TEXT NOT NULL, diff --git a/Guide/stripe.markdown b/Guide/stripe.markdown index 6b7a87319..e1eee1b44 100644 --- a/Guide/stripe.markdown +++ b/Guide/stripe.markdown @@ -93,7 +93,7 @@ Open the `Application/Schema.sql` and add this: ```sql CREATE TABLE plans ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, name TEXT NOT NULL, stripe_price_id TEXT NOT NULL ); @@ -109,7 +109,7 @@ Open `Application/Schema.sql` and add this `subscriptions` table: ```sql CREATE TABLE subscriptions ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, user_id UUID NOT NULL, starts_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, ends_at TIMESTAMP WITH TIME ZONE DEFAULT NULL, @@ -127,7 +127,7 @@ Additionally you also need to add the following fields to your `users` table: ```sql CREATE TABLE users ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, -- ..., stripe_customer_id TEXT DEFAULT NULL, @@ -415,7 +415,7 @@ Open `Application/Schema.sql` and add a `invoices` table: ```sql CREATE TABLE invoices ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, subscription_id UUID NOT NULL, stripe_invoice_id TEXT NOT NULL, invoice_url TEXT NOT NULL, diff --git a/Guide/validation.markdown b/Guide/validation.markdown index fbeaca417..dc6c4982e 100644 --- a/Guide/validation.markdown +++ b/Guide/validation.markdown @@ -324,7 +324,7 @@ Here's an excerpt from the `Schema.sql`: CREATE TYPE comment_moderation AS ENUM ('comment_moderation_pending', 'comment_moderation_approved', 'comment_moderation_rejected'); CREATE TABLE comments ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, post_id UUID NOT NULL, body TEXT NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL diff --git a/Guide/your-first-project.markdown b/Guide/your-first-project.markdown index bb5c4e6de..2690e8597 100644 --- a/Guide/your-first-project.markdown +++ b/Guide/your-first-project.markdown @@ -147,7 +147,7 @@ Open the `Application/Schema.sql` in your code editor to see the SQL queries whi ```sql CREATE TABLE posts ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, title TEXT NOT NULL, body TEXT NOT NULL ); diff --git a/ihp-datasync-typescript/Test/Spec.hs b/ihp-datasync-typescript/Test/Spec.hs index c11af8acf..7c04faa50 100644 --- a/ihp-datasync-typescript/Test/Spec.hs +++ b/ihp-datasync-typescript/Test/Spec.hs @@ -19,7 +19,7 @@ tests = do it "should generate a valid typescript definition file" do let schema = parseSqlStatements $ cs [plain| CREATE TABLE users ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, email TEXT NOT NULL, password_hash TEXT NOT NULL, locked_at TIMESTAMP WITH TIME ZONE DEFAULT NULL, @@ -28,7 +28,7 @@ tests = do ); CREATE TYPE colors AS ENUM ('red', 'blue'); CREATE TABLE tasks ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, title TEXT NOT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL, user_id UUID NOT NULL, @@ -414,7 +414,7 @@ tests = do let table = CreateTable { name = "tasks" , columns = - [ Column { name = "id", columnType = PUUID, defaultValue = Just (CallExpression "uuid_generate_v4" []), notNull = True, isUnique = False, generator = Nothing } + [ Column { name = "id", columnType = PUUID, defaultValue = Just (CallExpression "uuidv7" []), notNull = True, isUnique = False, generator = Nothing } , Column { name = "title", columnType = PText, defaultValue = Just (TextExpression "untitled"), notNull = True, isUnique = False, generator = Nothing } ] , primaryKeyConstraint = PrimaryKeyConstraint ["id"] diff --git a/ihp-datasync/IHP/DataSync/ChangeNotifications.hs b/ihp-datasync/IHP/DataSync/ChangeNotifications.hs index d64e7528d..cea43fbe5 100644 --- a/ihp-datasync/IHP/DataSync/ChangeNotifications.hs +++ b/ihp-datasync/IHP/DataSync/ChangeNotifications.hs @@ -105,7 +105,7 @@ createNotificationFunction table = [i| AND n.nspname = 'public' ) THEN CREATE UNLOGGED TABLE large_pg_notifications ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, payload TEXT DEFAULT NULL, created_at TIMESTAMP WITH TIME ZONE DEFAULT now() NOT NULL ); diff --git a/ihp-graphql/Test/GraphQL/SchemaCompilerSpec.hs b/ihp-graphql/Test/GraphQL/SchemaCompilerSpec.hs index 8a6915111..a6c681a1c 100644 --- a/ihp-graphql/Test/GraphQL/SchemaCompilerSpec.hs +++ b/ihp-graphql/Test/GraphQL/SchemaCompilerSpec.hs @@ -26,14 +26,14 @@ tests = do let sqlSchema = parseSqlStatements [trimming| -- Your database schema. Use the Schema Designer at http://localhost:8001/ to add some tables. CREATE TABLE users ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, email TEXT NOT NULL, password_hash TEXT NOT NULL, locked_at TIMESTAMP WITH TIME ZONE DEFAULT NULL, failed_login_attempts INT DEFAULT 0 NOT NULL ); CREATE TABLE tasks ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, title TEXT NOT NULL, body TEXT NOT NULL, user_id UUID NOT NULL diff --git a/ihp-ide/IHP/IDE/CodeGen/JobGenerator.hs b/ihp-ide/IHP/IDE/CodeGen/JobGenerator.hs index 5ecbf71ab..f35b9fe11 100644 --- a/ihp-ide/IHP/IDE/CodeGen/JobGenerator.hs +++ b/ihp-ide/IHP/IDE/CodeGen/JobGenerator.hs @@ -58,7 +58,7 @@ buildPlan' config = schemaSql = "" <> "CREATE TABLE " <> tableName <> " (\n" - <> " id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,\n" + <> " id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL,\n" <> " created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n" <> " updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n" <> " status JOB_STATUS DEFAULT 'job_status_not_started' NOT NULL,\n" diff --git a/ihp-ide/IHP/IDE/Data/View/Layout.hs b/ihp-ide/IHP/IDE/Data/View/Layout.hs index fdb0e5c3e..8497784a5 100644 --- a/ihp-ide/IHP/IDE/Data/View/Layout.hs +++ b/ihp-ide/IHP/IDE/Data/View/Layout.hs @@ -68,13 +68,17 @@ isBoolField fieldName tableCols = case (find (\c -> c.columnName == (cs fieldNam isSqlFunction :: Text -> Bool isSqlFunction text = text `elem` - [ "uuid_generate_v4()" + [ "uuidv7()" + , "uuidv4()" + , "uuid_generate_v4()" , "NOW()" , "NULL"] isSqlFunction_ :: ByteString -> Bool isSqlFunction_ text = text `elem` - [ "uuid_generate_v4()" + [ "uuidv7()" + , "uuidv4()" + , "uuid_generate_v4()" , "NOW()" , "NULL"] diff --git a/ihp-ide/IHP/IDE/SchemaDesigner/SchemaOperations.hs b/ihp-ide/IHP/IDE/SchemaDesigner/SchemaOperations.hs index c6ca53286..eba4e7e25 100644 --- a/ihp-ide/IHP/IDE/SchemaDesigner/SchemaOperations.hs +++ b/ihp-ide/IHP/IDE/SchemaDesigner/SchemaOperations.hs @@ -22,7 +22,7 @@ addTable tableName list = list <> [StatementCreateTable CreateTable [Column { name = "id" , columnType = PUUID - , defaultValue = Just (CallExpression "uuid_generate_v4" []) + , defaultValue = Just (CallExpression "uuidv7" []) , notNull = True , isUnique = False , generator = Nothing diff --git a/ihp-ide/Test/IDE/CodeGeneration/ControllerGenerator.hs b/ihp-ide/Test/IDE/CodeGeneration/ControllerGenerator.hs index a61720e4d..d580b5588 100644 --- a/ihp-ide/Test/IDE/CodeGeneration/ControllerGenerator.hs +++ b/ihp-ide/Test/IDE/CodeGeneration/ControllerGenerator.hs @@ -19,13 +19,13 @@ tests = do let schema = [ StatementCreateTable (table "pages") { columns = [ - (col "id" PUUID) { defaultValue = Just (CallExpression "uuid_generate_v4" []), notNull = True } + (col "id" PUUID) { defaultValue = Just (CallExpression "uuidv7" []), notNull = True } ] , primaryKeyConstraint = PrimaryKeyConstraint ["id"] }, StatementCreateTable (table "people") { columns = [ - (col "id" PUUID) { defaultValue = Just (CallExpression "uuid_generate_v4" []), notNull = True } + (col "id" PUUID) { defaultValue = Just (CallExpression "uuidv7" []), notNull = True } , (col "name" PText) { notNull = True } , (col "email" PText) { notNull = True } ] diff --git a/ihp-ide/Test/IDE/CodeGeneration/JobGenerator.hs b/ihp-ide/Test/IDE/CodeGeneration/JobGenerator.hs index ae08f66f6..81543219b 100644 --- a/ihp-ide/Test/IDE/CodeGeneration/JobGenerator.hs +++ b/ihp-ide/Test/IDE/CodeGeneration/JobGenerator.hs @@ -26,7 +26,7 @@ tests = do builtPlan `shouldBe` [ EnsureDirectory {directory = "Web/Job"} - , AppendToFile {filePath = "Application/Schema.sql", fileContent = "CREATE TABLE create_container_jobs (\n id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n status JOB_STATUS DEFAULT 'job_status_not_started' NOT NULL,\n last_error TEXT DEFAULT NULL,\n attempts_count INT DEFAULT 0 NOT NULL,\n locked_at TIMESTAMP WITH TIME ZONE DEFAULT NULL,\n locked_by UUID DEFAULT NULL,\n run_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL\n);\n"} + , AppendToFile {filePath = "Application/Schema.sql", fileContent = "CREATE TABLE create_container_jobs (\n id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL,\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n status JOB_STATUS DEFAULT 'job_status_not_started' NOT NULL,\n last_error TEXT DEFAULT NULL,\n attempts_count INT DEFAULT 0 NOT NULL,\n locked_at TIMESTAMP WITH TIME ZONE DEFAULT NULL,\n locked_by UUID DEFAULT NULL,\n run_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL\n);\n"} , CreateFile {filePath = "Web/Job/CreateContainer.hs", fileContent = "module Web.Job.CreateContainer where\nimport Web.Controller.Prelude\n\ninstance Job CreateContainerJob where\n perform CreateContainerJob { .. } = do\n putStrLn \"Hello World!\"\n"} , AddImport {filePath = "Web/Worker.hs", fileContent = "import Web.Job.CreateContainer"} , AppendToMarker {marker = "-- Generator Marker", filePath = "Web/Worker.hs", fileContent = " , worker @CreateContainerJob"} @@ -42,7 +42,7 @@ tests = do builtPlan `shouldBe` [ EnsureDirectory {directory = "Web/Job"} - , AppendToFile {filePath = "Application/Schema.sql", fileContent = "CREATE TABLE create_container_jobs (\n id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n status JOB_STATUS DEFAULT 'job_status_not_started' NOT NULL,\n last_error TEXT DEFAULT NULL,\n attempts_count INT DEFAULT 0 NOT NULL,\n locked_at TIMESTAMP WITH TIME ZONE DEFAULT NULL,\n locked_by UUID DEFAULT NULL,\n run_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL\n);\n"} + , AppendToFile {filePath = "Application/Schema.sql", fileContent = "CREATE TABLE create_container_jobs (\n id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL,\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n status JOB_STATUS DEFAULT 'job_status_not_started' NOT NULL,\n last_error TEXT DEFAULT NULL,\n attempts_count INT DEFAULT 0 NOT NULL,\n locked_at TIMESTAMP WITH TIME ZONE DEFAULT NULL,\n locked_by UUID DEFAULT NULL,\n run_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL\n);\n"} , CreateFile {filePath = "Web/Job/CreateContainer.hs", fileContent = "module Web.Job.CreateContainer where\nimport Web.Controller.Prelude\n\ninstance Job CreateContainerJob where\n perform CreateContainerJob { .. } = do\n putStrLn \"Hello World!\"\n"} , AddImport {filePath = "Web/Worker.hs", fileContent = "import Web.Job.CreateContainer"} , AppendToMarker {marker = "-- Generator Marker", filePath = "Web/Worker.hs", fileContent = " , worker @CreateContainerJob"} @@ -59,7 +59,7 @@ tests = do builtPlan `shouldBe` [ EnsureDirectory {directory = "Web/Job"} - , AppendToFile {filePath = "Application/Schema.sql", fileContent = "CREATE TABLE create_container_jobs (\n id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n status JOB_STATUS DEFAULT 'job_status_not_started' NOT NULL,\n last_error TEXT DEFAULT NULL,\n attempts_count INT DEFAULT 0 NOT NULL,\n locked_at TIMESTAMP WITH TIME ZONE DEFAULT NULL,\n locked_by UUID DEFAULT NULL,\n run_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL\n);\n"} + , AppendToFile {filePath = "Application/Schema.sql", fileContent = "CREATE TABLE create_container_jobs (\n id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL,\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n status JOB_STATUS DEFAULT 'job_status_not_started' NOT NULL,\n last_error TEXT DEFAULT NULL,\n attempts_count INT DEFAULT 0 NOT NULL,\n locked_at TIMESTAMP WITH TIME ZONE DEFAULT NULL,\n locked_by UUID DEFAULT NULL,\n run_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL\n);\n"} , CreateFile {filePath = "Web/Job/CreateContainer.hs", fileContent = "module Web.Job.CreateContainer where\nimport Web.Controller.Prelude\n\ninstance Job CreateContainerJob where\n perform CreateContainerJob { .. } = do\n putStrLn \"Hello World!\"\n"} , CreateFile {filePath = "Web/Worker.hs", fileContent = "module Web.Worker where\n\nimport IHP.Prelude\nimport Web.Types\nimport Generated.Types\nimport IHP.Job.Runner\nimport IHP.Job.Types\n\nimport Web.Job.CreateContainer\n\ninstance Worker WebApplication where\n workers _ =\n [ worker @CreateContainerJob\n -- Generator Marker\n ]\n"} ] @@ -75,7 +75,7 @@ tests = do builtPlan `shouldBe` [ EnsureDirectory {directory = "Admin/Job"} - , AppendToFile {filePath = "Application/Schema.sql", fileContent = "CREATE TABLE create_container_jobs (\n id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n status JOB_STATUS DEFAULT 'job_status_not_started' NOT NULL,\n last_error TEXT DEFAULT NULL,\n attempts_count INT DEFAULT 0 NOT NULL,\n locked_at TIMESTAMP WITH TIME ZONE DEFAULT NULL,\n locked_by UUID DEFAULT NULL,\n run_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL\n);\n"} + , AppendToFile {filePath = "Application/Schema.sql", fileContent = "CREATE TABLE create_container_jobs (\n id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL,\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n status JOB_STATUS DEFAULT 'job_status_not_started' NOT NULL,\n last_error TEXT DEFAULT NULL,\n attempts_count INT DEFAULT 0 NOT NULL,\n locked_at TIMESTAMP WITH TIME ZONE DEFAULT NULL,\n locked_by UUID DEFAULT NULL,\n run_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL\n);\n"} , CreateFile {filePath = "Admin/Job/CreateContainer.hs", fileContent = "module Admin.Job.CreateContainer where\nimport Admin.Controller.Prelude\n\ninstance Job CreateContainerJob where\n perform CreateContainerJob { .. } = do\n putStrLn \"Hello World!\"\n"} , AddImport {filePath = "Admin/Worker.hs", fileContent = "import Admin.Job.CreateContainer"} , AppendToMarker {marker = "-- Generator Marker", filePath = "Admin/Worker.hs", fileContent = " , worker @CreateContainerJob"} @@ -91,7 +91,7 @@ tests = do builtPlan `shouldBe` [ EnsureDirectory {directory = "Admin/Job"} - , AppendToFile {filePath = "Application/Schema.sql", fileContent = "CREATE TABLE create_container_jobs (\n id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n status JOB_STATUS DEFAULT 'job_status_not_started' NOT NULL,\n last_error TEXT DEFAULT NULL,\n attempts_count INT DEFAULT 0 NOT NULL,\n locked_at TIMESTAMP WITH TIME ZONE DEFAULT NULL,\n locked_by UUID DEFAULT NULL,\n run_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL\n);\n"} + , AppendToFile {filePath = "Application/Schema.sql", fileContent = "CREATE TABLE create_container_jobs (\n id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL,\n created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL,\n status JOB_STATUS DEFAULT 'job_status_not_started' NOT NULL,\n last_error TEXT DEFAULT NULL,\n attempts_count INT DEFAULT 0 NOT NULL,\n locked_at TIMESTAMP WITH TIME ZONE DEFAULT NULL,\n locked_by UUID DEFAULT NULL,\n run_at TIMESTAMP WITH TIME ZONE DEFAULT NOW() NOT NULL\n);\n"} , CreateFile {filePath = "Admin/Job/CreateContainer.hs", fileContent = "module Admin.Job.CreateContainer where\nimport Admin.Controller.Prelude\n\ninstance Job CreateContainerJob where\n perform CreateContainerJob { .. } = do\n putStrLn \"Hello World!\"\n"} , CreateFile {filePath = "Admin/Worker.hs", fileContent = "module Admin.Worker where\n\nimport IHP.Prelude\nimport Admin.Types\nimport Generated.Types\nimport IHP.Job.Runner\nimport IHP.Job.Types\n\nimport Admin.Job.CreateContainer\n\ninstance Worker AdminApplication where\n workers _ =\n [ worker @CreateContainerJob\n -- Generator Marker\n ]\n"} ] diff --git a/ihp-ide/Test/IDE/CodeGeneration/MailGenerator.hs b/ihp-ide/Test/IDE/CodeGeneration/MailGenerator.hs index a1bbda9e6..119d49535 100644 --- a/ihp-ide/Test/IDE/CodeGeneration/MailGenerator.hs +++ b/ihp-ide/Test/IDE/CodeGeneration/MailGenerator.hs @@ -20,7 +20,7 @@ tests = do let schema = [ StatementCreateTable (table "users") { columns = [ - (col "id" PUUID) { defaultValue = Just (CallExpression "uuid_generate_v4" []), notNull = True } + (col "id" PUUID) { defaultValue = Just (CallExpression "uuidv7" []), notNull = True } ] , primaryKeyConstraint = PrimaryKeyConstraint ["id"] } diff --git a/ihp-ide/Test/IDE/CodeGeneration/ViewGenerator.hs b/ihp-ide/Test/IDE/CodeGeneration/ViewGenerator.hs index 9bf78d32c..105319669 100644 --- a/ihp-ide/Test/IDE/CodeGeneration/ViewGenerator.hs +++ b/ihp-ide/Test/IDE/CodeGeneration/ViewGenerator.hs @@ -20,7 +20,7 @@ tests = do let schema = [ StatementCreateTable (table "pages") { columns = [ - (col "id" PUUID) { defaultValue = Just (CallExpression "uuid_generate_v4" []), notNull = True } + (col "id" PUUID) { defaultValue = Just (CallExpression "uuidv7" []), notNull = True } ] , primaryKeyConstraint = PrimaryKeyConstraint ["id"] } diff --git a/ihp-ide/Test/IDE/SchemaDesigner/CompilerSpec.hs b/ihp-ide/Test/IDE/SchemaDesigner/CompilerSpec.hs index 322284cda..85263d5bc 100644 --- a/ihp-ide/Test/IDE/SchemaDesigner/CompilerSpec.hs +++ b/ihp-ide/Test/IDE/SchemaDesigner/CompilerSpec.hs @@ -28,7 +28,7 @@ tests = do it "should compile a CREATE TABLE with columns" do let sql = cs [plain|CREATE TABLE users ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, firstname TEXT NOT NULL, lastname TEXT NOT NULL, password_hash TEXT NOT NULL, @@ -40,7 +40,7 @@ tests = do |] let statement = StatementCreateTable (table "users") { columns = [ - (col "id" PUUID) { defaultValue = Just (CallExpression "uuid_generate_v4" []), notNull = True } + (col "id" PUUID) { defaultValue = Just (CallExpression "uuidv7" []), notNull = True } , (col "firstname" PText) { notNull = True } , (col "lastname" PText) { notNull = True } , (col "password_hash" PText) { notNull = True } @@ -432,10 +432,10 @@ tests = do compileSql [statement] `shouldBe` sql it "should compile a CREATE TABLE statement with a multi-column UNIQUE (a, b) constraint" do - let sql = cs [plain|CREATE TABLE user_followers (\n id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL,\n user_id UUID NOT NULL,\n follower_id UUID NOT NULL,\n UNIQUE(user_id, follower_id)\n);\n|] + let sql = cs [plain|CREATE TABLE user_followers (\n id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL,\n user_id UUID NOT NULL,\n follower_id UUID NOT NULL,\n UNIQUE(user_id, follower_id)\n);\n|] let statement = StatementCreateTable (table "user_followers") { columns = - [ (col "id" PUUID) { defaultValue = Just (CallExpression "uuid_generate_v4" []), notNull = True } + [ (col "id" PUUID) { defaultValue = Just (CallExpression "uuidv7" []), notNull = True } , (col "user_id" PUUID) { notNull = True } , (col "follower_id" PUUID) { notNull = True } ] diff --git a/ihp-ide/Test/SchemaCompilerSpec.hs b/ihp-ide/Test/SchemaCompilerSpec.hs index 0657d7c4f..ca0235a76 100644 --- a/ihp-ide/Test/SchemaCompilerSpec.hs +++ b/ihp-ide/Test/SchemaCompilerSpec.hs @@ -417,10 +417,10 @@ tests = do it "should deal with multiple has many relationships to the same table" do let statements = parseSqlStatements [trimming| CREATE TABLE landing_pages ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL ); CREATE TABLE paragraph_ctas ( - id UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + id UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, landing_page_id UUID NOT NULL, to_landing_page_id UUID NOT NULL ); @@ -519,10 +519,10 @@ tests = do describe "compileStatementPreview for table with arbitrarily named primary key" do let statements = parseSqlStatements [trimming| CREATE TABLE things ( - thing_arbitrary_ident UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL + thing_arbitrary_ident UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL ); CREATE TABLE others ( - other_arbitrary_ident UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL, + other_arbitrary_ident UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL, thing_ref UUID NOT NULL ); ALTER TABLE others ADD CONSTRAINT other_thing_refs FOREIGN KEY (thing_ref) REFERENCES things (thing_arbitrary_ident) ON DELETE NO ACTION; @@ -583,10 +583,10 @@ tests = do describe "compileStatementPreview for table with composite primary key" do let statements = parseSqlStatements [trimming| CREATE TABLE bits ( - bit_arbitrary_ident UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL + bit_arbitrary_ident UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL ); CREATE TABLE parts ( - part_arbitrary_ident UUID DEFAULT uuid_generate_v4() PRIMARY KEY NOT NULL + part_arbitrary_ident UUID DEFAULT uuidv7() PRIMARY KEY NOT NULL ); CREATE TABLE bit_part_refs ( bit_ref UUID NOT NULL, diff --git a/ihp-ide/data/IHPSchema.sql b/ihp-ide/data/IHPSchema.sql index b313b1fdc..793dfdf6b 100644 --- a/ihp-ide/data/IHPSchema.sql +++ b/ihp-ide/data/IHPSchema.sql @@ -1,5 +1,5 @@ -- Provides all the default settings for a IHP database in development mode -CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; +-- Note: PostgreSQL 18+ has native uuidv7() and uuidv4() functions, no extension needed -- Used by IHP.Job CREATE TYPE JOB_STATUS AS ENUM ('job_status_not_started', 'job_status_running', 'job_status_failed', 'job_status_timed_out', 'job_status_succeeded', 'job_status_retry'); diff --git a/ihp-ide/data/static/IDE/ihp-schemadesigner.js b/ihp-ide/data/static/IDE/ihp-schemadesigner.js index 8ce2a9531..fceecb57e 100644 --- a/ihp-ide/data/static/IDE/ihp-schemadesigner.js +++ b/ihp-ide/data/static/IDE/ihp-schemadesigner.js @@ -56,7 +56,7 @@ function initSchemaDesigner() { case "UUID": if ($('div[data-attribute="' + $("#colName").val() +'"]').length == 0) { $('#defaultSelector').empty() - .append(new Option("uuid_generate_v4()", 'uuid_generate_v4()', true, true)) + .append(new Option("uuidv7()", 'uuidv7()', true, true)) .append(new Option("no default", "", false, false)) .trigger('change'); } else {