u
This commit is contained in:
@@ -54,11 +54,13 @@ Updated article
|
|||||||
|
|
||||||
| Status | Description |
|
| Status | Description |
|
||||||
|--------|-------------|
|
|--------|-------------|
|
||||||
| 400 | Invalid input, `attributeNameId` missing while `isParent` is true, article still
|
| 400 | Invalid input — `attributeNameId` missing while `isParent` is true, article still
|
||||||
has children, article has stock/suppliers/a Stückliste/options, or the attribute is
|
has children (disabling), or the attribute is already used by an ancestor parent.
|
||||||
already used by an ancestor parent article.
|
|
||||||
|
|
|
|
||||||
| 404 | Article or attribute name not found |
|
| 404 | Article or attribute name not found |
|
||||||
|
| 409 | Article state conflicts with becoming a variant parent — it still has stock,
|
||||||
|
assigned suppliers, a Stückliste, or options. Clear these first.
|
||||||
|
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -3,56 +3,90 @@
|
|||||||
-- One-off manual migration (no migration code is kept in the repo).
|
-- One-off manual migration (no migration code is kept in the repo).
|
||||||
-- sqlcmd -S <server> -d <db> -E -i scripts/migrate-parent-rename.mssql.sql
|
-- sqlcmd -S <server> -d <db> -E -i scripts/migrate-parent-rename.mssql.sql
|
||||||
--
|
--
|
||||||
-- Wrapped in a transaction and guarded so it is safe to re-run.
|
-- Guarded and safe to re-run. Safe to retry after a partial run.
|
||||||
-- Drop the existing index explicitly: SQL Server will not let a filtered
|
--
|
||||||
-- unique index be carried over to a renamed column.
|
-- NOTE ON BATCHING: sp_rename is deferred and its effect is not visible to
|
||||||
|
-- subsequent statements in the SAME batch. Each rename therefore runs in its
|
||||||
|
-- own batch (GO), and constraint/index recreation happens after a GO so the
|
||||||
|
-- new column names resolve.
|
||||||
|
|
||||||
SET XACT_ABORT ON;
|
SET XACT_ABORT ON;
|
||||||
|
GO
|
||||||
|
|
||||||
BEGIN TRANSACTION;
|
BEGIN TRANSACTION;
|
||||||
|
GO
|
||||||
|
|
||||||
-- Drop the old filtered unique index (references fathersort).
|
-- Drop the old filtered unique index (references fathersort).
|
||||||
IF EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'UQ_article_fatherarticle_fathersort')
|
IF EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'UQ_article_fatherarticle_fathersort')
|
||||||
DROP INDEX UQ_article_fatherarticle_fathersort ON article;
|
DROP INDEX UQ_article_fatherarticle_fathersort ON article;
|
||||||
|
GO
|
||||||
|
|
||||||
-- Drop the default constraints bound to the old column names.
|
-- Drop the default constraints bound to the old column names.
|
||||||
IF EXISTS (SELECT 1 FROM sys.default_constraints WHERE name = 'DF_article_is_father')
|
IF EXISTS (SELECT 1 FROM sys.default_constraints WHERE name = 'DF_article_is_father')
|
||||||
ALTER TABLE article DROP CONSTRAINT DF_article_is_father;
|
ALTER TABLE article DROP CONSTRAINT DF_article_is_father;
|
||||||
IF EXISTS (SELECT 1 FROM sys.default_constraints WHERE name = 'DF_article_fathersort')
|
IF EXISTS (SELECT 1 FROM sys.default_constraints WHERE name = 'DF_article_fathersort')
|
||||||
ALTER TABLE article DROP CONSTRAINT DF_article_fathersort;
|
ALTER TABLE article DROP CONSTRAINT DF_article_fathersort;
|
||||||
|
GO
|
||||||
|
|
||||||
-- Drop foreign keys bound to the old columns.
|
-- Drop foreign keys bound to the old columns.
|
||||||
IF EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_article_fatherarticle')
|
IF EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_article_fatherarticle')
|
||||||
ALTER TABLE article DROP CONSTRAINT FK_article_fatherarticle;
|
ALTER TABLE article DROP CONSTRAINT FK_article_fatherarticle;
|
||||||
IF EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_article_fatherattributename')
|
IF EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_article_fatherattributename')
|
||||||
ALTER TABLE article DROP CONSTRAINT FK_article_fatherattributename;
|
ALTER TABLE article DROP CONSTRAINT FK_article_fatherattributename;
|
||||||
|
GO
|
||||||
|
|
||||||
-- Rename the columns (sp_rename keeps indexes/FKs tracking the column).
|
-- Rename the columns (each sp_rename must be its own batch).
|
||||||
IF COL_LENGTH('article', 'fatherarticle_id') IS NOT NULL
|
IF COL_LENGTH('article', 'fatherarticle_id') IS NOT NULL
|
||||||
AND COL_LENGTH('article', 'parentarticle_id') IS NULL
|
AND COL_LENGTH('article', 'parentarticle_id') IS NULL
|
||||||
EXEC sp_rename 'article.fatherarticle_id', 'parentarticle_id', 'COLUMN';
|
EXEC sp_rename 'article.fatherarticle_id', 'parentarticle_id', 'COLUMN';
|
||||||
|
GO
|
||||||
|
|
||||||
IF COL_LENGTH('article', 'fatherattributename_id') IS NOT NULL
|
IF COL_LENGTH('article', 'fatherattributename_id') IS NOT NULL
|
||||||
AND COL_LENGTH('article', 'parentattributename_id') IS NULL
|
AND COL_LENGTH('article', 'parentattributename_id') IS NULL
|
||||||
EXEC sp_rename 'article.fatherattributename_id', 'parentattributename_id', 'COLUMN';
|
EXEC sp_rename 'article.fatherattributename_id', 'parentattributename_id', 'COLUMN';
|
||||||
|
GO
|
||||||
|
|
||||||
IF COL_LENGTH('article', 'fathersort') IS NOT NULL
|
IF COL_LENGTH('article', 'fathersort') IS NOT NULL
|
||||||
AND COL_LENGTH('article', 'parentsort') IS NULL
|
AND COL_LENGTH('article', 'parentsort') IS NULL
|
||||||
EXEC sp_rename 'article.fathersort', 'parentsort', 'COLUMN';
|
EXEC sp_rename 'article.fathersort', 'parentsort', 'COLUMN';
|
||||||
|
GO
|
||||||
|
|
||||||
IF COL_LENGTH('article', 'is_father') IS NOT NULL
|
IF COL_LENGTH('article', 'is_father') IS NOT NULL
|
||||||
AND COL_LENGTH('article', 'is_parent') IS NULL
|
AND COL_LENGTH('article', 'is_parent') IS NULL
|
||||||
EXEC sp_rename 'article.is_father', 'is_parent', 'COLUMN';
|
EXEC sp_rename 'article.is_father', 'is_parent', 'COLUMN';
|
||||||
|
GO
|
||||||
|
|
||||||
-- Recreate the constraints under their new names.
|
COMMIT TRANSACTION;
|
||||||
|
GO
|
||||||
|
|
||||||
|
-- Recreate the constraints under their new names (after the rename batches).
|
||||||
IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_article_parentarticle')
|
IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_article_parentarticle')
|
||||||
ALTER TABLE article ADD CONSTRAINT FK_article_parentarticle
|
ALTER TABLE article ADD CONSTRAINT FK_article_parentarticle
|
||||||
FOREIGN KEY (parentarticle_id) REFERENCES article(id) ON DELETE NO ACTION;
|
FOREIGN KEY (parentarticle_id) REFERENCES article(id) ON DELETE NO ACTION;
|
||||||
|
GO
|
||||||
|
|
||||||
IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_article_parentattributename')
|
IF NOT EXISTS (SELECT 1 FROM sys.foreign_keys WHERE name = 'FK_article_parentattributename')
|
||||||
ALTER TABLE article ADD CONSTRAINT FK_article_parentattributename
|
ALTER TABLE article ADD CONSTRAINT FK_article_parentattributename
|
||||||
FOREIGN KEY (parentattributename_id) REFERENCES attributename(id) ON DELETE NO ACTION;
|
FOREIGN KEY (parentattributename_id) REFERENCES attributename(id) ON DELETE NO ACTION;
|
||||||
|
GO
|
||||||
|
|
||||||
ALTER TABLE article ADD CONSTRAINT DF_article_is_parent DEFAULT (0) FOR is_parent;
|
IF NOT EXISTS (SELECT 1 FROM sys.default_constraints WHERE name = 'DF_article_is_parent')
|
||||||
ALTER TABLE article ADD CONSTRAINT DF_article_parentsort DEFAULT (0) FOR parentsort;
|
ALTER TABLE article ADD CONSTRAINT DF_article_is_parent DEFAULT (0) FOR is_parent;
|
||||||
|
GO
|
||||||
|
|
||||||
CREATE UNIQUE INDEX UQ_article_parentarticle_parentsort
|
IF NOT EXISTS (SELECT 1 FROM sys.default_constraints WHERE name = 'DF_article_parentsort')
|
||||||
ON article (parentarticle_id, parentsort)
|
ALTER TABLE article ADD CONSTRAINT DF_article_parentsort DEFAULT (0) FOR parentsort;
|
||||||
WHERE parentarticle_id IS NOT NULL;
|
GO
|
||||||
|
|
||||||
COMMIT TRANSACTION;
|
IF NOT EXISTS (SELECT 1 FROM sys.indexes WHERE name = 'UQ_article_parentarticle_parentsort')
|
||||||
|
CREATE UNIQUE INDEX UQ_article_parentarticle_parentsort
|
||||||
|
ON article (parentarticle_id, parentsort)
|
||||||
|
WHERE parentarticle_id IS NOT NULL;
|
||||||
|
GO
|
||||||
|
|
||||||
|
-- Verify
|
||||||
|
SELECT 'COL:' + c.name AS result
|
||||||
|
FROM sys.columns c
|
||||||
|
WHERE c.object_id = OBJECT_ID('article')
|
||||||
|
AND (c.name LIKE '%father%' OR c.name LIKE '%parent%');
|
||||||
|
GO
|
||||||
@@ -81,6 +81,13 @@ function articleErrorStatus(error) {
|
|||||||
if (error.message === 'Attribute name not found') return 404;
|
if (error.message === 'Attribute name not found') return 404;
|
||||||
if (error.message === 'attributeNameId is required to become a parent article') return 400;
|
if (error.message === 'attributeNameId is required to become a parent article') return 400;
|
||||||
if (error.message?.includes('already used by an ancestor parent')) return 400;
|
if (error.message?.includes('already used by an ancestor parent')) return 400;
|
||||||
|
// Variant-parent preconditions: a parent article may not carry stock,
|
||||||
|
// suppliers, a Stückliste or options. These are user-correctable 409s,
|
||||||
|
// not server faults — without these the route returns a bare 500.
|
||||||
|
if (error.message === 'An article with existing stock cannot become a parent article') return 409;
|
||||||
|
if (error.message === 'An article with assigned suppliers cannot become a parent article') return 409;
|
||||||
|
if (error.message === 'A Stückliste article cannot become a parent') return 409;
|
||||||
|
if (error.message === 'An article with options cannot become a parent') return 409;
|
||||||
if (error.message?.includes('cannot have attribute values for its variant attribute')) return 400;
|
if (error.message?.includes('cannot have attribute values for its variant attribute')) return 400;
|
||||||
if (error.message?.includes('A parent article cannot have') || error.message?.includes('parent article cannot have')) return 400;
|
if (error.message?.includes('A parent article cannot have') || error.message?.includes('parent article cannot have')) return 400;
|
||||||
if (error.message === 'Cannot disable parent mode on an article that still has children') return 400;
|
if (error.message === 'Cannot disable parent mode on an article that still has children') return 400;
|
||||||
@@ -1855,9 +1862,12 @@ export function register(app, basePath = '') {
|
|||||||
* $ref: '#/components/schemas/Article'
|
* $ref: '#/components/schemas/Article'
|
||||||
* 400:
|
* 400:
|
||||||
* description: |
|
* description: |
|
||||||
* Invalid input, `attributeNameId` missing while `isParent` is true, article still
|
* Invalid input — `attributeNameId` missing while `isParent` is true, article still
|
||||||
* has children, article has stock/suppliers/a Stückliste/options, or the attribute is
|
* has children (disabling), or the attribute is already used by an ancestor parent.
|
||||||
* already used by an ancestor parent article.
|
* 409:
|
||||||
|
* description: |
|
||||||
|
* Article state conflicts with becoming a variant parent — it still has stock,
|
||||||
|
* assigned suppliers, a Stückliste, or options. Clear these first.
|
||||||
* 404:
|
* 404:
|
||||||
* description: Article or attribute name not found
|
* description: Article or attribute name not found
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user