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
This commit is contained in:
parent
8d6d7dc6d8
commit
6b2824daab
|
@ -1,14 +1,11 @@
|
||||||
{
|
{
|
||||||
"root": true,
|
"root": true,
|
||||||
"plugins": ["@typescript-eslint", "import"],
|
"plugins": ["@typescript-eslint", "import"],
|
||||||
"extends": ["eslint:recommended", "prettier"],
|
"extends": ["eslint:recommended", "prettier", "plugin:import/recommended"],
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"ecmaVersion": 2019,
|
"ecmaVersion": 2019,
|
||||||
"sourceType": "module"
|
"sourceType": "module"
|
||||||
},
|
},
|
||||||
"settings": {
|
|
||||||
"import/core-modules": ["electron"]
|
|
||||||
},
|
|
||||||
"env": {
|
"env": {
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"node": true
|
"node": true
|
||||||
|
@ -43,6 +40,8 @@
|
||||||
"no-constant-condition": ["error", { "checkLoops": false }],
|
"no-constant-condition": ["error", { "checkLoops": false }],
|
||||||
"no-throw-literal": "error",
|
"no-throw-literal": "error",
|
||||||
"curly": "error",
|
"curly": "error",
|
||||||
|
"no-promise-executor-return": "error",
|
||||||
|
"no-return-await": "error",
|
||||||
|
|
||||||
"import/no-extraneous-dependencies": [
|
"import/no-extraneous-dependencies": [
|
||||||
"error",
|
"error",
|
||||||
|
@ -50,6 +49,7 @@
|
||||||
"devDependencies": [
|
"devDependencies": [
|
||||||
"**/*.{spec,mock}.*",
|
"**/*.{spec,mock}.*",
|
||||||
"src/**/test/*",
|
"src/**/test/*",
|
||||||
|
"src/renderer.ts",
|
||||||
"src/renderer/**/*",
|
"src/renderer/**/*",
|
||||||
"declarations/**/*",
|
"declarations/**/*",
|
||||||
"templates/**/*",
|
"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/no-default-export": "error",
|
||||||
"import/first": "error",
|
"import/first": "error",
|
||||||
"import/order": [
|
"import/order": [
|
||||||
|
@ -75,7 +100,9 @@
|
||||||
"plugin:@typescript-eslint/eslint-recommended",
|
"plugin:@typescript-eslint/eslint-recommended",
|
||||||
"plugin:@typescript-eslint/recommended",
|
"plugin:@typescript-eslint/recommended",
|
||||||
"plugin:@typescript-eslint/recommended-requiring-type-checking",
|
"plugin:@typescript-eslint/recommended-requiring-type-checking",
|
||||||
"prettier/@typescript-eslint"
|
"prettier/@typescript-eslint",
|
||||||
|
"plugin:import/typescript",
|
||||||
|
"plugin:import/electron"
|
||||||
],
|
],
|
||||||
"parser": "@typescript-eslint/parser",
|
"parser": "@typescript-eslint/parser",
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
|
|
|
@ -9,6 +9,7 @@ import '../modules/nhentai/nhentai-ipc-controller';
|
||||||
import { NhentaiAppWindow } from '../modules/nhentai/nhentai-app-window';
|
import { NhentaiAppWindow } from '../modules/nhentai/nhentai-app-window';
|
||||||
import { NhentaiSourceGetter } from '../modules/nhentai/nhentai-source-getter';
|
import { NhentaiSourceGetter } from '../modules/nhentai/nhentai-source-getter';
|
||||||
import { Store } from '../modules/store/store';
|
import { Store } from '../modules/store/store';
|
||||||
|
import '../modules/entity-api/entity-api-ipc-controller';
|
||||||
import BindingToSyntax = interfaces.BindingToSyntax;
|
import BindingToSyntax = interfaces.BindingToSyntax;
|
||||||
|
|
||||||
export const container = {
|
export const container = {
|
||||||
|
|
|
@ -2,16 +2,16 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
import { Author } from './author';
|
import { Author } from './author';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class AuthorName implements IdentifiableEntityInterface, NameEntityInterface {
|
export class AuthorName implements AuthorNameEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@ManyToOne(() => Author, (author: Author) => author.names, {
|
@ManyToOne(() => Author, (author: AuthorEntityInterface) => author.names, {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public entity!: Promise<Author>;
|
public entity!: Promise<AuthorEntityInterface>;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
|
|
@ -2,16 +2,16 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
import { AuthorRole } from './author-role';
|
import { AuthorRole } from './author-role';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class AuthorRoleName implements IdentifiableEntityInterface, NameEntityInterface {
|
export class AuthorRoleName implements AuthorRoleNameEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@ManyToOne(() => AuthorRole, (authorRole: AuthorRole) => authorRole.names, {
|
@ManyToOne(() => AuthorRole, (authorRole: AuthorRoleEntityInterface) => authorRole.names, {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public entity!: Promise<AuthorRole>;
|
public entity!: Promise<AuthorRoleEntityInterface>;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
|
|
@ -2,14 +2,10 @@ import { Column, Entity, ManyToMany, OneToMany, PrimaryGeneratedColumn } from 't
|
||||||
import { AuthorRoleName } from './author-role-name';
|
import { AuthorRoleName } from './author-role-name';
|
||||||
import { WorkAuthor } from './work-author';
|
import { WorkAuthor } from './work-author';
|
||||||
|
|
||||||
/**
|
|
||||||
* This entity describes the role an author has in a work.
|
|
||||||
* Examples: story writing, drawing, animating, publishing, ...
|
|
||||||
*/
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class AuthorRole implements IdentifiableEntityInterface, MultiNamedEntityInterface, DescribableEntityInterface {
|
export class AuthorRole implements AuthorRoleEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
@ -17,14 +13,11 @@ export class AuthorRole implements IdentifiableEntityInterface, MultiNamedEntity
|
||||||
})
|
})
|
||||||
public nameCanonical!: string;
|
public nameCanonical!: string;
|
||||||
|
|
||||||
@OneToMany(() => AuthorRoleName, (authorRoleName: AuthorRoleName) => authorRoleName.entity)
|
@OneToMany(() => AuthorRoleName, (authorRoleName: AuthorRoleNameEntityInterface) => authorRoleName.entity)
|
||||||
public names!: Promise<AuthorRoleName[]>;
|
public names!: Promise<AuthorRoleNameEntityInterface[]>;
|
||||||
|
|
||||||
/**
|
@ManyToMany(() => WorkAuthor, (workAuthor: WorkAuthorEntityInterface) => workAuthor.authorRoles)
|
||||||
* relation to the entity connecting with the author and work
|
public workAuthors!: Promise<WorkAuthorEntityInterface[]>;
|
||||||
*/
|
|
||||||
@ManyToMany(() => WorkAuthor, (workAuthor: WorkAuthor) => workAuthor.authorRoles)
|
|
||||||
public workAuthors!: Promise<WorkAuthor[]>;
|
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
|
|
@ -2,13 +2,10 @@ import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
import { AuthorName } from './author-name';
|
import { AuthorName } from './author-name';
|
||||||
import { WorkAuthor } from './work-author';
|
import { WorkAuthor } from './work-author';
|
||||||
|
|
||||||
/**
|
|
||||||
* This entity represents a single real-world entity, be it a person or named group of persons.
|
|
||||||
*/
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class Author implements IdentifiableEntityInterface, MultiNamedEntityInterface {
|
export class Author implements AuthorEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
@ -16,12 +13,9 @@ export class Author implements IdentifiableEntityInterface, MultiNamedEntityInte
|
||||||
})
|
})
|
||||||
public nameCanonical!: string;
|
public nameCanonical!: string;
|
||||||
|
|
||||||
@OneToMany(() => AuthorName, (authorName: AuthorName) => authorName.entity)
|
@OneToMany(() => AuthorName, (authorName: AuthorNameEntityInterface) => authorName.entity)
|
||||||
public names!: Promise<AuthorName[]>;
|
public names!: Promise<AuthorNameEntityInterface[]>;
|
||||||
|
|
||||||
/**
|
@OneToMany(() => WorkAuthor, (workAuthor: WorkAuthorEntityInterface) => workAuthor.author, {})
|
||||||
* ultimately connects the author with a work and their role in that work
|
public workAuthors!: Promise<WorkAuthorEntityInterface[]>;
|
||||||
*/
|
|
||||||
@OneToMany(() => WorkAuthor, (workAuthor: WorkAuthor) => workAuthor.author)
|
|
||||||
public workAuthors!: Promise<WorkAuthor[]>;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,34 +3,25 @@ import { PercentCheck } from '../decorators/percent-check';
|
||||||
import { Tag } from './tag';
|
import { Tag } from './tag';
|
||||||
import { WorkCharacter } from './work-character';
|
import { WorkCharacter } from './work-character';
|
||||||
|
|
||||||
/**
|
|
||||||
* This tag entity tags a character in a work.
|
|
||||||
*/
|
|
||||||
@Entity()
|
@Entity()
|
||||||
@PercentCheck('weight')
|
@PercentCheck('weight')
|
||||||
export class CharacterTag implements IdentifiableEntityInterface, WeightedEntityInterface {
|
export class CharacterTag implements CharacterTagEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
/**
|
@ManyToOne(() => WorkCharacter, (workCharacter: WorkCharacterEntityInterface) => workCharacter.characterTags, {
|
||||||
* the character ina work this tag describes
|
|
||||||
*/
|
|
||||||
@ManyToOne(() => WorkCharacter, (workCharacter: WorkCharacter) => workCharacter.characterTags, {
|
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public workCharacter!: Promise<WorkCharacter>;
|
public workCharacter!: Promise<WorkCharacterEntityInterface>;
|
||||||
|
|
||||||
/**
|
@ManyToOne(() => Tag, (tag: TagEntityInterface) => tag.characterTags, {
|
||||||
* the describing tag
|
|
||||||
*/
|
|
||||||
@ManyToOne(() => Tag, (tag: Tag) => tag.characterTags, {
|
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public tag!: Promise<Tag>;
|
public tag!: Promise<TagEntityInterface>;
|
||||||
|
|
||||||
@Column('int', {
|
@Column('int', {
|
||||||
nullable: true,
|
nullable: true,
|
||||||
|
|
|
@ -2,16 +2,16 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
import { Collection } from './collection';
|
import { Collection } from './collection';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class CollectionName implements IdentifiableEntityInterface, NameEntityInterface {
|
export class CollectionName implements CollectionNameEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@ManyToOne(() => Collection, (collection: Collection) => collection.names, {
|
@ManyToOne(() => Collection, (collection: CollectionEntityInterface) => collection.names, {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public entity!: Promise<Collection>;
|
public entity!: Promise<CollectionEntityInterface>;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
|
|
@ -2,34 +2,24 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
import { Collection } from './collection';
|
import { Collection } from './collection';
|
||||||
import { Work } from './work';
|
import { Work } from './work';
|
||||||
|
|
||||||
/**
|
|
||||||
* This entity orders works in a collection.
|
|
||||||
* The main use case is chronological ordering.
|
|
||||||
*/
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class CollectionPart implements IdentifiableEntityInterface, OrderableEntityInterface {
|
export class CollectionPart implements CollectionPartEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
/**
|
@ManyToOne(() => Collection, (collection: CollectionEntityInterface) => collection.parts, {
|
||||||
* the collection thw work is a part of
|
|
||||||
*/
|
|
||||||
@ManyToOne(() => Collection, (collection: Collection) => collection.parts, {
|
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public collection!: Promise<Collection>;
|
public collection!: Promise<CollectionEntityInterface>;
|
||||||
|
|
||||||
/**
|
@ManyToOne(() => Work, (work: WorkEntityInterface) => work.collectionParts, {
|
||||||
* the work inside the collection
|
|
||||||
*/
|
|
||||||
@ManyToOne(() => Work, (work: Work) => work.collectionParts, {
|
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public work!: Promise<Work>;
|
public work!: Promise<WorkEntityInterface>;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
|
|
@ -2,18 +2,10 @@ import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
import { CollectionName } from './collection-name';
|
import { CollectionName } from './collection-name';
|
||||||
import { CollectionPart } from './collection-part';
|
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()
|
@Entity()
|
||||||
export class Collection implements IdentifiableEntityInterface, MultiNamedEntityInterface {
|
export class Collection implements CollectionEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
@ -21,12 +13,9 @@ export class Collection implements IdentifiableEntityInterface, MultiNamedEntity
|
||||||
})
|
})
|
||||||
public nameCanonical!: string;
|
public nameCanonical!: string;
|
||||||
|
|
||||||
@OneToMany(() => CollectionName, (collectionName: CollectionName) => collectionName.entity)
|
@OneToMany(() => CollectionName, (collectionName: CollectionNameEntityInterface) => collectionName.entity)
|
||||||
public names!: Promise<CollectionName[]>;
|
public names!: Promise<CollectionNameEntityInterface[]>;
|
||||||
|
|
||||||
/**
|
@OneToMany(() => CollectionPart, (collectionPart: CollectionPartEntityInterface) => collectionPart.collection)
|
||||||
* the connecting entity between this collection and the work
|
public parts!: Promise<CollectionPartEntityInterface[]>;
|
||||||
*/
|
|
||||||
@OneToMany(() => CollectionPart, (collectionPart: CollectionPart) => collectionPart.collection)
|
|
||||||
public parts!: Promise<CollectionPart[]>;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,55 +2,33 @@ import { Column, Entity, JoinTable, ManyToMany, ManyToOne, PrimaryGeneratedColum
|
||||||
import { Source } from './source';
|
import { Source } from './source';
|
||||||
import { Work } from './work';
|
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()
|
@Entity()
|
||||||
export class Copy implements IdentifiableEntityInterface {
|
export class Copy implements CopyEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
/**
|
@ManyToOne(() => Work, (work: WorkEntityInterface) => work.copies, {
|
||||||
* the work this entity is a copy of
|
|
||||||
*/
|
|
||||||
@ManyToOne(() => Work, (work: Work) => work.copies, {
|
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public original!: Promise<Work>;
|
public original!: Promise<WorkEntityInterface>;
|
||||||
|
|
||||||
/**
|
@ManyToMany(() => Source, (source: SourceEntityInterface) => source.copies)
|
||||||
* where to find this specific copy
|
|
||||||
*/
|
|
||||||
@ManyToMany(() => Source, (source: Source) => source.copies)
|
|
||||||
@JoinTable()
|
@JoinTable()
|
||||||
public sources!: Promise<Source[]>;
|
public sources!: Promise<SourceEntityInterface[]>;
|
||||||
|
|
||||||
/**
|
|
||||||
* identifying hash of the file contents
|
|
||||||
*/
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
default: '',
|
default: '',
|
||||||
})
|
})
|
||||||
public hash!: string;
|
public hash!: string;
|
||||||
|
|
||||||
/**
|
|
||||||
* device location of the copy
|
|
||||||
*/
|
|
||||||
@Column('text', {
|
@Column('text', {
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
public location!: string | null;
|
public location!: string | null;
|
||||||
|
|
||||||
/**
|
|
||||||
* the ordering of the copies belonging to the same work,
|
|
||||||
* lower number is higher ranked
|
|
||||||
*/
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
default: 0,
|
default: 0,
|
||||||
|
|
|
@ -3,36 +3,24 @@ import { PercentCheck } from '../decorators/percent-check';
|
||||||
import { Tag } from './tag';
|
import { Tag } from './tag';
|
||||||
import { WorkCharacter } from './work-character';
|
import { WorkCharacter } from './work-character';
|
||||||
|
|
||||||
/**
|
|
||||||
* This tag entity tags an interaction between two characters.
|
|
||||||
*/
|
|
||||||
@Entity()
|
@Entity()
|
||||||
@PercentCheck('weight')
|
@PercentCheck('weight')
|
||||||
export class InteractionTag implements IdentifiableEntityInterface, WeightedEntityInterface {
|
export class InteractionTag implements InteractionTagEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
/**
|
@ManyToOne(() => Tag, (tag: TagEntityInterface) => tag.interactionTags, {
|
||||||
* the describing tag
|
|
||||||
*/
|
|
||||||
@ManyToOne(() => Tag, (tag: Tag) => tag.interactionTags, {
|
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public tag!: Promise<Tag>;
|
public tag!: Promise<TagEntityInterface>;
|
||||||
|
|
||||||
/**
|
@ManyToMany(() => WorkCharacter, (workCharacter: WorkCharacterEntityInterface) => workCharacter.interactWith)
|
||||||
* the actors of this interaction
|
public subjectCharacters!: Promise<WorkCharacterEntityInterface[]>;
|
||||||
*/
|
|
||||||
@ManyToMany(() => WorkCharacter, (workCharacter: WorkCharacter) => workCharacter.interactWith)
|
|
||||||
public subjectCharacters!: Promise<WorkCharacter[]>;
|
|
||||||
|
|
||||||
/**
|
@ManyToMany(() => WorkCharacter, (workCharacter: WorkCharacterEntityInterface) => workCharacter.interactedBy)
|
||||||
* the receivers of this interaction
|
public objectCharacters!: Promise<WorkCharacterEntityInterface[]>;
|
||||||
*/
|
|
||||||
@ManyToMany(() => WorkCharacter, (workCharacter: WorkCharacter) => workCharacter.interactedBy)
|
|
||||||
public objectCharacters!: Promise<WorkCharacter[]>;
|
|
||||||
|
|
||||||
@Column('int', {
|
@Column('int', {
|
||||||
nullable: true,
|
nullable: true,
|
||||||
|
|
|
@ -1,20 +1,11 @@
|
||||||
import { Entity, ManyToMany, PrimaryColumn } from 'typeorm';
|
import { Entity, ManyToMany, PrimaryColumn } from 'typeorm';
|
||||||
import { Work } from './work';
|
import { Work } from './work';
|
||||||
|
|
||||||
/**
|
|
||||||
* This entity is non-user-maintained and describes a language.
|
|
||||||
*/
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class Language {
|
export class Language implements LanguageEntityInterface {
|
||||||
/**
|
|
||||||
* ISO 639-1 two-letter language code
|
|
||||||
*/
|
|
||||||
@PrimaryColumn()
|
@PrimaryColumn()
|
||||||
public code!: string;
|
public code!: string;
|
||||||
|
|
||||||
/**
|
@ManyToMany(() => Work, (work: WorkEntityInterface) => work.languages)
|
||||||
* the works using this language
|
public works!: Promise<WorkEntityInterface[]>;
|
||||||
*/
|
|
||||||
@ManyToMany(() => Work, (work: Work) => work.languages)
|
|
||||||
public works!: Promise<Work[]>;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,16 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
import { Site } from './site';
|
import { Site } from './site';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class SiteName implements IdentifiableEntityInterface, NameEntityInterface {
|
export class SiteName implements SiteNameEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@ManyToOne(() => Site, (site: Site) => site.names, {
|
@ManyToOne(() => Site, (site: SiteEntityInterface) => site.names, {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public entity!: Promise<Site>;
|
public entity!: Promise<SiteEntityInterface>;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
|
|
@ -2,13 +2,10 @@ import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
import { SiteName } from './site-name';
|
import { SiteName } from './site-name';
|
||||||
import { Source } from './source';
|
import { Source } from './source';
|
||||||
|
|
||||||
/**
|
|
||||||
* This non-user-maintained entity describes an online provider of works which can be scraped.
|
|
||||||
*/
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class Site implements IdentifiableEntityInterface, MultiNamedEntityInterface {
|
export class Site implements SiteEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
@ -16,12 +13,9 @@ export class Site implements IdentifiableEntityInterface, MultiNamedEntityInterf
|
||||||
})
|
})
|
||||||
public nameCanonical!: string;
|
public nameCanonical!: string;
|
||||||
|
|
||||||
@OneToMany(() => SiteName, (siteName: SiteName) => siteName.entity)
|
@OneToMany(() => SiteName, (siteName: SiteNameEntityInterface) => siteName.entity)
|
||||||
public names!: Promise<SiteName[]>;
|
public names!: Promise<SiteNameEntityInterface[]>;
|
||||||
|
|
||||||
/**
|
@OneToMany(() => Source, (source: SourceEntityInterface) => source.site)
|
||||||
* sources belonging to this site
|
public sources!: Promise<SourceEntityInterface[]>;
|
||||||
*/
|
|
||||||
@OneToMany(() => Source, (source: Source) => source.site)
|
|
||||||
public sources!: Promise<Source[]>;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,36 +2,24 @@ import { Column, Entity, ManyToMany, ManyToOne, PrimaryGeneratedColumn } from 't
|
||||||
import { Copy } from './copy';
|
import { Copy } from './copy';
|
||||||
import { Site } from './site';
|
import { Site } from './site';
|
||||||
|
|
||||||
/**
|
|
||||||
* This entity describes an external source of a copy, in most cases that is a website.
|
|
||||||
*/
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class Source implements IdentifiableEntityInterface {
|
export class Source implements SourceEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
/**
|
|
||||||
* the uri to the sauce
|
|
||||||
*/
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
default: '',
|
default: '',
|
||||||
})
|
})
|
||||||
public uri!: string;
|
public uri!: string;
|
||||||
|
|
||||||
/**
|
@ManyToOne(() => Site, (site: SiteEntityInterface) => site.sources, {
|
||||||
* the site connected to the source
|
|
||||||
*/
|
|
||||||
@ManyToOne(() => Site, (site: Site) => site.sources, {
|
|
||||||
nullable: true,
|
nullable: true,
|
||||||
onDelete: 'RESTRICT',
|
onDelete: 'RESTRICT',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public site!: Promise<Site> | null;
|
public site!: Promise<SiteEntityInterface> | null;
|
||||||
|
|
||||||
/**
|
@ManyToMany(() => Copy, (copy: CopyEntityInterface) => copy.sources)
|
||||||
* the copies which can be found here
|
public copies!: Promise<CopyEntityInterface[]>;
|
||||||
*/
|
|
||||||
@ManyToMany(() => Copy, (copy: Copy) => copy.sources)
|
|
||||||
public copies!: Promise<Copy[]>;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,16 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
import { Tag } from './tag';
|
import { Tag } from './tag';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class TagName implements IdentifiableEntityInterface, NameEntityInterface {
|
export class TagName implements TagNameEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@ManyToOne(() => Tag, (tag: Tag) => tag.names, {
|
@ManyToOne(() => Tag, (tag: TagEntityInterface) => tag.names, {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public entity!: Promise<Tag>;
|
public entity!: Promise<TagEntityInterface>;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
|
|
@ -4,21 +4,10 @@ import { InteractionTag } from './interaction-tag';
|
||||||
import { TagName } from './tag-name';
|
import { TagName } from './tag-name';
|
||||||
import { WorkTag } from './work-tag';
|
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()
|
@Entity()
|
||||||
export class Tag
|
export class Tag implements TagEntityInterface {
|
||||||
implements
|
|
||||||
IdentifiableEntityInterface,
|
|
||||||
MultiNamedEntityInterface,
|
|
||||||
DescribableEntityInterface,
|
|
||||||
HierarchicalEntityInterface<Tag> {
|
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
@ -26,26 +15,17 @@ export class Tag
|
||||||
})
|
})
|
||||||
public nameCanonical!: string;
|
public nameCanonical!: string;
|
||||||
|
|
||||||
@OneToMany(() => TagName, (tagName: TagName) => tagName.entity)
|
@OneToMany(() => TagName, (tagName: TagNameEntityInterface) => tagName.entity)
|
||||||
public names!: Promise<TagName[]>;
|
public names!: Promise<TagNameEntityInterface[]>;
|
||||||
|
|
||||||
/**
|
@OneToMany(() => WorkTag, (workTag: WorkTagEntityInterface) => workTag.tag)
|
||||||
* this tag tagging a work
|
public workTags!: Promise<WorkTagEntityInterface[]>;
|
||||||
*/
|
|
||||||
@OneToMany(() => WorkTag, (workTag: WorkTag) => workTag.tag)
|
|
||||||
public workTags!: Promise<WorkTag[]>;
|
|
||||||
|
|
||||||
/**
|
@OneToMany(() => CharacterTag, (characterTag: CharacterTagEntityInterface) => characterTag.tag)
|
||||||
* this tag tagging characters
|
public characterTags!: Promise<CharacterTagEntityInterface[]>;
|
||||||
*/
|
|
||||||
@OneToMany(() => CharacterTag, (characterTag: CharacterTag) => characterTag.tag)
|
|
||||||
public characterTags!: Promise<CharacterTag[]>;
|
|
||||||
|
|
||||||
/**
|
@OneToMany(() => InteractionTag, (interactionTag: InteractionTagEntityInterface) => interactionTag.tag)
|
||||||
* this tag tagging a character interaction
|
public interactionTags!: Promise<InteractionTagEntityInterface[]>;
|
||||||
*/
|
|
||||||
@OneToMany(() => InteractionTag, (interactionTag: InteractionTag) => interactionTag.tag)
|
|
||||||
public interactionTags!: Promise<InteractionTag[]>;
|
|
||||||
|
|
||||||
@ManyToMany(() => Tag, (tag: Tag) => tag.children)
|
@ManyToMany(() => Tag, (tag: Tag) => tag.children)
|
||||||
@JoinTable()
|
@JoinTable()
|
||||||
|
|
|
@ -2,16 +2,20 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
import { TransformationType } from './transformation-type';
|
import { TransformationType } from './transformation-type';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class TransformationTypeName implements IdentifiableEntityInterface, NameEntityInterface {
|
export class TransformationTypeName implements TransformationTypeNameEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@ManyToOne(() => TransformationType, (transformationType: TransformationType) => transformationType.names, {
|
@ManyToOne(
|
||||||
nullable: false,
|
() => TransformationType,
|
||||||
onDelete: 'CASCADE',
|
(transformationType: TransformationTypeEntityInterface) => transformationType.names,
|
||||||
onUpdate: 'CASCADE',
|
{
|
||||||
})
|
nullable: false,
|
||||||
public entity!: Promise<TransformationType>;
|
onDelete: 'CASCADE',
|
||||||
|
onUpdate: 'CASCADE',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
public entity!: Promise<TransformationTypeEntityInterface>;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
|
|
@ -2,15 +2,10 @@ import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
import { Transformation } from './transformation';
|
import { Transformation } from './transformation';
|
||||||
import { TransformationTypeName } from './transformation-type-name';
|
import { TransformationTypeName } from './transformation-type-name';
|
||||||
|
|
||||||
/**
|
|
||||||
* This entity describes a transformation type.
|
|
||||||
* Possible type: translation, decensor, collection, ...
|
|
||||||
*/
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class TransformationType
|
export class TransformationType implements TransformationTypeEntityInterface {
|
||||||
implements IdentifiableEntityInterface, MultiNamedEntityInterface, DescribableEntityInterface {
|
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
@ -20,9 +15,10 @@ export class TransformationType
|
||||||
|
|
||||||
@OneToMany(
|
@OneToMany(
|
||||||
() => TransformationTypeName,
|
() => TransformationTypeName,
|
||||||
(transformationTypeName: TransformationTypeName) => transformationTypeName.entity
|
(transformationTypeName: TransformationTypeNameEntityInterface) => transformationTypeName.entity,
|
||||||
|
{}
|
||||||
)
|
)
|
||||||
public names!: Promise<TransformationTypeName[]>;
|
public names!: Promise<TransformationTypeNameEntityInterface[]>;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
@ -33,8 +29,8 @@ export class TransformationType
|
||||||
/**
|
/**
|
||||||
* the transformations of this type
|
* the transformations of this type
|
||||||
*/
|
*/
|
||||||
@OneToMany(() => Transformation, (transformation: Transformation) => transformation.type)
|
@OneToMany(() => Transformation, (transformation: TransformationEntityInterface) => transformation.type)
|
||||||
public transformations!: Promise<Transformation[]>;
|
public transformations!: Promise<TransformationEntityInterface[]>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* if that transformation conserves the tags of the original work
|
* if that transformation conserves the tags of the original work
|
||||||
|
|
|
@ -2,17 +2,11 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
import { TransformationType } from './transformation-type';
|
import { TransformationType } from './transformation-type';
|
||||||
import { Work } from './work';
|
import { Work } from './work';
|
||||||
|
|
||||||
/**
|
|
||||||
* This entity describes how one work is transformed to another.
|
|
||||||
*/
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class Transformation implements IdentifiableEntityInterface, OrderableEntityInterface {
|
export class Transformation implements TransformationEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
/**
|
|
||||||
* the work based on the original
|
|
||||||
*/
|
|
||||||
@ManyToOne(() => Work, (work: Work) => work.transformationOf, {
|
@ManyToOne(() => Work, (work: Work) => work.transformationOf, {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
|
@ -20,25 +14,23 @@ export class Transformation implements IdentifiableEntityInterface, OrderableEnt
|
||||||
})
|
})
|
||||||
public byWork!: Promise<Work>;
|
public byWork!: Promise<Work>;
|
||||||
|
|
||||||
/**
|
@ManyToOne(
|
||||||
* the transformation type
|
() => TransformationType,
|
||||||
*/
|
(transformationType: TransformationTypeEntityInterface) => transformationType.transformations,
|
||||||
@ManyToOne(() => TransformationType, (transformationType: TransformationType) => transformationType.transformations, {
|
{
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'RESTRICT',
|
onDelete: 'RESTRICT',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
}
|
||||||
public type!: Promise<TransformationType>;
|
)
|
||||||
|
public type!: Promise<TransformationTypeEntityInterface>;
|
||||||
|
|
||||||
/**
|
@ManyToOne(() => Work, (work: WorkEntityInterface) => work.transformedBy, {
|
||||||
* the original work
|
nullable: true,
|
||||||
*/
|
|
||||||
@ManyToOne(() => Work, (work: Work) => work.transformedBy, {
|
|
||||||
nullable: false,
|
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public ofWork!: Promise<Work>;
|
public ofWork!: Promise<WorkEntityInterface> | null;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
|
|
@ -3,40 +3,28 @@ import { Author } from './author';
|
||||||
import { AuthorRole } from './author-role';
|
import { AuthorRole } from './author-role';
|
||||||
import { Work } from './work';
|
import { Work } from './work';
|
||||||
|
|
||||||
/**
|
|
||||||
* This entity connects authors with their work and their role therein.
|
|
||||||
*/
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class WorkAuthor implements IdentifiableEntityInterface, OrderableEntityInterface {
|
export class WorkAuthor implements WorkAuthorEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
/**
|
@ManyToOne(() => Work, (work: WorkEntityInterface) => work.workAuthors, {
|
||||||
* the work
|
|
||||||
*/
|
|
||||||
@ManyToOne(() => Work, (work: Work) => work.workAuthors, {
|
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public work!: Promise<Work>;
|
public work!: Promise<WorkEntityInterface>;
|
||||||
|
|
||||||
/**
|
@ManyToMany(() => AuthorRole, (authorRole: AuthorRoleEntityInterface) => authorRole.workAuthors)
|
||||||
* the roles of the author in the work
|
|
||||||
*/
|
|
||||||
@ManyToMany(() => AuthorRole, (authorRole: AuthorRole) => authorRole.workAuthors)
|
|
||||||
@JoinTable()
|
@JoinTable()
|
||||||
public authorRoles!: Promise<AuthorRole[]>;
|
public authorRoles!: Promise<AuthorRoleEntityInterface[]>;
|
||||||
|
|
||||||
/**
|
@ManyToOne(() => Author, (author: AuthorEntityInterface) => author.workAuthors, {
|
||||||
* the author
|
|
||||||
*/
|
|
||||||
@ManyToOne(() => Author, (author: Author) => author.workAuthors, {
|
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'RESTRICT',
|
onDelete: 'RESTRICT',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public author!: Promise<Author>;
|
public author!: Promise<AuthorEntityInterface>;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
|
|
@ -2,16 +2,16 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
import { WorkCharacter } from './work-character';
|
import { WorkCharacter } from './work-character';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class WorkCharacterName implements IdentifiableEntityInterface, NameEntityInterface {
|
export class WorkCharacterName implements WorkCharacterNameEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@ManyToOne(() => WorkCharacter, (workCharacter: WorkCharacter) => workCharacter.names, {
|
@ManyToOne(() => WorkCharacter, (workCharacter: WorkCharacterEntityInterface) => workCharacter.names, {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public entity!: Promise<WorkCharacter>;
|
public entity!: Promise<WorkCharacterEntityInterface>;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
|
|
@ -5,14 +5,10 @@ import { Work } from './work';
|
||||||
import { WorkCharacterName } from './work-character-name';
|
import { WorkCharacterName } from './work-character-name';
|
||||||
import { WorldCharacter } from './world-character';
|
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()
|
@Entity()
|
||||||
export class WorkCharacter implements IdentifiableEntityInterface, MultiNamedEntityInterface {
|
export class WorkCharacter implements WorkCharacterEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
@ -20,40 +16,24 @@ export class WorkCharacter implements IdentifiableEntityInterface, MultiNamedEnt
|
||||||
})
|
})
|
||||||
public nameCanonical!: string;
|
public nameCanonical!: string;
|
||||||
|
|
||||||
@OneToMany(() => WorkCharacterName, (workCharacterName: WorkCharacterName) => workCharacterName.entity)
|
@OneToMany(() => WorkCharacterName, (workCharacterName: WorkCharacterNameEntityInterface) => workCharacterName.entity)
|
||||||
public names!: Promise<WorkCharacterName[]>;
|
public names!: Promise<WorkCharacterNameEntityInterface[]>;
|
||||||
|
|
||||||
/**
|
@ManyToMany(() => Work, (work: WorkEntityInterface) => work.workCharacters)
|
||||||
* the works the character is a part of
|
public works!: Promise<WorkEntityInterface[]>;
|
||||||
* one work character can be part of multiple works because of series
|
|
||||||
*/
|
|
||||||
@ManyToMany(() => Work, (work: Work) => work.workCharacters)
|
|
||||||
public works!: Promise<Work[]>;
|
|
||||||
|
|
||||||
/**
|
@ManyToMany(() => InteractionTag, (interactionTag: InteractionTagEntityInterface) => interactionTag.subjectCharacters)
|
||||||
* interaction with other characters as actor
|
|
||||||
*/
|
|
||||||
@ManyToMany(() => InteractionTag, (interactionTag: InteractionTag) => interactionTag.subjectCharacters)
|
|
||||||
@JoinTable()
|
@JoinTable()
|
||||||
public interactWith!: Promise<InteractionTag[]>;
|
public interactWith!: Promise<InteractionTagEntityInterface[]>;
|
||||||
|
|
||||||
/**
|
@ManyToMany(() => InteractionTag, (interactionTag: InteractionTagEntityInterface) => interactionTag.objectCharacters)
|
||||||
* interaction with other characters as receiver
|
|
||||||
*/
|
|
||||||
@ManyToMany(() => InteractionTag, (interactionTag: InteractionTag) => interactionTag.objectCharacters)
|
|
||||||
@JoinTable()
|
@JoinTable()
|
||||||
public interactedBy!: Promise<InteractionTag[]>;
|
public interactedBy!: Promise<InteractionTagEntityInterface[]>;
|
||||||
|
|
||||||
/**
|
@OneToMany(() => CharacterTag, (characterTag: CharacterTagEntityInterface) => characterTag.workCharacter)
|
||||||
* tags connected to the character
|
public characterTags!: Promise<CharacterTagEntityInterface[]>;
|
||||||
*/
|
|
||||||
@OneToMany(() => CharacterTag, (characterTag: CharacterTag) => characterTag.workCharacter)
|
|
||||||
public characterTags!: Promise<CharacterTag[]>;
|
|
||||||
|
|
||||||
/**
|
@ManyToMany(() => WorldCharacter, (worldCharacter: WorldCharacterEntityInterface) => worldCharacter.workCharacters)
|
||||||
* existing characters character is based on
|
|
||||||
*/
|
|
||||||
@ManyToMany(() => WorldCharacter, (worldCharacter: WorldCharacter) => worldCharacter.workCharacters)
|
|
||||||
@JoinTable()
|
@JoinTable()
|
||||||
public worldCharacters!: Promise<WorldCharacter[]>;
|
public worldCharacters!: Promise<WorldCharacterEntityInterface[]>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,16 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
import { Work } from './work';
|
import { Work } from './work';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class WorkName implements IdentifiableEntityInterface, NameEntityInterface {
|
export class WorkName implements WorkNameEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@ManyToOne(() => Work, (work: Work) => work.names, {
|
@ManyToOne(() => Work, (work: WorkEntityInterface) => work.names, {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public entity!: Promise<Work>;
|
public entity!: Promise<WorkEntityInterface>;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
|
|
@ -3,34 +3,25 @@ import { PercentCheck } from '../decorators/percent-check';
|
||||||
import { Tag } from './tag';
|
import { Tag } from './tag';
|
||||||
import { Work } from './work';
|
import { Work } from './work';
|
||||||
|
|
||||||
/**
|
|
||||||
* This tag entity tags a work.
|
|
||||||
*/
|
|
||||||
@Entity()
|
@Entity()
|
||||||
@PercentCheck('weight')
|
@PercentCheck('weight')
|
||||||
export class WorkTag implements IdentifiableEntityInterface, WeightedEntityInterface {
|
export class WorkTag implements WorkTagEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
/**
|
@ManyToOne(() => Tag, (tag: TagEntityInterface) => tag.workTags, {
|
||||||
* the describing tag
|
|
||||||
*/
|
|
||||||
@ManyToOne(() => Tag, (tag: Tag) => tag.workTags, {
|
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public tag!: Promise<Tag>;
|
public tag!: Promise<TagEntityInterface>;
|
||||||
|
|
||||||
/**
|
@ManyToOne(() => Work, (work: WorkEntityInterface) => work.workTags, {
|
||||||
* the tagged work
|
|
||||||
*/
|
|
||||||
@ManyToOne(() => Work, (work: Work) => work.workTags, {
|
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public work!: Promise<Work>;
|
public work!: Promise<WorkEntityInterface>;
|
||||||
|
|
||||||
@Column('int', {
|
@Column('int', {
|
||||||
nullable: true,
|
nullable: true,
|
||||||
|
|
|
@ -10,16 +10,11 @@ import { WorkName } from './work-name';
|
||||||
import { WorkTag } from './work-tag';
|
import { WorkTag } from './work-tag';
|
||||||
import { World } from './world';
|
import { World } from './world';
|
||||||
|
|
||||||
/**
|
|
||||||
* This is the main library entity.
|
|
||||||
*
|
|
||||||
* It describes a work of art organized by this software.
|
|
||||||
*/
|
|
||||||
@Entity()
|
@Entity()
|
||||||
@PercentCheck('rating')
|
@PercentCheck('rating')
|
||||||
export class Work implements IdentifiableEntityInterface, MultiNamedEntityInterface {
|
export class Work implements WorkEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
@ -27,88 +22,55 @@ export class Work implements IdentifiableEntityInterface, MultiNamedEntityInterf
|
||||||
})
|
})
|
||||||
public nameCanonical!: string;
|
public nameCanonical!: string;
|
||||||
|
|
||||||
@OneToMany(() => WorkName, (workName: WorkName) => workName.entity)
|
@OneToMany(() => WorkName, (workName: WorkNameEntityInterface) => workName.entity)
|
||||||
public names!: Promise<WorkName[]>;
|
public names!: Promise<WorkNameEntityInterface[]>;
|
||||||
|
|
||||||
/**
|
@OneToMany(() => Copy, (copy: CopyEntityInterface) => copy.original, {})
|
||||||
* digital representations of this work
|
public copies!: Promise<CopyEntityInterface[]>;
|
||||||
*/
|
|
||||||
@OneToMany(() => Copy, (copy: Copy) => copy.original)
|
|
||||||
public copies!: Promise<Copy[]>;
|
|
||||||
|
|
||||||
/**
|
@OneToMany(() => Transformation, (transformation: TransformationEntityInterface) => transformation.byWork)
|
||||||
* other works this work is a transformation of
|
public transformationOf!: Promise<TransformationEntityInterface[]>;
|
||||||
*/
|
|
||||||
@OneToMany(() => Transformation, (transformation: Transformation) => transformation.byWork)
|
|
||||||
public transformationOf!: Promise<Transformation[]>;
|
|
||||||
|
|
||||||
/**
|
@OneToMany(() => Transformation, (transformation: TransformationEntityInterface) => transformation.ofWork)
|
||||||
* other works this work is transformed by
|
public transformedBy!: Promise<TransformationEntityInterface[]>;
|
||||||
*/
|
|
||||||
@OneToMany(() => Transformation, (transformation: Transformation) => transformation.ofWork)
|
|
||||||
public transformedBy!: Promise<Transformation[]>;
|
|
||||||
|
|
||||||
/**
|
@OneToMany(() => WorkAuthor, (workAuthor: WorkAuthorEntityInterface) => workAuthor.work)
|
||||||
* the authors/publishers of this work
|
public workAuthors!: Promise<WorkAuthorEntityInterface[]>;
|
||||||
*/
|
|
||||||
@OneToMany(() => WorkAuthor, (workAuthor: WorkAuthor) => workAuthor.work)
|
|
||||||
public workAuthors!: Promise<WorkAuthor[]>;
|
|
||||||
|
|
||||||
/**
|
@OneToMany(() => WorkTag, (workTag: WorkTagEntityInterface) => workTag.work)
|
||||||
* tags describing this work
|
public workTags!: Promise<WorkTagEntityInterface[]>;
|
||||||
*/
|
|
||||||
@OneToMany(() => WorkTag, (workTag: WorkTag) => workTag.work)
|
|
||||||
public workTags!: Promise<WorkTag[]>;
|
|
||||||
|
|
||||||
/**
|
@ManyToMany(() => WorkCharacter, (workCharacter: WorkCharacterEntityInterface) => workCharacter.works)
|
||||||
* characters in this work
|
|
||||||
*/
|
|
||||||
@ManyToMany(() => WorkCharacter, (workCharacter: WorkCharacter) => workCharacter.works)
|
|
||||||
@JoinTable()
|
@JoinTable()
|
||||||
public workCharacters!: Promise<WorkCharacter[]>;
|
public workCharacters!: Promise<WorkCharacterEntityInterface[]>;
|
||||||
|
|
||||||
/**
|
@ManyToMany(() => World, (world: WorldEntityInterface) => world.works)
|
||||||
* fictional worlds in which this work takes place
|
|
||||||
*/
|
|
||||||
@ManyToMany(() => World, (world: World) => world.works)
|
|
||||||
@JoinTable()
|
@JoinTable()
|
||||||
public worlds!: Promise<World[]>;
|
public worlds!: Promise<WorldEntityInterface[]>;
|
||||||
|
|
||||||
/**
|
|
||||||
* if this work i canon in above fictional world
|
|
||||||
*/
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
default: false,
|
default: false,
|
||||||
})
|
})
|
||||||
public isCanonical!: boolean;
|
public isCanonical!: boolean;
|
||||||
|
|
||||||
/**
|
|
||||||
* the user rating of this work
|
|
||||||
*/
|
|
||||||
@Column('int', {
|
@Column('int', {
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
public rating!: number | null;
|
public rating!: number | null;
|
||||||
|
|
||||||
/**
|
|
||||||
* the release date of the work
|
|
||||||
*/
|
|
||||||
@Column('date', {
|
@Column('date', {
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
public releaseDate!: Date | null;
|
public releaseDate!: string | null;
|
||||||
|
|
||||||
/**
|
@ManyToMany(() => Language, (language: LanguageEntityInterface) => language.works)
|
||||||
* the languages of the work (if applicable)
|
|
||||||
*/
|
|
||||||
@ManyToMany(() => Language, (language: Language) => language.works)
|
|
||||||
@JoinTable()
|
@JoinTable()
|
||||||
public languages!: Promise<Language[]>;
|
public languages!: Promise<LanguageEntityInterface[]>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the collections this work is a part of
|
* the collections this work is a part of
|
||||||
*/
|
*/
|
||||||
@OneToMany(() => CollectionPart, (collectionPart: CollectionPart) => collectionPart.work)
|
@OneToMany(() => CollectionPart, (collectionPart: CollectionPartEntityInterface) => collectionPart.work)
|
||||||
public collectionParts!: Promise<CollectionPart[]>;
|
public collectionParts!: Promise<CollectionPartEntityInterface[]>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,16 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
import { WorldCharacter } from './world-character';
|
import { WorldCharacter } from './world-character';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class WorldCharacterName implements IdentifiableEntityInterface, NameEntityInterface {
|
export class WorldCharacterName implements WorldCharacterNameEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@ManyToOne(() => WorldCharacter, (worldCharacter: WorldCharacter) => worldCharacter.names, {
|
@ManyToOne(() => WorldCharacter, (worldCharacter: WorldCharacterEntityInterface) => worldCharacter.names, {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public entity!: Promise<WorldCharacter>;
|
public entity!: Promise<WorldCharacterEntityInterface>;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
|
|
@ -3,14 +3,10 @@ import { WorkCharacter } from './work-character';
|
||||||
import { World } from './world';
|
import { World } from './world';
|
||||||
import { WorldCharacterName } from './world-character-name';
|
import { WorldCharacterName } from './world-character-name';
|
||||||
|
|
||||||
/**
|
|
||||||
* This entity describes a canon character in a fictional world.
|
|
||||||
*/
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class WorldCharacter
|
export class WorldCharacter implements WorldCharacterEntityInterface {
|
||||||
implements IdentifiableEntityInterface, MultiNamedEntityInterface, HierarchicalEntityInterface<WorldCharacter> {
|
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
@ -18,25 +14,22 @@ export class WorldCharacter
|
||||||
})
|
})
|
||||||
public nameCanonical!: string;
|
public nameCanonical!: string;
|
||||||
|
|
||||||
@OneToMany(() => WorldCharacterName, (worldCharacterName: WorldCharacterName) => worldCharacterName.entity)
|
@OneToMany(
|
||||||
public names!: Promise<WorldCharacterName[]>;
|
() => WorldCharacterName,
|
||||||
|
(worldCharacterName: WorldCharacterNameEntityInterface) => worldCharacterName.entity
|
||||||
|
)
|
||||||
|
public names!: Promise<WorldCharacterNameEntityInterface[]>;
|
||||||
|
|
||||||
/**
|
@ManyToMany(() => WorkCharacter, (workCharacter: WorkCharacterEntityInterface) => workCharacter.worldCharacters)
|
||||||
* the characters in works which are based on this one
|
|
||||||
*/
|
|
||||||
@ManyToMany(() => WorkCharacter, (workCharacter: WorkCharacter) => workCharacter.worldCharacters)
|
|
||||||
public workCharacters!: Promise<WorkCharacter[]>;
|
public workCharacters!: Promise<WorkCharacter[]>;
|
||||||
|
|
||||||
/**
|
@ManyToMany(() => World, (world: WorldEntityInterface) => world.worldCharacters)
|
||||||
* the fictional worlds this character is a part of
|
public worlds!: Promise<WorldEntityInterface[]>;
|
||||||
*/
|
|
||||||
@ManyToMany(() => World, (world: World) => world.worldCharacters)
|
|
||||||
public worlds!: Promise<World[]>;
|
|
||||||
|
|
||||||
@ManyToMany(() => WorldCharacter, (worldCharacter: WorldCharacter) => worldCharacter.children)
|
@ManyToMany(() => WorldCharacter, (worldCharacter: WorldCharacterEntityInterface) => worldCharacter.children)
|
||||||
@JoinTable()
|
@JoinTable()
|
||||||
public parents!: Promise<WorldCharacter[]>;
|
public parents!: Promise<WorldCharacterEntityInterface[]>;
|
||||||
|
|
||||||
@ManyToMany(() => WorldCharacter, (worldCharacter: WorldCharacter) => worldCharacter.parents)
|
@ManyToMany(() => WorldCharacter, (worldCharacter: WorldCharacterEntityInterface) => worldCharacter.parents)
|
||||||
public children!: Promise<WorldCharacter[]>;
|
public children!: Promise<WorldCharacterEntityInterface[]>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,16 +2,16 @@ import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from 'typeorm';
|
||||||
import { World } from './world';
|
import { World } from './world';
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class WorldName implements IdentifiableEntityInterface, NameEntityInterface {
|
export class WorldName implements WorldNameEntityInterface {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@ManyToOne(() => World, (world: World) => world.names, {
|
@ManyToOne(() => World, (world: WorldEntityInterface) => world.names, {
|
||||||
nullable: false,
|
nullable: false,
|
||||||
onDelete: 'CASCADE',
|
onDelete: 'CASCADE',
|
||||||
onUpdate: 'CASCADE',
|
onUpdate: 'CASCADE',
|
||||||
})
|
})
|
||||||
public entity!: Promise<World>;
|
public entity!: Promise<WorldEntityInterface>;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
|
|
@ -3,14 +3,10 @@ import { Work } from './work';
|
||||||
import { WorldCharacter } from './world-character';
|
import { WorldCharacter } from './world-character';
|
||||||
import { WorldName } from './world-name';
|
import { WorldName } from './world-name';
|
||||||
|
|
||||||
/**
|
|
||||||
* This entity describes a fictional world.
|
|
||||||
*/
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class World
|
export class World implements WorldEntityInterface {
|
||||||
implements IdentifiableEntityInterface, MultiNamedEntityInterface, HierarchicalEntityInterface<World> {
|
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
public id!: number;
|
public readonly id!: number;
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: false,
|
nullable: false,
|
||||||
|
@ -18,26 +14,20 @@ export class World
|
||||||
})
|
})
|
||||||
public nameCanonical!: string;
|
public nameCanonical!: string;
|
||||||
|
|
||||||
@OneToMany(() => WorldName, (worldName: WorldName) => worldName.entity)
|
@OneToMany(() => WorldName, (worldName: WorldNameEntityInterface) => worldName.entity)
|
||||||
public names!: Promise<WorldName[]>;
|
public names!: Promise<WorldNameEntityInterface[]>;
|
||||||
|
|
||||||
/**
|
@ManyToMany(() => Work, (work: WorkEntityInterface) => work.worlds)
|
||||||
* works taking place in this world
|
public works!: Promise<WorkEntityInterface[]>;
|
||||||
*/
|
|
||||||
@ManyToMany(() => Work, (work: Work) => work.worlds)
|
|
||||||
public works!: Promise<Work[]>;
|
|
||||||
|
|
||||||
/**
|
@ManyToMany(() => WorldCharacter, (worldCharacter: WorldCharacterEntityInterface) => worldCharacter.worlds)
|
||||||
* canon characters in this world
|
|
||||||
*/
|
|
||||||
@ManyToMany(() => WorldCharacter, (worldCharacter: WorldCharacter) => worldCharacter.worlds)
|
|
||||||
@JoinTable()
|
@JoinTable()
|
||||||
public worldCharacters!: Promise<WorldCharacter[]>;
|
public worldCharacters!: Promise<WorldCharacterEntityInterface[]>;
|
||||||
|
|
||||||
@ManyToMany(() => World, (world: World) => world.parents)
|
@ManyToMany(() => World, (world: WorldEntityInterface) => world.parents)
|
||||||
public children!: Promise<World[]>;
|
public children!: Promise<WorldEntityInterface[]>;
|
||||||
|
|
||||||
@ManyToMany(() => World, (world: World) => world.children)
|
@ManyToMany(() => World, (world: WorldEntityInterface) => world.children)
|
||||||
@JoinTable()
|
@JoinTable()
|
||||||
public parents!: Promise<World[]>;
|
public parents!: Promise<WorldEntityInterface[]>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { MigrationInterface, QueryRunner } from 'typeorm';
|
import type { MigrationInterface, QueryRunner } from 'typeorm';
|
||||||
|
|
||||||
export class initialMigration1597705000730 implements MigrationInterface {
|
export class initial1611508597488 implements MigrationInterface {
|
||||||
name = 'initialMigration1597705000730';
|
name = 'initial1611508597488';
|
||||||
|
|
||||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
await queryRunner.query(
|
await queryRunner.query(
|
||||||
|
@ -39,7 +39,7 @@ export class initialMigration1597705000730 implements MigrationInterface {
|
||||||
`CREATE TABLE "transformation_type" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "nameCanonical" varchar NOT NULL DEFAULT (''), "description" varchar NOT NULL DEFAULT (''), "conservesTags" boolean NOT NULL DEFAULT (0))`
|
`CREATE TABLE "transformation_type" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "nameCanonical" varchar NOT NULL DEFAULT (''), "description" varchar NOT NULL DEFAULT (''), "conservesTags" boolean NOT NULL DEFAULT (0))`
|
||||||
);
|
);
|
||||||
await queryRunner.query(
|
await queryRunner.query(
|
||||||
`CREATE TABLE "transformation" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "order" integer NOT NULL DEFAULT (0), "byWorkId" integer NOT NULL, "typeId" integer NOT NULL, "ofWorkId" integer NOT NULL)`
|
`CREATE TABLE "transformation" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "order" integer NOT NULL DEFAULT (0), "byWorkId" integer NOT NULL, "typeId" integer NOT NULL, "ofWorkId" integer)`
|
||||||
);
|
);
|
||||||
await queryRunner.query(
|
await queryRunner.query(
|
||||||
`CREATE TABLE "interaction_tag" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "weight" integer, "tagId" integer NOT NULL, CONSTRAINT "weight needs to be between 0 and 9007199254740991" CHECK (weight >= 0 AND weight <= 9007199254740991))`
|
`CREATE TABLE "interaction_tag" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "weight" integer, "tagId" integer NOT NULL, CONSTRAINT "weight needs to be between 0 and 9007199254740991" CHECK (weight >= 0 AND weight <= 9007199254740991))`
|
||||||
|
@ -236,7 +236,7 @@ export class initialMigration1597705000730 implements MigrationInterface {
|
||||||
await queryRunner.query(`DROP TABLE "transformation_type_name"`);
|
await queryRunner.query(`DROP TABLE "transformation_type_name"`);
|
||||||
await queryRunner.query(`ALTER TABLE "temporary_transformation_type_name" RENAME TO "transformation_type_name"`);
|
await queryRunner.query(`ALTER TABLE "temporary_transformation_type_name" RENAME TO "transformation_type_name"`);
|
||||||
await queryRunner.query(
|
await queryRunner.query(
|
||||||
`CREATE TABLE "temporary_transformation" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "order" integer NOT NULL DEFAULT (0), "byWorkId" integer NOT NULL, "typeId" integer NOT NULL, "ofWorkId" integer NOT NULL, CONSTRAINT "FK_263a368f9017f5725c4fa12351b" FOREIGN KEY ("byWorkId") REFERENCES "work" ("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "FK_4deb36ce15d6547c1ed7e994720" FOREIGN KEY ("typeId") REFERENCES "transformation_type" ("id") ON DELETE RESTRICT ON UPDATE CASCADE, CONSTRAINT "FK_d41fc0471e72b5d1dda372a662c" FOREIGN KEY ("ofWorkId") REFERENCES "work" ("id") ON DELETE CASCADE ON UPDATE CASCADE)`
|
`CREATE TABLE "temporary_transformation" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "order" integer NOT NULL DEFAULT (0), "byWorkId" integer NOT NULL, "typeId" integer NOT NULL, "ofWorkId" integer, CONSTRAINT "FK_263a368f9017f5725c4fa12351b" FOREIGN KEY ("byWorkId") REFERENCES "work" ("id") ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT "FK_4deb36ce15d6547c1ed7e994720" FOREIGN KEY ("typeId") REFERENCES "transformation_type" ("id") ON DELETE RESTRICT ON UPDATE CASCADE, CONSTRAINT "FK_d41fc0471e72b5d1dda372a662c" FOREIGN KEY ("ofWorkId") REFERENCES "work" ("id") ON DELETE CASCADE ON UPDATE CASCADE)`
|
||||||
);
|
);
|
||||||
await queryRunner.query(
|
await queryRunner.query(
|
||||||
`INSERT INTO "temporary_transformation"("id", "order", "byWorkId", "typeId", "ofWorkId") SELECT "id", "order", "byWorkId", "typeId", "ofWorkId" FROM "transformation"`
|
`INSERT INTO "temporary_transformation"("id", "order", "byWorkId", "typeId", "ofWorkId") SELECT "id", "order", "byWorkId", "typeId", "ofWorkId" FROM "transformation"`
|
||||||
|
@ -788,7 +788,7 @@ export class initialMigration1597705000730 implements MigrationInterface {
|
||||||
await queryRunner.query(`DROP TABLE "temporary_interaction_tag"`);
|
await queryRunner.query(`DROP TABLE "temporary_interaction_tag"`);
|
||||||
await queryRunner.query(`ALTER TABLE "transformation" RENAME TO "temporary_transformation"`);
|
await queryRunner.query(`ALTER TABLE "transformation" RENAME TO "temporary_transformation"`);
|
||||||
await queryRunner.query(
|
await queryRunner.query(
|
||||||
`CREATE TABLE "transformation" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "order" integer NOT NULL DEFAULT (0), "byWorkId" integer NOT NULL, "typeId" integer NOT NULL, "ofWorkId" integer NOT NULL)`
|
`CREATE TABLE "transformation" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "order" integer NOT NULL DEFAULT (0), "byWorkId" integer NOT NULL, "typeId" integer NOT NULL, "ofWorkId" integer)`
|
||||||
);
|
);
|
||||||
await queryRunner.query(
|
await queryRunner.query(
|
||||||
`INSERT INTO "transformation"("id", "order", "byWorkId", "typeId", "ofWorkId") SELECT "id", "order", "byWorkId", "typeId", "ofWorkId" FROM "temporary_transformation"`
|
`INSERT INTO "transformation"("id", "order", "byWorkId", "typeId", "ofWorkId") SELECT "id", "order", "byWorkId", "typeId", "ofWorkId" FROM "temporary_transformation"`
|
|
@ -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}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.BULGARIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.BURMESE}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.CATALAN_VALENCIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.CHAMORRO}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.CHECHEN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.CHICHEWA_CHEWA_NYANJA}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.CHINESE}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.CHUVASH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.CORNISH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.CORSICAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.CREE}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.CROATIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.CZECH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.DANISH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.DIVEHI_DHIVEHI_MALDIVIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.DUTCH_FLEMISH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.DZONGKHA}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.ENGLISH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.ESPERANTO}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.ESTONIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.EWE}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.FAROESE}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.FIJIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.FINNISH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.FRENCH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.FULAH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.GALICIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.GEORGIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.GERMAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.GREEK_MODERN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.GUARANI}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.GUJARATI}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.HAITIAN_HAITIAN_CREOLE}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.HAUSA}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.HEBREW}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.HERERO}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.HINDI}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.HIRI_MOTU}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.HUNGARIAN}')`);
|
||||||
|
await queryRunner.query(
|
||||||
|
`INSERT INTO language VALUES('${LangCode.INTERLINGUA_INTERNATIONAL_AUXILIARY_LANGUAGE_ASSOCIATION}')`
|
||||||
|
);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.INDONESIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.INTERLINGUE_OCCIDENTAL}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.IRISH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.IGBO}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.INUPIAQ}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.IDO}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.ICELANDIC}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.ITALIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.INUKTITUT}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.JAPANESE}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.JAVANESE}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.KALAALLISUT_GREENLANDIC}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.KANNADA}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.KANURI}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.KASHMIRI}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.KAZAKH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.CENTRAL_KHMER}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.KIKUYU_GIKUYU}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.KINYARWANDA}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.KIRGHIZ_KYRGYZ}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.KOMI}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.KONGO}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.KOREAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.KURDISH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.KUANYAMA_KWANYAMA}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.LATIN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.LUXEMBOURGISH_LETZEBURGESCH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.GANDA}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.LIMBURGAN_LIMBURGER_LIMBURGISH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.LINGALA}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.LAO}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.LITHUANIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.LUBA_KATANGA}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.LATVIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.MANX}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.MACEDONIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.MALAGASY}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.MALAY}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.MALAYALAM}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.MALTESE}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.MAORI}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.MARATHI}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.MARSHALLESE}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.MONGOLIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.NAURU}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.NAVAJO_NAVAHO}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.NORTH_NDEBELE}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.NEPALI}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.NDONGA}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.NORWEGIAN_BOKMAL}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.NORWEGIAN_NYNORSK}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.NORWEGIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.SICHUAN_YI_NUOSU}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.SOUTH_NDEBELE}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.OCCITAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.OJIBWA}')`);
|
||||||
|
await queryRunner.query(
|
||||||
|
`INSERT INTO language VALUES('${LangCode.CHURCH_SLAVIC_OLD_SLAVONIC_CHURCH_SLAVONIC_OLD_BULGARIAN_OLD_CHURCH_SLAVONIC}')`
|
||||||
|
);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.OROMO}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.ORIYA}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.OSSETIAN_OSSETIC}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.PUNJABI_PANJABI}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.PALI}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.PERSIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.POLISH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.PASHTO_PUSHTO}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.PORTUGUESE}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.QUECHUA}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.ROMANSH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.RUNDI}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.ROMANIAN_MOLDAVIAN_MOLDOVAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.RUSSIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.SANSKRIT}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.SARDINIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.SINDHI}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.NORTHERN_SAMI}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.SAMOAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.SANGO}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.SERBIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.GAELIC_SCOTTISH_GAELIC}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.SHONA}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.SINHALA_SINHALESE}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.SLOVAK}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.SLOVENIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.SOMALI}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.SOUTHERN_SOTHO}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.SPANISH_CASTILIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.SUNDANESE}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.SWAHILI}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.SWATI}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.SWEDISH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.TAMIL}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.TELUGU}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.TAJIK}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.THAI}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.TIGRINYA}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.TIBETAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.TURKMEN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.TAGALOG}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.TSWANA}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.TONGA_TONGA_ISLANDS}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.TURKISH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.TSONGA}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.TATAR}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.TWI}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.TAHITIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.UIGHUR_UYGHUR}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.UKRAINIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.URDU}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.UZBEK}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.VENDA}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.VIETNAMESE}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.VOLAPUK}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.WALLOON}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.WELSH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.WOLOF}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.WESTERN_FRISIAN}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.XHOSA}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.YIDDISH}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.YORUBA}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.ZHUANG_CHUANG}')`);
|
||||||
|
await queryRunner.query(`INSERT INTO language VALUES('${LangCode.ZULU}')`);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
await queryRunner.clearTable('language');
|
||||||
|
}
|
||||||
|
}
|
|
@ -131,5 +131,21 @@ export abstract class AppWindow implements AppWindowInterface {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected getTime(selector: string): Promise<number | undefined> {
|
||||||
|
return new Promise<number | undefined>((resolve) => {
|
||||||
|
this.getWindow()
|
||||||
|
.webContents.executeJavaScript(`Date(document.querySelector('${selector}').dateTime).getTime()`)
|
||||||
|
.then((time) => {
|
||||||
|
resolve(time);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
void this.logger.warning(
|
||||||
|
`Could not get the of the presumed HTMLTimeElement with the selector '${selector}'.`
|
||||||
|
);
|
||||||
|
resolve(undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract load(window: BrowserWindow): Promise<void>;
|
protected abstract load(window: BrowserWindow): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import type { WebContents } from 'electron';
|
import type { WebContents, BrowserWindowConstructorOptions, LoadURLOptions } from 'electron';
|
||||||
import type { BrowserWindowConstructorOptions, LoadURLOptions } from 'electron';
|
|
||||||
import { promisify } from 'util';
|
import { promisify } from 'util';
|
||||||
import { AppWindow } from './app-window';
|
import { AppWindow } from './app-window';
|
||||||
import type { UrlAppWindowInterface } from './url-app-window-interface';
|
import type { UrlAppWindowInterface } from './url-app-window-interface';
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
export function dateObjectToString(date: Date): string {
|
||||||
|
return `${date.getUTCFullYear()}-${`${date.getUTCMonth()}`.padStart(2, '0')}-${`${date.getUTCDate()}`.padStart(
|
||||||
|
2,
|
||||||
|
'0'
|
||||||
|
)}`;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { workSerializer } from '../../../shared/services/serialization/serializers/work';
|
||||||
|
import { Database, getConnection } from '../../core/database';
|
||||||
|
import { Work } from '../../entities/library/work';
|
||||||
|
import { answer } from '../ipc/annotations/answer';
|
||||||
|
|
||||||
|
export class EntityApiIpcController implements IpcController {
|
||||||
|
private constructor() {}
|
||||||
|
|
||||||
|
@answer(IpcChannel.ENTITY_GET_WORK)
|
||||||
|
public async getWork({ id }: { id: number }): Promise<WorkSerializedInterface> {
|
||||||
|
const connection = await getConnection(Database.LIBRARY);
|
||||||
|
const work = await connection.manager.getRepository(Work).findOneOrFail(id);
|
||||||
|
|
||||||
|
return workSerializer.serialize(work);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(): EntityApiIpcController {
|
||||||
|
return new EntityApiIpcController();
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ describe('Nhentai App Window', () => {
|
||||||
const nhentaiAppWindow: NhentaiAppWindowInterface = container.get('nhentai-app-window');
|
const nhentaiAppWindow: NhentaiAppWindowInterface = container.get('nhentai-app-window');
|
||||||
|
|
||||||
let expectedGallery: Nhentai.Gallery = {
|
let expectedGallery: Nhentai.Gallery = {
|
||||||
|
url: 'https://nhentai.net/g/117300/',
|
||||||
title: {
|
title: {
|
||||||
pre: '[Homunculus]',
|
pre: '[Homunculus]',
|
||||||
main: 'Renai Sample',
|
main: 'Renai Sample',
|
||||||
|
@ -43,11 +44,14 @@ describe('Nhentai App Window', () => {
|
||||||
'uncensored',
|
'uncensored',
|
||||||
'small breasts',
|
'small breasts',
|
||||||
],
|
],
|
||||||
|
languages: ['english', 'translated'],
|
||||||
|
uploadTime: 1411853968970,
|
||||||
};
|
};
|
||||||
let gallery = await nhentaiAppWindow.getGallery('117300');
|
let gallery = await nhentaiAppWindow.getGallery('117300');
|
||||||
expect(gallery).deep.equalInAnyOrder(expectedGallery, 'Renai Sample is not got correctly');
|
expect(gallery).deep.equalInAnyOrder(expectedGallery, 'Renai Sample is not got correctly');
|
||||||
|
|
||||||
expectedGallery = {
|
expectedGallery = {
|
||||||
|
url: 'https://nhentai.net/g/273405/',
|
||||||
title: {
|
title: {
|
||||||
pre: '(COMIC1☆12) [MOSQUITONE. (Great Mosu)]',
|
pre: '(COMIC1☆12) [MOSQUITONE. (Great Mosu)]',
|
||||||
main: 'Koisuru Dai Akuma | The Archdemon In Love',
|
main: 'Koisuru Dai Akuma | The Archdemon In Love',
|
||||||
|
@ -58,6 +62,8 @@ describe('Nhentai App Window', () => {
|
||||||
parodies: ['gabriel dropout'],
|
parodies: ['gabriel dropout'],
|
||||||
characters: ['satanichia kurumizawa mcdowell'],
|
characters: ['satanichia kurumizawa mcdowell'],
|
||||||
tags: ['sole female', 'sole male', 'defloration', 'uncensored', 'kissing'],
|
tags: ['sole female', 'sole male', 'defloration', 'uncensored', 'kissing'],
|
||||||
|
languages: ['english', 'translated'],
|
||||||
|
uploadTime: 1558833881932,
|
||||||
};
|
};
|
||||||
gallery = await nhentaiAppWindow.getGallery('273405');
|
gallery = await nhentaiAppWindow.getGallery('273405');
|
||||||
expect(gallery).deep.equalInAnyOrder(expectedGallery, 'The Archdemon in Love is not got correctly!');
|
expect(gallery).deep.equalInAnyOrder(expectedGallery, 'The Archdemon in Love is not got correctly!');
|
||||||
|
|
|
@ -34,6 +34,8 @@ import {
|
||||||
loginPageIsReady,
|
loginPageIsReady,
|
||||||
favoritePageIsReady,
|
favoritePageIsReady,
|
||||||
pageIsReady,
|
pageIsReady,
|
||||||
|
timeSelector,
|
||||||
|
tagLabelLanguages,
|
||||||
} from './nhentai-util';
|
} from './nhentai-util';
|
||||||
|
|
||||||
const waitInterval = 2000;
|
const waitInterval = 2000;
|
||||||
|
@ -98,7 +100,9 @@ export class NhentaiAppWindow extends CloudflareSiteAppWindow implements Nhentai
|
||||||
await this.open();
|
await this.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bookUrl = getBookUrl(identifier);
|
||||||
const gallery: Nhentai.Gallery = {
|
const gallery: Nhentai.Gallery = {
|
||||||
|
url: bookUrl,
|
||||||
title: {
|
title: {
|
||||||
pre: '',
|
pre: '',
|
||||||
main: '',
|
main: '',
|
||||||
|
@ -109,10 +113,11 @@ export class NhentaiAppWindow extends CloudflareSiteAppWindow implements Nhentai
|
||||||
parodies: [],
|
parodies: [],
|
||||||
characters: [],
|
characters: [],
|
||||||
tags: [],
|
tags: [],
|
||||||
|
languages: [],
|
||||||
|
uploadTime: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
const release = await this.acquireLock();
|
const release = await this.acquireLock();
|
||||||
const bookUrl = getBookUrl(identifier);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this.loadGalleryPageSafe(bookUrl);
|
await this.loadGalleryPageSafe(bookUrl);
|
||||||
|
@ -141,6 +146,12 @@ export class NhentaiAppWindow extends CloudflareSiteAppWindow implements Nhentai
|
||||||
this.getTags(tagLabelTags).then((tags: string[]) => {
|
this.getTags(tagLabelTags).then((tags: string[]) => {
|
||||||
gallery.tags = tags;
|
gallery.tags = tags;
|
||||||
}),
|
}),
|
||||||
|
this.getTags(tagLabelLanguages).then((languages: string[]) => {
|
||||||
|
gallery.languages = languages;
|
||||||
|
}),
|
||||||
|
this.getTime(timeSelector).then((time?: number) => {
|
||||||
|
gallery.uploadTime = time;
|
||||||
|
}),
|
||||||
]);
|
]);
|
||||||
this.close();
|
this.close();
|
||||||
release();
|
release();
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { createWriteStream } from 'fs-extra';
|
import { createWriteStream } from 'fs-extra';
|
||||||
import { container } from '../../core/container';
|
import { container } from '../../core/container';
|
||||||
import { Database, getConnection } from '../../core/database';
|
|
||||||
import type { Work } from '../../entities/library/work';
|
import type { Work } from '../../entities/library/work';
|
||||||
import type { DialogInterface } from '../dialog/dialog-interface';
|
import type { DialogInterface } from '../dialog/dialog-interface';
|
||||||
import { answer } from '../ipc/annotations/answer';
|
import { answer } from '../ipc/annotations/answer';
|
||||||
|
@ -53,9 +52,8 @@ export class NhentaiIpcController implements IpcController {
|
||||||
@answer(IpcChannel.NHENTAI_GET_WORK)
|
@answer(IpcChannel.NHENTAI_GET_WORK)
|
||||||
public async nhentaiGetWork({ galleryId }: { galleryId: string }): Promise<Work> {
|
public async nhentaiGetWork({ galleryId }: { galleryId: string }): Promise<Work> {
|
||||||
const work = await this.nhentaiSourceGetter.find(galleryId);
|
const work = await this.nhentaiSourceGetter.find(galleryId);
|
||||||
const { manager } = await getConnection(Database.LIBRARY);
|
|
||||||
|
|
||||||
return manager.save(work);
|
return work;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get(): NhentaiIpcController {
|
public get(): NhentaiIpcController {
|
||||||
|
|
|
@ -1,7 +1,18 @@
|
||||||
import { injectable } from 'inversify';
|
import { injectable } from 'inversify';
|
||||||
|
import { Database, getConnection } from '../../core/database';
|
||||||
import { inject } from '../../core/inject';
|
import { inject } from '../../core/inject';
|
||||||
|
import { Copy } from '../../entities/library/copy';
|
||||||
|
import { Language } from '../../entities/library/language';
|
||||||
|
import { Source } from '../../entities/library/source';
|
||||||
import { Work } from '../../entities/library/work';
|
import { Work } from '../../entities/library/work';
|
||||||
|
import { dateObjectToString } from '../date/date-util';
|
||||||
import type { SourceGetterInterface } from '../source/source-getter-interface';
|
import type { SourceGetterInterface } from '../source/source-getter-interface';
|
||||||
|
import { isNhentaiRealLanguage, languageToLangCode, NhentaiRealLanguage } from './nhentai-util';
|
||||||
|
|
||||||
|
async function getLanguage(nhentaiLanguageIdentifier: NhentaiRealLanguage): Promise<LanguageEntityInterface> {
|
||||||
|
const { manager } = await getConnection(Database.LIBRARY);
|
||||||
|
return manager.getRepository(Language).findOneOrFail(languageToLangCode[nhentaiLanguageIdentifier]);
|
||||||
|
}
|
||||||
|
|
||||||
@injectable()
|
@injectable()
|
||||||
export class NhentaiSourceGetter implements SourceGetterInterface {
|
export class NhentaiSourceGetter implements SourceGetterInterface {
|
||||||
|
@ -11,12 +22,39 @@ export class NhentaiSourceGetter implements SourceGetterInterface {
|
||||||
this.nhentaiApi = nhentaiApi;
|
this.nhentaiApi = nhentaiApi;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async find(identifier: string): Promise<Work> {
|
public async find(identifier: string): Promise<WorkEntityInterface> {
|
||||||
const gallery = await this.nhentaiApi.getGallery(identifier);
|
const gallery = await this.nhentaiApi.getGallery(identifier);
|
||||||
|
|
||||||
const work = new Work();
|
const work = new Work();
|
||||||
|
const copy = new Copy();
|
||||||
|
const source = new Source();
|
||||||
|
|
||||||
|
const { manager } = await getConnection(Database.LIBRARY);
|
||||||
|
|
||||||
|
source.uri = gallery.url;
|
||||||
|
|
||||||
|
copy.sources = Promise.resolve([source]);
|
||||||
|
|
||||||
work.nameCanonical = gallery.title.main;
|
work.nameCanonical = gallery.title.main;
|
||||||
|
if (gallery.uploadTime) {
|
||||||
|
work.releaseDate = dateObjectToString(new Date(gallery.uploadTime));
|
||||||
|
}
|
||||||
|
if (gallery.languages.length) {
|
||||||
|
const filteredLanguages: NhentaiRealLanguage[] = gallery.languages.filter(
|
||||||
|
(language): language is NhentaiRealLanguage => {
|
||||||
|
if (language === 'translated') {
|
||||||
|
// new transformation of type 'translation' here (source getter needs more abstraction before this can be done elegantly)
|
||||||
|
return false;
|
||||||
|
} else if (isNhentaiRealLanguage(language)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
work.languages = Promise.all(filteredLanguages.map((language) => getLanguage(language)));
|
||||||
|
}
|
||||||
|
work.copies = Promise.resolve([copy]);
|
||||||
|
await manager.save([work, copy, source]);
|
||||||
|
|
||||||
return work;
|
return work;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,12 +19,30 @@ export const postTitleSelector = 'h1.title .after';
|
||||||
export const labeledTagContainerSelector = '.tag-container.field-name';
|
export const labeledTagContainerSelector = '.tag-container.field-name';
|
||||||
export const tagSelector = '.tag';
|
export const tagSelector = '.tag';
|
||||||
export const tagNameSelector = 'span.name';
|
export const tagNameSelector = 'span.name';
|
||||||
|
export const timeSelector = 'time';
|
||||||
|
|
||||||
export const tagLabelParodies = 'Parodies';
|
export const tagLabelParodies = 'Parodies';
|
||||||
export const tagLabelCharacters = 'Characters';
|
export const tagLabelCharacters = 'Characters';
|
||||||
export const tagLabelTags = 'Tags';
|
export const tagLabelTags = 'Tags';
|
||||||
export const tagLabelArtists = 'Artists';
|
export const tagLabelArtists = 'Artists';
|
||||||
export const tagLabelGroups = 'Groups';
|
export const tagLabelGroups = 'Groups';
|
||||||
|
export const tagLabelLanguages = 'Languages';
|
||||||
|
|
||||||
|
export const languageToLangCode = {
|
||||||
|
japanese: LangCode.JAPANESE,
|
||||||
|
english: LangCode.ENGLISH,
|
||||||
|
chinese: LangCode.CHINESE,
|
||||||
|
};
|
||||||
|
export type NhentaiRealLanguage = keyof typeof languageToLangCode;
|
||||||
|
export type NhentaiLanguage = NhentaiRealLanguage | 'translated';
|
||||||
|
|
||||||
|
export function isNhentaiLanguage(language: string): language is NhentaiLanguage {
|
||||||
|
return isNhentaiRealLanguage(language) || language === 'translated';
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isNhentaiRealLanguage(language: string): language is NhentaiRealLanguage {
|
||||||
|
return Object.keys(languageToLangCode).includes(language);
|
||||||
|
}
|
||||||
|
|
||||||
export function pageIsReady(webContents: WebContents): Promise<boolean> {
|
export function pageIsReady(webContents: WebContents): Promise<boolean> {
|
||||||
return webContents.executeJavaScript(`!!document.getElementById('content')`) as Promise<boolean>;
|
return webContents.executeJavaScript(`!!document.getElementById('content')`) as Promise<boolean>;
|
||||||
|
|
|
@ -5,6 +5,7 @@ declare namespace Nhentai {
|
||||||
};
|
};
|
||||||
|
|
||||||
type Gallery = {
|
type Gallery = {
|
||||||
|
url: string;
|
||||||
title: {
|
title: {
|
||||||
pre: string;
|
pre: string;
|
||||||
main: string;
|
main: string;
|
||||||
|
@ -15,5 +16,7 @@ declare namespace Nhentai {
|
||||||
parodies: string[];
|
parodies: string[];
|
||||||
characters: string[];
|
characters: string[];
|
||||||
tags: string[];
|
tags: string[];
|
||||||
|
languages: string[];
|
||||||
|
uploadTime?: number;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
import { Work } from '../../entities/library/work';
|
/**
|
||||||
|
* This interface describes an object which can find works based on some identifying property.
|
||||||
interface SourceGetterInterface {
|
*/
|
||||||
find(identifier: string): Promise<Work>;
|
export interface SourceGetterInterface {
|
||||||
|
/**
|
||||||
|
* This method finds the work, deserializes it and all its relations into entities and persists them.
|
||||||
|
* @returns the persisted work
|
||||||
|
*/
|
||||||
|
find(identifier: string): Promise<WorkEntityInterface>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
<script>
|
||||||
|
import { onMount } from 'svelte';
|
||||||
|
import { entityApi } from '../../services/api';
|
||||||
|
|
||||||
|
export let id;
|
||||||
|
|
||||||
|
let work;
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
entityApi.fetchWork(id).then((workSerialized) => {
|
||||||
|
work = workSerialized;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="work">{#if work}{JSON.stringify(work)}{/if}</div>
|
|
@ -1,4 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
|
import Work from '../content/Work.svelte';
|
||||||
import { nhentaiGetWork } from '../../services/api';
|
import { nhentaiGetWork } from '../../services/api';
|
||||||
import SvelteButton from '../elements/SvelteButton.svelte';
|
import SvelteButton from '../elements/SvelteButton.svelte';
|
||||||
import { t } from '../../services/utils';
|
import { t } from '../../services/utils';
|
||||||
|
@ -14,5 +15,7 @@
|
||||||
<div class="nhentai-get-work">
|
<div class="nhentai-get-work">
|
||||||
<label><input type="text" placeholder="177013" bind:value="{galleryId}" /></label
|
<label><input type="text" placeholder="177013" bind:value="{galleryId}" /></label
|
||||||
><SvelteButton on:click="{handleClick}">{t('Get')}</SvelteButton>
|
><SvelteButton on:click="{handleClick}">{t('Get')}</SvelteButton>
|
||||||
<div>{JSON.stringify(work)}</div>
|
{#if work}
|
||||||
|
<Work id="{work.id}" />
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,36 +1,15 @@
|
||||||
import { ipcRenderer } from 'electron';
|
import { ipcClient } from './ipc-client';
|
||||||
import { uuid } from '../../shared/services/uuid';
|
|
||||||
import IpcRendererEvent = Electron.IpcRendererEvent;
|
|
||||||
|
|
||||||
const ipcClient: IpcClient = {
|
|
||||||
ask: (channel: IpcChannel, data?: unknown): Promise<unknown> => {
|
|
||||||
const id = uuid();
|
|
||||||
const payload: IpcPayload = {
|
|
||||||
id,
|
|
||||||
data,
|
|
||||||
};
|
|
||||||
|
|
||||||
return new Promise((resolve: (value?: unknown) => void, reject: (reason?: Error) => void): void => {
|
|
||||||
const listener = (event: IpcRendererEvent, response: IpcResponse): void => {
|
|
||||||
if (response.id === id) {
|
|
||||||
if (response.success) {
|
|
||||||
resolve(response.data);
|
|
||||||
} else {
|
|
||||||
reject(new Error(response.error));
|
|
||||||
}
|
|
||||||
ipcRenderer.removeListener(channel, listener);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ipcRenderer.on(channel, listener);
|
|
||||||
ipcRenderer.send(channel, payload);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
export function nhentaiSaveFavorites(): Promise<void> {
|
export function nhentaiSaveFavorites(): Promise<void> {
|
||||||
return ipcClient.ask(IpcChannel.NHENTAI_SAVE_FAVORITES) as Promise<void>;
|
return ipcClient.ask(IpcChannel.NHENTAI_SAVE_FAVORITES) as Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function nhentaiGetWork(galleryId: string): Promise<Work> {
|
export function nhentaiGetWork(galleryId: string): Promise<WorkEntityInterface> {
|
||||||
return ipcClient.ask(IpcChannel.NHENTAI_GET_WORK, { galleryId }) as Promise<Work>;
|
return ipcClient.ask(IpcChannel.NHENTAI_GET_WORK, { galleryId }) as Promise<WorkEntityInterface>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const entityApi = {
|
||||||
|
fetchWork(id: number): Promise<WorkSerializedInterface> {
|
||||||
|
return ipcClient.ask(IpcChannel.ENTITY_GET_WORK, { id });
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { ipcRenderer } from 'electron';
|
||||||
|
import { uuid } from '../../shared/services/uuid';
|
||||||
|
|
||||||
|
export const ipcClient: IpcClientInterface = {
|
||||||
|
ask: (channel: IpcChannel, data?: never): Promise<never> => {
|
||||||
|
const id = uuid();
|
||||||
|
const payload: IpcPayload = {
|
||||||
|
id,
|
||||||
|
data,
|
||||||
|
};
|
||||||
|
|
||||||
|
return new Promise<never>((resolve, reject): void => {
|
||||||
|
const listener = (event: Electron.Renderer.IpcRendererEvent, response: IpcResponse): void => {
|
||||||
|
if (response.id === id) {
|
||||||
|
if (response.success) {
|
||||||
|
resolve(response.data as never);
|
||||||
|
} else {
|
||||||
|
reject(new Error(response.error));
|
||||||
|
}
|
||||||
|
ipcRenderer.removeListener(channel, listener);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ipcRenderer.on(channel, listener);
|
||||||
|
ipcRenderer.send(channel, payload);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
|
@ -0,0 +1,7 @@
|
||||||
|
export class Serializer<Entity, Serialized> {
|
||||||
|
public readonly serialize: (entity: Entity) => Promise<Serialized>;
|
||||||
|
|
||||||
|
public constructor(serialize: (entity: Entity) => Promise<Serialized>) {
|
||||||
|
this.serialize = serialize;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
import { Serializer } from '../serializer';
|
||||||
|
|
||||||
|
export const workSerializer = new Serializer<WorkEntityInterface, WorkSerializedInterface>(async (work) => {
|
||||||
|
const [
|
||||||
|
languages,
|
||||||
|
collectionParts,
|
||||||
|
copies,
|
||||||
|
names,
|
||||||
|
transformationOf,
|
||||||
|
transformedBy,
|
||||||
|
workAuthors,
|
||||||
|
workCharacters,
|
||||||
|
workTags,
|
||||||
|
worlds,
|
||||||
|
] = await Promise.all([
|
||||||
|
work.languages,
|
||||||
|
work.collectionParts,
|
||||||
|
work.copies,
|
||||||
|
work.names,
|
||||||
|
work.transformationOf,
|
||||||
|
work.transformedBy,
|
||||||
|
work.workAuthors,
|
||||||
|
work.workCharacters,
|
||||||
|
work.workTags,
|
||||||
|
work.worlds,
|
||||||
|
]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: work.id,
|
||||||
|
isCanonical: work.isCanonical,
|
||||||
|
nameCanonical: work.nameCanonical,
|
||||||
|
rating: work.rating,
|
||||||
|
releaseDate: work.releaseDate,
|
||||||
|
languages: languages.map((e) => e.code),
|
||||||
|
collectionParts: collectionParts.map((e) => e.id),
|
||||||
|
copies: copies.map((e) => e.id),
|
||||||
|
names: names.map((e) => e.id),
|
||||||
|
transformationOf: transformationOf.map((e) => e.id),
|
||||||
|
transformedBy: transformedBy.map((e) => e.id),
|
||||||
|
workAuthors: workAuthors.map((e) => e.id),
|
||||||
|
workCharacters: workCharacters.map((e) => e.id),
|
||||||
|
workTags: workTags.map((e) => e.id),
|
||||||
|
worlds: worlds.map((e) => e.id),
|
||||||
|
};
|
||||||
|
});
|
|
@ -1,3 +0,0 @@
|
||||||
type Work = {
|
|
||||||
nameCanonical: string;
|
|
||||||
};
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
interface AuthorNameInterface extends IdentifiableInterface, NameInterface {
|
||||||
|
entity: Promise<AuthorInterface> | Identifier;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
interface AuthorRoleNameInterface extends IdentifiableInterface, NameInterface {
|
||||||
|
entity: Promise<AuthorRoleInterface> | Identifier;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
/**
|
||||||
|
* This entity describes the role an author has in a work.
|
||||||
|
* Examples: story writing, drawing, animating, publishing, ...
|
||||||
|
*/
|
||||||
|
interface AuthorRoleInterface extends IdentifiableInterface, MultiNamedInterface, DescribableInterface {
|
||||||
|
names: Promise<AuthorRoleNameInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* relation to the entity connecting with the author and work
|
||||||
|
*/
|
||||||
|
workAuthors: Promise<WorkAuthorInterface[]> | Identifier[];
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
/**
|
||||||
|
* This entity represents a single real-world entity, be it a person or named group of persons.
|
||||||
|
*/
|
||||||
|
interface AuthorInterface extends IdentifiableInterface, MultiNamedInterface {
|
||||||
|
names: Promise<AuthorNameInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ultimately connects the author with a work and their role in that work
|
||||||
|
*/
|
||||||
|
workAuthors: Promise<WorkAuthorInterface[]> | Identifier[];
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
/**
|
||||||
|
* This tag entity tags a character in a work.
|
||||||
|
*/
|
||||||
|
interface CharacterTagInterface extends IdentifiableInterface, WeightedInterface {
|
||||||
|
/**
|
||||||
|
* the character ina work this tag describes
|
||||||
|
*/
|
||||||
|
workCharacter: Promise<WorkCharacterInterface> | Identifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the describing tag
|
||||||
|
*/
|
||||||
|
tag: Promise<TagInterface> | Identifier;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
interface CollectionNameInterface extends IdentifiableInterface, NameInterface {
|
||||||
|
entity: Promise<CollectionInterface> | Identifier;
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
/**
|
||||||
|
* This entity orders works in a collection.
|
||||||
|
* The main use case is chronological ordering.
|
||||||
|
*/
|
||||||
|
interface CollectionPartInterface extends IdentifiableInterface, OrderableInterface {
|
||||||
|
/**
|
||||||
|
* the collection thw work is a part of
|
||||||
|
*/
|
||||||
|
collection: Promise<CollectionInterface> | Identifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the work inside the collection
|
||||||
|
*/
|
||||||
|
work: Promise<WorkInterface> | Identifier;
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
interface CollectionInterface extends IdentifiableInterface, MultiNamedInterface {
|
||||||
|
names: Promise<CollectionNameInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the connecting entity between this collection and the work
|
||||||
|
*/
|
||||||
|
parts: Promise<CollectionPartInterface[]> | Identifier[];
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
* 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).
|
||||||
|
*/
|
||||||
|
interface CopyInterface extends IdentifiableInterface {
|
||||||
|
/**
|
||||||
|
* the work this entity is a copy of
|
||||||
|
*/
|
||||||
|
original: Promise<WorkInterface> | Identifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* where to find this specific copy
|
||||||
|
*/
|
||||||
|
sources: Promise<SourceInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* identifying hash of the file contents
|
||||||
|
*/
|
||||||
|
hash: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* device location of the copy
|
||||||
|
*/
|
||||||
|
location: string | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the ordering of the copies belonging to the same work,
|
||||||
|
* lower number is higher ranked
|
||||||
|
*/
|
||||||
|
ranking: number;
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* Entities extending this one have a user-maintained description.
|
* Entities extending this one have a user-maintained description.
|
||||||
*/
|
*/
|
||||||
interface DescribableEntityInterface {
|
interface DescribableInterface {
|
||||||
/**
|
/**
|
||||||
* a text describing this entity
|
* a text describing this entity
|
||||||
*/
|
*/
|
|
@ -1,14 +1,14 @@
|
||||||
/**
|
/**
|
||||||
* Entities implementing this interface build a hierarchy.
|
* Entities implementing this interface build a hierarchy.
|
||||||
*/
|
*/
|
||||||
interface HierarchicalEntityInterface<T> {
|
interface HierarchicalInterface<T> {
|
||||||
/**
|
/**
|
||||||
* parent entities
|
* parent entities
|
||||||
*/
|
*/
|
||||||
parents: Promise<T[]>;
|
parents: Promise<T[]> | Identifier[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* child entities
|
* child entities
|
||||||
*/
|
*/
|
||||||
children: Promise<T[]>;
|
children: Promise<T[]> | Identifier[];
|
||||||
}
|
}
|
|
@ -2,9 +2,9 @@
|
||||||
* Every database entity should implement this one.
|
* Every database entity should implement this one.
|
||||||
* It does nothing more but guarantee there is an id column.
|
* It does nothing more but guarantee there is an id column.
|
||||||
*/
|
*/
|
||||||
interface IdentifiableEntityInterface {
|
interface IdentifiableInterface {
|
||||||
/**
|
/**
|
||||||
* the entity id
|
* the entity id
|
||||||
*/
|
*/
|
||||||
id: number;
|
readonly id: Identifier;
|
||||||
}
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
/**
|
||||||
|
* This tag entity tags an interaction between two characters.
|
||||||
|
*/
|
||||||
|
interface InteractionTagInterface extends IdentifiableInterface, WeightedInterface {
|
||||||
|
/**
|
||||||
|
* the describing tag
|
||||||
|
*/
|
||||||
|
tag: Promise<TagInterface> | Identifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the actors of this interaction
|
||||||
|
*/
|
||||||
|
subjectCharacters: Promise<WorkCharacterInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the receivers of this interaction
|
||||||
|
*/
|
||||||
|
objectCharacters: Promise<WorkCharacterInterface[]> | Identifier[];
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
/**
|
||||||
|
* This entity is non-user-maintained and describes a language.
|
||||||
|
*/
|
||||||
|
interface LanguageInterface {
|
||||||
|
/**
|
||||||
|
* ISO 639-1 two-letter language code
|
||||||
|
*/
|
||||||
|
code: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the works using this language
|
||||||
|
*/
|
||||||
|
works: Promise<WorkInterface[]> | Identifier[];
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* Entities extending this interface can have multiple names.
|
* Entities extending this interface can have multiple names.
|
||||||
*/
|
*/
|
||||||
interface MultiNamedEntityInterface {
|
interface MultiNamedInterface {
|
||||||
/**
|
/**
|
||||||
* the name which is displayed in the user interface
|
* the name which is displayed in the user interface
|
||||||
*/
|
*/
|
||||||
|
@ -10,5 +10,5 @@ interface MultiNamedEntityInterface {
|
||||||
/**
|
/**
|
||||||
* other names for the entity
|
* other names for the entity
|
||||||
*/
|
*/
|
||||||
names: Promise<NameEntityInterface[]>;
|
names: Promise<NameInterface[]> | Identifier[];
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* This entity describes a single name of an entity with multiple names.
|
* This entity describes a single name of an entity with multiple names.
|
||||||
*/
|
*/
|
||||||
interface NameEntityInterface {
|
interface NameInterface {
|
||||||
/**
|
/**
|
||||||
* the name
|
* the name
|
||||||
*/
|
*/
|
||||||
|
@ -10,5 +10,5 @@ interface NameEntityInterface {
|
||||||
/**
|
/**
|
||||||
* the entity to which the names belong
|
* the entity to which the names belong
|
||||||
*/
|
*/
|
||||||
entity: Promise<MultiNamedEntityInterface>;
|
entity: Promise<MultiNamedInterface> | Identifier;
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* Entities implementing this interface can be ordered.
|
* Entities implementing this interface can be ordered.
|
||||||
*/
|
*/
|
||||||
interface OrderableEntityInterface {
|
interface OrderableInterface {
|
||||||
/**
|
/**
|
||||||
* a lower number means a higher ordering
|
* a lower number means a higher ordering
|
||||||
*/
|
*/
|
|
@ -0,0 +1,3 @@
|
||||||
|
interface SiteNameInterface extends IdentifiableInterface, NameInterface {
|
||||||
|
entity: Promise<SiteInterface> | Identifier;
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
/**
|
||||||
|
* This non-user-maintained entity describes an online provider of works which can be scraped.
|
||||||
|
*/
|
||||||
|
interface SiteInterface extends IdentifiableInterface, MultiNamedInterface {
|
||||||
|
names: Promise<SiteNameInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* sources belonging to this site
|
||||||
|
*/
|
||||||
|
sources: Promise<SourceInterface[]> | Identifier[];
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
/**
|
||||||
|
* This entity describes an external source of a copy, in most cases that is a website.
|
||||||
|
*/
|
||||||
|
interface SourceInterface extends IdentifiableInterface {
|
||||||
|
/**
|
||||||
|
* the uri to the sauce
|
||||||
|
*/
|
||||||
|
uri: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the site connected to the source
|
||||||
|
*/
|
||||||
|
site: Promise<SiteInterface> | Identifier | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the copies which can be found here
|
||||||
|
*/
|
||||||
|
copies: Promise<CopyInterface[]> | Identifier[];
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
interface TagNameInterface extends IdentifiableInterface, NameInterface {
|
||||||
|
entity: Promise<TagInterface> | Identifier;
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
interface TagInterface
|
||||||
|
extends IdentifiableInterface,
|
||||||
|
MultiNamedInterface,
|
||||||
|
DescribableInterface,
|
||||||
|
HierarchicalInterface<TagInterface> {
|
||||||
|
names: Promise<TagNameInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this tag tagging a work
|
||||||
|
*/
|
||||||
|
workTags: Promise<WorkTagInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this tag tagging characters
|
||||||
|
*/
|
||||||
|
characterTags: Promise<CharacterTagInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this tag tagging a character interaction
|
||||||
|
*/
|
||||||
|
interactionTags: Promise<InteractionTagInterface[]> | Identifier[];
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
interface TransformationTypeNameInterface extends IdentifiableInterface, NameInterface {
|
||||||
|
entity: Promise<TransformationTypeInterface> | Identifier;
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
/**
|
||||||
|
* This entity describes a transformation type.
|
||||||
|
* Possible type: translation, decensor, collection, ...
|
||||||
|
*/
|
||||||
|
interface TransformationTypeInterface extends IdentifiableInterface, MultiNamedInterface, DescribableInterface {
|
||||||
|
names: Promise<TransformationTypeNameInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the transformations of this type
|
||||||
|
*/
|
||||||
|
transformations: Promise<TransformationInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if that transformation conserves the tags of the original work
|
||||||
|
*/
|
||||||
|
conservesTags: boolean;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
/**
|
||||||
|
* This entity describes how one work is transformed to another.
|
||||||
|
*/
|
||||||
|
interface TransformationInterface extends IdentifiableInterface, OrderableInterface {
|
||||||
|
/**
|
||||||
|
* the work based on the original
|
||||||
|
*/
|
||||||
|
byWork: Promise<WorkInterface> | Identifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the transformation type
|
||||||
|
*/
|
||||||
|
type: Promise<TransformationTypeInterface> | Identifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the original work, it being null meaning that the original work is unknown
|
||||||
|
*/
|
||||||
|
ofWork: Promise<WorkInterface> | Identifier | null;
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
/**
|
/**
|
||||||
* An entity implementing this interface has a weight property.
|
* An entity implementing this interface has a weight property.
|
||||||
*/
|
*/
|
||||||
interface WeightedEntityInterface {
|
interface WeightedInterface {
|
||||||
/**
|
/**
|
||||||
* the weight, mathematically a number (0,1], practically between (0,Number.MAX_SAFE_INTEGER]
|
* the weight, mathematically a number (0,1], practically between (0,Number.MAX_SAFE_INTEGER]
|
||||||
* the weight can also be not not defined, null in the database
|
* the weight can also be not not defined, null in the database
|
|
@ -0,0 +1,19 @@
|
||||||
|
/**
|
||||||
|
* This entity connects authors with their work and their role therein.
|
||||||
|
*/
|
||||||
|
interface WorkAuthorInterface extends IdentifiableInterface, OrderableInterface {
|
||||||
|
/**
|
||||||
|
* the work
|
||||||
|
*/
|
||||||
|
work: Promise<WorkInterface> | Identifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the roles of the author in the work
|
||||||
|
*/
|
||||||
|
authorRoles: Promise<AuthorRoleInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the author
|
||||||
|
*/
|
||||||
|
author: Promise<AuthorInterface> | Identifier;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
interface WorkCharacterNameInterface extends IdentifiableInterface, NameInterface {
|
||||||
|
entity: Promise<WorkCharacterInterface> | Identifier;
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
* This entity describes a character in a work.
|
||||||
|
* The character can be original or based on one or more existing characters.
|
||||||
|
*/
|
||||||
|
interface WorkCharacterInterface extends IdentifiableInterface, MultiNamedInterface {
|
||||||
|
names: Promise<WorkCharacterNameInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the works the character is a part of
|
||||||
|
* one work character can be part of multiple works because of series
|
||||||
|
*/
|
||||||
|
works: Promise<WorkInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* interaction with other characters as actor
|
||||||
|
*/
|
||||||
|
interactWith: Promise<InteractionTagInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* interaction with other characters as receiver
|
||||||
|
*/
|
||||||
|
interactedBy: Promise<InteractionTagInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tags connected to the character
|
||||||
|
*/
|
||||||
|
characterTags: Promise<CharacterTagInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* existing characters character is based on
|
||||||
|
*/
|
||||||
|
worldCharacters: Promise<WorldCharacterInterface[]> | Identifier[];
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
interface WorkNameInterface extends IdentifiableInterface, NameInterface {
|
||||||
|
entity: Promise<WorkInterface> | Identifier;
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
/**
|
||||||
|
* This tag entity tags a work.
|
||||||
|
*/
|
||||||
|
interface WorkTagInterface extends IdentifiableInterface, WeightedInterface {
|
||||||
|
/**
|
||||||
|
* the describing tag
|
||||||
|
*/
|
||||||
|
tag: Promise<TagInterface> | Identifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the tagged work
|
||||||
|
*/
|
||||||
|
work: Promise<WorkInterface> | Identifier;
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/**
|
||||||
|
* This is the main library entity.
|
||||||
|
*
|
||||||
|
* It describes a work of art organized by this software.
|
||||||
|
*/
|
||||||
|
interface WorkInterface extends IdentifiableInterface, MultiNamedInterface {
|
||||||
|
names: Promise<WorkNameInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* digital representations of this work
|
||||||
|
*/
|
||||||
|
copies: Promise<CopyInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* other works this work is a transformation of
|
||||||
|
*/
|
||||||
|
transformationOf: Promise<TransformationInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* other works this work is transformed by
|
||||||
|
*/
|
||||||
|
transformedBy: Promise<TransformationInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the authors/publishers of this work
|
||||||
|
*/
|
||||||
|
workAuthors: Promise<WorkAuthorInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* tags describing this work
|
||||||
|
*/
|
||||||
|
workTags: Promise<WorkTagInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* characters in this work
|
||||||
|
*/
|
||||||
|
workCharacters: Promise<WorkCharacterInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* fictional worlds in which this work takes place
|
||||||
|
*/
|
||||||
|
worlds: Promise<WorldInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* if this work i canon in above fictional world
|
||||||
|
*/
|
||||||
|
isCanonical: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the user rating of this work
|
||||||
|
*/
|
||||||
|
rating: number | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the release date of the work, in YYYY-MM-DD format
|
||||||
|
*/
|
||||||
|
releaseDate: string | null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the languages of the work (if applicable)
|
||||||
|
*/
|
||||||
|
languages: Promise<LanguageInterface[]> | string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the collections this work is a part of
|
||||||
|
*/
|
||||||
|
collectionParts: Promise<CollectionPartInterface[]> | Identifier[];
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
interface WorldCharacterNameInterface extends IdentifiableInterface, NameInterface {
|
||||||
|
entity: Promise<WorldCharacterInterface> | Identifier;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
/**
|
||||||
|
* This entity describes a canon character in a fictional world.
|
||||||
|
*/
|
||||||
|
interface WorldCharacterInterface
|
||||||
|
extends IdentifiableInterface,
|
||||||
|
MultiNamedInterface,
|
||||||
|
HierarchicalInterface<WorldCharacterInterface> {
|
||||||
|
names: Promise<WorldCharacterNameInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the characters in works which are based on this one
|
||||||
|
*/
|
||||||
|
workCharacters: Promise<WorkCharacterInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the fictional worlds this character is a part of
|
||||||
|
*/
|
||||||
|
worlds: Promise<WorldInterface[]> | Identifier[];
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
interface WorldNameInterface extends IdentifiableInterface, NameInterface {
|
||||||
|
entity: Promise<WorldInterface> | Identifier;
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
/**
|
||||||
|
* This entity describes a fictional world.
|
||||||
|
*/
|
||||||
|
interface WorldInterface extends IdentifiableInterface, MultiNamedInterface, HierarchicalInterface<WorldInterface> {
|
||||||
|
names: Promise<WorldNameInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* works taking place in this world
|
||||||
|
*/
|
||||||
|
works: Promise<WorkInterface[]> | Identifier[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* canon characters in this world
|
||||||
|
*/
|
||||||
|
worldCharacters: Promise<WorldCharacterInterface[]> | Identifier[];
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
interface AuthorNameEntityInterface extends AuthorNameInterface {
|
||||||
|
entity: Promise<AuthorEntityInterface>;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
interface AuthorRoleNameEntityInterface extends AuthorRoleNameInterface {
|
||||||
|
entity: Promise<AuthorRoleEntityInterface>;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
interface AuthorRoleEntityInterface extends AuthorRoleInterface {
|
||||||
|
names: Promise<AuthorRoleNameEntityInterface[]>;
|
||||||
|
|
||||||
|
workAuthors: Promise<WorkAuthorEntityInterface[]>;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
interface AuthorEntityInterface extends AuthorInterface {
|
||||||
|
names: Promise<AuthorNameEntityInterface[]>;
|
||||||
|
|
||||||
|
workAuthors: Promise<WorkAuthorEntityInterface[]>;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
interface CharacterTagEntityInterface extends CharacterTagInterface {
|
||||||
|
workCharacter: Promise<WorkCharacterEntityInterface>;
|
||||||
|
|
||||||
|
tag: Promise<TagEntityInterface>;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
interface CollectionNameEntityInterface extends CollectionNameInterface {
|
||||||
|
entity: Promise<CollectionEntityInterface>;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
interface CollectionPartEntityInterface extends CollectionPartInterface {
|
||||||
|
collection: Promise<CollectionEntityInterface>;
|
||||||
|
|
||||||
|
work: Promise<WorkEntityInterface>;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
interface CollectionEntityInterface extends CollectionInterface {
|
||||||
|
names: Promise<CollectionNameEntityInterface[]>;
|
||||||
|
|
||||||
|
parts: Promise<CollectionPartEntityInterface[]>;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
interface CopyEntityInterface extends CopyInterface {
|
||||||
|
original: Promise<WorkEntityInterface>;
|
||||||
|
|
||||||
|
sources: Promise<SourceEntityInterface[]>;
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
interface InteractionTagEntityInterface extends InteractionTagInterface {
|
||||||
|
tag: Promise<TagEntityInterface>;
|
||||||
|
|
||||||
|
subjectCharacters: Promise<WorkCharacterEntityInterface[]>;
|
||||||
|
|
||||||
|
objectCharacters: Promise<WorkCharacterEntityInterface[]>;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
interface LanguageEntityInterface extends LanguageInterface {
|
||||||
|
works: Promise<WorkEntityInterface[]>;
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
interface SiteNameEntityInterface extends SiteNameInterface {
|
||||||
|
entity: Promise<SiteEntityInterface>;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
interface SiteEntityInterface extends SiteInterface {
|
||||||
|
names: Promise<SiteNameEntityInterface[]>;
|
||||||
|
|
||||||
|
sources: Promise<SourceEntityInterface[]>;
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue