-
Notifications
You must be signed in to change notification settings - Fork 615
add addMissingSchemaFields task #5101
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
b96e13e
4beeed2
c15a6e7
80a96aa
64576d9
eb623ec
4a6802a
8b81ab0
2bcf377
f33d52f
ba9d6b1
21a722a
90bc5f7
05e3214
a50f9ab
5580277
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,13 +14,52 @@ | |
| // is difficult to guarantee, you may wish to write a task instead. | ||
|
|
||
| module.exports = { | ||
| options: { alias: 'migration' }, | ||
| options: { | ||
| alias: 'migration', | ||
| skipMigrationTasks: [ | ||
| '@apostrophecms/migration:add-missing-schema-fields' | ||
| ] | ||
| }, | ||
| async init(self) { | ||
| self.migrations = []; | ||
| await self.enableCollection(); | ||
| }, | ||
| handlers(self) { | ||
| return { | ||
| 'apostrophe:modulesRegistered': { | ||
| setSkipMigration() { | ||
| if ( | ||
| self.apos.isTask() && | ||
| self.options.skipMigrationTasks.includes(self.apos.argv._.at(0)) | ||
| ) { | ||
| self.apos.skipMigration = true; | ||
| } | ||
| } | ||
| }, | ||
| before: { | ||
| async addMissingSchemaFields() { | ||
| await self.addMissingSchemaFields(); | ||
| } | ||
| }, | ||
| after: { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see why you did this, but previously, these "requirements" were guaranteed to come last, even after the So, please make them individual handlers on a new |
||
| async requirements() { | ||
| // Inserts the global doc in the default locale if it does not exist; | ||
| // same for other singleton piece types registered by other modules | ||
| for (const apostropheModule of Object.values(self.apos.modules)) { | ||
| if ( | ||
| self.apos.instanceOf(apostropheModule, '@apostrophecms/piece-type') && | ||
| apostropheModule.options.singletonAuto | ||
| ) { | ||
| await apostropheModule.insertIfMissing(); | ||
| } | ||
| } | ||
| await self.apos.page.implementParkAllInDefaultLocale(); | ||
| await self.apos.doc.replicate(); // emits beforeReplicate and afterReplicate events | ||
|
Check warning on line 57 in modules/@apostrophecms/migration/index.js
|
||
| // Replicate will have created the parked pages across locales if needed, | ||
| // but we may still need to reset parked properties | ||
| await self.apos.page.implementParkAllInOtherLocales(); | ||
| } | ||
| }, | ||
| 'apostrophe:ready': { | ||
| addSortifyMigrations() { | ||
| const managers = self.apos.doc.managers; | ||
|
|
@@ -41,11 +80,6 @@ | |
| }); | ||
| }); | ||
| } | ||
| }, | ||
| before: { | ||
| async addMissingSchemaFields() { | ||
| await self.addMissingSchemaFields(); | ||
| } | ||
| } | ||
| }; | ||
| }, | ||
|
|
@@ -236,43 +270,51 @@ | |
| // Perform the actual migrations. Implementation of | ||
| // the @apostrophecms/migration:migrate task | ||
| async migrate(options) { | ||
| await self.emit('before'); | ||
| if (self.apos.isNew) { | ||
| await self.apos.lock.withLock('@apostrophecms/migration:migrate', async () => { | ||
| if (self.apos.skipMigration === true) { | ||
| return; | ||
| } | ||
|
|
||
| await self.emit('before'); | ||
|
|
||
| if (self.apos.isNew) { | ||
| // Since the site is brand new (zero documents), we may assume | ||
| // it requires no migrations. Mark them all as "done" but note | ||
| // that they were skipped, just in case we decide that's an issue | ||
| // later | ||
| const at = new Date(); | ||
| // Just in case the db has no documents but did | ||
| // start to run migrations on a previous attempt, | ||
| // which causes an occasional unique key error if not | ||
| // corrected for here. | ||
| // | ||
| // Other migration-related facts that are not migration | ||
| // names are stored with a leading *, leave them alone | ||
| await self.db.removeMany({ | ||
| _id: /^[^*]/ | ||
| }); | ||
| await self.db.insertMany(self.migrations.map(migration => ({ | ||
| _id: migration.name, | ||
| at, | ||
| skipped: true | ||
| }))); | ||
| } else { | ||
| for (const migration of self.migrations) { | ||
| await self.runOne(migration); | ||
| const at = new Date(); | ||
| // Just in case the db has no documents but did | ||
| // start to run migrations on a previous attempt, | ||
| // which causes an occasional unique key error if not | ||
| // corrected for here. | ||
| // | ||
| // Other migration-related facts that are not migration | ||
| // names are stored with a leading *, leave them alone | ||
| await self.db.removeMany({ | ||
| _id: /^[^*]/ | ||
| }); | ||
| await self.db.insertMany(self.migrations.map(migration => ({ | ||
| _id: migration.name, | ||
| at, | ||
| skipped: true | ||
| }))); | ||
| } else { | ||
| for (const migration of self.migrations) { | ||
| await self.runOne(migration); | ||
| } | ||
| } | ||
| } | ||
| // In production, this event is emitted only at the end of the migrate | ||
| // command line task. In dev it is emitted at every startup after the | ||
| // automatic migration. | ||
| // | ||
| // Intentionally emitted regardless of whether the site is new or not. | ||
| // | ||
| // This is the right time to park pages, for instance, because the | ||
| // database is guaranteed to be in a stable state, whether because the | ||
| // site is new or because migrations ran successfully. | ||
| await self.emit('after'); | ||
|
|
||
| // In production, this event is emitted only at the end of the migrate | ||
| // command line task. In dev it is emitted at every startup after the | ||
| // automatic migration. | ||
| // | ||
| // Intentionally emitted regardless of whether the site is new or not. | ||
| // | ||
| // This is the right time to park pages, for instance, because the | ||
| // database is guaranteed to be in a stable state, whether because the | ||
| // site is new or because migrations ran successfully. | ||
| await self.emit('after'); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Emit a new |
||
| }); | ||
| }, | ||
| async runOne(migration) { | ||
| const info = await self.db.findOne({ _id: migration.name }); | ||
|
|
@@ -305,6 +347,12 @@ | |
| // and automatically detect whether any work | ||
| // must be done | ||
| task: () => {} | ||
| }, | ||
| 'add-missing-schema-fields': { | ||
| usage: 'Add missing schema fields to existing database documents', | ||
| task: async () => { | ||
| await self.addMissingSchemaFields(); | ||
| } | ||
| } | ||
| }; | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| import config from './config.js'; | ||
| import apostrophe from '../../index.js'; | ||
|
|
||
| export default apostrophe(config); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| export default { | ||
| root: import.meta, | ||
| shortName: 'add-missing-schema-fields-project', | ||
| baseUrl: 'http://localhost:3000', | ||
| modules: { | ||
| '@apostrophecms/express': { | ||
| options: { | ||
| address: '127.0.0.1' | ||
| } | ||
| }, | ||
| product: {} | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| export default { | ||
| extend: '@apostrophecms/piece-type', | ||
| options: { | ||
| label: 'Product', | ||
| pluralLabel: 'Products' | ||
| }, | ||
| fields: { | ||
| add: { | ||
| price: { | ||
| type: 'float', | ||
| label: 'Price', | ||
| required: true | ||
| }, | ||
| description: { | ||
| type: 'string', | ||
| label: 'Description', | ||
| textarea: true, | ||
| required: true | ||
| }, | ||
| image: { | ||
| label: 'Product photo', | ||
| type: 'area', | ||
| options: { | ||
| max: 1, | ||
| widgets: { | ||
| '@apostrophecms/image': {} | ||
| } | ||
| } | ||
| }, | ||
| copyright: { | ||
| type: 'string', | ||
| label: 'Copyright' | ||
| } | ||
| }, | ||
| group: { | ||
| basics: { | ||
| label: 'Basics', | ||
| fields: [ 'title', 'price', 'description', 'image', 'copyright' ] | ||
| // 👆 'title' is included here because it is in the default `basics` | ||
| // group for all piece types. Since we are replacing that group, we | ||
| // include it ourselves. | ||
| } | ||
| } | ||
| }, | ||
| init(self) { | ||
| self.apos.migration.add('add-first-product', self.addFirstProduct); | ||
| self.apos.migration.add('add-copyright-notice', self.addCopyrightNotice); | ||
| }, | ||
| methods(self) { | ||
| return { | ||
| async addFirstProduct() { | ||
| await self.apos.modules.product.insert( | ||
| self.apos.task.getReq(), | ||
| { | ||
| ...self.apos.modules.product.newInstance(), | ||
| title: 'My first product', | ||
| price: 10.00, | ||
| description: 'Product description' | ||
| } | ||
| ); | ||
| }, | ||
| async addCopyrightNotice() { | ||
| await self.apos.migration.eachDoc({ | ||
| type: 'product' | ||
| }, async (doc) => { | ||
| if (doc.copyright === undefined) { | ||
| await self.apos.doc.db.updateOne({ | ||
| _id: doc._id | ||
| }, { | ||
| $set: { copyright: '©2024 ApostropheCMS. All rights reserved.' } | ||
| }); | ||
| } | ||
| }); | ||
| } | ||
| }; | ||
| } | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| { | ||
| "name": "add-missing-schema-fields-project", | ||
| "version": "1.0.0", | ||
| "description": "", | ||
| "main": "app.js", | ||
| "type": "module", | ||
| "scripts": { | ||
| "test": "echo \"Error: no test specified\" && exit 1" | ||
| }, | ||
| "keywords": [], | ||
| "author": "", | ||
| "license": "ISC", | ||
| "dependencies": { | ||
| "apostrophe": "file:../../." | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Recreating the section because this is not part of today's release, easier for me to handle future conflict.