fix: hmr gathered
This commit is contained in:
parent
d5d0e8d74e
commit
6374af578e
|
@ -92,12 +92,21 @@ export const hooks = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Invoked when a gathered set is HMR'd.
|
||||
* @param {constructor} gathered The gathered set.
|
||||
* @param {string} hook The gather hook; e.g. `@flecks/db/server.models`.
|
||||
*/
|
||||
'@flecks/core.hmr.gathered': (gathered, hook) => {
|
||||
// Do something with the gathered set...
|
||||
},
|
||||
|
||||
/**
|
||||
* Invoked when a gathered class is HMR'd.
|
||||
* @param {constructor} Class The class.
|
||||
* @param {string} hook The gather hook; e.g. `@flecks/db/server.models`.
|
||||
*/
|
||||
'@flecks/core.hmr.gathered': (Class, hook) => {
|
||||
'@flecks/core.hmr.gathered.class': (Class, hook) => {
|
||||
// Do something with Class...
|
||||
},
|
||||
|
||||
|
|
|
@ -169,6 +169,15 @@ export default class Flecks {
|
|||
);
|
||||
}
|
||||
|
||||
checkAndDecorateRawGathered(hook, raw, check) {
|
||||
// Gather classes and check.
|
||||
check(raw, hook);
|
||||
// Decorate and check.
|
||||
const decorated = this.invokeComposed(`${hook}.decorate`, raw);
|
||||
check(decorated, `${hook}.decorate`);
|
||||
return decorated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy this instance.
|
||||
*/
|
||||
|
@ -285,10 +294,7 @@ export default class Flecks {
|
|||
}
|
||||
// Gather classes and check.
|
||||
const raw = this.invokeMerge(hook);
|
||||
check(raw, hook);
|
||||
// Decorate and check.
|
||||
const decorated = this.invokeComposed(`${hook}.decorate`, raw);
|
||||
check(decorated, `${hook}.decorate`);
|
||||
const decorated = this.checkAndDecorateRawGathered(hook, raw, check);
|
||||
// Assign unique IDs to each class and sort by type.
|
||||
let uid = 1;
|
||||
const ids = {};
|
||||
|
@ -311,9 +317,15 @@ export default class Flecks {
|
|||
[ByType]: types,
|
||||
};
|
||||
// Register for HMR?
|
||||
if (module.hot) {
|
||||
hotGathered.set(hook, {idProperty, gathered, typeProperty});
|
||||
}
|
||||
hotGathered.set(
|
||||
hook,
|
||||
{
|
||||
check,
|
||||
idProperty,
|
||||
typeProperty,
|
||||
gathered,
|
||||
},
|
||||
);
|
||||
debug("gathered '%s': %O", hook, Object.keys(gathered[ByType]));
|
||||
return gathered;
|
||||
}
|
||||
|
@ -654,10 +666,6 @@ export default class Flecks {
|
|||
/**
|
||||
* Refresh a fleck's hooks, configuration, and any gathered classes.
|
||||
*
|
||||
* @example
|
||||
* module.hot.accept('@flecks/example', async () => {
|
||||
* flecks.refresh('@flecks/example', require('@flecks/example'));
|
||||
* });
|
||||
* @param {string} fleck
|
||||
* @param {object} M The fleck module
|
||||
* @protected
|
||||
|
@ -671,9 +679,7 @@ export default class Flecks {
|
|||
// Write config.
|
||||
this.configureFleckDefaults(fleck);
|
||||
// HMR.
|
||||
if (module.hot) {
|
||||
this.refreshGathered(fleck);
|
||||
}
|
||||
this.refreshGathered(fleck);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -688,23 +694,36 @@ export default class Flecks {
|
|||
value: [
|
||||
hook,
|
||||
{
|
||||
check,
|
||||
idProperty,
|
||||
gathered,
|
||||
typeProperty,
|
||||
},
|
||||
],
|
||||
} = current;
|
||||
const updates = this.invokeFleck(hook, fleck);
|
||||
if (updates) {
|
||||
debug('updating gathered %s from %s...', hook, fleck);
|
||||
const entries = Object.entries(updates);
|
||||
for (let i = 0, [type, Class] = entries[i]; i < entries.length; ++i) {
|
||||
let raw;
|
||||
// If decorating, gather all again
|
||||
if (this.fleckImplements(fleck, `${hook}.decorate`)) {
|
||||
raw = this.invokeMerge(hook);
|
||||
debugSilly('%s implements %s.decorate', fleck, hook);
|
||||
}
|
||||
// If only implementing, gather and decorate.
|
||||
else if (this.fleckImplements(fleck, hook)) {
|
||||
raw = this.invokeFleck(hook, fleck);
|
||||
debugSilly('%s implements %s', fleck, hook);
|
||||
}
|
||||
if (raw) {
|
||||
const decorated = this.checkAndDecorateRawGathered(hook, raw, check);
|
||||
debug('updating gathered %s from %s... %O', hook, fleck, decorated);
|
||||
const entries = Object.entries(decorated);
|
||||
entries.forEach(([type, Class]) => {
|
||||
const {[type]: {[idProperty]: id}} = gathered;
|
||||
const Subclass = wrapGathered(Class, id, idProperty, type, typeProperty);
|
||||
// eslint-disable-next-line no-multi-assign
|
||||
gathered[type] = gathered[id] = gathered[ById][id] = gathered[ByType][type] = Subclass;
|
||||
this.invoke('@flecks/core.hmr.gathered', Subclass, hook);
|
||||
}
|
||||
this.invoke('@flecks/core.hmr.gathered.class', Subclass, hook);
|
||||
});
|
||||
this.invoke('@flecks/core.hmr.gathered', gathered, hook);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import {ByType, D} from '@flecks/core';
|
||||
import Sequelize from 'sequelize';
|
||||
|
||||
import register from './register';
|
||||
|
||||
const debug = D('@flecks/db/server/connection');
|
||||
|
||||
export async function createDatabaseConnection(flecks) {
|
||||
|
@ -34,16 +36,6 @@ export async function createDatabaseConnection(flecks) {
|
|||
logging: false,
|
||||
...config,
|
||||
});
|
||||
const Models = flecks.get('$flecks/db.models')[ByType];
|
||||
Object.values(Models)
|
||||
.filter((Model) => Model.attributes)
|
||||
.forEach((Model) => {
|
||||
Model.init(Model.attributes, {
|
||||
sequelize,
|
||||
underscored: true,
|
||||
...(Model.modelOptions || {}),
|
||||
});
|
||||
});
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
try {
|
||||
|
@ -58,64 +50,8 @@ export async function createDatabaseConnection(flecks) {
|
|||
});
|
||||
}
|
||||
}
|
||||
const dependencies = {};
|
||||
Object.values(Models).forEach((Model) => {
|
||||
Model.associate(Models);
|
||||
});
|
||||
Object.values(Models).forEach((Model) => {
|
||||
const associations = Object.entries(Model.associations);
|
||||
for (let i = 0; i < associations.length; i++) {
|
||||
if (associations[i][1].isSelfAssociation) {
|
||||
// eslint-disable-next-line no-continue
|
||||
continue;
|
||||
}
|
||||
if ('BelongsToMany' === associations[i][1].associationType) {
|
||||
if (associations[i][1].through.model.isManagedByFlecks) {
|
||||
const {name} = associations[i][1].through.model;
|
||||
if (!dependencies[name]) {
|
||||
dependencies[name] = new Set();
|
||||
}
|
||||
dependencies[name].add(Model.name);
|
||||
}
|
||||
}
|
||||
if ('BelongsTo' === associations[i][1].associationType) {
|
||||
if (!dependencies[Model.name]) {
|
||||
dependencies[Model.name] = new Set();
|
||||
}
|
||||
dependencies[Model.name].add(associations[i][1].target.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
const entries = Object.values(Models);
|
||||
let lastLength = entries.length;
|
||||
while (entries.length > 0) {
|
||||
for (let i = 0; i < entries.length; i++) {
|
||||
const Model = entries[i];
|
||||
if (
|
||||
!dependencies[Model.name]
|
||||
|| 0 === dependencies[Model.name].length
|
||||
) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await Model.sync();
|
||||
const dependents = Object.keys(dependencies);
|
||||
for (let j = 0; j < dependents.length; j++) {
|
||||
const dependent = dependents[j];
|
||||
if (dependencies[dependent].has(Model.name)) {
|
||||
dependencies[dependent].delete(Model.name);
|
||||
if (0 === dependencies[dependent].size) {
|
||||
delete dependencies[dependent];
|
||||
}
|
||||
}
|
||||
}
|
||||
entries.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (entries.length === lastLength) {
|
||||
throw new TypeError(`@flecks/db circular dependencies: '${entries.join("', '")}'`);
|
||||
}
|
||||
lastLength = entries.length;
|
||||
}
|
||||
const Models = flecks.get('$flecks/db.models')[ByType];
|
||||
await register(Models, sequelize);
|
||||
debug('synchronizing...');
|
||||
await sequelize.sync();
|
||||
debug('synchronized');
|
||||
|
|
71
packages/db/src/register.js
Normal file
71
packages/db/src/register.js
Normal file
|
@ -0,0 +1,71 @@
|
|||
async function register(Models, sequelize) {
|
||||
Object.values(Models)
|
||||
.filter((Model) => Model.attributes)
|
||||
.forEach((Model) => {
|
||||
Model.init(Model.attributes, {
|
||||
sequelize,
|
||||
underscored: true,
|
||||
...(Model.modelOptions || {}),
|
||||
});
|
||||
});
|
||||
const dependencies = {};
|
||||
Object.values(Models).forEach((Model) => {
|
||||
Model.associate(Models);
|
||||
});
|
||||
Object.values(Models).forEach((Model) => {
|
||||
const associations = Object.entries(Model.associations);
|
||||
for (let i = 0; i < associations.length; i++) {
|
||||
if (associations[i][1].isSelfAssociation) {
|
||||
// eslint-disable-next-line no-continue
|
||||
continue;
|
||||
}
|
||||
if ('BelongsToMany' === associations[i][1].associationType) {
|
||||
if (associations[i][1].through.model.isManagedByFlecks) {
|
||||
const {name} = associations[i][1].through.model;
|
||||
if (!dependencies[name]) {
|
||||
dependencies[name] = new Set();
|
||||
}
|
||||
dependencies[name].add(Model.name);
|
||||
}
|
||||
}
|
||||
if ('BelongsTo' === associations[i][1].associationType) {
|
||||
if (!dependencies[Model.name]) {
|
||||
dependencies[Model.name] = new Set();
|
||||
}
|
||||
dependencies[Model.name].add(associations[i][1].target.name);
|
||||
}
|
||||
}
|
||||
});
|
||||
const entries = Object.values(Models);
|
||||
let lastLength = entries.length;
|
||||
while (entries.length > 0) {
|
||||
for (let i = 0; i < entries.length; i++) {
|
||||
const Model = entries[i];
|
||||
if (
|
||||
!dependencies[Model.name]
|
||||
|| 0 === dependencies[Model.name].length
|
||||
) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await Model.sync(); await Model.sync();
|
||||
const dependents = Object.keys(dependencies);
|
||||
for (let j = 0; j < dependents.length; j++) {
|
||||
const dependent = dependents[j];
|
||||
if (dependencies[dependent].has(Model.name)) {
|
||||
dependencies[dependent].delete(Model.name);
|
||||
if (0 === dependencies[dependent].size) {
|
||||
delete dependencies[dependent];
|
||||
}
|
||||
}
|
||||
}
|
||||
entries.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (entries.length === lastLength) {
|
||||
throw new TypeError(`@flecks/db circular dependencies: '${entries.join("', '")}'`);
|
||||
}
|
||||
lastLength = entries.length;
|
||||
}
|
||||
}
|
||||
|
||||
export default register;
|
|
@ -1,5 +1,6 @@
|
|||
import {createDatabaseConnection} from './connection';
|
||||
import containers from './containers';
|
||||
import register from './register';
|
||||
|
||||
export {DataTypes as Types, Op, default as Sequelize} from 'sequelize';
|
||||
|
||||
|
@ -36,6 +37,11 @@ export const hooks = {
|
|||
*/
|
||||
username: undefined,
|
||||
}),
|
||||
'@flecks/core.hmr.gathered': (gathered, hook, flecks) => {
|
||||
if ('@flecks/db/server.models' === hook) {
|
||||
register(gathered, flecks.get('$flecks/db/sequelize'));
|
||||
}
|
||||
},
|
||||
'@flecks/core.starting': (flecks) => {
|
||||
flecks.set('$flecks/db.models', flecks.gather(
|
||||
'@flecks/db/server.models',
|
||||
|
|
Loading…
Reference in New Issue
Block a user