Browse Source

feat: add work serialization (and basis for the other entities) and an example ipc channel to get a work entity

This commit also adds language codes and a migration which inserts them all into the database.

BREAKING CHANGE: redoes the initial database migration
0.x
Xymorot 4 months ago
parent
commit
6b2824daab
148 changed files with 1683 additions and 516 deletions
  1. +32
    -5
      .eslintrc.json
  2. +1
    -0
      src/main/core/container.ts
  3. +4
    -4
      src/main/entities/library/author-name.ts
  4. +4
    -4
      src/main/entities/library/author-role-name.ts
  5. +6
    -13
      src/main/entities/library/author-role.ts
  6. +6
    -12
      src/main/entities/library/author.ts
  7. +6
    -15
      src/main/entities/library/character-tag.ts
  8. +4
    -4
      src/main/entities/library/collection-name.ts
  9. +6
    -16
      src/main/entities/library/collection-part.ts
  10. +6
    -17
      src/main/entities/library/collection.ts
  11. +6
    -28
      src/main/entities/library/copy.ts
  12. +8
    -20
      src/main/entities/library/interaction-tag.ts
  13. +3
    -12
      src/main/entities/library/language.ts
  14. +4
    -4
      src/main/entities/library/site-name.ts
  15. +6
    -12
      src/main/entities/library/site.ts
  16. +6
    -18
      src/main/entities/library/source.ts
  17. +4
    -4
      src/main/entities/library/tag-name.ts
  18. +13
    -33
      src/main/entities/library/tag.ts
  19. +12
    -8
      src/main/entities/library/transformation-type-name.ts
  20. +7
    -11
      src/main/entities/library/transformation-type.ts
  21. +15
    -23
      src/main/entities/library/transformation.ts
  22. +8
    -20
      src/main/entities/library/work-author.ts
  23. +4
    -4
      src/main/entities/library/work-character-name.ts
  24. +16
    -36
      src/main/entities/library/work-character.ts
  25. +4
    -4
      src/main/entities/library/work-name.ts
  26. +6
    -15
      src/main/entities/library/work-tag.ts
  27. +23
    -61
      src/main/entities/library/work.ts
  28. +4
    -4
      src/main/entities/library/world-character-name.ts
  29. +14
    -21
      src/main/entities/library/world-character.ts
  30. +4
    -4
      src/main/entities/library/world-name.ts
  31. +12
    -22
      src/main/entities/library/world.ts
  32. +5
    -5
      src/main/migrations/library/1611508597488-initial.ts
  33. +198
    -0
      src/main/migrations/library/1611508644004-add_languages.ts
  34. +16
    -0
      src/main/modules/app-window/app-window.ts
  35. +1
    -2
      src/main/modules/app-window/url-app-window.ts
  36. +6
    -0
      src/main/modules/date/date-util.ts
  37. +20
    -0
      src/main/modules/entity-api/entity-api-ipc-controller.ts
  38. +6
    -0
      src/main/modules/nhentai/nhentai-app-window.spec.ts
  39. +12
    -1
      src/main/modules/nhentai/nhentai-app-window.ts
  40. +1
    -3
      src/main/modules/nhentai/nhentai-ipc-controller.ts
  41. +39
    -1
      src/main/modules/nhentai/nhentai-source-getter.ts
  42. +18
    -0
      src/main/modules/nhentai/nhentai-util.ts
  43. +3
    -0
      src/main/modules/nhentai/nhentai.d.ts
  44. +9
    -4
      src/main/modules/source/source-getter-interface.d.ts
  45. +16
    -0
      src/renderer/components/content/Work.svelte
  46. +4
    -1
      src/renderer/components/modules/NhentaiGetWork.svelte
  47. +9
    -30
      src/renderer/services/api.ts
  48. +27
    -0
      src/renderer/services/ipc-client.ts
  49. +7
    -0
      src/shared/services/serialization/serializer.ts
  50. +45
    -0
      src/shared/services/serialization/serializers/work.ts
  51. +0
    -3
      src/shared/types/entities/work.d.ts
  52. +3
    -0
      src/shared/types/entity-api/base/author-name.d.ts
  53. +3
    -0
      src/shared/types/entity-api/base/author-role-name.d.ts
  54. +12
    -0
      src/shared/types/entity-api/base/author-role.d.ts
  55. +11
    -0
      src/shared/types/entity-api/base/author.d.ts
  56. +14
    -0
      src/shared/types/entity-api/base/character-tag.d.ts
  57. +3
    -0
      src/shared/types/entity-api/base/collection-name.d.ts
  58. +15
    -0
      src/shared/types/entity-api/base/collection-part.d.ts
  59. +16
    -0
      src/shared/types/entity-api/base/collection.d.ts
  60. +33
    -0
      src/shared/types/entity-api/base/copy.d.ts
  61. +1
    -1
      src/shared/types/entity-api/base/describable.d.ts
  62. +3
    -3
      src/shared/types/entity-api/base/hierarchical.d.ts
  63. +2
    -2
      src/shared/types/entity-api/base/identifiable.d.ts
  64. +19
    -0
      src/shared/types/entity-api/base/interaction-tag.d.ts
  65. +14
    -0
      src/shared/types/entity-api/base/language.d.ts
  66. +2
    -2
      src/shared/types/entity-api/base/multi-named.d.ts
  67. +2
    -2
      src/shared/types/entity-api/base/name.d.ts
  68. +1
    -1
      src/shared/types/entity-api/base/orderable.d.ts
  69. +3
    -0
      src/shared/types/entity-api/base/site-name.d.ts
  70. +11
    -0
      src/shared/types/entity-api/base/site.d.ts
  71. +19
    -0
      src/shared/types/entity-api/base/source.d.ts
  72. +3
    -0
      src/shared/types/entity-api/base/tag-name.d.ts
  73. +28
    -0
      src/shared/types/entity-api/base/tag.d.ts
  74. +3
    -0
      src/shared/types/entity-api/base/transformation-type-name.d.ts
  75. +17
    -0
      src/shared/types/entity-api/base/transformation-type.d.ts
  76. +19
    -0
      src/shared/types/entity-api/base/transformation.d.ts
  77. +1
    -1
      src/shared/types/entity-api/base/weighted.d.ts
  78. +19
    -0
      src/shared/types/entity-api/base/work-author.d.ts
  79. +3
    -0
      src/shared/types/entity-api/base/work-character-name.d.ts
  80. +33
    -0
      src/shared/types/entity-api/base/work-character.d.ts
  81. +3
    -0
      src/shared/types/entity-api/base/work-name.d.ts
  82. +14
    -0
      src/shared/types/entity-api/base/work-tag.d.ts
  83. +68
    -0
      src/shared/types/entity-api/base/work.d.ts
  84. +3
    -0
      src/shared/types/entity-api/base/world-character-name.d.ts
  85. +19
    -0
      src/shared/types/entity-api/base/world-character.d.ts
  86. +3
    -0
      src/shared/types/entity-api/base/world-name.d.ts
  87. +16
    -0
      src/shared/types/entity-api/base/world.d.ts
  88. +3
    -0
      src/shared/types/entity-api/entities/author-name.d.ts
  89. +3
    -0
      src/shared/types/entity-api/entities/author-role-name.d.ts
  90. +5
    -0
      src/shared/types/entity-api/entities/author-role.d.ts
  91. +5
    -0
      src/shared/types/entity-api/entities/author.d.ts
  92. +5
    -0
      src/shared/types/entity-api/entities/character-tag.d.ts
  93. +3
    -0
      src/shared/types/entity-api/entities/collection-name.d.ts
  94. +5
    -0
      src/shared/types/entity-api/entities/collection-part.d.ts
  95. +5
    -0
      src/shared/types/entity-api/entities/collection.d.ts
  96. +5
    -0
      src/shared/types/entity-api/entities/copy.d.ts
  97. +7
    -0
      src/shared/types/entity-api/entities/interaction-tag.d.ts
  98. +3
    -0
      src/shared/types/entity-api/entities/language.d.ts
  99. +3
    -0
      src/shared/types/entity-api/entities/site-name.d.ts
  100. +5
    -0
      src/shared/types/entity-api/entities/site.d.ts

+ 32
- 5
.eslintrc.json View File

@ -1,14 +1,11 @@
{
"root": true,
"plugins": ["@typescript-eslint", "import"],
"extends": ["eslint:recommended", "prettier"],
"extends": ["eslint:recommended", "prettier", "plugin:import/recommended"],
"parserOptions": {
"ecmaVersion": 2019,
"sourceType": "module"
},
"settings": {
"import/core-modules": ["electron"]
},
"env": {
"browser": true,
"node": true
@ -43,6 +40,8 @@
"no-constant-condition": ["error", { "checkLoops": false }],
"no-throw-literal": "error",
"curly": "error",
"no-promise-executor-return": "error",
"no-return-await": "error",
"import/no-extraneous-dependencies": [
"error",
@ -50,6 +49,7 @@
"devDependencies": [
"**/*.{spec,mock}.*",
"src/**/test/*",
"src/renderer.ts",
"src/renderer/**/*",
"declarations/**/*",
"templates/**/*",
@ -57,6 +57,31 @@
]
}
],
"import/no-restricted-paths": [
"error",
{
"zones": [
{
"target": "./src/main",
"from": "./src",
"except": ["./main", "./shared"],
"message": "only import from main/shared"
},
{
"target": "./src/renderer",
"from": "./src",
"except": ["./renderer", "./shared"],
"message": "only import from renderer/shared"
},
{
"target": "./src/shared",
"from": "./src",
"except": ["./shared"],
"message": "only import from shared"
}
]
}
],
"import/no-default-export": "error",
"import/first": "error",
"import/order": [
@ -75,7 +100,9 @@
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"prettier/@typescript-eslint"
"prettier/@typescript-eslint",
"plugin:import/typescript",
"plugin:import/electron"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {


+ 1
- 0
src/main/core/container.ts View File

@ -9,6 +9,7 @@ import '../modules/nhentai/nhentai-ipc-controller';
import { NhentaiAppWindow } from '../modules/nhentai/nhentai-app-window';
import { NhentaiSourceGetter } from '../modules/nhentai/nhentai-source-getter';
import { Store } from '../modules/store/store';
import '../modules/entity-api/entity-api-ipc-controller';
import BindingToSyntax = interfaces.BindingToSyntax;
export const container = {


+ 4
- 4
src/main/entities/library/author-name.ts View File

@ -2,16 +2,16 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { Author } from './author';
@Entity()
export class AuthorName implements IdentifiableEntityInterface, NameEntityInterface {
export class AuthorName implements AuthorNameEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@ManyToOne(() => Author, (author: Author) => author.names, {
@ManyToOne(() => Author, (author: AuthorEntityInterface) => author.names, {
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public entity!: Promise<Author>;
public entity!: Promise<AuthorEntityInterface>;
@Column({
nullable: false,


+ 4
- 4
src/main/entities/library/author-role-name.ts View File

@ -2,16 +2,16 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { AuthorRole } from './author-role';
@Entity()
export class AuthorRoleName implements IdentifiableEntityInterface, NameEntityInterface {
export class AuthorRoleName implements AuthorRoleNameEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@ManyToOne(() => AuthorRole, (authorRole: AuthorRole) => authorRole.names, {
@ManyToOne(() => AuthorRole, (authorRole: AuthorRoleEntityInterface) => authorRole.names, {
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public entity!: Promise<AuthorRole>;
public entity!: Promise<AuthorRoleEntityInterface>;
@Column({
nullable: false,


+ 6
- 13
src/main/entities/library/author-role.ts View File

@ -2,14 +2,10 @@ import { Column, Entity, ManyToMany, OneToMany, PrimaryGeneratedColumn } from 't
import { AuthorRoleName } from './author-role-name';
import { WorkAuthor } from './work-author';
/**
* This entity describes the role an author has in a work.
* Examples: story writing, drawing, animating, publishing, ...
*/
@Entity()
export class AuthorRole implements IdentifiableEntityInterface, MultiNamedEntityInterface, DescribableEntityInterface {
export class AuthorRole implements AuthorRoleEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@Column({
nullable: false,
@ -17,14 +13,11 @@ export class AuthorRole implements IdentifiableEntityInterface, MultiNamedEntity
})
public nameCanonical!: string;
@OneToMany(() => AuthorRoleName, (authorRoleName: AuthorRoleName) => authorRoleName.entity)
public names!: Promise<AuthorRoleName[]>;
@OneToMany(() => AuthorRoleName, (authorRoleName: AuthorRoleNameEntityInterface) => authorRoleName.entity)
public names!: Promise<AuthorRoleNameEntityInterface[]>;
/**
* relation to the entity connecting with the author and work
*/
@ManyToMany(() => WorkAuthor, (workAuthor: WorkAuthor) => workAuthor.authorRoles)
public workAuthors!: Promise<WorkAuthor[]>;
@ManyToMany(() => WorkAuthor, (workAuthor: WorkAuthorEntityInterface) => workAuthor.authorRoles)
public workAuthors!: Promise<WorkAuthorEntityInterface[]>;
@Column({
nullable: false,


+ 6
- 12
src/main/entities/library/author.ts View File

@ -2,13 +2,10 @@ import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
import { AuthorName } from './author-name';
import { WorkAuthor } from './work-author';
/**
* This entity represents a single real-world entity, be it a person or named group of persons.
*/
@Entity()
export class Author implements IdentifiableEntityInterface, MultiNamedEntityInterface {
export class Author implements AuthorEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@Column({
nullable: false,
@ -16,12 +13,9 @@ export class Author implements IdentifiableEntityInterface, MultiNamedEntityInte
})
public nameCanonical!: string;
@OneToMany(() => AuthorName, (authorName: AuthorName) => authorName.entity)
public names!: Promise<AuthorName[]>;
@OneToMany(() => AuthorName, (authorName: AuthorNameEntityInterface) => authorName.entity)
public names!: Promise<AuthorNameEntityInterface[]>;
/**
* ultimately connects the author with a work and their role in that work
*/
@OneToMany(() => WorkAuthor, (workAuthor: WorkAuthor) => workAuthor.author)
public workAuthors!: Promise<WorkAuthor[]>;
@OneToMany(() => WorkAuthor, (workAuthor: WorkAuthorEntityInterface) => workAuthor.author, {})
public workAuthors!: Promise<WorkAuthorEntityInterface[]>;
}

+ 6
- 15
src/main/entities/library/character-tag.ts View File

@ -3,34 +3,25 @@ import { PercentCheck } from '../decorators/percent-check';
import { Tag } from './tag';
import { WorkCharacter } from './work-character';
/**
* This tag entity tags a character in a work.
*/
@Entity()
@PercentCheck('weight')
export class CharacterTag implements IdentifiableEntityInterface, WeightedEntityInterface {
export class CharacterTag implements CharacterTagEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
/**
* the character ina work this tag describes
*/
@ManyToOne(() => WorkCharacter, (workCharacter: WorkCharacter) => workCharacter.characterTags, {
@ManyToOne(() => WorkCharacter, (workCharacter: WorkCharacterEntityInterface) => workCharacter.characterTags, {
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public workCharacter!: Promise<WorkCharacter>;
public workCharacter!: Promise<WorkCharacterEntityInterface>;
/**
* the describing tag
*/
@ManyToOne(() => Tag, (tag: Tag) => tag.characterTags, {
@ManyToOne(() => Tag, (tag: TagEntityInterface) => tag.characterTags, {
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public tag!: Promise<Tag>;
public tag!: Promise<TagEntityInterface>;
@Column('int', {
nullable: true,


+ 4
- 4
src/main/entities/library/collection-name.ts View File

@ -2,16 +2,16 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { Collection } from './collection';
@Entity()
export class CollectionName implements IdentifiableEntityInterface, NameEntityInterface {
export class CollectionName implements CollectionNameEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@ManyToOne(() => Collection, (collection: Collection) => collection.names, {
@ManyToOne(() => Collection, (collection: CollectionEntityInterface) => collection.names, {
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public entity!: Promise<Collection>;
public entity!: Promise<CollectionEntityInterface>;
@Column({
nullable: false,


+ 6
- 16
src/main/entities/library/collection-part.ts View File

@ -2,34 +2,24 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { Collection } from './collection';
import { Work } from './work';
/**
* This entity orders works in a collection.
* The main use case is chronological ordering.
*/
@Entity()
export class CollectionPart implements IdentifiableEntityInterface, OrderableEntityInterface {
export class CollectionPart implements CollectionPartEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
/**
* the collection thw work is a part of
*/
@ManyToOne(() => Collection, (collection: Collection) => collection.parts, {
@ManyToOne(() => Collection, (collection: CollectionEntityInterface) => collection.parts, {
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public collection!: Promise<Collection>;
public collection!: Promise<CollectionEntityInterface>;
/**
* the work inside the collection
*/
@ManyToOne(() => Work, (work: Work) => work.collectionParts, {
@ManyToOne(() => Work, (work: WorkEntityInterface) => work.collectionParts, {
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public work!: Promise<Work>;
public work!: Promise<WorkEntityInterface>;
@Column({
nullable: false,


+ 6
- 17
src/main/entities/library/collection.ts View File

@ -2,18 +2,10 @@ import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
import { CollectionName } from './collection-name';
import { CollectionPart } from './collection-part';
/**
* A collection is a set of works.
* For example, this can be a series or a set of alternate angles.
* What constitutes as a collection is ultimately up to the user.
*
* As a general rule of thumb:
* If authors of works see them as belonging together, they are a collection
*/
@Entity()
export class Collection implements IdentifiableEntityInterface, MultiNamedEntityInterface {
export class Collection implements CollectionEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@Column({
nullable: false,
@ -21,12 +13,9 @@ export class Collection implements IdentifiableEntityInterface, MultiNamedEntity
})
public nameCanonical!: string;
@OneToMany(() => CollectionName, (collectionName: CollectionName) => collectionName.entity)
public names!: Promise<CollectionName[]>;
@OneToMany(() => CollectionName, (collectionName: CollectionNameEntityInterface) => collectionName.entity)
public names!: Promise<CollectionNameEntityInterface[]>;
/**
* the connecting entity between this collection and the work
*/
@OneToMany(() => CollectionPart, (collectionPart: CollectionPart) => collectionPart.collection)
public parts!: Promise<CollectionPart[]>;
@OneToMany(() => CollectionPart, (collectionPart: CollectionPartEntityInterface) => collectionPart.collection)
public parts!: Promise<CollectionPartEntityInterface[]>;
}

+ 6
- 28
src/main/entities/library/copy.ts View File

@ -2,55 +2,33 @@ import { Column, Entity, JoinTable, ManyToMany, ManyToOne, PrimaryGeneratedColum
import { Source } from './source';
import { Work } from './work';
/**
* A copy is the digital counterpart of a work.
* It corresponds to a unique file or set of files which represent the work on the users device.
*
* Multiple works can have multiple copies (think of different scans of a physical work, or lossy compression).
*/
@Entity()
export class Copy implements IdentifiableEntityInterface {
export class Copy implements CopyEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
/**
* the work this entity is a copy of
*/
@ManyToOne(() => Work, (work: Work) => work.copies, {
@ManyToOne(() => Work, (work: WorkEntityInterface) => work.copies, {
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public original!: Promise<Work>;
public original!: Promise<WorkEntityInterface>;
/**
* where to find this specific copy
*/
@ManyToMany(() => Source, (source: Source) => source.copies)
@ManyToMany(() => Source, (source: SourceEntityInterface) => source.copies)
@JoinTable()
public sources!: Promise<Source[]>;
public sources!: Promise<SourceEntityInterface[]>;
/**
* identifying hash of the file contents
*/
@Column({
nullable: false,
default: '',
})
public hash!: string;
/**
* device location of the copy
*/
@Column('text', {
nullable: true,
})
public location!: string | null;
/**
* the ordering of the copies belonging to the same work,
* lower number is higher ranked
*/
@Column({
nullable: false,
default: 0,


+ 8
- 20
src/main/entities/library/interaction-tag.ts View File

@ -3,36 +3,24 @@ import { PercentCheck } from '../decorators/percent-check';
import { Tag } from './tag';
import { WorkCharacter } from './work-character';
/**
* This tag entity tags an interaction between two characters.
*/
@Entity()
@PercentCheck('weight')
export class InteractionTag implements IdentifiableEntityInterface, WeightedEntityInterface {
export class InteractionTag implements InteractionTagEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
/**
* the describing tag
*/
@ManyToOne(() => Tag, (tag: Tag) => tag.interactionTags, {
@ManyToOne(() => Tag, (tag: TagEntityInterface) => tag.interactionTags, {
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public tag!: Promise<Tag>;
public tag!: Promise<TagEntityInterface>;
/**
* the actors of this interaction
*/
@ManyToMany(() => WorkCharacter, (workCharacter: WorkCharacter) => workCharacter.interactWith)
public subjectCharacters!: Promise<WorkCharacter[]>;
@ManyToMany(() => WorkCharacter, (workCharacter: WorkCharacterEntityInterface) => workCharacter.interactWith)
public subjectCharacters!: Promise<WorkCharacterEntityInterface[]>;
/**
* the receivers of this interaction
*/
@ManyToMany(() => WorkCharacter, (workCharacter: WorkCharacter) => workCharacter.interactedBy)
public objectCharacters!: Promise<WorkCharacter[]>;
@ManyToMany(() => WorkCharacter, (workCharacter: WorkCharacterEntityInterface) => workCharacter.interactedBy)
public objectCharacters!: Promise<WorkCharacterEntityInterface[]>;
@Column('int', {
nullable: true,


+ 3
- 12
src/main/entities/library/language.ts View File

@ -1,20 +1,11 @@
import { Entity, ManyToMany, PrimaryColumn } from 'typeorm';
import { Work } from './work';
/**
* This entity is non-user-maintained and describes a language.
*/
@Entity()
export class Language {
/**
* ISO 639-1 two-letter language code
*/
export class Language implements LanguageEntityInterface {
@PrimaryColumn()
public code!: string;
/**
* the works using this language
*/
@ManyToMany(() => Work, (work: Work) => work.languages)
public works!: Promise<Work[]>;
@ManyToMany(() => Work, (work: WorkEntityInterface) => work.languages)
public works!: Promise<WorkEntityInterface[]>;
}

+ 4
- 4
src/main/entities/library/site-name.ts View File

@ -2,16 +2,16 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { Site } from './site';
@Entity()
export class SiteName implements IdentifiableEntityInterface, NameEntityInterface {
export class SiteName implements SiteNameEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@ManyToOne(() => Site, (site: Site) => site.names, {
@ManyToOne(() => Site, (site: SiteEntityInterface) => site.names, {
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public entity!: Promise<Site>;
public entity!: Promise<SiteEntityInterface>;
@Column({
nullable: false,


+ 6
- 12
src/main/entities/library/site.ts View File

@ -2,13 +2,10 @@ import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
import { SiteName } from './site-name';
import { Source } from './source';
/**
* This non-user-maintained entity describes an online provider of works which can be scraped.
*/
@Entity()
export class Site implements IdentifiableEntityInterface, MultiNamedEntityInterface {
export class Site implements SiteEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@Column({
nullable: false,
@ -16,12 +13,9 @@ export class Site implements IdentifiableEntityInterface, MultiNamedEntityInterf
})
public nameCanonical!: string;
@OneToMany(() => SiteName, (siteName: SiteName) => siteName.entity)
public names!: Promise<SiteName[]>;
@OneToMany(() => SiteName, (siteName: SiteNameEntityInterface) => siteName.entity)
public names!: Promise<SiteNameEntityInterface[]>;
/**
* sources belonging to this site
*/
@OneToMany(() => Source, (source: Source) => source.site)
public sources!: Promise<Source[]>;
@OneToMany(() => Source, (source: SourceEntityInterface) => source.site)
public sources!: Promise<SourceEntityInterface[]>;
}

+ 6
- 18
src/main/entities/library/source.ts View File

@ -2,36 +2,24 @@ import { Column, Entity, ManyToMany, ManyToOne, PrimaryGeneratedColumn } from 't
import { Copy } from './copy';
import { Site } from './site';
/**
* This entity describes an external source of a copy, in most cases that is a website.
*/
@Entity()
export class Source implements IdentifiableEntityInterface {
export class Source implements SourceEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
/**
* the uri to the sauce
*/
@Column({
nullable: false,
default: '',
})
public uri!: string;
/**
* the site connected to the source
*/
@ManyToOne(() => Site, (site: Site) => site.sources, {
@ManyToOne(() => Site, (site: SiteEntityInterface) => site.sources, {
nullable: true,
onDelete: 'RESTRICT',
onUpdate: 'CASCADE',
})
public site!: Promise<Site> | null;
public site!: Promise<SiteEntityInterface> | null;
/**
* the copies which can be found here
*/
@ManyToMany(() => Copy, (copy: Copy) => copy.sources)
public copies!: Promise<Copy[]>;
@ManyToMany(() => Copy, (copy: CopyEntityInterface) => copy.sources)
public copies!: Promise<CopyEntityInterface[]>;
}

+ 4
- 4
src/main/entities/library/tag-name.ts View File

@ -2,16 +2,16 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { Tag } from './tag';
@Entity()
export class TagName implements IdentifiableEntityInterface, NameEntityInterface {
export class TagName implements TagNameEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@ManyToOne(() => Tag, (tag: Tag) => tag.names, {
@ManyToOne(() => Tag, (tag: TagEntityInterface) => tag.names, {
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public entity!: Promise<Tag>;
public entity!: Promise<TagEntityInterface>;
@Column({
nullable: false,


+ 13
- 33
src/main/entities/library/tag.ts View File

@ -4,21 +4,10 @@ import { InteractionTag } from './interaction-tag';
import { TagName } from './tag-name';
import { WorkTag } from './work-tag';
/**
* This entity is the main tag entity.
* Tags have a name and a description.
* They can tag a work, a character, or a character interaction.
* They can also be in a hierarchy
*/
@Entity()
export class Tag
implements
IdentifiableEntityInterface,
MultiNamedEntityInterface,
DescribableEntityInterface,
HierarchicalEntityInterface<Tag> {
export class Tag implements TagEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@Column({
nullable: false,
@ -26,26 +15,17 @@ export class Tag
})
public nameCanonical!: string;
@OneToMany(() => TagName, (tagName: TagName) => tagName.entity)
public names!: Promise<TagName[]>;
/**
* this tag tagging a work
*/
@OneToMany(() => WorkTag, (workTag: WorkTag) => workTag.tag)
public workTags!: Promise<WorkTag[]>;
/**
* this tag tagging characters
*/
@OneToMany(() => CharacterTag, (characterTag: CharacterTag) => characterTag.tag)
public characterTags!: Promise<CharacterTag[]>;
/**
* this tag tagging a character interaction
*/
@OneToMany(() => InteractionTag, (interactionTag: InteractionTag) => interactionTag.tag)
public interactionTags!: Promise<InteractionTag[]>;
@OneToMany(() => TagName, (tagName: TagNameEntityInterface) => tagName.entity)
public names!: Promise<TagNameEntityInterface[]>;
@OneToMany(() => WorkTag, (workTag: WorkTagEntityInterface) => workTag.tag)
public workTags!: Promise<WorkTagEntityInterface[]>;
@OneToMany(() => CharacterTag, (characterTag: CharacterTagEntityInterface) => characterTag.tag)
public characterTags!: Promise<CharacterTagEntityInterface[]>;
@OneToMany(() => InteractionTag, (interactionTag: InteractionTagEntityInterface) => interactionTag.tag)
public interactionTags!: Promise<InteractionTagEntityInterface[]>;
@ManyToMany(() => Tag, (tag: Tag) => tag.children)
@JoinTable()


+ 12
- 8
src/main/entities/library/transformation-type-name.ts View File

@ -2,16 +2,20 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { TransformationType } from './transformation-type';
@Entity()
export class TransformationTypeName implements IdentifiableEntityInterface, NameEntityInterface {
export class TransformationTypeName implements TransformationTypeNameEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@ManyToOne(() => TransformationType, (transformationType: TransformationType) => transformationType.names, {
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public entity!: Promise<TransformationType>;
@ManyToOne(
() => TransformationType,
(transformationType: TransformationTypeEntityInterface) => transformationType.names,
{
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
}
)
public entity!: Promise<TransformationTypeEntityInterface>;
@Column({
nullable: false,


+ 7
- 11
src/main/entities/library/transformation-type.ts View File

@ -2,15 +2,10 @@ import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
import { Transformation } from './transformation';
import { TransformationTypeName } from './transformation-type-name';
/**
* This entity describes a transformation type.
* Possible type: translation, decensor, collection, ...
*/
@Entity()
export class TransformationType
implements IdentifiableEntityInterface, MultiNamedEntityInterface, DescribableEntityInterface {
export class TransformationType implements TransformationTypeEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@Column({
nullable: false,
@ -20,9 +15,10 @@ export class TransformationType
@OneToMany(
() => TransformationTypeName,
(transformationTypeName: TransformationTypeName) => transformationTypeName.entity
(transformationTypeName: TransformationTypeNameEntityInterface) => transformationTypeName.entity,
{}
)
public names!: Promise<TransformationTypeName[]>;
public names!: Promise<TransformationTypeNameEntityInterface[]>;
@Column({
nullable: false,
@ -33,8 +29,8 @@ export class TransformationType
/**
* the transformations of this type
*/
@OneToMany(() => Transformation, (transformation: Transformation) => transformation.type)
public transformations!: Promise<Transformation[]>;
@OneToMany(() => Transformation, (transformation: TransformationEntityInterface) => transformation.type)
public transformations!: Promise<TransformationEntityInterface[]>;
/**
* if that transformation conserves the tags of the original work


+ 15
- 23
src/main/entities/library/transformation.ts View File

@ -2,17 +2,11 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { TransformationType } from './transformation-type';
import { Work } from './work';
/**
* This entity describes how one work is transformed to another.
*/
@Entity()
export class Transformation implements IdentifiableEntityInterface, OrderableEntityInterface {
export class Transformation implements TransformationEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
/**
* the work based on the original
*/
@ManyToOne(() => Work, (work: Work) => work.transformationOf, {
nullable: false,
onDelete: 'CASCADE',
@ -20,25 +14,23 @@ export class Transformation implements IdentifiableEntityInterface, OrderableEnt
})
public byWork!: Promise<Work>;
/**
* the transformation type
*/
@ManyToOne(() => TransformationType, (transformationType: TransformationType) => transformationType.transformations, {
nullable: false,
onDelete: 'RESTRICT',
onUpdate: 'CASCADE',
})
public type!: Promise<TransformationType>;
@ManyToOne(
() => TransformationType,
(transformationType: TransformationTypeEntityInterface) => transformationType.transformations,
{
nullable: false,
onDelete: 'RESTRICT',
onUpdate: 'CASCADE',
}
)
public type!: Promise<TransformationTypeEntityInterface>;
/**
* the original work
*/
@ManyToOne(() => Work, (work: Work) => work.transformedBy, {
nullable: false,
@ManyToOne(() => Work, (work: WorkEntityInterface) => work.transformedBy, {
nullable: true,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public ofWork!: Promise<Work>;
public ofWork!: Promise<WorkEntityInterface> | null;
@Column({
nullable: false,


+ 8
- 20
src/main/entities/library/work-author.ts View File

@ -3,40 +3,28 @@ import { Author } from './author';
import { AuthorRole } from './author-role';
import { Work } from './work';
/**
* This entity connects authors with their work and their role therein.
*/
@Entity()
export class WorkAuthor implements IdentifiableEntityInterface, OrderableEntityInterface {
export class WorkAuthor implements WorkAuthorEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
/**
* the work
*/
@ManyToOne(() => Work, (work: Work) => work.workAuthors, {
@ManyToOne(() => Work, (work: WorkEntityInterface) => work.workAuthors, {
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public work!: Promise<Work>;
public work!: Promise<WorkEntityInterface>;
/**
* the roles of the author in the work
*/
@ManyToMany(() => AuthorRole, (authorRole: AuthorRole) => authorRole.workAuthors)
@ManyToMany(() => AuthorRole, (authorRole: AuthorRoleEntityInterface) => authorRole.workAuthors)
@JoinTable()
public authorRoles!: Promise<AuthorRole[]>;
public authorRoles!: Promise<AuthorRoleEntityInterface[]>;
/**
* the author
*/
@ManyToOne(() => Author, (author: Author) => author.workAuthors, {
@ManyToOne(() => Author, (author: AuthorEntityInterface) => author.workAuthors, {
nullable: false,
onDelete: 'RESTRICT',
onUpdate: 'CASCADE',
})
public author!: Promise<Author>;
public author!: Promise<AuthorEntityInterface>;
@Column({
nullable: false,


+ 4
- 4
src/main/entities/library/work-character-name.ts View File

@ -2,16 +2,16 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { WorkCharacter } from './work-character';
@Entity()
export class WorkCharacterName implements IdentifiableEntityInterface, NameEntityInterface {
export class WorkCharacterName implements WorkCharacterNameEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@ManyToOne(() => WorkCharacter, (workCharacter: WorkCharacter) => workCharacter.names, {
@ManyToOne(() => WorkCharacter, (workCharacter: WorkCharacterEntityInterface) => workCharacter.names, {
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public entity!: Promise<WorkCharacter>;
public entity!: Promise<WorkCharacterEntityInterface>;
@Column({
nullable: false,


+ 16
- 36
src/main/entities/library/work-character.ts View File

@ -5,14 +5,10 @@ import { Work } from './work';
import { WorkCharacterName } from './work-character-name';
import { WorldCharacter } from './world-character';
/**
* This entity describes a character in a work.
* The character can be original or based on one or more existing characters.
*/
@Entity()
export class WorkCharacter implements IdentifiableEntityInterface, MultiNamedEntityInterface {
export class WorkCharacter implements WorkCharacterEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@Column({
nullable: false,
@ -20,40 +16,24 @@ export class WorkCharacter implements IdentifiableEntityInterface, MultiNamedEnt
})
public nameCanonical!: string;
@OneToMany(() => WorkCharacterName, (workCharacterName: WorkCharacterName) => workCharacterName.entity)
public names!: Promise<WorkCharacterName[]>;
@OneToMany(() => WorkCharacterName, (workCharacterName: WorkCharacterNameEntityInterface) => workCharacterName.entity)
public names!: Promise<WorkCharacterNameEntityInterface[]>;
/**
* the works the character is a part of
* one work character can be part of multiple works because of series
*/
@ManyToMany(() => Work, (work: Work) => work.workCharacters)
public works!: Promise<Work[]>;
@ManyToMany(() => Work, (work: WorkEntityInterface) => work.workCharacters)
public works!: Promise<WorkEntityInterface[]>;
/**
* interaction with other characters as actor
*/
@ManyToMany(() => InteractionTag, (interactionTag: InteractionTag) => interactionTag.subjectCharacters)
@ManyToMany(() => InteractionTag, (interactionTag: InteractionTagEntityInterface) => interactionTag.subjectCharacters)
@JoinTable()
public interactWith!: Promise<InteractionTag[]>;
public interactWith!: Promise<InteractionTagEntityInterface[]>;
/**
* interaction with other characters as receiver
*/
@ManyToMany(() => InteractionTag, (interactionTag: InteractionTag) => interactionTag.objectCharacters)
@ManyToMany(() => InteractionTag, (interactionTag: InteractionTagEntityInterface) => interactionTag.objectCharacters)
@JoinTable()
public interactedBy!: Promise<InteractionTag[]>;
/**
* tags connected to the character
*/
@OneToMany(() => CharacterTag, (characterTag: CharacterTag) => characterTag.workCharacter)
public characterTags!: Promise<CharacterTag[]>;
/**
* existing characters character is based on
*/
@ManyToMany(() => WorldCharacter, (worldCharacter: WorldCharacter) => worldCharacter.workCharacters)
public interactedBy!: Promise<InteractionTagEntityInterface[]>;
@OneToMany(() => CharacterTag, (characterTag: CharacterTagEntityInterface) => characterTag.workCharacter)
public characterTags!: Promise<CharacterTagEntityInterface[]>;
@ManyToMany(() => WorldCharacter, (worldCharacter: WorldCharacterEntityInterface) => worldCharacter.workCharacters)
@JoinTable()
public worldCharacters!: Promise<WorldCharacter[]>;
public worldCharacters!: Promise<WorldCharacterEntityInterface[]>;
}

+ 4
- 4
src/main/entities/library/work-name.ts View File

@ -2,16 +2,16 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { Work } from './work';
@Entity()
export class WorkName implements IdentifiableEntityInterface, NameEntityInterface {
export class WorkName implements WorkNameEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@ManyToOne(() => Work, (work: Work) => work.names, {
@ManyToOne(() => Work, (work: WorkEntityInterface) => work.names, {
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public entity!: Promise<Work>;
public entity!: Promise<WorkEntityInterface>;
@Column({
nullable: false,


+ 6
- 15
src/main/entities/library/work-tag.ts View File

@ -3,34 +3,25 @@ import { PercentCheck } from '../decorators/percent-check';
import { Tag } from './tag';
import { Work } from './work';
/**
* This tag entity tags a work.
*/
@Entity()
@PercentCheck('weight')
export class WorkTag implements IdentifiableEntityInterface, WeightedEntityInterface {
export class WorkTag implements WorkTagEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
/**
* the describing tag
*/
@ManyToOne(() => Tag, (tag: Tag) => tag.workTags, {
@ManyToOne(() => Tag, (tag: TagEntityInterface) => tag.workTags, {
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public tag!: Promise<Tag>;
public tag!: Promise<TagEntityInterface>;
/**
* the tagged work
*/
@ManyToOne(() => Work, (work: Work) => work.workTags, {
@ManyToOne(() => Work, (work: WorkEntityInterface) => work.workTags, {
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public work!: Promise<Work>;
public work!: Promise<WorkEntityInterface>;
@Column('int', {
nullable: true,


+ 23
- 61
src/main/entities/library/work.ts View File

@ -10,16 +10,11 @@ import { WorkName } from './work-name';
import { WorkTag } from './work-tag';
import { World } from './world';
/**
* This is the main library entity.
*
* It describes a work of art organized by this software.
*/
@Entity()
@PercentCheck('rating')
export class Work implements IdentifiableEntityInterface, MultiNamedEntityInterface {
export class Work implements WorkEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@Column({
nullable: false,
@ -27,88 +22,55 @@ export class Work implements IdentifiableEntityInterface, MultiNamedEntityInterf
})
public nameCanonical!: string;
@OneToMany(() => WorkName, (workName: WorkName) => workName.entity)
public names!: Promise<WorkName[]>;
@OneToMany(() => WorkName, (workName: WorkNameEntityInterface) => workName.entity)
public names!: Promise<WorkNameEntityInterface[]>;
/**
* digital representations of this work
*/
@OneToMany(() => Copy, (copy: Copy) => copy.original)
public copies!: Promise<Copy[]>;
@OneToMany(() => Copy, (copy: CopyEntityInterface) => copy.original, {})
public copies!: Promise<CopyEntityInterface[]>;
/**
* other works this work is a transformation of
*/
@OneToMany(() => Transformation, (transformation: Transformation) => transformation.byWork)
public transformationOf!: Promise<Transformation[]>;
@OneToMany(() => Transformation, (transformation: TransformationEntityInterface) => transformation.byWork)
public transformationOf!: Promise<TransformationEntityInterface[]>;
/**
* other works this work is transformed by
*/
@OneToMany(() => Transformation, (transformation: Transformation) => transformation.ofWork)
public transformedBy!: Promise<Transformation[]>;
@OneToMany(() => Transformation, (transformation: TransformationEntityInterface) => transformation.ofWork)
public transformedBy!: Promise<TransformationEntityInterface[]>;
/**
* the authors/publishers of this work
*/
@OneToMany(() => WorkAuthor, (workAuthor: WorkAuthor) => workAuthor.work)
public workAuthors!: Promise<WorkAuthor[]>;
@OneToMany(() => WorkAuthor, (workAuthor: WorkAuthorEntityInterface) => workAuthor.work)
public workAuthors!: Promise<WorkAuthorEntityInterface[]>;
/**
* tags describing this work
*/
@OneToMany(() => WorkTag, (workTag: WorkTag) => workTag.work)
public workTags!: Promise<WorkTag[]>;
@OneToMany(() => WorkTag, (workTag: WorkTagEntityInterface) => workTag.work)
public workTags!: Promise<WorkTagEntityInterface[]>;
/**
* characters in this work
*/
@ManyToMany(() => WorkCharacter, (workCharacter: WorkCharacter) => workCharacter.works)
@ManyToMany(() => WorkCharacter, (workCharacter: WorkCharacterEntityInterface) => workCharacter.works)
@JoinTable()
public workCharacters!: Promise<WorkCharacter[]>;
public workCharacters!: Promise<WorkCharacterEntityInterface[]>;
/**
* fictional worlds in which this work takes place
*/
@ManyToMany(() => World, (world: World) => world.works)
@ManyToMany(() => World, (world: WorldEntityInterface) => world.works)
@JoinTable()
public worlds!: Promise<World[]>;
public worlds!: Promise<WorldEntityInterface[]>;
/**
* if this work i canon in above fictional world
*/
@Column({
nullable: false,
default: false,
})
public isCanonical!: boolean;
/**
* the user rating of this work
*/
@Column('int', {
nullable: true,
})
public rating!: number | null;
/**
* the release date of the work
*/
@Column('date', {
nullable: true,
})
public releaseDate!: Date | null;
public releaseDate!: string | null;
/**
* the languages of the work (if applicable)
*/
@ManyToMany(() => Language, (language: Language) => language.works)
@ManyToMany(() => Language, (language: LanguageEntityInterface) => language.works)
@JoinTable()
public languages!: Promise<Language[]>;
public languages!: Promise<LanguageEntityInterface[]>;
/**
* the collections this work is a part of
*/
@OneToMany(() => CollectionPart, (collectionPart: CollectionPart) => collectionPart.work)
public collectionParts!: Promise<CollectionPart[]>;
@OneToMany(() => CollectionPart, (collectionPart: CollectionPartEntityInterface) => collectionPart.work)
public collectionParts!: Promise<CollectionPartEntityInterface[]>;
}

+ 4
- 4
src/main/entities/library/world-character-name.ts View File

@ -2,16 +2,16 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { WorldCharacter } from './world-character';
@Entity()
export class WorldCharacterName implements IdentifiableEntityInterface, NameEntityInterface {
export class WorldCharacterName implements WorldCharacterNameEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@ManyToOne(() => WorldCharacter, (worldCharacter: WorldCharacter) => worldCharacter.names, {
@ManyToOne(() => WorldCharacter, (worldCharacter: WorldCharacterEntityInterface) => worldCharacter.names, {
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public entity!: Promise<WorldCharacter>;
public entity!: Promise<WorldCharacterEntityInterface>;
@Column({
nullable: false,


+ 14
- 21
src/main/entities/library/world-character.ts View File

@ -3,14 +3,10 @@ import { WorkCharacter } from './work-character';
import { World } from './world';
import { WorldCharacterName } from './world-character-name';
/**
* This entity describes a canon character in a fictional world.
*/
@Entity()
export class WorldCharacter
implements IdentifiableEntityInterface, MultiNamedEntityInterface, HierarchicalEntityInterface<WorldCharacter> {
export class WorldCharacter implements WorldCharacterEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@Column({
nullable: false,
@ -18,25 +14,22 @@ export class WorldCharacter
})
public nameCanonical!: string;
@OneToMany(() => WorldCharacterName, (worldCharacterName: WorldCharacterName) => worldCharacterName.entity)
public names!: Promise<WorldCharacterName[]>;
@OneToMany(
() => WorldCharacterName,
(worldCharacterName: WorldCharacterNameEntityInterface) => worldCharacterName.entity
)
public names!: Promise<WorldCharacterNameEntityInterface[]>;
/**
* the characters in works which are based on this one
*/
@ManyToMany(() => WorkCharacter, (workCharacter: WorkCharacter) => workCharacter.worldCharacters)
@ManyToMany(() => WorkCharacter, (workCharacter: WorkCharacterEntityInterface) => workCharacter.worldCharacters)
public workCharacters!: Promise<WorkCharacter[]>;
/**
* the fictional worlds this character is a part of
*/
@ManyToMany(() => World, (world: World) => world.worldCharacters)
public worlds!: Promise<World[]>;
@ManyToMany(() => World, (world: WorldEntityInterface) => world.worldCharacters)
public worlds!: Promise<WorldEntityInterface[]>;
@ManyToMany(() => WorldCharacter, (worldCharacter: WorldCharacter) => worldCharacter.children)
@ManyToMany(() => WorldCharacter, (worldCharacter: WorldCharacterEntityInterface) => worldCharacter.children)
@JoinTable()
public parents!: Promise<WorldCharacter[]>;
public parents!: Promise<WorldCharacterEntityInterface[]>;
@ManyToMany(() => WorldCharacter, (worldCharacter: WorldCharacter) => worldCharacter.parents)
public children!: Promise<WorldCharacter[]>;
@ManyToMany(() => WorldCharacter, (worldCharacter: WorldCharacterEntityInterface) => worldCharacter.parents)
public children!: Promise<WorldCharacterEntityInterface[]>;
}

+ 4
- 4
src/main/entities/library/world-name.ts View File

@ -2,16 +2,16 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
import { World } from './world';
@Entity()
export class WorldName implements IdentifiableEntityInterface, NameEntityInterface {
export class WorldName implements WorldNameEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@ManyToOne(() => World, (world: World) => world.names, {
@ManyToOne(() => World, (world: WorldEntityInterface) => world.names, {
nullable: false,
onDelete: 'CASCADE',
onUpdate: 'CASCADE',
})
public entity!: Promise<World>;
public entity!: Promise<WorldEntityInterface>;
@Column({
nullable: false,


+ 12
- 22
src/main/entities/library/world.ts View File

@ -3,14 +3,10 @@ import { Work } from './work';
import { WorldCharacter } from './world-character';
import { WorldName } from './world-name';
/**
* This entity describes a fictional world.
*/
@Entity()
export class World
implements IdentifiableEntityInterface, MultiNamedEntityInterface, HierarchicalEntityInterface<World> {
export class World implements WorldEntityInterface {
@PrimaryGeneratedColumn()
public id!: number;
public readonly id!: number;
@Column({
nullable: false,
@ -18,26 +14,20 @@ export class World
})
public nameCanonical!: string;
@OneToMany(() => WorldName, (worldName: WorldName) => worldName.entity)
public names!: Promise<WorldName[]>;
@OneToMany(() => WorldName, (worldName: WorldNameEntityInterface) => worldName.entity)
public names!: Promise<WorldNameEntityInterface[]>;
/**
* works taking place in this world
*/
@ManyToMany(() => Work, (work: Work) => work.worlds)
public works!: Promise<Work[]>;
@ManyToMany(() => Work, (work: WorkEntityInterface) => work.worlds)
public works!: Promise<WorkEntityInterface[]>;
/**
* canon characters in this world
*/
@ManyToMany(() => WorldCharacter, (worldCharacter: WorldCharacter) => worldCharacter.worlds)
@ManyToMany(() => WorldCharacter, (worldCharacter: WorldCharacterEntityInterface) => worldCharacter.worlds)
@JoinTable()
public worldCharacters!: Promise<WorldCharacter[]>;
public worldCharacters!: Promise<WorldCharacterEntityInterface[]>;
@ManyToMany(() => World, (world: World) => world.parents)
public children!: Promise<World[]>;
@ManyToMany(() => World, (world: WorldEntityInterface) => world.parents)
public children!: Promise<WorldEntityInterface[]>;
@ManyToMany(() => World, (world: World) => world.children)
@ManyToMany(() => World, (world: WorldEntityInterface) => world.children)
@JoinTable()
public parents!: Promise<World[]>;
public parents!: Promise<WorldEntityInterface[]>;
}

src/main/migrations/library/1597705000730-initial_migration.ts → src/main/migrations/library/1611508597488-initial.ts View File


+ 198
- 0
src/main/migrations/library/1611508644004-add_languages.ts View File

@ -0,0 +1,198 @@
import type { MigrationInterface, QueryRunner } from 'typeorm';
export class addLanguages1611508644004 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.ABKHAZIAN}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.AFAR}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.AFRIKAANS}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.AKAN}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.ALBANIAN}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.AMHARIC}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.ARABIC}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.ARAGONESE}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.ARMENIAN}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.ASSAMESE}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.AVARIC}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.AVESTAN}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.AYMARA}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.AZERBAIJANI}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.BAMBARA}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.BASHKIR}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.BASQUE}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.BELARUSIAN}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.BENGALI}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.BIHARI_LANGUAGES}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.BISLAMA}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.BOSNIAN}')`);
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.BRETON}')`);