From eed99ce49873e682df2fd20a7c5842d7657a2cf3 Mon Sep 17 00:00:00 2001 From: Gregor Becker Date: Sun, 3 Sep 2023 19:57:09 +0200 Subject: [PATCH 1/3] docs(pinia-orm-1333): Broken link or missing reference --- .../2.model/7.single-table-inheritance.md | 134 ++++++++++++++++++ 1 file changed, 134 insertions(+) diff --git a/docs/content/1.guide/2.model/7.single-table-inheritance.md b/docs/content/1.guide/2.model/7.single-table-inheritance.md index c5c25ba02..963561e26 100644 --- a/docs/content/1.guide/2.model/7.single-table-inheritance.md +++ b/docs/content/1.guide/2.model/7.single-table-inheritance.md @@ -395,3 +395,137 @@ If you are using decorators you need to use `...super.schemas[super.entity]` ins @Attr('terrier') declare race: string } ```` + +## Notes on Circular Imports + +If you decide to declare each entity model in a separate file, and use `import` calls to cross-reference entity models between your file, you may get an error at runtime saying: + +```bash +TypeError: Super expression must either be null or a function, not undefined. +``` + +If so, it means that you have cycles in your dependency tree and that your bundler doesn't handle them (usually they don't). We describe here a solution, inspired by [Michel Weststrate's article](https://medium.com/visual-development/how-to-fix-nasty-circular-dependency-issues-once-and-for-all-in-javascript-typescript-a04c987cf0de). + +### Initial setup + +Here is an example of the initial setup you might have: + +`Person.js` references its child `Adult.js` because it needs it for type definition. + +```js +// File 1: Person.js + +import { Model } from 'pinia-orm' +import Adult from './Adult' + +export default class Person extends Model { + static entity = 'person' + + static types () { + return { + PERSON: Person, + ADULT: Adult + } + } + + static fields () { + return { + id: this.attr(null), + name: this.attr(''), + type: this.attr('PERSON') + } + } +} +``` + +`Adult.js` references its parent model, through `Person.js`. + +```js +// File 2: Adult.js + +import Person from './Person' + +export default class Adult extends Person { + static entity = 'adult' + + static baseEntity = 'person' + + static fields() { + return { + ...super.fields(), + job: this.attr('') + } + } +} +``` + +### Solution: How to Break Cycles + +The solution, as presented in [this article](https://medium.com/visual-development/how-to-fix-nasty-circular-dependency-issues-once-and-for-all-in-javascript-typescript-a04c987cf0de), is to use an intermediate file which imports and exports all entities used in the hierarchy. + +```js +// New file: PersonHierarchy.js + +export * from './Person' +export * from './Adult' +``` + +You'll need to change the involved entities files to take into account the changes: + +```js +// File 1: Person.js + +import { Model } from 'pinia-orm' +import { Adult } from './PersonHierarchy' // Here, we change the import. + +// We export directly the named class. +export class Person extends Model { + static entity = 'person' + + static types () { + return { + PERSON: Person, + ADULT: Adult + } + } + + static fields () { + return { + id: this.attr(null), + name: this.attr(''), + type: this.attr('PERSON') + } + } +} + +// We also export a default. +export default Person +``` + +```js +// File 2: Adult.js + +import { Person } from './PersonHierarchy' // Here, we change the import. +// import { Person } from './Person' // this should also work + +// We export directly the named class. +export class Adult extends Person { + static entity = 'adult' + + static baseEntity = 'person' + + static fields() { + return { + ...super.fields(), + job: this.attr('') + } + } +} + +// We also export a default. +export default Adult; +``` + +### Default Export + +In our solution, we also expose a `default` export in the different file, which can be used in subsequent files. Indeed, what is important in our case (in comparison with the generic case described in [Michel Weststrate's article](https://medium.com/visual-development/how-to-fix-nasty-circular-dependency-issues-once-and-for-all-in-javascript-typescript-a04c987cf0de)) is that the classes of a hierarchy **and** the store initialization file reference the intermediate file. But since all classes are "setup" when declaring the database, there is no risk in referencing the classes directly afterward (without going through the intermediate file). From 37bc4d72877ddc67ef0073c4b908c157a762a412 Mon Sep 17 00:00:00 2001 From: Gregor Becker Date: Sun, 3 Sep 2023 20:05:19 +0200 Subject: [PATCH 2/3] docs(pinia-orm): update note display --- docs/content/1.guide/2.model/7.single-table-inheritance.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/content/1.guide/2.model/7.single-table-inheritance.md b/docs/content/1.guide/2.model/7.single-table-inheritance.md index 963561e26..89c2b95f6 100644 --- a/docs/content/1.guide/2.model/7.single-table-inheritance.md +++ b/docs/content/1.guide/2.model/7.single-table-inheritance.md @@ -126,7 +126,9 @@ class Adult extends Person { } ``` -> **NOTE:** If you import Models from other files, you might get circular reference error. Please take a look at [this section](#notes-on-circular-imports) for more detail and how to avoid it. +::alert{type="info"} +If you import Models from other files, you might get circular reference error. Please take a look at [this section](#notes-on-circular-imports) for more detail and how to avoid it. +::alert Now, you can create mixed types of records at once. From 4b0d87635b9cc65d68ecde967c30652970ab768d Mon Sep 17 00:00:00 2001 From: Gregor Becker Date: Sun, 3 Sep 2023 20:09:27 +0200 Subject: [PATCH 3/3] docs(pinia-orm): wrong closing --- docs/content/1.guide/2.model/7.single-table-inheritance.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/1.guide/2.model/7.single-table-inheritance.md b/docs/content/1.guide/2.model/7.single-table-inheritance.md index 89c2b95f6..5ba2d50bc 100644 --- a/docs/content/1.guide/2.model/7.single-table-inheritance.md +++ b/docs/content/1.guide/2.model/7.single-table-inheritance.md @@ -128,7 +128,7 @@ class Adult extends Person { ::alert{type="info"} If you import Models from other files, you might get circular reference error. Please take a look at [this section](#notes-on-circular-imports) for more detail and how to avoid it. -::alert +:: Now, you can create mixed types of records at once.