@@ -10,6 +10,9 @@ import { Knex } from 'knex';
1010 * Note: Property names remain unchanged - existing properties will now receive values
1111 * in the format 'code::{table_name}::{id}' instead of plain string values.
1212 *
13+ * Inserts are idempotent (WHERE NOT EXISTS) so the migration can be re-run safely
14+ * after a pg_restore without duplicate key errors.
15+ *
1316 * @export
1417 * @param {Knex } knex
1518 * @return {* } {Promise<void>}
@@ -20,76 +23,102 @@ export async function up(knex: Knex): Promise<void> {
2023 set search_path=biohub,public;
2124
2225 ----------------------------------------------------------------------------------------
23- -- Insert codeset feature type
26+ -- Insert codeset feature type (idempotent)
2427 ----------------------------------------------------------------------------------------
2528 INSERT INTO feature_type (name, display_name, description)
26- VALUES (
27- 'codeset',
28- 'Codeset',
29- 'A code table containing standardized categories and code values.'
29+ SELECT 'codeset', 'Codeset', 'A code table containing standardized categories and code values.'
30+ WHERE NOT EXISTS (
31+ SELECT 1 FROM feature_type
32+ WHERE name = 'codeset' AND record_end_date IS NULL
3033 );
3134
3235 ----------------------------------------------------------------------------------------
33- -- Insert categories feature property
36+ -- Insert categories feature property (idempotent)
3437 ----------------------------------------------------------------------------------------
35- INSERT INTO
38+ INSERT INTO
3639 feature_property (feature_property_type_id, name, display_name, description, calculated_value)
37- VALUES (
38- (SELECT feature_property_type_id FROM feature_property_type WHERE name = 'object'),
40+ SELECT
41+ (SELECT feature_property_type_id FROM feature_property_type WHERE name = 'object' AND record_end_date IS NULL ),
3942 'categories',
4043 'Categories',
4144 'An object of categories, each containing standardized code values.',
4245 false
46+ WHERE NOT EXISTS (
47+ SELECT 1 FROM feature_property
48+ WHERE name = 'categories' AND record_end_date IS NULL
4349 );
4450
4551 ----------------------------------------------------------------------------------------
46- -- Link categories property to codeset feature type
52+ -- Link categories property to codeset feature type (idempotent)
4753 ----------------------------------------------------------------------------------------
48- INSERT INTO
54+ INSERT INTO
4955 feature_type_property (feature_type_id, feature_property_id, required_value)
50- VALUES (
51- (SELECT feature_type_id FROM feature_type WHERE name = 'codeset'),
52- (SELECT feature_property_id FROM feature_property WHERE name = 'categories'),
56+ SELECT
57+ (SELECT feature_type_id FROM feature_type WHERE name = 'codeset' AND record_end_date IS NULL ),
58+ (SELECT feature_property_id FROM feature_property WHERE name = 'categories' AND record_end_date IS NULL ),
5359 true
60+ WHERE NOT EXISTS (
61+ SELECT 1 FROM feature_type_property ftp
62+ WHERE ftp.feature_type_id = (SELECT feature_type_id FROM feature_type WHERE name = 'codeset' AND record_end_date IS NULL)
63+ AND ftp.feature_property_id = (SELECT feature_property_id FROM feature_property WHERE name = 'categories' AND record_end_date IS NULL)
64+ AND ftp.record_end_date IS NULL
5465 );
5566
5667 ----------------------------------------------------------------------------------------
57- -- Insert partnership properties for dataset feature type
68+ -- Insert partnership properties for dataset feature type (idempotent)
5869 ----------------------------------------------------------------------------------------
59- INSERT INTO
70+ INSERT INTO
71+ feature_property (feature_property_type_id, name, display_name, description, calculated_value)
72+ SELECT (SELECT feature_property_type_id FROM feature_property_type WHERE name = 'array' AND record_end_date IS NULL),
73+ 'indigenous_partnerships',
74+ 'Indigenous Partnerships',
75+ 'An array of indigenous partnerships',
76+ false
77+ WHERE NOT EXISTS (
78+ SELECT 1 FROM feature_property
79+ WHERE name = 'indigenous_partnerships' AND record_end_date IS NULL
80+ );
81+
82+ INSERT INTO
6083 feature_property (feature_property_type_id, name, display_name, description, calculated_value)
61- VALUES
62- (
63- (SELECT feature_property_type_id FROM feature_property_type WHERE name = 'array'),
64- 'indigenous_partnerships',
65- 'Indigenous Partnerships',
66- 'An array of indigenous partnerships',
67- false
68- ),
69- (
70- (SELECT feature_property_type_id FROM feature_property_type WHERE name = 'array'),
71- 'stakeholder_partnerships',
72- 'Stakeholder Partnerships',
73- 'An array of stakeholder partnerships',
74- false
75- );
76-
77- ----------------------------------------------------------------------------------------
78- -- Link partnership properties to dataset feature type
79- ----------------------------------------------------------------------------------------
80- INSERT INTO
84+ SELECT (SELECT feature_property_type_id FROM feature_property_type WHERE name = 'array' AND record_end_date IS NULL),
85+ 'stakeholder_partnerships',
86+ 'Stakeholder Partnerships',
87+ 'An array of stakeholder partnerships',
88+ false
89+ WHERE NOT EXISTS (
90+ SELECT 1 FROM feature_property
91+ WHERE name = 'stakeholder_partnerships' AND record_end_date IS NULL
92+ );
93+
94+ ----------------------------------------------------------------------------------------
95+ -- Link partnership properties to dataset feature type (idempotent)
96+ ----------------------------------------------------------------------------------------
97+ INSERT INTO
8198 feature_type_property (feature_type_id, feature_property_id, required_value)
82- VALUES
83- (
84- (SELECT feature_type_id FROM feature_type WHERE name = 'dataset'),
85- (SELECT feature_property_id FROM feature_property WHERE name = 'indigenous_partnerships'),
86- false
87- ),
88- (
89- (SELECT feature_type_id FROM feature_type WHERE name = 'dataset'),
90- (SELECT feature_property_id FROM feature_property WHERE name = 'stakeholder_partnerships'),
91- false
92- );
99+ SELECT
100+ (SELECT feature_type_id FROM feature_type WHERE name = 'dataset' AND record_end_date IS NULL),
101+ (SELECT feature_property_id FROM feature_property WHERE name = 'indigenous_partnerships' AND record_end_date IS NULL),
102+ false
103+ WHERE NOT EXISTS (
104+ SELECT 1 FROM feature_type_property ftp
105+ WHERE ftp.feature_type_id = (SELECT feature_type_id FROM feature_type WHERE name = 'dataset' AND record_end_date IS NULL)
106+ AND ftp.feature_property_id = (SELECT feature_property_id FROM feature_property WHERE name = 'indigenous_partnerships' AND record_end_date IS NULL)
107+ AND ftp.record_end_date IS NULL
108+ );
109+
110+ INSERT INTO
111+ feature_type_property (feature_type_id, feature_property_id, required_value)
112+ SELECT
113+ (SELECT feature_type_id FROM feature_type WHERE name = 'dataset' AND record_end_date IS NULL),
114+ (SELECT feature_property_id FROM feature_property WHERE name = 'stakeholder_partnerships' AND record_end_date IS NULL),
115+ false
116+ WHERE NOT EXISTS (
117+ SELECT 1 FROM feature_type_property ftp
118+ WHERE ftp.feature_type_id = (SELECT feature_type_id FROM feature_type WHERE name = 'dataset' AND record_end_date IS NULL)
119+ AND ftp.feature_property_id = (SELECT feature_property_id FROM feature_property WHERE name = 'stakeholder_partnerships' AND record_end_date IS NULL)
120+ AND ftp.record_end_date IS NULL
121+ );
93122 ` ) ;
94123}
95124
0 commit comments