feat(edit): 编辑页类目树逻辑开发
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
SET search_path TO atlas, public;
|
||||
|
||||
-- Ozon exposes catalog metadata through a seller credential. Keep the cache
|
||||
-- scoped to that store so a region/account-specific response never leaks into
|
||||
-- another store's publishing flow. The older platform-wide tables remain for
|
||||
-- historical commission data and are intentionally not repurposed here.
|
||||
CREATE TABLE store_product_categories (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
workspace_id UUID NOT NULL,
|
||||
store_id UUID NOT NULL,
|
||||
platform_id UUID NOT NULL,
|
||||
parent_id UUID REFERENCES store_product_categories(id) ON DELETE RESTRICT,
|
||||
external_category_id TEXT NOT NULL,
|
||||
external_type_id TEXT,
|
||||
name TEXT NOT NULL,
|
||||
path TEXT NOT NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
source_payload JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
synced_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
FOREIGN KEY (workspace_id, store_id, platform_id)
|
||||
REFERENCES stores(workspace_id, id, platform_id) ON DELETE CASCADE,
|
||||
UNIQUE (workspace_id, id),
|
||||
UNIQUE (workspace_id, store_id, id),
|
||||
UNIQUE (store_id, external_category_id, external_type_id)
|
||||
);
|
||||
CREATE INDEX ix_store_product_categories_tree
|
||||
ON store_product_categories (workspace_id, store_id, parent_id, path, id);
|
||||
CREATE INDEX ix_store_product_categories_active
|
||||
ON store_product_categories (workspace_id, store_id, is_active, path, id);
|
||||
|
||||
CREATE TABLE store_product_category_attributes (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
workspace_id UUID NOT NULL,
|
||||
store_id UUID NOT NULL,
|
||||
platform_id UUID NOT NULL,
|
||||
store_product_category_id UUID NOT NULL,
|
||||
platform_attribute_id TEXT NOT NULL,
|
||||
complex_id TEXT NOT NULL DEFAULT '0',
|
||||
name TEXT NOT NULL,
|
||||
value_type TEXT NOT NULL CHECK (value_type IN ('text', 'integer', 'decimal', 'boolean', 'dictionary')),
|
||||
is_required BOOLEAN NOT NULL DEFAULT false,
|
||||
is_collection BOOLEAN NOT NULL DEFAULT false,
|
||||
max_value_count INTEGER NOT NULL DEFAULT 1 CHECK (max_value_count BETWEEN 1 AND 100),
|
||||
dictionary_id TEXT,
|
||||
is_aspect BOOLEAN NOT NULL DEFAULT false,
|
||||
source_payload JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
synced_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
FOREIGN KEY (workspace_id, store_id, platform_id)
|
||||
REFERENCES stores(workspace_id, id, platform_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (workspace_id, store_id, store_product_category_id)
|
||||
REFERENCES store_product_categories(workspace_id, store_id, id) ON DELETE CASCADE,
|
||||
UNIQUE (store_id, store_product_category_id, platform_attribute_id, complex_id),
|
||||
CHECK ((value_type = 'dictionary') = (dictionary_id IS NOT NULL)),
|
||||
CHECK (is_collection OR max_value_count = 1)
|
||||
);
|
||||
CREATE INDEX ix_store_product_category_attributes_lookup
|
||||
ON store_product_category_attributes (workspace_id, store_id, store_product_category_id, is_required DESC, name, id);
|
||||
|
||||
CREATE TABLE store_attribute_dictionary_values (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
workspace_id UUID NOT NULL,
|
||||
store_id UUID NOT NULL,
|
||||
platform_id UUID NOT NULL,
|
||||
store_product_category_id UUID NOT NULL,
|
||||
dictionary_id TEXT NOT NULL,
|
||||
external_value_id TEXT NOT NULL,
|
||||
value TEXT NOT NULL,
|
||||
is_active BOOLEAN NOT NULL DEFAULT true,
|
||||
source_payload JSONB NOT NULL DEFAULT '{}'::jsonb,
|
||||
synced_at TIMESTAMPTZ,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
FOREIGN KEY (workspace_id, store_id, platform_id)
|
||||
REFERENCES stores(workspace_id, id, platform_id) ON DELETE CASCADE,
|
||||
FOREIGN KEY (workspace_id, store_id, store_product_category_id)
|
||||
REFERENCES store_product_categories(workspace_id, store_id, id) ON DELETE CASCADE,
|
||||
UNIQUE (store_id, store_product_category_id, dictionary_id, external_value_id)
|
||||
);
|
||||
CREATE INDEX ix_store_attribute_dictionary_values_search
|
||||
ON store_attribute_dictionary_values (workspace_id, store_id, store_product_category_id, dictionary_id, is_active, value, external_value_id);
|
||||
|
||||
ALTER TABLE product_platform_profiles
|
||||
ADD COLUMN store_product_category_id UUID,
|
||||
ADD CONSTRAINT fk_product_platform_profiles_store_category
|
||||
FOREIGN KEY (workspace_id, target_store_id, store_product_category_id)
|
||||
REFERENCES store_product_categories(workspace_id, store_id, id) ON DELETE RESTRICT;
|
||||
|
||||
ALTER TABLE product_unmapped_attributes
|
||||
ADD COLUMN original_store_product_category_id UUID,
|
||||
ADD CONSTRAINT fk_product_unmapped_attributes_store_category
|
||||
FOREIGN KEY (workspace_id, original_store_product_category_id)
|
||||
REFERENCES store_product_categories(workspace_id, id) ON DELETE SET NULL;
|
||||
|
||||
DO $$
|
||||
DECLARE table_name TEXT;
|
||||
BEGIN
|
||||
FOREACH table_name IN ARRAY ARRAY[
|
||||
'store_product_categories',
|
||||
'store_product_category_attributes',
|
||||
'store_attribute_dictionary_values'
|
||||
] LOOP
|
||||
EXECUTE format('ALTER TABLE %I ENABLE ROW LEVEL SECURITY', table_name);
|
||||
EXECUTE format('ALTER TABLE %I FORCE ROW LEVEL SECURITY', table_name);
|
||||
EXECUTE format('CREATE POLICY workspace_isolation ON %I USING (workspace_id = app_current_workspace_id()) WITH CHECK (workspace_id = app_current_workspace_id())', table_name);
|
||||
END LOOP;
|
||||
END $$;
|
||||
Reference in New Issue
Block a user