diff --git a/_database/sql/migrations/2026-07-10-065552-0000_create_tags/down.sql b/_database/sql/migrations/2026-07-10-065552-0000_create_tags/down.sql new file mode 100644 index 0000000000..311e762f7d --- /dev/null +++ b/_database/sql/migrations/2026-07-10-065552-0000_create_tags/down.sql @@ -0,0 +1,5 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +DROP TABLE IF EXISTS tags; diff --git a/_database/sql/migrations/2026-07-10-065552-0000_create_tags/up.sql b/_database/sql/migrations/2026-07-10-065552-0000_create_tags/up.sql new file mode 100644 index 0000000000..166dbd73c6 --- /dev/null +++ b/_database/sql/migrations/2026-07-10-065552-0000_create_tags/up.sql @@ -0,0 +1,38 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +CREATE TABLE tags ( + -- Not used for anything except replication. + id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + + -- Effective "primary key". + token VARCHAR(32) NOT NULL, + + -- The display value of the tag, as entered by the creator. + tag_value VARCHAR(255) NOT NULL, + + -- Lowercased copy of `tag_value` for case-insensitive uniqueness and lookup. + -- (The table collation is utf8mb4_bin, so the code must lowercase this.) + tag_value_lowercase VARCHAR(255) NOT NULL, + + -- The user that created the tag. + creator_user_token VARCHAR(32) NOT NULL, + + -- Rollup statistic for usage counts. + use_count INT(10) UNSIGNED NOT NULL DEFAULT 0, + + -- ========== TIMESTAMPS ========== + + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + maybe_deleted_at TIMESTAMP NULL DEFAULT NULL, + + -- INDICES -- + PRIMARY KEY (id), + UNIQUE KEY (token), + UNIQUE KEY (tag_value_lowercase, creator_user_token), + + KEY index_creator_user_token (creator_user_token) + +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; diff --git a/_database/sql/migrations/2026-07-10-065553-0000_create_media_file_tags/down.sql b/_database/sql/migrations/2026-07-10-065553-0000_create_media_file_tags/down.sql new file mode 100644 index 0000000000..9084b732fe --- /dev/null +++ b/_database/sql/migrations/2026-07-10-065553-0000_create_media_file_tags/down.sql @@ -0,0 +1,5 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +DROP TABLE IF EXISTS media_file_tags; diff --git a/_database/sql/migrations/2026-07-10-065553-0000_create_media_file_tags/up.sql b/_database/sql/migrations/2026-07-10-065553-0000_create_media_file_tags/up.sql new file mode 100644 index 0000000000..c3ef35fb8d --- /dev/null +++ b/_database/sql/migrations/2026-07-10-065553-0000_create_media_file_tags/up.sql @@ -0,0 +1,32 @@ +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +CREATE TABLE media_file_tags ( + -- Not used for anything except replication. + id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + + -- The media file being tagged. + media_file_token VARCHAR(32) NOT NULL, + + -- The tag applied to the media file. + tag_token VARCHAR(32) NOT NULL, + + -- The user that owns this tagging. + user_token VARCHAR(32) NOT NULL, + + -- ========== TIMESTAMPS ========== + + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + + -- INDICES -- + PRIMARY KEY (id), + UNIQUE KEY (media_file_token, tag_token, user_token), + + KEY index_media_file_token_and_user_token (media_file_token, user_token), + KEY index_tag_token_and_user_token (tag_token, user_token), + KEY index_media_file_token (media_file_token), + KEY index_tag_token (tag_token), + KEY index_user_token (user_token) + +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; diff --git a/_database/sql/migrations_squashed/media_file_tags.sql b/_database/sql/migrations_squashed/media_file_tags.sql new file mode 100644 index 0000000000..69e145ba93 --- /dev/null +++ b/_database/sql/migrations_squashed/media_file_tags.sql @@ -0,0 +1,36 @@ +-- NB: This is a manually squashed view of all the CREATE and ALTER statements, +-- with comments attached to the fields for centralized documentation. + +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +-- N:M mapping between `media_files` and `tags`, scoped to the owning user. +CREATE TABLE media_file_tags ( + -- Not used for anything except replication. + id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + + -- The media file being tagged. + media_file_token VARCHAR(32) NOT NULL, + + -- The tag applied to the media file. + tag_token VARCHAR(32) NOT NULL, + + -- The user that owns this tagging. + user_token VARCHAR(32) NOT NULL, + + -- ========== TIMESTAMPS ========== + + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + + -- INDICES -- + PRIMARY KEY (id), + UNIQUE KEY (media_file_token, tag_token, user_token), + + KEY index_media_file_token_and_user_token (media_file_token, user_token), + KEY index_tag_token_and_user_token (tag_token, user_token), + KEY index_media_file_token (media_file_token), + KEY index_tag_token (tag_token), + KEY index_user_token (user_token) + +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin; diff --git a/_database/sql/migrations_squashed/tags.sql b/_database/sql/migrations_squashed/tags.sql new file mode 100644 index 0000000000..ba0836b869 --- /dev/null +++ b/_database/sql/migrations_squashed/tags.sql @@ -0,0 +1,44 @@ +-- NB: This is a manually squashed view of all the CREATE and ALTER statements, +-- with comments attached to the fields for centralized documentation. + +-- noinspection SqlDialectInspectionForFile +-- noinspection SqlNoDataSourceInspectionForFile +-- noinspection SqlResolveForFile + +-- User-created tags for media files. Tags are scoped per-user: two users can +-- each have their own tag with the same value. Applied to media files via the +-- `media_file_tags` join table. +CREATE TABLE tags ( + -- Not used for anything except replication. + id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT, + + -- Effective "primary key". + token VARCHAR(32) NOT NULL, + + -- The display value of the tag, as entered by the creator. + tag_value VARCHAR(255) NOT NULL, + + -- Lowercased copy of `tag_value` for case-insensitive uniqueness and lookup. + -- (The table collation is utf8mb4_bin, so the code must lowercase this.) + tag_value_lowercase VARCHAR(255) NOT NULL, + + -- The user that created the tag. + creator_user_token VARCHAR(32) NOT NULL, + + -- Rollup statistic for usage counts. + use_count INT(10) UNSIGNED NOT NULL DEFAULT 0, + + -- ========== TIMESTAMPS ========== + + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + maybe_deleted_at TIMESTAMP NULL DEFAULT NULL, + + -- INDICES -- + PRIMARY KEY (id), + UNIQUE KEY (token), + UNIQUE KEY (tag_value_lowercase, creator_user_token), + + KEY index_creator_user_token (creator_user_token) + +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;