diff --git a/generators/bootstrap-application-server/types.d.ts b/generators/bootstrap-application-server/types.d.ts index b38850bd3e38..38b19313d87c 100644 --- a/generators/bootstrap-application-server/types.d.ts +++ b/generators/bootstrap-application-server/types.d.ts @@ -32,6 +32,10 @@ type DatabaseTypeSqlApplication = GenericDerivedProperty & prodDatabaseType: string; }; +export type LiquibaseApplication = DatabaseTypeSqlApplication & { + incrementalChangelog: boolean; +}; + type DatabaseTypeApplication = | DatabaseTypeSqlApplication | GenericDerivedProperty diff --git a/generators/database-changelog-liquibase/__snapshots__/incremental-liquibase.spec.mts.snap b/generators/database-changelog-liquibase/__snapshots__/incremental-liquibase.spec.mts.snap new file mode 100644 index 000000000000..43b1e2a6ec90 --- /dev/null +++ b/generators/database-changelog-liquibase/__snapshots__/incremental-liquibase.spec.mts.snap @@ -0,0 +1,2313 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`jhipster:app --incremental-changelog regenerating the application should match snapshot 1`] = ` +Object { + "src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +", + }, + "src/main/resources/config/liquibase/changelog/20200101000100_added_entity_One.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +", + }, + "src/main/resources/config/liquibase/changelog/20200101000200_added_entity_Another.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + + + + + +", + }, + "src/main/resources/config/liquibase/changelog/20200102000100_updated_entity_One.xml": Object { + "contents": null, + }, + "src/main/resources/config/liquibase/changelog/20200102000100_updated_entity_constraints_One.xml": Object { + "contents": null, + }, + "src/main/resources/config/liquibase/changelog/20200102000200_updated_entity_Another.xml": Object { + "contents": null, + }, + "src/main/resources/config/liquibase/changelog/20200102000200_updated_entity_constraints_Another.xml": Object { + "contents": null, + }, + "src/main/resources/config/liquibase/data/authority.csv": Object { + "contents": "name +ROLE_ADMIN +ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user.csv": Object { + "contents": "id;login;password_hash;first_name;last_name;email;image_url;activated;lang_key;created_by;last_modified_by +1;admin;$2a$10$gSAhZrxMllrbgj/kkK9UceBPpChGWJA7SYIb1Mqo.n5aNLq1/oRrC;Administrator;Administrator;admin@localhost;;true;en;system;system +2;user;$2a$10$VEjxo0jq2YG9Rbk2HmX9S.k1uZBGYUHdUcid3g/vfiEl7lwWgOH/K;User;User;user@localhost;;true;en;system;system +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user_authority.csv": Object { + "contents": "user_id;authority_name +1;ROLE_ADMIN +1;ROLE_USER +2;ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/fake-data/20200101000100_entity_one.csv": Object { + "contents": "id;original +1;Technician initiatives Vista +2;Personal Inverse Object-based +3;Florida Operations Optional +4;Branding +5;Directives Gorgeous Keyboard +6;mesh +7;Soft Alabama +8;Card cohesive Clothing +9;bottom-line +10;Interactions Licensed Turnpike +", + }, + "src/main/resources/config/liquibase/fake-data/20200101000200_entity_another.csv": Object { + "contents": "id;original +1;Berkshire transmitter +2;core channels +3;invoice +4;XML repurpose +5;Toys Computer +6;Montana Berkshire Jordanian +7;Organized Licensed +8;Bedfordshire +9;mint capacitor Intelligent +10;azure reinvent +", + }, + "src/main/resources/config/liquibase/master.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + +", + }, +} +`; + +exports[`jhipster:app --incremental-changelog when adding a field with constraints should match snapshot 1`] = ` +Object { + "src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +", + }, + "src/main/resources/config/liquibase/changelog/20200101000100_added_entity_Customer.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + + + + + +", + }, + "src/main/resources/config/liquibase/changelog/20200102000100_updated_entity_Customer.xml": Object { + "contents": " + + + + + + + + + + + + +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/changelog/20200102000100_updated_entity_constraints_Customer.xml": Object { + "contents": " + + + + + + + +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/changelog/20200102000100_updated_entity_migrate_Customer.xml": Object { + "contents": " + + + + + + + + + + + + + +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/authority.csv": Object { + "contents": "name +ROLE_ADMIN +ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user.csv": Object { + "contents": "id;login;password_hash;first_name;last_name;email;image_url;activated;lang_key;created_by;last_modified_by +1;admin;$2a$10$gSAhZrxMllrbgj/kkK9UceBPpChGWJA7SYIb1Mqo.n5aNLq1/oRrC;Administrator;Administrator;admin@localhost;;true;en;system;system +2;user;$2a$10$VEjxo0jq2YG9Rbk2HmX9S.k1uZBGYUHdUcid3g/vfiEl7lwWgOH/K;User;User;user@localhost;;true;en;system;system +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user_authority.csv": Object { + "contents": "user_id;authority_name +1;ROLE_ADMIN +1;ROLE_USER +2;ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/fake-data/20200101000100_entity_customer.csv": Object { + "contents": "id;original +1;Assistant +2;Market +3;program payment User-friendly +4;Team-oriented +5;index +6;auxiliary experiences +7;Sahara +8;Kong deposit +9;indexing Ball +10;users +", + }, + "src/main/resources/config/liquibase/fake-data/20200102000100_entity_customer.csv": Object { + "contents": "id;foo +1;Assistant +2;Market +3;program payment User-friendly +4;Team-oriented +5;index +6;auxiliary experiences +7;Sahara +8;Kong deposit +9;indexing Ball +10;users +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/master.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + + +", + "stateCleared": "modified", + }, +} +`; + +exports[`jhipster:app --incremental-changelog when adding a field without constraints should match snapshot 1`] = ` +Object { + "src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +", + }, + "src/main/resources/config/liquibase/changelog/20200101000100_added_entity_Customer.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + + + + + +", + }, + "src/main/resources/config/liquibase/changelog/20200102000100_updated_entity_Customer.xml": Object { + "contents": " + + + + + + + + + + + + +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/changelog/20200102000100_updated_entity_constraints_Customer.xml": Object { + "contents": null, + }, + "src/main/resources/config/liquibase/changelog/20200102000100_updated_entity_migrate_Customer.xml": Object { + "contents": " + + + + + + + + + + + + + +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/authority.csv": Object { + "contents": "name +ROLE_ADMIN +ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user.csv": Object { + "contents": "id;login;password_hash;first_name;last_name;email;image_url;activated;lang_key;created_by;last_modified_by +1;admin;$2a$10$gSAhZrxMllrbgj/kkK9UceBPpChGWJA7SYIb1Mqo.n5aNLq1/oRrC;Administrator;Administrator;admin@localhost;;true;en;system;system +2;user;$2a$10$VEjxo0jq2YG9Rbk2HmX9S.k1uZBGYUHdUcid3g/vfiEl7lwWgOH/K;User;User;user@localhost;;true;en;system;system +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user_authority.csv": Object { + "contents": "user_id;authority_name +1;ROLE_ADMIN +1;ROLE_USER +2;ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/fake-data/20200101000100_entity_customer.csv": Object { + "contents": "id;original +1;Assistant +2;Market +3;program payment User-friendly +4;Team-oriented +5;index +6;auxiliary experiences +7;Sahara +8;Kong deposit +9;indexing Ball +10;users +", + }, + "src/main/resources/config/liquibase/fake-data/20200102000100_entity_customer.csv": Object { + "contents": "id;foo +1;Assistant +2;Market +3;program payment User-friendly +4;Team-oriented +5;index +6;auxiliary experiences +7;Sahara +8;Kong deposit +9;indexing Ball +10;users +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/master.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + +", + "stateCleared": "modified", + }, +} +`; + +exports[`jhipster:app --incremental-changelog when adding a relationship should match snapshot 1`] = ` +Object { + "src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +", + }, + "src/main/resources/config/liquibase/changelog/20200101000100_added_entity_One.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + + + + + +", + }, + "src/main/resources/config/liquibase/changelog/20200101000200_added_entity_Another.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + + + + + +", + }, + "src/main/resources/config/liquibase/changelog/20200102000100_updated_entity_One.xml": Object { + "contents": " + + + + + + + + + + + + + +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/changelog/20200102000100_updated_entity_constraints_One.xml": Object { + "contents": " + + + + + + + + + + + + + +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/changelog/20200102000100_updated_entity_migrate_One.xml": Object { + "contents": " + + + + + + + + + + + + + +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/authority.csv": Object { + "contents": "name +ROLE_ADMIN +ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user.csv": Object { + "contents": "id;login;password_hash;first_name;last_name;email;image_url;activated;lang_key;created_by;last_modified_by +1;admin;$2a$10$gSAhZrxMllrbgj/kkK9UceBPpChGWJA7SYIb1Mqo.n5aNLq1/oRrC;Administrator;Administrator;admin@localhost;;true;en;system;system +2;user;$2a$10$VEjxo0jq2YG9Rbk2HmX9S.k1uZBGYUHdUcid3g/vfiEl7lwWgOH/K;User;User;user@localhost;;true;en;system;system +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user_authority.csv": Object { + "contents": "user_id;authority_name +1;ROLE_ADMIN +1;ROLE_USER +2;ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/fake-data/20200101000100_entity_one.csv": Object { + "contents": "id;original +1;Technician initiatives Vista +2;Personal Inverse Object-based +3;Florida Operations Optional +4;Branding +5;Directives Gorgeous Keyboard +6;mesh +7;Soft Alabama +8;Card cohesive Clothing +9;bottom-line +10;Interactions Licensed Turnpike +", + }, + "src/main/resources/config/liquibase/fake-data/20200102000100_entity_one.csv": Object { + "contents": "id +1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/master.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + + + +", + "stateCleared": "modified", + }, +} +`; + +exports[`jhipster:app --incremental-changelog when creating a new application should match snapshot 1`] = ` +Object { + "src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/authority.csv": Object { + "contents": "name +ROLE_ADMIN +ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user.csv": Object { + "contents": "id;login;password_hash;first_name;last_name;email;image_url;activated;lang_key;created_by;last_modified_by +1;admin;$2a$10$gSAhZrxMllrbgj/kkK9UceBPpChGWJA7SYIb1Mqo.n5aNLq1/oRrC;Administrator;Administrator;admin@localhost;;true;en;system;system +2;user;$2a$10$VEjxo0jq2YG9Rbk2HmX9S.k1uZBGYUHdUcid3g/vfiEl7lwWgOH/K;User;User;user@localhost;;true;en;system;system +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user_authority.csv": Object { + "contents": "user_id;authority_name +1;ROLE_ADMIN +1;ROLE_USER +2;ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/master.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + +", + "stateCleared": "modified", + }, +} +`; + +exports[`jhipster:app --incremental-changelog when incremental liquibase files exists with --recreate-initial-changelog should match snapshot 1`] = ` +Object { + "src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/authority.csv": Object { + "contents": "name +ROLE_ADMIN +ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user.csv": Object { + "contents": "id;login;password_hash;first_name;last_name;email;image_url;activated;lang_key;created_by;last_modified_by +1;admin;$2a$10$gSAhZrxMllrbgj/kkK9UceBPpChGWJA7SYIb1Mqo.n5aNLq1/oRrC;Administrator;Administrator;admin@localhost;;true;en;system;system +2;user;$2a$10$VEjxo0jq2YG9Rbk2HmX9S.k1uZBGYUHdUcid3g/vfiEl7lwWgOH/K;User;User;user@localhost;;true;en;system;system +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user_authority.csv": Object { + "contents": "user_id;authority_name +1;ROLE_ADMIN +1;ROLE_USER +2;ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/master.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + +", + "stateCleared": "modified", + }, +} +`; + +exports[`jhipster:app --incremental-changelog when incremental liquibase files exists with default options should match snapshot 1`] = ` +Object { + "src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml": Object { + "contents": "00000000000000_initial_schema.xml", + }, + "src/main/resources/config/liquibase/data/authority.csv": Object { + "contents": "name +ROLE_ADMIN +ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user.csv": Object { + "contents": "id;login;password_hash;first_name;last_name;email;image_url;activated;lang_key;created_by;last_modified_by +1;admin;$2a$10$gSAhZrxMllrbgj/kkK9UceBPpChGWJA7SYIb1Mqo.n5aNLq1/oRrC;Administrator;Administrator;admin@localhost;;true;en;system;system +2;user;$2a$10$VEjxo0jq2YG9Rbk2HmX9S.k1uZBGYUHdUcid3g/vfiEl7lwWgOH/K;User;User;user@localhost;;true;en;system;system +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user_authority.csv": Object { + "contents": "user_id;authority_name +1;ROLE_ADMIN +1;ROLE_USER +2;ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/master.xml": Object { + "contents": "master.xml", + }, +} +`; + +exports[`jhipster:app --incremental-changelog when removing a field with constraints should match snapshot 1`] = ` +Object { + "src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +", + }, + "src/main/resources/config/liquibase/changelog/20200101000100_added_entity_Customer.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +", + }, + "src/main/resources/config/liquibase/changelog/20200102000100_updated_entity_Customer.xml": Object { + "contents": " + + + + + + + + + + + + +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/changelog/20200102000100_updated_entity_constraints_Customer.xml": Object { + "contents": null, + }, + "src/main/resources/config/liquibase/data/authority.csv": Object { + "contents": "name +ROLE_ADMIN +ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user.csv": Object { + "contents": "id;login;password_hash;first_name;last_name;email;image_url;activated;lang_key;created_by;last_modified_by +1;admin;$2a$10$gSAhZrxMllrbgj/kkK9UceBPpChGWJA7SYIb1Mqo.n5aNLq1/oRrC;Administrator;Administrator;admin@localhost;;true;en;system;system +2;user;$2a$10$VEjxo0jq2YG9Rbk2HmX9S.k1uZBGYUHdUcid3g/vfiEl7lwWgOH/K;User;User;user@localhost;;true;en;system;system +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user_authority.csv": Object { + "contents": "user_id;authority_name +1;ROLE_ADMIN +1;ROLE_USER +2;ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/fake-data/20200101000100_entity_customer.csv": Object { + "contents": "id;original;foo +1;Assistant;Market +2;program payment User-friendly;Team-oriented +3;index;auxiliary experiences +4;Sahara;Kong deposit +5;indexing Ball;users +6;Directives Soft Implementation;partnerships Uzbekistan intelligence +7;Ergonomic Generic bluetooth;copying +8;multi-byte;Handmade violet +9;primary;Renminbi plum +10;Dollar calculate Chair;Cheese Loan Lead +", + }, + "src/main/resources/config/liquibase/master.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + +", + "stateCleared": "modified", + }, +} +`; + +exports[`jhipster:app --incremental-changelog when removing a field without constraints should match snapshot 1`] = ` +Object { + "src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +", + }, + "src/main/resources/config/liquibase/changelog/20200101000100_added_entity_Customer.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +", + }, + "src/main/resources/config/liquibase/changelog/20200102000100_updated_entity_Customer.xml": Object { + "contents": " + + + + + + + + + + + + +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/changelog/20200102000100_updated_entity_constraints_Customer.xml": Object { + "contents": null, + }, + "src/main/resources/config/liquibase/data/authority.csv": Object { + "contents": "name +ROLE_ADMIN +ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user.csv": Object { + "contents": "id;login;password_hash;first_name;last_name;email;image_url;activated;lang_key;created_by;last_modified_by +1;admin;$2a$10$gSAhZrxMllrbgj/kkK9UceBPpChGWJA7SYIb1Mqo.n5aNLq1/oRrC;Administrator;Administrator;admin@localhost;;true;en;system;system +2;user;$2a$10$VEjxo0jq2YG9Rbk2HmX9S.k1uZBGYUHdUcid3g/vfiEl7lwWgOH/K;User;User;user@localhost;;true;en;system;system +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/data/user_authority.csv": Object { + "contents": "user_id;authority_name +1;ROLE_ADMIN +1;ROLE_USER +2;ROLE_USER +", + "stateCleared": "modified", + }, + "src/main/resources/config/liquibase/fake-data/20200101000100_entity_customer.csv": Object { + "contents": "id;original;foo +1;Assistant;Market +2;program payment User-friendly;Team-oriented +3;index;auxiliary experiences +4;Sahara;Kong deposit +5;indexing Ball;users +6;Directives Soft Implementation;partnerships Uzbekistan intelligence +7;Ergonomic Generic bluetooth;copying +8;multi-byte;Handmade violet +9;primary;Renminbi plum +10;Dollar calculate Chair;Cheese Loan Lead +", + }, + "src/main/resources/config/liquibase/master.xml": Object { + "contents": " + + + + + + + + + + + + + + + + + + + + + +", + "stateCleared": "modified", + }, +} +`; diff --git a/generators/database-changelog-liquibase/files.js b/generators/database-changelog-liquibase/files.cjs similarity index 95% rename from generators/database-changelog-liquibase/files.js rename to generators/database-changelog-liquibase/files.cjs index 125b0efd1f1f..c9536d17ffcc 100644 --- a/generators/database-changelog-liquibase/files.js +++ b/generators/database-changelog-liquibase/files.cjs @@ -110,7 +110,7 @@ const fakeFiles = { interpolate: INTERPOLATE_REGEX, }, renameTo: generator => { - if (!generator.jhipsterConfig.incrementalChangelog || generator.configOptions.recreateInitialChangelog) { + if (!generator.incrementalChangelog || generator.recreateInitialChangelog) { return `config/liquibase/fake-data/${generator.entity.entityTableName}.csv`; } @@ -132,7 +132,7 @@ const fakeFiles = { { condition: generator => generator.entity.fieldsContainTextBlob === true, path: SERVER_MAIN_RES_DIR, - templates: [{ file: 'config/liquibase/fake-data/blob/hipster.txt' }], + templates: ['config/liquibase/fake-data/blob/hipster.txt'], }, ], }; diff --git a/generators/database-changelog-liquibase/generator.cjs b/generators/database-changelog-liquibase/generator.cjs new file mode 100644 index 000000000000..74ad9571fbd5 --- /dev/null +++ b/generators/database-changelog-liquibase/generator.cjs @@ -0,0 +1,411 @@ +/** + * Copyright 2013-2022 the original author or authors from the JHipster project. + * + * This file is part of the JHipster project, see https://www.jhipster.tech/ + * for more information. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +const assert = require('assert'); +const _ = require('lodash'); + +const BaseApplication = require('../base-application/generator.cjs'); +const { addEntityFiles, updateEntityFiles, updateConstraintsFiles, updateMigrateFiles, fakeFiles } = require('./files.cjs'); +const { stringify } = require('../../utils/index.js'); +const { CommonDBTypes } = require('../../jdl/jhipster/field-types.js'); +const { GENERATOR_DATABASE_CHANGELOG_LIQUIBASE, GENERATOR_BOOTSTRAP_APPLICATION_SERVER } = require('../generator-list.js'); + +const TYPE_LONG = CommonDBTypes.LONG; + +const constants = require('../generator-constants'); + +// TODO v8: Remove this constant +const { LIQUIBASE_DTD_VERSION } = constants; +const { prepareFieldForTemplates } = require('../../utils/field'); +const { prepareRelationshipForTemplates } = require('../../utils/relationship'); +const { prepareFieldForLiquibaseTemplates } = require('../../utils/liquibase'); + +module.exports = class DatabaseChangelogLiquibase extends BaseApplication { + constructor(args, options, features) { + super(args, options, features); + + if (this.options.help) return; + + assert(this.options.databaseChangelog, 'Changelog is required'); + this.databaseChangelog = this.options.databaseChangelog; + if (!this.databaseChangelog.changelogDate) { + this.databaseChangelog.changelogDate = this.dateFormatForLiquibase(); + } + + // Set number of rows to be generated + this.numberOfRows = 10; + this.entityChanges = {}; + } + + async _postConstruct() { + await this.dependsOnJHipster(GENERATOR_BOOTSTRAP_APPLICATION_SERVER); + if (!this.fromBlueprint) { + await this.composeWithBlueprints(GENERATOR_DATABASE_CHANGELOG_LIQUIBASE); + } + } + + get preparing() { + return this.asPreparingTaskGroup({ + prepareEntityForTemplates({ application }) { + const databaseChangelog = this.databaseChangelog; + const entity = this.configOptions.sharedEntities[databaseChangelog.entityName]; + if (!entity) { + throw new Error(`Shared entity ${databaseChangelog.entityName} was not found`); + } + this.entity = entity; + const entityChanges = this.entityChanges; + entityChanges.skipFakeData = application.skipFakeData || entity.skipFakeData; + + entityChanges.allFields = entity.fields + .filter(field => !field.transient) + .map(field => prepareFieldForLiquibaseTemplates(entity, field)); + + if (databaseChangelog.type === 'entity-new') { + entityChanges.fields = entityChanges.allFields; + } else { + entityChanges.addedFields = databaseChangelog.addedFields + .map(field => prepareFieldForTemplates(entity, field, this)) + .filter(field => !field.transient) + .map(field => prepareFieldForLiquibaseTemplates(entity, field)); + entityChanges.removedFields = databaseChangelog.removedFields + .map(field => prepareFieldForTemplates(entity, field, this)) + .filter(field => !field.transient) + .map(field => prepareFieldForLiquibaseTemplates(entity, field)); + } + }, + + prepareFakeData() { + const entity = this.entity; + const entityChanges = this.entityChanges; + const seed = `${entity.entityClass}-liquibase`; + this.resetEntitiesFakeData(seed); + + const databaseChangelog = this.databaseChangelog; + entity.liquibaseFakeData = []; + + // fakeDataCount must be limited to the size of required unique relationships. + Object.defineProperty(entity, 'fakeDataCount', { + get: () => { + const uniqueRelationships = entity.relationships.filter(rel => rel.unique && (rel.relationshipRequired || rel.id)); + return _.min([entity.liquibaseFakeData.length, ...uniqueRelationships.map(rel => rel.otherEntity.fakeDataCount)]); + }, + configurable: true, + }); + + for (let rowNumber = 0; rowNumber < this.numberOfRows; rowNumber++) { + const rowData = {}; + const fields = + databaseChangelog.type === 'entity-new' + ? // generate id fields first to improve reproducibility + [...entityChanges.fields.filter(f => f.id), ...entityChanges.fields.filter(f => !f.id)] + : [...entityChanges.allFields.filter(f => f.id), ...entityChanges.addedFields.filter(f => !f.id)]; + fields.forEach((field, idx) => { + if (field.derived) { + Object.defineProperty(rowData, field.fieldName, { + get: () => { + if (!field.derivedEntity.liquibaseFakeData || rowNumber >= field.derivedEntity.liquibaseFakeData.length) { + return undefined; + } + return field.derivedEntity.liquibaseFakeData[rowNumber][field.fieldName]; + }, + }); + return; + } + let data; + if (field.id && field.fieldType === TYPE_LONG) { + data = rowNumber + 1; + } else { + data = field.generateFakeData(); + } + rowData[field.fieldName] = data; + }); + + entity.liquibaseFakeData.push(rowData); + } + this.configOptions.sharedLiquibaseFakeData = this.configOptions.sharedLiquibaseFakeData || {}; + this.configOptions.sharedLiquibaseFakeData[_.upperFirst(entity.name)] = entity.liquibaseFakeData; + }, + }); + } + + get [BaseApplication.PREPARING]() { + if (this.delegateToBlueprint) return {}; + return this.preparing; + } + + get default() { + return { + prepareRelationshipsForTemplates() { + const entityChanges = this.entityChanges; + const databaseChangelog = this.databaseChangelog; + const entity = this.entity; + if (databaseChangelog.type === 'entity-new') { + entityChanges.relationships = entity.relationships.map(relationship => + this._prepareRelationshipForTemplates(entity, relationship) + ); + } else { + entityChanges.addedRelationships = databaseChangelog.addedRelationships + .map(relationship => { + const otherEntityName = this._.upperFirst(relationship.otherEntityName); + relationship.otherEntity = this.configOptions.sharedEntities[otherEntityName]; + if (!relationship.otherEntity) { + throw new Error(`Error at entity ${entity.name}: could not find the entity of the relationship ${stringify(relationship)}`); + } + return relationship; + }) + .map(relationship => prepareRelationshipForTemplates(entity, relationship, this)) + .map(relationship => this._prepareRelationshipForTemplates(entity, relationship)); + entityChanges.removedRelationships = databaseChangelog.removedRelationships + .map(relationship => { + const otherEntityName = this._.upperFirst(relationship.otherEntityName); + relationship.otherEntity = this.configOptions.oldSharedEntities[otherEntityName]; + if (!relationship.otherEntity) { + throw new Error(`Error at entity ${entity.name}: could not find the entity of the relationship ${stringify(relationship)}`); + } + return relationship; + }) + .map(relationship => prepareRelationshipForTemplates(entity, relationship, this, true)) + .map(relationship => this._prepareRelationshipForTemplates(entity, relationship)); + } + }, + setupConstants() { + // Make constants available in templates + // TODO v8: Remove this constant + this.LIQUIBASE_DTD_VERSION = LIQUIBASE_DTD_VERSION; + }, + }; + } + + get [BaseApplication.DEFAULT]() { + if (this.delegateToBlueprint) return {}; + return this.default; + } + + // Public API method used by the getter and also by Blueprints + get writingEntities() { + return { + writeLiquibaseFiles({ application }) { + const entity = this.entity; + if (entity.skipServer) { + return {}; + } + const entityChanges = this.entityChanges; + const databaseChangelog = this.databaseChangelog; + + /* Required by the templates */ + const writeContext = { + entity, + databaseChangelog, + changelogDate: databaseChangelog.changelogDate, + databaseType: entity.databaseType, + prodDatabaseType: entity.prodDatabaseType, + authenticationType: entity.authenticationType, + jhiPrefix: entity.jhiPrefix, + reactive: application.reactive, + incrementalChangelog: application.incrementalChangelog, + recreateInitialChangelog: this.configOptions.recreateInitialChangelog, + }; + + if (databaseChangelog.type === 'entity-new') { + return this._writeLiquibaseFiles(writeContext, entityChanges); + } + + entityChanges.requiresUpdateChangelogs = + entityChanges.addedFields.length > 0 || + entityChanges.removedFields.length > 0 || + entityChanges.addedRelationships.some( + relationship => relationship.shouldWriteRelationship || relationship.shouldWriteJoinTable + ) || + entityChanges.removedRelationships.some( + relationship => relationship.shouldWriteRelationship || relationship.shouldWriteJoinTable + ); + + if (entityChanges.requiresUpdateChangelogs) { + entityChanges.hasFieldConstraint = entityChanges.addedFields.some(field => field.unique || !field.nullable); + entityChanges.hasRelationshipConstraint = entityChanges.addedRelationships.some( + relationship => + (relationship.shouldWriteRelationship || relationship.shouldWriteJoinTable) && (relationship.unique || !relationship.nullable) + ); + entityChanges.shouldWriteAnyRelationship = entityChanges.addedRelationships.some( + relationship => relationship.shouldWriteRelationship || relationship.shouldWriteJoinTable + ); + + return this._writeUpdateFiles(writeContext, entityChanges); + } + return undefined; + }, + }; + } + + get [BaseApplication.WRITING_ENTITIES]() { + if (this.delegateToBlueprint) return {}; + if (this.options.skipWriting) { + return {}; + } + return this.writingEntities; + } + + // Public API method used by the getter and also by Blueprints + get postWritingEntities() { + return { + writeLiquibaseFiles({ application }) { + const entity = this.entity; + if (entity.skipServer) { + return {}; + } + const databaseChangelog = this.databaseChangelog; + const entityChanges = this.entityChanges; + + if (databaseChangelog.type === 'entity-new') { + return this._addLiquibaseFilesReferences(entity, databaseChangelog); + } + if (entityChanges.requiresUpdateChangelogs) { + return this._addUpdateFilesReferences(entity, databaseChangelog, entityChanges); + } + return undefined; + }, + }; + } + + get [BaseApplication.POST_WRITING_ENTITIES]() { + if (this.delegateToBlueprint) return {}; + if (this.options.skipWriting) { + return {}; + } + return this.postWritingEntities; + } + + /** + * Write files for new entities. + */ + _writeLiquibaseFiles(writeContext, entityChanges) { + const promises = []; + const context = { + ...writeContext, + skipFakeData: entityChanges.skipFakeData, + fields: entityChanges.allFields, + allFields: entityChanges.allFields, + relationships: entityChanges.relationships, + }; + // Write initial liquibase files + promises.push(this.writeFiles({ sections: addEntityFiles, context })); + if (!entityChanges.skipFakeData) { + promises.push(this.writeFiles({ sections: fakeFiles, context })); + } + + return Promise.all(promises); + } + + /** + * Write files for new entities. + */ + _addLiquibaseFilesReferences(entity, databaseChangelog) { + const fileName = `${databaseChangelog.changelogDate}_added_entity_${entity.entityClass}`; + if (entity.incremental) { + this.addIncrementalChangelogToLiquibase(fileName); + } else { + this.addChangelogToLiquibase(fileName); + } + + if (entity.fieldsContainOwnerManyToMany || entity.fieldsContainOwnerOneToOne || entity.fieldsContainManyToOne) { + const constFileName = `${databaseChangelog.changelogDate}_added_entity_constraints_${entity.entityClass}`; + if (entity.incremental) { + this.addIncrementalChangelogToLiquibase(constFileName); + } else { + this.addConstraintsChangelogToLiquibase(constFileName); + } + } + } + + /** + * Write files for updated entities. + */ + _writeUpdateFiles(writeContext, entityChanges) { + const { + addedFields, + allFields, + removedFields, + addedRelationships, + removedRelationships, + hasFieldConstraint, + hasRelationshipConstraint, + shouldWriteAnyRelationship, + } = entityChanges; + + const context = { + ...writeContext, + skipFakeData: entityChanges.skipFakeData, + addedFields, + removedFields, + fields: addedFields, + allFields, + hasFieldConstraint, + addedRelationships, + removedRelationships, + relationships: addedRelationships, + hasRelationshipConstraint, + shouldWriteAnyRelationship, + }; + + const promises = []; + promises.push(this.writeFiles({ sections: updateEntityFiles, context })); + + if (!entityChanges.skipFakeData && (entityChanges.addedFields.length > 0 || shouldWriteAnyRelationship)) { + promises.push(this.writeFiles({ sections: fakeFiles, context })); + promises.push(this.writeFiles({ sections: updateMigrateFiles, context })); + } + + if (hasFieldConstraint || shouldWriteAnyRelationship) { + promises.push(this.writeFiles({ sections: updateConstraintsFiles, context })); + } + return Promise.all(promises); + } + + /** + * Write files for updated entities. + */ + _addUpdateFilesReferences(entity, databaseChangelog, entityChanges) { + this.addIncrementalChangelogToLiquibase(`${databaseChangelog.changelogDate}_updated_entity_${entity.entityClass}`); + + if (!entityChanges.skipFakeData && (entityChanges.addedFields.length > 0 || entityChanges.shouldWriteAnyRelationship)) { + this.addIncrementalChangelogToLiquibase(`${databaseChangelog.changelogDate}_updated_entity_migrate_${entity.entityClass}`); + } + + if (entityChanges.hasFieldConstraint || entityChanges.shouldWriteAnyRelationship) { + this.addIncrementalChangelogToLiquibase(`${databaseChangelog.changelogDate}_updated_entity_constraints_${entity.entityClass}`); + } + } + + _prepareRelationshipForTemplates(entity, relationship) { + relationship.shouldWriteRelationship = + relationship.relationshipType === 'many-to-one' || + (relationship.relationshipType === 'one-to-one' && relationship.ownerSide === true); + + if (relationship.shouldWriteJoinTable) { + const joinTableName = relationship.joinTable.name; + const prodDatabaseType = entity.prodDatabaseType; + _.defaults(relationship.joinTable, { + constraintName: this.getFKConstraintName(joinTableName, entity.entityTableName, prodDatabaseType), + otherConstraintName: this.getFKConstraintName(joinTableName, relationship.columnName, prodDatabaseType), + }); + } + + relationship.columnDataType = relationship.otherEntity.columnType; + return relationship; + } +}; diff --git a/generators/database-changelog-liquibase/generator.spec.mjs b/generators/database-changelog-liquibase/generator.spec.mjs index f18ce6c28e3b..d593a27a72c0 100644 --- a/generators/database-changelog-liquibase/generator.spec.mjs +++ b/generators/database-changelog-liquibase/generator.spec.mjs @@ -22,7 +22,7 @@ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; import testSupport from '../../test/support/index.cjs'; -import Generator from './index.js'; +import Generator from './index.mjs'; const { snakeCase } = lodash; const { testBlueprintSupport } = testSupport; diff --git a/test/app/incremental-changelog.spec.js b/generators/database-changelog-liquibase/incremental-liquibase.spec.mts similarity index 65% rename from test/app/incremental-changelog.spec.js rename to generators/database-changelog-liquibase/incremental-liquibase.spec.mts index 90abdd7c1fb8..64494fa04a32 100644 --- a/test/app/incremental-changelog.spec.js +++ b/generators/database-changelog-liquibase/incremental-liquibase.spec.mts @@ -1,11 +1,18 @@ -const path = require('path'); -const fs = require('fs'); -const assert = require('yeoman-assert'); -const helpers = require('yeoman-test'); +import path, { basename, join } from 'path'; +import { jestExpect as expect } from 'mocha-expect-snapshot'; +import { existsSync, mkdirSync, writeFileSync } from 'fs'; +import { fileURLToPath } from 'url'; -const expectedFiles = require('../utils/expected-files'); -const { SERVER_MAIN_RES_DIR } = require('../../generators/generator-constants'); -const { createImporterFromContent } = require('../../jdl/jdl-importer'); +import { skipPrettierHelpers as helpers } from '../../test/utils/utils.mjs'; +import constants from '../generator-constants.js'; +import jdlImporter from '../../jdl/jdl-importer.js'; +import expectedFiles from '../../test/utils/expected-files.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +const { createImporterFromContent } = jdlImporter; +const { SERVER_MAIN_RES_DIR } = constants; const incrementalFiles = [ `${SERVER_MAIN_RES_DIR}config/liquibase/master.xml`, @@ -38,6 +45,8 @@ relationship ManyToOne { } `; +const generatorPath = join(__dirname, '../app/index.mjs'); + describe('jhipster:app --incremental-changelog', function () { this.timeout(45000); const options = { @@ -52,14 +61,8 @@ describe('jhipster:app --incremental-changelog', function () { }; context('when creating a new application', () => { let runResult; - before(() => { - return helpers - .create(path.join(__dirname, '../../generators/app')) - .withOptions(options) - .run() - .then(result => { - runResult = result; - }); + before(async () => { + runResult = await helpers.run(generatorPath).withOptions(options); }); after(() => runResult.cleanup()); @@ -71,29 +74,30 @@ describe('jhipster:app --incremental-changelog', function () { it('creates expected liquibase files', () => { runResult.assertFile(expectedFiles.liquibase); }); + + it('should match snapshot', () => { + expect(runResult.getSnapshot('**/src/main/resources/config/liquibase/**')).toMatchSnapshot(); + }); }); context('when incremental liquibase files exists', () => { context('with default options', () => { let runResult; - before(() => { - return helpers - .create(path.join(__dirname, '../../generators/app')) + before(async () => { + runResult = await helpers + .create(generatorPath) .withOptions(options) .doInDir(cwd => { incrementalFiles.forEach(filePath => { - filePath = path.join(cwd, filePath); + filePath = join(cwd, filePath); const dirname = path.dirname(filePath); - if (!fs.existsSync(dirname)) { - fs.mkdirSync(dirname, { recursive: true }); + if (!existsSync(dirname)) { + mkdirSync(dirname, { recursive: true }); } - fs.writeFileSync(filePath, filePath); + writeFileSync(filePath, basename(filePath)); }); }) - .run() - .then(result => { - runResult = result; - }); + .run(); }); after(() => runResult.cleanup()); @@ -108,31 +112,32 @@ describe('jhipster:app --incremental-changelog', function () { it('should not override existing incremental files', () => { incrementalFiles.forEach(filePath => { - runResult.assertFileContent(filePath, filePath); + runResult.assertFileContent(filePath, basename(filePath)); }); }); + + it('should match snapshot', () => { + expect(runResult.getSnapshot('**/src/main/resources/config/liquibase/**')).toMatchSnapshot(); + }); }); context('with --recreate-initial-changelog', () => { let runResult; - before(() => { - return helpers - .create(path.join(__dirname, '../../generators/app')) + before(async () => { + runResult = await helpers + .create(generatorPath) .withOptions({ ...options, recreateInitialChangelog: true }) .doInDir(cwd => { incrementalFiles.forEach(filePath => { - filePath = path.join(cwd, filePath); + filePath = join(cwd, filePath); const dirname = path.dirname(filePath); - if (!fs.existsSync(dirname)) { - fs.mkdirSync(dirname, { recursive: true }); + if (!existsSync(dirname)) { + mkdirSync(dirname, { recursive: true }); } - fs.writeFileSync(filePath, filePath); + writeFileSync(filePath, basename(filePath)); }); }) - .run() - .then(result => { - runResult = result; - }); + .run(); }); after(() => runResult.cleanup()); @@ -150,41 +155,40 @@ describe('jhipster:app --incremental-changelog', function () { runResult.assertNoFileContent(filePath, filePath); }); }); + + it('should match snapshot', () => { + expect(runResult.getSnapshot('**/src/main/resources/config/liquibase/**')).toMatchSnapshot(); + }); }); }); context('regenerating the application', () => { let runResult; - before(() => { - const state = createImporterFromContent(jdlApplicationWithRelationshipToUser, { + before(async () => { + const initialState = createImporterFromContent(jdlApplicationWithRelationshipToUser, { ...options, skipFileGeneration: true, creationTimestampConfig: options.creationTimestamp, }).import(); - const applicationWithEntities = state.exportedApplicationsWithEntities[baseName]; - assert(applicationWithEntities); - assert.equal(applicationWithEntities.entities.length, 2); - return helpers - .create(path.join(__dirname, '../../generators/app')) + const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; + expect(applicationWithEntities).toBeTruthy(); + expect(applicationWithEntities.entities.length).toBe(2); + runResult = await helpers + .create(generatorPath) .withOptions({ ...options, applicationWithEntities }) - .run() - .then(result => { - const state = createImporterFromContent(jdlApplicationWithRelationshipToUser, { - skipFileGeneration: true, - ...options, - }).import(); - return result - .create(path.join(__dirname, '../../generators/app')) - .withOptions({ - ...options, - applicationWithEntities: state.exportedApplicationsWithEntities.JhipsterApp, - creationTimestamp: '2020-01-02', - }) - .run() - .then(result => { - runResult = result; - }); - }); + .run(); + const state = createImporterFromContent(jdlApplicationWithRelationshipToUser, { + skipFileGeneration: true, + ...options, + }).import(); + runResult = await runResult + .create(generatorPath) + .withOptions({ + ...options, + applicationWithEntities: state.exportedApplicationsWithEntities.JhipsterApp, + creationTimestamp: '2020-01-02', + }) + .run(); }); after(() => runResult.cleanup()); @@ -193,7 +197,7 @@ describe('jhipster:app --incremental-changelog', function () { runResult.assertFile(['.yo-rc.json']); }); it('should create entity config file', () => { - runResult.assertFile([path.join('.jhipster', 'One.json'), path.join('.jhipster', 'Another.json')]); + runResult.assertFile([join('.jhipster', 'One.json'), join('.jhipster', 'Another.json')]); }); it('should create entity initial changelog', () => { runResult.assertFile([ @@ -215,13 +219,17 @@ describe('jhipster:app --incremental-changelog', function () { `${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200102000200_updated_entity_constraints_Another.xml`, ]); }); + + it('should match snapshot', () => { + expect(runResult.getSnapshot('**/src/main/resources/config/liquibase/**')).toMatchSnapshot(); + }); }); context('when adding a field without constraints', () => { let runResult; - before(() => { + before(async () => { const baseName = 'JhipsterApp'; - const state = createImporterFromContent( + const initialState = createImporterFromContent( ` ${jdlApplication} entity Customer { @@ -234,39 +242,35 @@ entity Customer { creationTimestampConfig: options.creationTimestamp, } ).import(); - const applicationWithEntities = state.exportedApplicationsWithEntities[baseName]; - assert(applicationWithEntities); - assert.equal(applicationWithEntities.entities.length, 1); - return helpers - .create(path.join(__dirname, '../../generators/app')) + const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; + expect(applicationWithEntities).toBeTruthy(); + expect(applicationWithEntities.entities.length).toBe(1); + runResult = await helpers + .create(generatorPath) .withOptions({ ...options, applicationWithEntities }) - .run() - .then(result => { - const state = createImporterFromContent( - ` + .run(); + + const state = createImporterFromContent( + ` ${jdlApplication} entity Customer { original String foo String } `, - { - skipFileGeneration: true, - ...options, - } - ).import(); - return result - .create(path.join(__dirname, '../../generators/app')) - .withOptions({ - ...options, - applicationWithEntities: state.exportedApplicationsWithEntities.JhipsterApp, - creationTimestamp: '2020-01-02', - }) - .run() - .then(result => { - runResult = result; - }); - }); + { + skipFileGeneration: true, + ...options, + } + ).import(); + runResult = await runResult + .create(generatorPath) + .withOptions({ + ...options, + applicationWithEntities: state.exportedApplicationsWithEntities.JhipsterApp, + creationTimestamp: '2020-01-02', + }) + .run(); }); after(() => runResult.cleanup()); @@ -275,7 +279,7 @@ entity Customer { runResult.assertFile(['.yo-rc.json']); }); it('should create entity config file', () => { - runResult.assertFile([path.join('.jhipster', 'Customer.json')]); + runResult.assertFile([join('.jhipster', 'Customer.json')]); }); it('should create entity initial changelog', () => { runResult.assertFile([`${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200101000100_added_entity_Customer.xml`]); @@ -301,13 +305,16 @@ entity Customer { it('should not create the entity constraint update changelog', () => { runResult.assertNoFile([`${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200102000100_updated_entity_constraints_Customer.xml`]); }); + it('should match snapshot', () => { + expect(runResult.getSnapshot('**/src/main/resources/config/liquibase/**')).toMatchSnapshot(); + }); }); context('when adding a field with constraints', () => { let runResult; - before(() => { + before(async () => { const baseName = 'JhipsterApp'; - const state = createImporterFromContent( + const initialState = createImporterFromContent( ` ${jdlApplication} entity Customer { @@ -320,39 +327,36 @@ entity Customer { creationTimestampConfig: options.creationTimestamp, } ).import(); - const applicationWithEntities = state.exportedApplicationsWithEntities[baseName]; - assert(applicationWithEntities); - assert.equal(applicationWithEntities.entities.length, 1); - return helpers - .create(path.join(__dirname, '../../generators/app')) + const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; + expect(applicationWithEntities).toBeTruthy(); + expect(applicationWithEntities.entities.length).toBe(1); + runResult = await helpers + .create(generatorPath) .withOptions({ ...options, applicationWithEntities }) - .run() - .then(result => { - const state = createImporterFromContent( - ` + .run(); + + const regenerateState = createImporterFromContent( + ` ${jdlApplication} entity Customer { - original String - foo String required + original String + foo String required } `, - { - skipFileGeneration: true, - ...options, - } - ).import(); - return result - .create(path.join(__dirname, '../../generators/app')) - .withOptions({ - ...options, - applicationWithEntities: state.exportedApplicationsWithEntities.JhipsterApp, - creationTimestamp: '2020-01-02', - }) - .run() - .then(result => { - runResult = result; - }); - }); + { + skipFileGeneration: true, + ...options, + } + ).import(); + + runResult = await runResult + .create(generatorPath) + .withOptions({ + ...options, + applicationWithEntities: regenerateState.exportedApplicationsWithEntities.JhipsterApp, + creationTimestamp: '2020-01-02', + }) + .run(); }); after(() => runResult.cleanup()); @@ -361,7 +365,7 @@ entity Customer { runResult.assertFile(['.yo-rc.json']); }); it('should create entity config file', () => { - runResult.assertFile([path.join('.jhipster', 'Customer.json')]); + runResult.assertFile([join('.jhipster', 'Customer.json')]); }); it('should create entity initial changelog', () => { runResult.assertFile([`${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200101000100_added_entity_Customer.xml`]); @@ -387,13 +391,16 @@ entity Customer { it('should create the entity constraint update changelog', () => { runResult.assertFile([`${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200102000100_updated_entity_constraints_Customer.xml`]); }); + it('should match snapshot', () => { + expect(runResult.getSnapshot('**/src/main/resources/config/liquibase/**')).toMatchSnapshot(); + }); }); context('when removing a field without constraints', () => { let runResult; - before(() => { + before(async () => { const baseName = 'JhipsterApp'; - const state = createImporterFromContent( + const initialState = createImporterFromContent( ` ${jdlApplication} entity Customer { @@ -407,38 +414,34 @@ entity Customer { creationTimestampConfig: options.creationTimestamp, } ).import(); - const applicationWithEntities = state.exportedApplicationsWithEntities[baseName]; - assert(applicationWithEntities); - assert.equal(applicationWithEntities.entities.length, 1); - return helpers - .create(path.join(__dirname, '../../generators/app')) + const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; + expect(applicationWithEntities).toBeTruthy(); + expect(applicationWithEntities.entities.length).toBe(1); + runResult = await helpers + .create(generatorPath) .withOptions({ ...options, applicationWithEntities }) - .run() - .then(result => { - const state = createImporterFromContent( - ` + .run(); + + const state = createImporterFromContent( + ` ${jdlApplication} entity Customer { original String } `, - { - skipFileGeneration: true, - ...options, - } - ).import(); - return result - .create(path.join(__dirname, '../../generators/app')) - .withOptions({ - ...options, - applicationWithEntities: state.exportedApplicationsWithEntities[baseName], - creationTimestamp: '2020-01-02', - }) - .run() - .then(result => { - runResult = result; - }); - }); + { + skipFileGeneration: true, + ...options, + } + ).import(); + runResult = await runResult + .create(generatorPath) + .withOptions({ + ...options, + applicationWithEntities: state.exportedApplicationsWithEntities[baseName], + creationTimestamp: '2020-01-02', + }) + .run(); }); after(() => runResult.cleanup()); @@ -447,7 +450,7 @@ entity Customer { runResult.assertFile(['.yo-rc.json']); }); it('should create entity config file', () => { - runResult.assertFile([path.join('.jhipster', 'Customer.json')]); + runResult.assertFile([join('.jhipster', 'Customer.json')]); }); it('should create entity initial changelog', () => { runResult.assertFile([`${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200101000100_added_entity_Customer.xml`]); @@ -473,13 +476,16 @@ entity Customer { it('should not create the entity constraint update changelog', () => { runResult.assertNoFile([`${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200102000100_updated_entity_constraints_Customer.xml`]); }); + it('should match snapshot', () => { + expect(runResult.getSnapshot('**/src/main/resources/config/liquibase/**')).toMatchSnapshot(); + }); }); context('when removing a field with constraints', () => { let runResult; - before(() => { + before(async () => { const baseName = 'JhipsterApp'; - const state = createImporterFromContent( + const initialState = createImporterFromContent( ` ${jdlApplication} entity Customer { @@ -493,38 +499,34 @@ entity Customer { creationTimestampConfig: options.creationTimestamp, } ).import(); - const applicationWithEntities = state.exportedApplicationsWithEntities[baseName]; - assert(applicationWithEntities); - assert.equal(applicationWithEntities.entities.length, 1); - return helpers - .create(path.join(__dirname, '../../generators/app')) + const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; + expect(applicationWithEntities).toBeTruthy(); + expect(applicationWithEntities.entities.length).toBe(1); + runResult = await helpers + .create(generatorPath) .withOptions({ ...options, applicationWithEntities }) - .run() - .then(result => { - const state = createImporterFromContent( - ` + .run(); + + const state = createImporterFromContent( + ` ${jdlApplication} entity Customer { original String } `, - { - skipFileGeneration: true, - ...options, - } - ).import(); - return result - .create(path.join(__dirname, '../../generators/app')) - .withOptions({ - ...options, - applicationWithEntities: state.exportedApplicationsWithEntities[baseName], - creationTimestamp: '2020-01-02', - }) - .run() - .then(result => { - runResult = result; - }); - }); + { + skipFileGeneration: true, + ...options, + } + ).import(); + runResult = await runResult + .create(generatorPath) + .withOptions({ + ...options, + applicationWithEntities: state.exportedApplicationsWithEntities[baseName], + creationTimestamp: '2020-01-02', + }) + .run(); }); after(() => runResult.cleanup()); @@ -533,7 +535,7 @@ entity Customer { runResult.assertFile(['.yo-rc.json']); }); it('should create entity config file', () => { - runResult.assertFile([path.join('.jhipster', 'Customer.json')]); + runResult.assertFile([join('.jhipster', 'Customer.json')]); }); it('should create entity initial changelog', () => { runResult.assertFile([`${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200101000100_added_entity_Customer.xml`]); @@ -559,49 +561,48 @@ entity Customer { it('should create the entity constraint update changelog', () => { runResult.assertNoFile([`${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200102000100_updated_entity_constraints_Customer.xml`]); }); + it('should match snapshot', () => { + expect(runResult.getSnapshot('**/src/main/resources/config/liquibase/**')).toMatchSnapshot(); + }); }); context('when adding a relationship', () => { let runResult; - before(() => { + before(async () => { const baseName = 'JhipsterApp'; - const state = createImporterFromContent(jdlApplicationWithEntities, { + const initialState = createImporterFromContent(jdlApplicationWithEntities, { ...options, skipFileGeneration: true, creationTimestampConfig: options.creationTimestamp, }).import(); - const applicationWithEntities = state.exportedApplicationsWithEntities[baseName]; - assert(applicationWithEntities); - assert.equal(applicationWithEntities.entities.length, 2); - return helpers - .create(path.join(__dirname, '../../generators/app')) + const applicationWithEntities = initialState.exportedApplicationsWithEntities[baseName]; + expect(applicationWithEntities).toBeTruthy(); + expect(applicationWithEntities.entities.length).toBe(2); + runResult = await helpers + .create(generatorPath) .withOptions({ ...options, applicationWithEntities }) - .run() - .then(result => { - const state = createImporterFromContent( - ` + .run(); + + const state = createImporterFromContent( + ` ${jdlApplicationWithEntities} relationship OneToOne { One to Another, } `, - { - skipFileGeneration: true, - ...options, - } - ).import(); - return result - .create(path.join(__dirname, '../../generators/app')) - .withOptions({ - ...options, - applicationWithEntities: state.exportedApplicationsWithEntities[baseName], - creationTimestamp: '2020-01-02', - }) - .run() - .then(result => { - runResult = result; - }); - }); + { + skipFileGeneration: true, + ...options, + } + ).import(); + runResult = await runResult + .create(generatorPath) + .withOptions({ + ...options, + applicationWithEntities: state.exportedApplicationsWithEntities[baseName], + creationTimestamp: '2020-01-02', + }) + .run(); }); after(() => runResult.cleanup()); @@ -610,7 +611,7 @@ relationship OneToOne { runResult.assertFile(['.yo-rc.json']); }); it('should create entity config file', () => { - runResult.assertFile([path.join('.jhipster', 'One.json'), path.join('.jhipster', 'Another.json')]); + runResult.assertFile([join('.jhipster', 'One.json'), join('.jhipster', 'Another.json')]); }); it('should create entity initial changelog', () => { runResult.assertFile([ @@ -636,5 +637,8 @@ relationship OneToOne { it('should create the entity constraint update changelog', () => { runResult.assertFile([`${SERVER_MAIN_RES_DIR}config/liquibase/changelog/20200102000100_updated_entity_constraints_One.xml`]); }); + it('should match snapshot', () => { + expect(runResult.getSnapshot('**/src/main/resources/config/liquibase/**')).toMatchSnapshot(); + }); }); }); diff --git a/generators/database-changelog-liquibase/index.js b/generators/database-changelog-liquibase/index.js deleted file mode 100644 index 22daf35a4d42..000000000000 --- a/generators/database-changelog-liquibase/index.js +++ /dev/null @@ -1,414 +0,0 @@ -/** - * Copyright 2013-2022 the original author or authors from the JHipster project. - * - * This file is part of the JHipster project, see https://www.jhipster.tech/ - * for more information. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -const assert = require('assert'); -const _ = require('lodash'); - -const BaseBlueprintGenerator = require('../generator-base-blueprint'); -const { - LOADING_PRIORITY, - PREPARING_PRIORITY, - DEFAULT_PRIORITY, - WRITING_PRIORITY, - PREPARING_RELATIONSHIPS_PRIORITY, - POST_WRITING_PRIORITY, -} = require('../../lib/constants/priorities.cjs').compat; -const { addEntityFiles, updateEntityFiles, updateConstraintsFiles, updateMigrateFiles, fakeFiles } = require('./files'); -const { SQL } = require('../../jdl/jhipster/database-types'); -const { stringify } = require('../../utils'); -const { CommonDBTypes } = require('../../jdl/jhipster/field-types'); -const { GENERATOR_DATABASE_CHANGELOG_LIQUIBASE } = require('../generator-list'); - -const TYPE_LONG = CommonDBTypes.LONG; - -const constants = require('../generator-constants'); - -// TODO v8: Remove this constant -const { LIQUIBASE_DTD_VERSION } = constants; -const { prepareFieldForTemplates } = require('../../utils/field'); -const { prepareRelationshipForTemplates } = require('../../utils/relationship'); -const { prepareFieldForLiquibaseTemplates } = require('../../utils/liquibase'); - -/** - * Base class for a generator that can be extended through a blueprint. - * - * @class - * @extends {BaseBlueprintGenerator} - */ -module.exports = class extends BaseBlueprintGenerator { - constructor(args, options, features) { - super(args, options, features); - - if (this.options.help) return; - - assert(this.options.databaseChangelog, 'Changelog is required'); - this.databaseChangelog = this.options.databaseChangelog; - if (!this.databaseChangelog.changelogDate) { - this.databaseChangelog.changelogDate = this.dateFormatForLiquibase(); - } - - // Set number of rows to be generated - this.numberOfRows = 10; - } - - async _postConstruct() { - if (!this.fromBlueprint) { - await this.composeWithBlueprints(GENERATOR_DATABASE_CHANGELOG_LIQUIBASE); - } - } - - _loading() { - return { - loadSharedConfig() { - this.loadAppConfig(); - this.loadDerivedAppConfig(); - this.loadClientConfig(); - this.loadDerivedClientConfig(); - this.loadServerConfig(); - this.loadTranslationConfig(); - this.loadPlatformConfig(); - }, - }; - } - - get [LOADING_PRIORITY]() { - if (this.delegateToBlueprint) return {}; - return this._loading(); - } - - _preparing() { - return { - prepareEntityForTemplates() { - const databaseChangelog = this.databaseChangelog; - this.entity = this.configOptions.sharedEntities[databaseChangelog.entityName]; - if (!this.entity) { - throw new Error(`Shared entity ${databaseChangelog.entityName} was not found`); - } - - this.allFields = this.entity.fields - .filter(field => !field.transient) - .map(field => prepareFieldForLiquibaseTemplates(this.entity, field)); - - if (databaseChangelog.type === 'entity-new') { - this.fields = this.allFields; - } else { - this.addedFields = this.databaseChangelog.addedFields - .map(field => prepareFieldForTemplates(this.entity, field, this)) - .filter(field => !field.transient) - .map(field => prepareFieldForLiquibaseTemplates(this.entity, field)); - this.removedFields = this.databaseChangelog.removedFields - .map(field => prepareFieldForTemplates(this.entity, field, this)) - .filter(field => !field.transient) - .map(field => prepareFieldForLiquibaseTemplates(this.entity, field)); - } - }, - - prepareFakeData() { - const databaseChangelog = this.databaseChangelog; - this.entity.liquibaseFakeData = []; - - // fakeDataCount must be limited to the size of required unique relationships. - Object.defineProperty(this.entity, 'fakeDataCount', { - get: () => { - const uniqueRelationships = this.entity.relationships.filter(rel => rel.unique && (rel.relationshipRequired || rel.id)); - return _.min([this.entity.liquibaseFakeData.length, ...uniqueRelationships.map(rel => rel.otherEntity.fakeDataCount)]); - }, - configurable: true, - }); - - for (let rowNumber = 0; rowNumber < this.numberOfRows; rowNumber++) { - const rowData = {}; - const fields = - databaseChangelog.type === 'entity-new' - ? // generate id fields first to improve reproducibility - [...this.fields.filter(f => f.id), ...this.fields.filter(f => !f.id)] - : [...this.allFields.filter(f => f.id), ...this.addedFields.filter(f => !f.id)]; - fields.forEach((field, idx) => { - if (field.derived) { - Object.defineProperty(rowData, field.fieldName, { - get: () => { - if (!field.derivedEntity.liquibaseFakeData || rowNumber >= field.derivedEntity.liquibaseFakeData.length) { - return undefined; - } - return field.derivedEntity.liquibaseFakeData[rowNumber][field.fieldName]; - }, - }); - return; - } - let data; - if (field.id && field.fieldType === TYPE_LONG) { - data = rowNumber + 1; - } else { - data = field.generateFakeData(); - } - rowData[field.fieldName] = data; - }); - - this.entity.liquibaseFakeData.push(rowData); - } - this.configOptions.sharedLiquibaseFakeData = this.configOptions.sharedLiquibaseFakeData || {}; - this.configOptions.sharedLiquibaseFakeData[_.upperFirst(this.entity.name)] = this.entity.liquibaseFakeData; - }, - }; - } - - get [PREPARING_PRIORITY]() { - if (this.delegateToBlueprint) return {}; - return this._preparing(); - } - - _preparingRelationships() { - return { - prepareRelationshipsForTemplates() { - const databaseChangelog = this.databaseChangelog; - if (databaseChangelog.type === 'entity-new') { - this.relationships = this.entity.relationships.map(relationship => - this._prepareRelationshipForTemplates(this.entity, relationship) - ); - } else { - this.addedRelationships = this.databaseChangelog.addedRelationships - .map(relationship => { - const otherEntityName = this._.upperFirst(relationship.otherEntityName); - relationship.otherEntity = this.configOptions.sharedEntities[otherEntityName]; - if (!relationship.otherEntity) { - throw new Error( - `Error at entity ${this.entity.name}: could not find the entity of the relationship ${stringify(relationship)}` - ); - } - return relationship; - }) - .map(relationship => prepareRelationshipForTemplates(this.entity, relationship, this)) - .map(relationship => this._prepareRelationshipForTemplates(this.entity, relationship)); - this.removedRelationships = this.databaseChangelog.removedRelationships - .map(relationship => { - const otherEntityName = this._.upperFirst(relationship.otherEntityName); - relationship.otherEntity = this.configOptions.oldSharedEntities[otherEntityName]; - if (!relationship.otherEntity) { - throw new Error( - `Error at entity ${this.entity.name}: could not find the entity of the relationship ${stringify(relationship)}` - ); - } - return relationship; - }) - .map(relationship => prepareRelationshipForTemplates(this.entity, relationship, this, true)) - .map(relationship => this._prepareRelationshipForTemplates(this.entity, relationship)); - } - }, - }; - } - - get [PREPARING_RELATIONSHIPS_PRIORITY]() { - if (this.delegateToBlueprint) return {}; - return this._preparingRelationships(); - } - - // Public API method used by the getter and also by Blueprints - _default() { - return { - setupConstants() { - // Make constants available in templates - // TODO v8: Remove this constant - this.LIQUIBASE_DTD_VERSION = LIQUIBASE_DTD_VERSION; - }, - }; - } - - get [DEFAULT_PRIORITY]() { - if (this.delegateToBlueprint) return {}; - return this._default(); - } - - // Public API method used by the getter and also by Blueprints - _writing() { - return { - writeLiquibaseFiles() { - const config = this.jhipsterConfig; - if (config.skipServer || this.entity.skipServer || config.databaseType !== SQL) { - return undefined; - } - - const databaseChangelog = this.databaseChangelog; - - /* Required by the templates */ - Object.assign(this, { - databaseChangelog, - changelogDate: databaseChangelog.changelogDate, - databaseType: this.entity.databaseType, - prodDatabaseType: this.entity.prodDatabaseType, - authenticationType: this.entity.authenticationType, - jhiPrefix: this.entity.jhiPrefix, - skipFakeData: this.entity.skipFakeData || config.skipFakeData, - reactive: config.reactive, - }); - - if (databaseChangelog.type === 'entity-new') { - return this._writeLiquibaseFiles(); - } - if ( - this.addedFields.length > 0 || - this.removedFields.length > 0 || - this.addedRelationships.some(relationship => relationship.shouldWriteRelationship || relationship.shouldWriteJoinTable) || - this.removedRelationships.some(relationship => relationship.shouldWriteRelationship || relationship.shouldWriteJoinTable) - ) { - return this._writeUpdateFiles(); - } - return undefined; - }, - }; - } - - get [WRITING_PRIORITY]() { - if (this.delegateToBlueprint) return {}; - if (this.options.skipWriting) { - return {}; - } - return this._writing(); - } - - // Public API method used by the getter and also by Blueprints - _postWriting() { - return { - writeLiquibaseFiles() { - const config = this.jhipsterConfig; - if (config.skipServer || this.entity.skipServer || config.databaseType !== SQL) { - return undefined; - } - - if (this.databaseChangelog.type === 'entity-new') { - return this._addLiquibaseFilesReferences(); - } - if ( - this.addedFields.length > 0 || - this.removedFields.length > 0 || - this.addedRelationships.some(relationship => relationship.shouldWriteRelationship || relationship.shouldWriteJoinTable) || - this.removedRelationships.some(relationship => relationship.shouldWriteRelationship || relationship.shouldWriteJoinTable) - ) { - return this._addUpdateFilesReferences(); - } - return undefined; - }, - }; - } - - get [POST_WRITING_PRIORITY]() { - if (this.delegateToBlueprint) return {}; - if (this.options.skipWriting) { - return {}; - } - return this._postWriting(); - } - - /** - * Write files for new entities. - */ - _writeLiquibaseFiles() { - const promises = []; - // Write initial liquibase files - promises.push(this.writeFiles({ sections: addEntityFiles })); - if (!this.skipFakeData) { - promises.push(this.writeFiles({ sections: fakeFiles })); - } - - return Promise.all(promises); - } - - /** - * Write files for new entities. - */ - _addLiquibaseFilesReferences() { - const fileName = `${this.changelogDate}_added_entity_${this.entity.entityClass}`; - if (this.incremental) { - this.addIncrementalChangelogToLiquibase(fileName); - } else { - this.addChangelogToLiquibase(fileName); - } - - if (this.entity.fieldsContainOwnerManyToMany || this.entity.fieldsContainOwnerOneToOne || this.entity.fieldsContainManyToOne) { - const constFileName = `${this.changelogDate}_added_entity_constraints_${this.entity.entityClass}`; - if (this.incremental) { - this.addIncrementalChangelogToLiquibase(constFileName); - } else { - this.addConstraintsChangelogToLiquibase(constFileName); - } - } - } - - /** - * Write files for updated entities. - */ - _writeUpdateFiles() { - this.hasFieldConstraint = this.addedFields.some(field => field.unique || !field.nullable); - this.hasRelationshipConstraint = this.addedRelationships.some( - relationship => - (relationship.shouldWriteRelationship || relationship.shouldWriteJoinTable) && (relationship.unique || !relationship.nullable) - ); - this.shouldWriteAnyRelationship = this.addedRelationships.some( - relationship => relationship.shouldWriteRelationship || relationship.shouldWriteJoinTable - ); - - const promises = []; - promises.push(this.writeFiles({ sections: updateEntityFiles })); - - if (!this.skipFakeData && (this.addedFields.length > 0 || this.shouldWriteAnyRelationship)) { - this.fields = this.addedFields; - this.relationships = this.addedRelationships; - promises.push(this.writeFiles({ sections: fakeFiles })); - promises.push(this.writeFiles({ sections: updateMigrateFiles })); - } - - if (this.hasFieldConstraint || this.shouldWriteAnyRelationship) { - promises.push(this.writeFiles({ sections: updateConstraintsFiles })); - } - return Promise.all(promises); - } - - /** - * Write files for updated entities. - */ - _addUpdateFilesReferences() { - this.addIncrementalChangelogToLiquibase(`${this.databaseChangelog.changelogDate}_updated_entity_${this.entity.entityClass}`); - - if (!this.skipFakeData && (this.addedFields.length > 0 || this.shouldWriteAnyRelationship)) { - this.addIncrementalChangelogToLiquibase(`${this.databaseChangelog.changelogDate}_updated_entity_migrate_${this.entity.entityClass}`); - } - - if (this.hasFieldConstraint || this.shouldWriteAnyRelationship) { - this.addIncrementalChangelogToLiquibase( - `${this.databaseChangelog.changelogDate}_updated_entity_constraints_${this.entity.entityClass}` - ); - } - } - - _prepareRelationshipForTemplates(entity, relationship) { - relationship.shouldWriteRelationship = - relationship.relationshipType === 'many-to-one' || - (relationship.relationshipType === 'one-to-one' && relationship.ownerSide === true); - - if (relationship.shouldWriteJoinTable) { - const joinTableName = relationship.joinTable.name; - const prodDatabaseType = entity.prodDatabaseType; - _.defaults(relationship.joinTable, { - constraintName: this.getFKConstraintName(joinTableName, entity.entityTableName, prodDatabaseType), - otherConstraintName: this.getFKConstraintName(joinTableName, relationship.columnName, prodDatabaseType), - }); - } - - relationship.columnDataType = relationship.otherEntity.columnType; - return relationship; - } -}; diff --git a/generators/database-changelog-liquibase/index.mjs b/generators/database-changelog-liquibase/index.mjs index f40fb4c80608..3402215ea0d2 100644 --- a/generators/database-changelog-liquibase/index.mjs +++ b/generators/database-changelog-liquibase/index.mjs @@ -16,5 +16,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { default } from './index.js'; -export { addEntityFiles, updateEntityFiles, updateConstraintsFiles, updateMigrateFiles, fakeFiles } from './files.js'; +export { default } from './generator.cjs'; +export { addEntityFiles, updateEntityFiles, updateConstraintsFiles, updateMigrateFiles, fakeFiles } from './files.cjs'; diff --git a/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity.xml.ejs b/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity.xml.ejs index 429d9c675c75..7f8b72ae302d 100644 --- a/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity.xml.ejs +++ b/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity.xml.ejs @@ -28,9 +28,9 @@ Added the entity <%= entity.entityClass %>. --> - > + > <%_ for (field of fields) { _%> - <% if (field.id && field.liquibaseAutoIncrement) { %> autoIncrement="true" <%_ } %>> + <% if (field.id && field.liquibaseAutoIncrement) { %> autoIncrement="true" <%_ } %>> <%_ if (field.id) { _%> <%_ } else if (field.unique) { _%> @@ -49,7 +49,7 @@ if ((relationship.relationshipType === 'many-to-one' || (relationship.relationshipType === 'one-to-one' && relationship.ownerSide === true)) && !relationship.id) { relationship.otherEntity.primaryKey.fields.forEach(idField => { - const uniqueConstraintName = relationship.relationshipType === 'one-to-one' ? getUXConstraintName(entity.entityTableName, relationship.columnName + '_' + idField.columnName, entity.prodDatabaseType) : null; + const uniqueConstraintName = relationship.relationshipType === 'one-to-one' ? this.getUXConstraintName(entity.entityTableName, relationship.columnName + '_' + idField.columnName, entity.prodDatabaseType) : null; _%> unique="true" uniqueConstraintName="<%= uniqueConstraintName %>"<% } %> /> diff --git a/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity_constraints.xml.ejs b/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity_constraints.xml.ejs index 149586940452..68f9f8b59003 100644 --- a/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity_constraints.xml.ejs +++ b/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/added_entity_constraints.xml.ejs @@ -31,15 +31,15 @@ ownerSide = relationship.ownerSide, otherEntityTableName = relationship.otherEntityTableName; if (relationshipType === 'many-to-one' || (relationshipType === 'one-to-one' && ownerSide)) { - const constraintName = getFKConstraintName(entity.entityTableName, relationshipName, prodDatabaseType); + const constraintName = this.getFKConstraintName(entity.entityTableName, relationshipName, prodDatabaseType); let baseColumnNames; let referencedColumnNames; if (relationshipType === 'one-to-one' && ownerSide && relationship.id === true) { - baseColumnNames = relationship.otherEntity.primaryKey.fields.map(field => getColumnName(field.columnName)).join(','); - referencedColumnNames = relationship.otherEntity.primaryKey.fields.map(field => getColumnName(field.columnName)).join(','); + baseColumnNames = relationship.otherEntity.primaryKey.fields.map(field => this.getColumnName(field.columnName)).join(','); + referencedColumnNames = relationship.otherEntity.primaryKey.fields.map(field => this.getColumnName(field.columnName)).join(','); } else if (relationship.otherEntity) { - baseColumnNames = relationship.otherEntity.primaryKey.fields.map(field => getColumnName(relationshipName + '_' + field.columnName)).join(','); - referencedColumnNames = relationship.otherEntity.primaryKey.fields.map(field => getColumnName(field.columnName)).join(','); + baseColumnNames = relationship.otherEntity.primaryKey.fields.map(field => this.getColumnName(relationshipName + '_' + field.columnName)).join(','); + referencedColumnNames = relationship.otherEntity.primaryKey.fields.map(field => this.getColumnName(field.columnName)).join(','); } %> <%_ for (field of addedFields) { _%> - /> + /> <%_ if (field.shouldCreateContentType) { _%> <%_ } @@ -136,7 +136,7 @@ if (removedRelationships && removedRelationships.length) { for (relationship of removedRelationships) { if (relationship.shouldWriteRelationship) { _%> - + <%_ } } /* ======== End dropForeignKeyConstraint ======== */ _%> diff --git a/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/updated_entity_constraints.xml.ejs b/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/updated_entity_constraints.xml.ejs index 76e10a459c12..8fc111392da7 100644 --- a/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/updated_entity_constraints.xml.ejs +++ b/generators/database-changelog-liquibase/templates/src/main/resources/config/liquibase/changelog/updated_entity_constraints.xml.ejs @@ -63,7 +63,7 @@ if (hasFieldConstraint) { _%> const relationshipData = addedRelationships[idx]; if (relationshipData.unique) { const idField = relationship.otherEntity.primaryKey.ownFields[0]; - const uniqueConstraintName = relationshipData.relationshipType === 'one-to-one' ? getUXConstraintName(entity.entityTableName, relationshipData.columnName + '_' + idField.columnName, entity.prodDatabaseType) : null; + const uniqueConstraintName = relationshipData.relationshipType === 'one-to-one' ? this.getUXConstraintName(entity.entityTableName, relationshipData.columnName + '_' + idField.columnName, entity.prodDatabaseType) : null; _%> const relationship = addedRelationships[idx]; relationshipName = relationship.relationshipName; if (relationship.shouldWriteRelationship) { - const constraintName = getFKConstraintName(entityTableName, relationshipName, prodDatabaseType); - let baseColumnName = getColumnName(relationshipName) + '_id'; + const constraintName = this.getFKConstraintName(entityTableName, relationshipName, prodDatabaseType); + let baseColumnName = this.getColumnName(relationshipName) + '_id'; if (relationship.relationshipType === 'one-to-one' && relationship.id === true) { baseColumnName = 'id'; } @@ -100,8 +100,8 @@ if (hasFieldConstraint) { _%> referencedColumnNames="id" referencedTableName="<%= relationship.otherEntityTableName %>"/> <%_ } else if (relationship.shouldWriteJoinTable) { - const constraintName = getFKConstraintName(relationship.joinTable.name, getColumnName(entityTableName), prodDatabaseType); - const otherEntityConstraintName = getFKConstraintName(relationship.joinTable.name, getColumnName(relationshipName), prodDatabaseType); + const constraintName = this.getFKConstraintName(relationship.joinTable.name, this.getColumnName(entityTableName), prodDatabaseType); + const otherEntityConstraintName = this.getFKConstraintName(relationship.joinTable.name, this.getColumnName(relationshipName), prodDatabaseType); _%> <%_ } diff --git a/generators/database-changelog/index.js b/generators/database-changelog/generator.mts similarity index 61% rename from generators/database-changelog/index.js rename to generators/database-changelog/generator.mts index e8f38c4473b1..497c57a1d960 100644 --- a/generators/database-changelog/index.js +++ b/generators/database-changelog/generator.mts @@ -16,13 +16,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -const fs = require('fs'); +import fs from 'fs'; -const BaseBlueprintGenerator = require('../generator-base-blueprint'); -const { DEFAULT_PRIORITY } = require('../../lib/constants/priorities.cjs').compat; +import BaseApplication from '../base-application/index.mjs'; +import type { DefaultTaskGroup } from '../base-application/tasks.js'; +import type { LiquibaseApplication } from '../bootstrap-application-server/types.js'; +import constants from '../generator-constants.js'; +import { + GENERATOR_DATABASE_CHANGELOG, + GENERATOR_DATABASE_CHANGELOG_LIQUIBASE, + GENERATOR_BOOTSTRAP_APPLICATION_SERVER, +} from '../generator-list.mjs'; -const { JHIPSTER_CONFIG_DIR } = require('../generator-constants'); -const { GENERATOR_DATABASE_CHANGELOG, GENERATOR_DATABASE_CHANGELOG_LIQUIBASE } = require('../generator-list'); +const { JHIPSTER_CONFIG_DIR } = constants; const BASE_CHANGELOG = { addedFields: [], @@ -31,13 +37,12 @@ const BASE_CHANGELOG = { removedRelationships: [], }; -/* eslint-disable consistent-return */ -module.exports = class extends BaseBlueprintGenerator { - constructor(args, options, features) { +export default class DatabaseChangelogGenerator extends BaseApplication { + constructor(args: any, options: any, features: any) { super(args, options, { unique: 'namespace', ...features }); this.argument('entities', { - desc: 'Which entities to generate a new changelog', + description: 'Which entities to generate a new changelog', type: Array, required: false, }); @@ -50,55 +55,49 @@ module.exports = class extends BaseBlueprintGenerator { } async _postConstruct() { + this.dependsOnJHipster(GENERATOR_BOOTSTRAP_APPLICATION_SERVER); if (!this.fromBlueprint) { await this.composeWithBlueprints(GENERATOR_DATABASE_CHANGELOG); } } - _default() { + override get default(): DefaultTaskGroup { return { - async calculateChangelogs() { - const diff = this._generateChangelogFromFiles(); - - await Promise.all( - diff.map(([fieldChanges, _relationshipChanges]) => { - if (fieldChanges.type === 'entity-new') { - return this._composeWithIncrementalChangelogProvider(fieldChanges); - } - if (fieldChanges.addedFields.length > 0 || fieldChanges.removedFields.length > 0) { - return this._composeWithIncrementalChangelogProvider(fieldChanges); - } - return undefined; - }) - ); - - await Promise.all( - diff.map(([_fieldChanges, relationshipChanges]) => { - if ( - relationshipChanges && - relationshipChanges.incremental && - (relationshipChanges.addedRelationships.length > 0 || relationshipChanges.removedRelationships.length > 0) - ) { - return this._composeWithIncrementalChangelogProvider(relationshipChanges); - } - return undefined; - }) - ); + async calculateChangelogs({ application }) { + const diffs = this._generateChangelogFromFiles(application); + for (const [fieldChanges] of diffs) { + if (fieldChanges.type === 'entity-new') { + await this._composeWithIncrementalChangelogProvider(fieldChanges); + } + if (fieldChanges.addedFields.length > 0 || fieldChanges.removedFields.length > 0) { + await this._composeWithIncrementalChangelogProvider(fieldChanges); + } + } + // eslint-disable-next-line no-unused-vars + for (const [_fieldChanges, relationshipChanges] of diffs) { + if ( + relationshipChanges && + relationshipChanges.incremental && + (relationshipChanges.addedRelationships.length > 0 || relationshipChanges.removedRelationships.length > 0) + ) { + await this._composeWithIncrementalChangelogProvider(relationshipChanges); + } + } }, }; } - get [DEFAULT_PRIORITY]() { + get [BaseApplication.DEFAULT]() { if (this.delegateToBlueprint) return {}; - return this._default(); + return this.default; } /* ======================================================================== */ /* private methods use within generator */ /* ======================================================================== */ - _composeWithIncrementalChangelogProvider(databaseChangelog) { - const skipWriting = this.options.skipWriting || !this.options.entities.includes(databaseChangelog.entityName); + _composeWithIncrementalChangelogProvider(databaseChangelog: any) { + const skipWriting = this.options.entities.length !== 0 && !this.options.entities.includes(databaseChangelog.entityName); return this.composeWithJHipster(GENERATOR_DATABASE_CHANGELOG_LIQUIBASE, { databaseChangelog, skipWriting, @@ -109,18 +108,18 @@ module.exports = class extends BaseBlueprintGenerator { /** * Generate changelog from differences between the liquibase entity and current entity. */ - _generateChangelogFromFiles() { + _generateChangelogFromFiles(application: LiquibaseApplication) { // Compare entity changes and create changelogs return this.getExistingEntityNames().map(entityName => { const filename = this.destinationPath(JHIPSTER_CONFIG_DIR, `${entityName}.json`); - const newConfig = this.fs.readJSON(filename); - const newFields = (newConfig.fields || []).filter(field => !field.transient); - const newRelationships = newConfig.relationships || []; + const newConfig: any = this.fs.readJSON(filename); + const newFields: any[] = (newConfig.fields || []).filter((field: any) => !field.transient); + const newRelationships: any[] = newConfig.relationships || []; if ( this.configOptions.recreateInitialChangelog || - !this.jhipsterConfig.incrementalChangelog || + !application.incrementalChangelog || !fs.existsSync(filename) || !fs.existsSync( this.destinationPath(`src/main/resources/config/liquibase/changelog/${newConfig.changelogDate}_added_entity_${entityName}.xml`) @@ -136,15 +135,15 @@ module.exports = class extends BaseBlueprintGenerator { }, ]; } - this._debug(`Calculating diffs for ${entityName}`); + (this as any)._debug(`Calculating diffs for ${entityName}`); - const oldConfig = JSON.parse(fs.readFileSync(filename)); + const oldConfig: any = JSON.parse(fs.readFileSync(filename) as any); // Share old entity this.configOptions.oldSharedEntities[entityName] = oldConfig; - const oldFields = (oldConfig.fields || []).filter(field => !field.transient); - const oldFieldNames = oldFields.map(field => field.fieldName); - const newFieldNames = newFields.map(field => field.fieldName); + const oldFields: any[] = (oldConfig.fields || []).filter((field: any) => !field.transient); + const oldFieldNames: string[] = oldFields.map(field => field.fieldName); + const newFieldNames: string[] = newFields.map(field => field.fieldName); // Calculate new fields const addedFieldNames = newFieldNames.filter(fieldName => !oldFieldNames.includes(fieldName)); @@ -154,7 +153,7 @@ module.exports = class extends BaseBlueprintGenerator { const removedFields = removedFieldNames.map(fieldName => oldFields.find(field => fieldName === field.fieldName)); const newRelationshipNames = newRelationships.map(relationship => relationship.relationshipName); - const oldRelationships = oldConfig.relationships || []; + const oldRelationships: any[] = oldConfig.relationships || []; const oldRelationshipNames = oldRelationships.map(relationship => relationship.relationshipName); // Calculate new relationships @@ -174,4 +173,4 @@ module.exports = class extends BaseBlueprintGenerator { ]; }); } -}; +} diff --git a/generators/database-changelog/generator.spec.mjs b/generators/database-changelog/generator.spec.mts similarity index 97% rename from generators/database-changelog/generator.spec.mjs rename to generators/database-changelog/generator.spec.mts index f18ce6c28e3b..91ef135a9f9f 100644 --- a/generators/database-changelog/generator.spec.mjs +++ b/generators/database-changelog/generator.spec.mts @@ -22,7 +22,7 @@ import { basename, dirname } from 'path'; import { fileURLToPath } from 'url'; import testSupport from '../../test/support/index.cjs'; -import Generator from './index.js'; +import Generator from './generator.mjs'; const { snakeCase } = lodash; const { testBlueprintSupport } = testSupport; diff --git a/generators/database-changelog/index.mjs b/generators/database-changelog/index.mts similarity index 94% rename from generators/database-changelog/index.mjs rename to generators/database-changelog/index.mts index ff40fdd754bd..4aff6a0f21ae 100644 --- a/generators/database-changelog/index.mjs +++ b/generators/database-changelog/index.mts @@ -16,4 +16,4 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export { default } from './index.js'; +export { default } from './generator.mjs'; diff --git a/lib/constants/priorities.cjs b/lib/constants/priorities.cjs index 8db78a2aea0e..ebbfcd56cde0 100644 --- a/lib/constants/priorities.cjs +++ b/lib/constants/priorities.cjs @@ -303,7 +303,7 @@ const CUSTOM_PRIORITIES_ENTITIES = [ { priorityName: POST_WRITING_ENTITIES, queueName: POST_WRITING_ENTITIES_QUEUE, - before: POST_WRITING, + before: PRE_CONFLICTS, skip: true, }, ].reverse();