Ctrl K
ComunidadGuías…

deploy/migrations/0090_star_gift_collectibles.up.sql

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
-- Collectible Star Gifts: immutable published attribute pools, unique gift instances and
-- peer-owned gift collections. Marketplace/transfer/auction/craft/TON state is intentionally
-- absent from this schema.

CREATE SEQUENCE public.unique_star_gift_id_seq AS bigint START WITH 9200000000000001;

CREATE TABLE public.star_gift_collectible_revisions (
    id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    gift_id bigint NOT NULL REFERENCES public.star_gift_catalog(gift_id) ON DELETE RESTRICT,
    revision integer NOT NULL,
    upgrade_stars bigint NOT NULL,
    supply_total integer NOT NULL,
    issued integer DEFAULT 0 NOT NULL,
    slug_prefix text NOT NULL,
    status text DEFAULT 'draft' NOT NULL,
    created_by text DEFAULT '' NOT NULL,
    command_id text DEFAULT '' NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    published_at timestamp with time zone,
    CONSTRAINT star_gift_collectible_revision_uniq UNIQUE (gift_id, revision),
    CONSTRAINT star_gift_collectible_command_uniq UNIQUE (gift_id, command_id),
    CONSTRAINT star_gift_collectible_price_check CHECK (upgrade_stars > 0),
    CONSTRAINT star_gift_collectible_supply_check CHECK (supply_total > 0 AND issued >= 0 AND issued <= supply_total),
    CONSTRAINT star_gift_collectible_slug_check CHECK (slug_prefix ~ '^[a-z0-9][a-z0-9-]{0,47}$'),
    CONSTRAINT star_gift_collectible_status_check CHECK (status IN ('draft', 'published')),
    CONSTRAINT star_gift_collectible_publish_check CHECK (
        (status = 'draft' AND published_at IS NULL) OR
        (status = 'published' AND published_at IS NOT NULL)
    )
);

CREATE TABLE public.star_gift_collectible_models (
    id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    collectible_revision_id bigint NOT NULL REFERENCES public.star_gift_collectible_revisions(id) ON DELETE CASCADE,
    name text NOT NULL,
    document_id bigint NOT NULL REFERENCES public.documents(id) ON DELETE RESTRICT,
    animation_json jsonb NOT NULL,
    animation_sha256 bytea NOT NULL,
    source_name text DEFAULT '' NOT NULL,
    source_format text NOT NULL,
    width integer NOT NULL,
    height integer NOT NULL,
    frame_rate double precision DEFAULT 0 NOT NULL,
    in_point double precision DEFAULT 0 NOT NULL,
    out_point double precision DEFAULT 0 NOT NULL,
    rarity_permille integer NOT NULL,
    sort_order integer DEFAULT 0 NOT NULL,
    CONSTRAINT star_gift_collectible_model_name_uniq UNIQUE (collectible_revision_id, name),
    CONSTRAINT star_gift_collectible_model_id_revision_uniq UNIQUE (id, collectible_revision_id),
    CONSTRAINT star_gift_collectible_model_rarity_check CHECK (rarity_permille BETWEEN 1 AND 1000),
    CONSTRAINT star_gift_collectible_model_shape_check CHECK (width = 512 AND height = 512 AND jsonb_typeof(animation_json) = 'object'),
    CONSTRAINT star_gift_collectible_model_source_check CHECK (source_format IN ('tgs', 'lottie'))
);

CREATE TABLE public.star_gift_collectible_patterns (
    id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    collectible_revision_id bigint NOT NULL REFERENCES public.star_gift_collectible_revisions(id) ON DELETE CASCADE,
    name text NOT NULL,
    document_id bigint NOT NULL REFERENCES public.documents(id) ON DELETE RESTRICT,
    animation_json jsonb NOT NULL,
    animation_sha256 bytea NOT NULL,
    source_name text DEFAULT '' NOT NULL,
    source_format text NOT NULL,
    width integer NOT NULL,
    height integer NOT NULL,
    frame_rate double precision DEFAULT 0 NOT NULL,
    in_point double precision DEFAULT 0 NOT NULL,
    out_point double precision DEFAULT 0 NOT NULL,
    rarity_permille integer NOT NULL,
    sort_order integer DEFAULT 0 NOT NULL,
    CONSTRAINT star_gift_collectible_pattern_name_uniq UNIQUE (collectible_revision_id, name),
    CONSTRAINT star_gift_collectible_pattern_id_revision_uniq UNIQUE (id, collectible_revision_id),
    CONSTRAINT star_gift_collectible_pattern_rarity_check CHECK (rarity_permille BETWEEN 1 AND 1000),
    CONSTRAINT star_gift_collectible_pattern_shape_check CHECK (width = 512 AND height = 512 AND jsonb_typeof(animation_json) = 'object'),
    CONSTRAINT star_gift_collectible_pattern_source_check CHECK (source_format IN ('tgs', 'lottie'))
);

CREATE TABLE public.star_gift_collectible_backdrops (
    id bigint GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    collectible_revision_id bigint NOT NULL REFERENCES public.star_gift_collectible_revisions(id) ON DELETE CASCADE,
    name text NOT NULL,
    backdrop_id integer NOT NULL,
    center_color integer NOT NULL,
    edge_color integer NOT NULL,
    pattern_color integer NOT NULL,
    text_color integer NOT NULL,
    rarity_permille integer NOT NULL,
    sort_order integer DEFAULT 0 NOT NULL,
    CONSTRAINT star_gift_collectible_backdrop_name_uniq UNIQUE (collectible_revision_id, name),
    CONSTRAINT star_gift_collectible_backdrop_display_uniq UNIQUE (collectible_revision_id, backdrop_id),
    CONSTRAINT star_gift_collectible_backdrop_id_revision_uniq UNIQUE (id, collectible_revision_id),
    CONSTRAINT star_gift_collectible_backdrop_rarity_check CHECK (rarity_permille BETWEEN 1 AND 1000),
    CONSTRAINT star_gift_collectible_backdrop_color_check CHECK (
        center_color BETWEEN 0 AND 16777215 AND edge_color BETWEEN 0 AND 16777215 AND
        pattern_color BETWEEN 0 AND 16777215 AND text_color BETWEEN 0 AND 16777215
    )
);

ALTER TABLE public.star_gift_catalog
    ADD COLUMN collectible_revision_id bigint,
    ADD CONSTRAINT star_gift_catalog_collectible_revision_fk FOREIGN KEY (collectible_revision_id)
        REFERENCES public.star_gift_collectible_revisions(id) ON DELETE RESTRICT;

CREATE TABLE public.unique_star_gifts (
    id bigint DEFAULT nextval('public.unique_star_gift_id_seq') PRIMARY KEY,
    gift_id bigint NOT NULL REFERENCES public.star_gift_catalog(gift_id) ON DELETE RESTRICT,
    collectible_revision_id bigint NOT NULL REFERENCES public.star_gift_collectible_revisions(id) ON DELETE RESTRICT,
    source_saved_gift_id bigint NOT NULL REFERENCES public.peer_star_gifts(id) ON DELETE RESTRICT,
    title text DEFAULT '' NOT NULL,
    slug text NOT NULL,
    num integer NOT NULL,
    owner_peer_type text NOT NULL,
    owner_peer_id bigint NOT NULL,
    model_attribute_id bigint NOT NULL,
    pattern_attribute_id bigint NOT NULL,
    backdrop_attribute_id bigint NOT NULL,
    keep_original_details boolean DEFAULT false NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    updated_at timestamp with time zone DEFAULT now() NOT NULL,
    CONSTRAINT unique_star_gift_slug_uniq UNIQUE (slug),
    CONSTRAINT unique_star_gift_number_uniq UNIQUE (gift_id, num),
    CONSTRAINT unique_star_gift_source_uniq UNIQUE (source_saved_gift_id),
    CONSTRAINT unique_star_gift_owner_check CHECK (owner_peer_type IN ('user', 'channel') AND owner_peer_id > 0),
    CONSTRAINT unique_star_gift_num_check CHECK (num > 0),
    CONSTRAINT unique_star_gift_model_fk FOREIGN KEY (model_attribute_id, collectible_revision_id)
        REFERENCES public.star_gift_collectible_models(id, collectible_revision_id) ON DELETE RESTRICT,
    CONSTRAINT unique_star_gift_pattern_fk FOREIGN KEY (pattern_attribute_id, collectible_revision_id)
        REFERENCES public.star_gift_collectible_patterns(id, collectible_revision_id) ON DELETE RESTRICT,
    CONSTRAINT unique_star_gift_backdrop_fk FOREIGN KEY (backdrop_attribute_id, collectible_revision_id)
        REFERENCES public.star_gift_collectible_backdrops(id, collectible_revision_id) ON DELETE RESTRICT
);

ALTER TABLE public.peer_star_gifts
    ADD COLUMN unique_gift_id bigint,
    ADD COLUMN upgrade_msg_id integer DEFAULT 0 NOT NULL,
    ADD COLUMN pinned_order integer DEFAULT 0 NOT NULL,
    ADD CONSTRAINT peer_star_gifts_unique_gift_fk FOREIGN KEY (unique_gift_id)
        REFERENCES public.unique_star_gifts(id) ON DELETE RESTRICT DEFERRABLE INITIALLY DEFERRED,
    ADD CONSTRAINT peer_star_gifts_terminal_state_check CHECK (NOT converted OR unique_gift_id IS NULL),
    ADD CONSTRAINT peer_star_gifts_pinned_order_check CHECK (pinned_order >= 0);

CREATE UNIQUE INDEX peer_star_gifts_unique_gift_uniq ON public.peer_star_gifts(unique_gift_id)
    WHERE unique_gift_id IS NOT NULL;
CREATE INDEX unique_star_gifts_owner_idx ON public.unique_star_gifts(owner_peer_type, owner_peer_id, id DESC);

CREATE TABLE public.star_gift_upgrade_commands (
    user_id bigint NOT NULL,
    command_key text NOT NULL,
    source_saved_gift_id bigint NOT NULL REFERENCES public.peer_star_gifts(id) ON DELETE RESTRICT,
    form_id bigint DEFAULT 0 NOT NULL,
    unique_gift_id bigint NOT NULL REFERENCES public.unique_star_gifts(id) ON DELETE RESTRICT,
    balance_after bigint NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    CONSTRAINT star_gift_upgrade_commands_pkey PRIMARY KEY (user_id, command_key),
    CONSTRAINT star_gift_upgrade_command_source_uniq UNIQUE (source_saved_gift_id)
);

CREATE TABLE public.star_gift_collections (
    collection_id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
    owner_peer_type text NOT NULL,
    owner_peer_id bigint NOT NULL,
    title text NOT NULL,
    sort_order integer DEFAULT 0 NOT NULL,
    hash bigint DEFAULT 0 NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    updated_at timestamp with time zone DEFAULT now() NOT NULL,
    CONSTRAINT star_gift_collection_owner_check CHECK (owner_peer_type IN ('user', 'channel') AND owner_peer_id > 0),
    CONSTRAINT star_gift_collection_title_check CHECK (char_length(title) BETWEEN 1 AND 12),
    CONSTRAINT star_gift_collection_owner_id_uniq UNIQUE (owner_peer_type, owner_peer_id, collection_id)
);

CREATE INDEX star_gift_collections_owner_order_idx
    ON public.star_gift_collections(owner_peer_type, owner_peer_id, sort_order, collection_id);

CREATE TABLE public.star_gift_collection_items (
    collection_id integer NOT NULL REFERENCES public.star_gift_collections(collection_id) ON DELETE CASCADE,
    saved_gift_id bigint NOT NULL REFERENCES public.peer_star_gifts(id) ON DELETE CASCADE,
    sort_order integer DEFAULT 0 NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    CONSTRAINT star_gift_collection_items_pkey PRIMARY KEY (collection_id, saved_gift_id)
);

CREATE INDEX star_gift_collection_items_order_idx
    ON public.star_gift_collection_items(collection_id, sort_order, saved_gift_id);
CREATE INDEX star_gift_collection_items_saved_idx
    ON public.star_gift_collection_items(saved_gift_id, collection_id);

-- Published definitions are immutable. The only permitted update is incrementing issued while
-- all definition columns remain byte-for-byte equal.
CREATE FUNCTION public.telesrv_guard_collectible_revision() RETURNS trigger
    LANGUAGE plpgsql AS $$
BEGIN
    IF OLD.status = 'published' THEN
        IF TG_OP = 'DELETE' THEN
            RAISE EXCEPTION 'published collectible revision is immutable';
        END IF;
        IF NEW.gift_id <> OLD.gift_id OR NEW.revision <> OLD.revision OR
           NEW.upgrade_stars <> OLD.upgrade_stars OR NEW.supply_total <> OLD.supply_total OR
           NEW.slug_prefix <> OLD.slug_prefix OR NEW.status <> OLD.status OR
           NEW.created_by <> OLD.created_by OR NEW.command_id <> OLD.command_id OR
           NEW.created_at <> OLD.created_at OR NEW.published_at <> OLD.published_at THEN
            RAISE EXCEPTION 'published collectible revision is immutable';
        END IF;
    END IF;
    IF TG_OP = 'DELETE' THEN
        RETURN OLD;
    END IF;
    RETURN NEW;
END;
$$;

CREATE TRIGGER star_gift_collectible_revision_guard
    BEFORE UPDATE OR DELETE ON public.star_gift_collectible_revisions
    FOR EACH ROW EXECUTE FUNCTION public.telesrv_guard_collectible_revision();

CREATE FUNCTION public.telesrv_guard_collectible_attribute() RETURNS trigger
    LANGUAGE plpgsql AS $$
DECLARE
    revision_status text;
BEGIN
    SELECT status INTO revision_status FROM public.star_gift_collectible_revisions
    WHERE id = COALESCE(OLD.collectible_revision_id, NEW.collectible_revision_id);
    IF revision_status = 'published' THEN
        RAISE EXCEPTION 'published collectible attributes are immutable';
    END IF;
    IF TG_OP = 'DELETE' THEN
        RETURN OLD;
    END IF;
    RETURN NEW;
END;
$$;

CREATE TRIGGER star_gift_collectible_model_guard BEFORE UPDATE OR DELETE ON public.star_gift_collectible_models
    FOR EACH ROW EXECUTE FUNCTION public.telesrv_guard_collectible_attribute();
CREATE TRIGGER star_gift_collectible_pattern_guard BEFORE UPDATE OR DELETE ON public.star_gift_collectible_patterns
    FOR EACH ROW EXECUTE FUNCTION public.telesrv_guard_collectible_attribute();
CREATE TRIGGER star_gift_collectible_backdrop_guard BEFORE UPDATE OR DELETE ON public.star_gift_collectible_backdrops
    FOR EACH ROW EXECUTE FUNCTION public.telesrv_guard_collectible_attribute();