diff --git a/.vscode/settings.json b/.vscode/settings.json index 812953b..bc63ed0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,5 +8,9 @@ "prettier.enable": false, "[typescript]": { "editor.defaultFormatter": "vscode.typescript-language-features" - } + }, + "javascript.preferences.quoteStyle": "single", + "javascript.preferences.importModuleSpecifierEnding": "minimal", + "typescript.preferences.importModuleSpecifierEnding": "minimal", + "typescript.preferences.includePackageJsonAutoImports": "on" } \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index da54cd5..089c4de 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM node:alpine WORKDIR /app COPY ./package.json ./ -RUN npm i +RUN yarn COPY ./ ./ ENTRYPOINT [ "yarn","dev" ] \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 1efd5ba..7ca0bb8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,9 +12,12 @@ services: DB_USER: lfk DB_PASSWORD: changeme DB_NAME: lfk + NODE_ENV: production backend_db: image: postgres:11-alpine environment: POSTGRES_DB: lfk POSTGRES_PASSWORD: changeme - POSTGRES_USER: lfk \ No newline at end of file + POSTGRES_USER: lfk + ports: + - 5432:5432 \ No newline at end of file diff --git a/src/controllers/RunnerController.ts b/src/controllers/RunnerController.ts new file mode 100644 index 0000000..da80b31 --- /dev/null +++ b/src/controllers/RunnerController.ts @@ -0,0 +1,89 @@ +import { JsonController, Param, Body, Get, Post, Put, Delete, OnUndefined } from 'routing-controllers'; +import { getConnectionManager, Repository } from 'typeorm'; +import { EntityFromBody } from 'typeorm-routing-controllers-extensions'; +import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; +import { Runner } from '../models/Runner'; +import { RunnerGroupNeededError, RunnerGroupNotFoundError, RunnerIdsNotMatchingError, RunnerNotFoundError, RunnerOnlyOneGroupAllowedError } from '../errors/RunnerErrors'; +import { CreateRunner } from '../models/CreateRunner'; + + +@JsonController('/runners') +//@Authorized('RUNNERS:read') +export class RunnerController { + private runnerRepository: Repository; + + /** + * Gets the repository of this controller's model/entity. + */ + constructor() { + this.runnerRepository = getConnectionManager().get().getRepository(Runner); + } + + @Get() + @ResponseSchema(Runner, { isArray: true }) + @OpenAPI({ description: 'Lists all runners.' }) + getAll() { + return this.runnerRepository.find(); + } + + @Get('/:id') + @ResponseSchema(Runner) + @ResponseSchema(RunnerNotFoundError, { statusCode: 404 }) + @OnUndefined(RunnerNotFoundError) + @OpenAPI({ description: 'Returns a runner of a specified id (if it exists)' }) + getOne(@Param('id') id: number) { + return this.runnerRepository.findOne({ id: id }); + } + + @Post() + @ResponseSchema(Runner) + @ResponseSchema(RunnerOnlyOneGroupAllowedError) + @ResponseSchema(RunnerGroupNeededError) + @ResponseSchema(RunnerGroupNotFoundError) + @OpenAPI({ description: 'Create a new runner object (id will be generated automagicly).' }) + async post(@Body({ validate: true }) createRunner: CreateRunner) { + let runner; + try { + runner = await createRunner.toRunner(); + } catch (error) { + return error; + } + + return this.runnerRepository.save(runner); + } + + @Put('/:id') + @ResponseSchema(Runner) + @ResponseSchema(RunnerNotFoundError, { statusCode: 404 }) + @ResponseSchema(RunnerIdsNotMatchingError, { statusCode: 406 }) + @OpenAPI({ description: "Update a runner object (id can't be changed)." }) + async put(@Param('id') id: number, @EntityFromBody() runner: Runner) { + let oldRunner = await this.runnerRepository.findOne({ id: id }); + + if (!oldRunner) { + throw new RunnerNotFoundError(); + } + + if (oldRunner.id != runner.id) { + throw new RunnerIdsNotMatchingError(); + } + + await this.runnerRepository.update(oldRunner, runner); + return runner; + } + + @Delete('/:id') + @ResponseSchema(Runner) + @ResponseSchema(RunnerNotFoundError, { statusCode: 404 }) + @OpenAPI({ description: 'Delete a specified runner (if it exists).' }) + async remove(@Param('id') id: number) { + let runner = await this.runnerRepository.findOne({ id: id }); + + if (!runner) { + throw new RunnerNotFoundError(); + } + + await this.runnerRepository.delete(runner); + return runner; + } +} diff --git a/src/controllers/RunnerOrganisationController.ts b/src/controllers/RunnerOrganisationController.ts new file mode 100644 index 0000000..1575ef0 --- /dev/null +++ b/src/controllers/RunnerOrganisationController.ts @@ -0,0 +1,87 @@ +import { JsonController, Param, Body, Get, Post, Put, Delete, OnUndefined } from 'routing-controllers'; +import { getConnectionManager, Repository } from 'typeorm'; +import { EntityFromBody } from 'typeorm-routing-controllers-extensions'; +import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; +import { RunnerOrganisation } from '../models/RunnerOrganisation'; +import { RunnerOrganisationIdsNotMatchingError, RunnerOrganisationNotFoundError } from '../errors/RunnerOrganisationErrors'; +import { CreateRunnerOrganisation } from '../models/CreateRunnerOrganisation'; +import { RunnerGroup } from '../models/RunnerGroup'; + + +@JsonController('/organisations') +//@Authorized('RUNNERS:read') +export class RunnerOrganisationController { + private runnerOrganisationRepository: Repository; + + /** + * Gets the repository of this controller's model/entity. + */ + constructor() { + this.runnerOrganisationRepository = getConnectionManager().get().getRepository(RunnerOrganisation); + } + + @Get() + @ResponseSchema(RunnerOrganisation, { isArray: true }) + @OpenAPI({ description: 'Lists all runnerOrganisations.' }) + getAll() { + return this.runnerOrganisationRepository.find(); + } + + @Get('/:id') + @ResponseSchema(RunnerOrganisation) + @ResponseSchema(RunnerOrganisationNotFoundError, { statusCode: 404 }) + @OnUndefined(RunnerOrganisationNotFoundError) + @OpenAPI({ description: 'Returns a runnerOrganisation of a specified id (if it exists)' }) + getOne(@Param('id') id: number) { + return this.runnerOrganisationRepository.findOne({ id: id }); + } + + @Post() + @ResponseSchema(RunnerOrganisation) + @OpenAPI({ description: 'Create a new runnerOrganisation object (id will be generated automagicly).' }) + async post(@Body({ validate: true }) createRunnerOrganisation: CreateRunnerOrganisation) { + let runnerOrganisation; + try { + runnerOrganisation = await createRunnerOrganisation.toRunnerOrganisation(); + } catch (error) { + return error; + } + + return this.runnerOrganisationRepository.save(runnerOrganisation); + } + + @Put('/:id') + @ResponseSchema(RunnerOrganisation) + @ResponseSchema(RunnerOrganisationNotFoundError, { statusCode: 404 }) + @ResponseSchema(RunnerOrganisationIdsNotMatchingError, { statusCode: 406 }) + @OpenAPI({ description: "Update a runnerOrganisation object (id can't be changed)." }) + async put(@Param('id') id: number, @EntityFromBody() runnerOrganisation: RunnerOrganisation) { + let oldRunnerOrganisation = await this.runnerOrganisationRepository.findOne({ id: id }); + + if (!oldRunnerOrganisation) { + throw new RunnerOrganisationNotFoundError(); + } + + if (oldRunnerOrganisation.id != runnerOrganisation.id) { + throw new RunnerOrganisationIdsNotMatchingError(); + } + + await this.runnerOrganisationRepository.update(oldRunnerOrganisation, runnerOrganisation); + return runnerOrganisation; + } + + @Delete('/:id') + @ResponseSchema(RunnerOrganisation) + @ResponseSchema(RunnerOrganisationNotFoundError, { statusCode: 404 }) + @OpenAPI({ description: 'Delete a specified runnerOrganisation (if it exists).' }) + async remove(@Param('id') id: number) { + let runnerOrganisation = await this.runnerOrganisationRepository.findOne({ id: id }); + + if (!runnerOrganisation) { + throw new RunnerOrganisationNotFoundError(); + } + + await this.runnerOrganisationRepository.delete(runnerOrganisation); + return runnerOrganisation; + } +} diff --git a/src/controllers/TrackController.ts b/src/controllers/TrackController.ts index d0b3a0c..7b22cc2 100644 --- a/src/controllers/TrackController.ts +++ b/src/controllers/TrackController.ts @@ -4,20 +4,11 @@ import { EntityFromBody } from 'typeorm-routing-controllers-extensions'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { Track } from '../models/Track'; import { IsInt, IsNotEmpty, IsPositive, IsString } from 'class-validator'; -import {TrackIdsNotMatchingError, TrackNotFoundError} from "../errors/TrackErrors"; - -class CreateTrack { - @IsString() - @IsNotEmpty() - name: string; - - @IsInt() - @IsPositive() - length: number; -} +import { TrackIdsNotMatchingError, TrackNotFoundError } from "../errors/TrackErrors"; +import { CreateTrack } from '../models/CreateTrack'; @JsonController('/tracks') -@Authorized("TRACKS:read") +//@Authorized("TRACKS:read") export class TrackController { private trackRepository: Repository; @@ -37,7 +28,7 @@ export class TrackController { @Get('/:id') @ResponseSchema(Track) - @ResponseSchema(TrackNotFoundError, {statusCode: 404}) + @ResponseSchema(TrackNotFoundError, { statusCode: 404 }) @OnUndefined(TrackNotFoundError) @OpenAPI({ description: "Returns a track of a specified id (if it exists)" }) getOne(@Param('id') id: number) { @@ -51,14 +42,14 @@ export class TrackController { @Body({ validate: true }) track: CreateTrack ) { - return this.trackRepository.save(track); + return this.trackRepository.save(track.toTrack()); } @Put('/:id') @ResponseSchema(Track) - @ResponseSchema(TrackNotFoundError, {statusCode: 404}) - @ResponseSchema(TrackIdsNotMatchingError, {statusCode: 406}) - @OpenAPI({description: "Update a track object (id can't be changed)."}) + @ResponseSchema(TrackNotFoundError, { statusCode: 404 }) + @ResponseSchema(TrackIdsNotMatchingError, { statusCode: 406 }) + @OpenAPI({ description: "Update a track object (id can't be changed)." }) async put(@Param('id') id: number, @EntityFromBody() track: Track) { let oldTrack = await this.trackRepository.findOne({ id: id }); @@ -66,7 +57,7 @@ export class TrackController { throw new TrackNotFoundError(); } - if(oldTrack.id != track.id){ + if (oldTrack.id != track.id) { throw new TrackIdsNotMatchingError(); } @@ -76,8 +67,8 @@ export class TrackController { @Delete('/:id') @ResponseSchema(Track) - @ResponseSchema(TrackNotFoundError, {statusCode: 404}) - @OpenAPI({description: "Delete a specified track (if it exists)."}) + @ResponseSchema(TrackNotFoundError, { statusCode: 404 }) + @OpenAPI({ description: "Delete a specified track (if it exists)." }) async remove(@Param('id') id: number) { let track = await this.trackRepository.findOne({ id: id }); diff --git a/src/errors/RunnerErrors.ts b/src/errors/RunnerErrors.ts new file mode 100644 index 0000000..0be6419 --- /dev/null +++ b/src/errors/RunnerErrors.ts @@ -0,0 +1,52 @@ +import { JsonController, Param, Body, Get, Post, Put, Delete, NotFoundError, OnUndefined, NotAcceptableError } from 'routing-controllers'; +import { IsInt, IsNotEmpty, IsPositive, IsString } from 'class-validator'; + +/** + * Error to throw when a runner couldn't be found. + * Implemented this ways to work with the json-schema conversion for openapi. + */ +export class RunnerNotFoundError extends NotFoundError { + @IsString() + name = "RunnerNotFoundError" + + @IsString() + message = "Runner not found!" +} + +/** + * Error to throw when two runners' ids don't match. + * Usually occurs when a user tries to change a runner's id. + * Implemented this ways to work with the json-schema conversion for openapi. + */ +export class RunnerIdsNotMatchingError extends NotAcceptableError { + @IsString() + name = "RunnerIdsNotMatchingError" + + @IsString() + message = "The id's don't match!! \n And if you wanted to change a runner's id: This isn't allowed" +} + +export class RunnerOnlyOneGroupAllowedError extends NotAcceptableError { + @IsString() + name = "RunnerOnlyOneGroupAllowedError" + + @IsString() + message = "Runner's can only be part of one group (team or organisiation)! \n You provided an id for both." +} + +export class RunnerGroupNeededError extends NotAcceptableError { + @IsString() + name = "RunnerGroupNeededError" + + @IsString() + message = "Runner's need to be part of one group (team or organisiation)! \n You provided neither." +} + + +export class RunnerGroupNotFoundError extends NotFoundError { + @IsString() + name = "RunnerGroupNotFoundError" + + @IsString() + message = "The group you provided couldn't be located in the system. \n Please check your request." +} \ No newline at end of file diff --git a/src/errors/RunnerOrganisationErrors.ts b/src/errors/RunnerOrganisationErrors.ts new file mode 100644 index 0000000..f846ffa --- /dev/null +++ b/src/errors/RunnerOrganisationErrors.ts @@ -0,0 +1,27 @@ +import { JsonController, Param, Body, Get, Post, Put, Delete, NotFoundError, OnUndefined, NotAcceptableError } from 'routing-controllers'; +import { IsInt, IsNotEmpty, IsPositive, IsString } from 'class-validator'; + +/** + * Error to throw when a runner couldn't be found. + * Implemented this ways to work with the json-schema conversion for openapi. + */ +export class RunnerOrganisationNotFoundError extends NotFoundError { + @IsString() + name = "RunnerOrganisationNotFoundError" + + @IsString() + message = "RunnerOrganisation not found!" +} + +/** + * Error to throw when two runners' ids don't match. + * Usually occurs when a user tries to change a runner's id. + * Implemented this ways to work with the json-schema conversion for openapi. + */ +export class RunnerOrganisationIdsNotMatchingError extends NotAcceptableError { + @IsString() + name = "RunnerOrganisationIdsNotMatchingError" + + @IsString() + message = "The id's don't match!! \n And if you wanted to change a runner's id: This isn't allowed" +} \ No newline at end of file diff --git a/src/models/CreateRunner.ts b/src/models/CreateRunner.ts new file mode 100644 index 0000000..9eb15eb --- /dev/null +++ b/src/models/CreateRunner.ts @@ -0,0 +1,58 @@ +import { IsEmail, IsInt, IsNotEmpty, IsOptional, IsPhoneNumber, IsPositive, IsString } from 'class-validator'; +import { Runner } from '../models/Runner'; +import { getConnectionManager, Repository } from 'typeorm'; +import { group } from 'console'; +import { RunnerOnlyOneGroupAllowedError, RunnerGroupNeededError, RunnerGroupNotFoundError } from '../errors/RunnerErrors'; +import { RunnerOrganisation } from './RunnerOrganisation'; +import { RunnerTeam } from './RunnerTeam'; +import { RunnerGroup } from './RunnerGroup'; +import { Address } from 'cluster'; + +export class CreateRunner { + @IsString() + firstname: string; + @IsString() + middlename?: string; + @IsString() + lastname: string; + @IsString() + phone?: string; + @IsString() + email?: string; + @IsInt() + @IsOptional() + teamId?: number + @IsInt() + @IsOptional() + orgId?: number + + public async toRunner(): Promise { + let newRunner: Runner = new Runner(); + + if (this.teamId !== undefined && this.orgId !== undefined) { + throw new RunnerOnlyOneGroupAllowedError(); + } + if (this.teamId === undefined && this.orgId === undefined) { + throw new RunnerGroupNeededError(); + } + + if (this.teamId) { + newRunner.group = await getConnectionManager().get().getRepository(RunnerTeam).findOne({ id: this.teamId }); + } + if (this.orgId) { + newRunner.group = await getConnectionManager().get().getRepository(RunnerOrganisation).findOne({ id: this.orgId }); + } + if (!newRunner.group) { + throw new RunnerGroupNotFoundError(); + } + + newRunner.firstname = this.firstname; + newRunner.middlename = this.middlename; + newRunner.lastname = this.lastname; + newRunner.phone = this.phone; + newRunner.email = this.email; + + console.log(newRunner) + return newRunner; + } +} \ No newline at end of file diff --git a/src/models/CreateRunnerOrganisation.ts b/src/models/CreateRunnerOrganisation.ts new file mode 100644 index 0000000..b7e5c71 --- /dev/null +++ b/src/models/CreateRunnerOrganisation.ts @@ -0,0 +1,15 @@ +import { IsString } from 'class-validator'; +import { RunnerOrganisation } from './RunnerOrganisation'; + +export class CreateRunnerOrganisation { + @IsString() + name: string; + + public async toRunnerOrganisation(): Promise { + let newRunnerOrganisation: RunnerOrganisation = new RunnerOrganisation(); + + newRunnerOrganisation.name = this.name; + + return newRunnerOrganisation; + } +} \ No newline at end of file diff --git a/src/models/CreateTrack.ts b/src/models/CreateTrack.ts new file mode 100644 index 0000000..015a58f --- /dev/null +++ b/src/models/CreateTrack.ts @@ -0,0 +1,30 @@ +import { IsInt, IsNotEmpty, IsPositive, IsString } from 'class-validator'; +import { Track } from './Track'; + +export class CreateTrack { + /** + * The track's name. + */ + @IsString() + @IsNotEmpty() + name: string; + + /** + * The track's distance in meters (must be greater 0). + */ + @IsInt() + @IsPositive() + distance: number; + + /** + * Converts a Track object based on this. + */ + public toTrack(): Track { + let newTrack: Track = new Track(); + + newTrack.name = this.name; + newTrack.distance = this.distance; + + return newTrack; + } +} \ No newline at end of file diff --git a/src/models/DistanceDonation.ts b/src/models/DistanceDonation.ts index 79bf0b8..b54c642 100644 --- a/src/models/DistanceDonation.ts +++ b/src/models/DistanceDonation.ts @@ -1,5 +1,5 @@ -import { Entity, Column, ManyToOne } from "typeorm"; -import { IsInt, IsNotEmpty, IsPositive,} from "class-validator"; +import { Entity, Column, ManyToOne, ChildEntity } from "typeorm"; +import { IsInt, IsNotEmpty, IsPositive, } from "class-validator"; import { Donation } from "./Donation"; import { Runner } from "./Runner"; @@ -7,7 +7,7 @@ import { Runner } from "./Runner"; * Defines a distance based donation. * Here people donate a certain amout per kilometer */ -@Entity() +@ChildEntity() export class DistanceDonation extends Donation { /** * The runner associated. diff --git a/src/models/Donation.ts b/src/models/Donation.ts index b94e182..c4ab699 100644 --- a/src/models/Donation.ts +++ b/src/models/Donation.ts @@ -1,4 +1,4 @@ -import { PrimaryGeneratedColumn, Column, ManyToOne, Entity } from "typeorm"; +import { PrimaryGeneratedColumn, Column, ManyToOne, Entity, TableInheritance } from "typeorm"; import { IsInt, IsNotEmpty, @@ -11,6 +11,7 @@ import { Participant } from "./Participant"; * Defines the donation interface. */ @Entity() +@TableInheritance({ column: { name: "type", type: "varchar" } }) export abstract class Donation { /** * Autogenerated unique id (primary key). diff --git a/src/models/Donor.ts b/src/models/Donor.ts index 5d0af07..ca65afd 100644 --- a/src/models/Donor.ts +++ b/src/models/Donor.ts @@ -1,11 +1,11 @@ -import { Entity, Column } from "typeorm"; +import { Entity, Column, ChildEntity } from "typeorm"; import { IsBoolean } from "class-validator"; import { Participant } from "./Participant"; /** * Defines a donor. */ -@Entity() +@ChildEntity() export class Donor extends Participant { /** * Does this donor need a receipt?. diff --git a/src/models/FixedDonation.ts b/src/models/FixedDonation.ts index e429ddf..dd05c40 100644 --- a/src/models/FixedDonation.ts +++ b/src/models/FixedDonation.ts @@ -1,11 +1,11 @@ -import { Entity, Column } from "typeorm"; -import { IsInt, IsPositive,} from "class-validator"; +import { Entity, Column, ChildEntity } from "typeorm"; +import { IsInt, IsPositive, } from "class-validator"; import { Donation } from "./Donation"; /** * Defines a fixed donation. */ -@Entity() +@ChildEntity() export class FixedDonation extends Donation { /** diff --git a/src/models/Participant.ts b/src/models/Participant.ts index e80d348..53562a3 100644 --- a/src/models/Participant.ts +++ b/src/models/Participant.ts @@ -1,4 +1,4 @@ -import { PrimaryGeneratedColumn, Column, OneToMany, ManyToOne, Entity } from "typeorm"; +import { PrimaryGeneratedColumn, Column, OneToMany, ManyToOne, Entity, TableInheritance } from "typeorm"; import { IsEmail, IsInt, @@ -15,6 +15,7 @@ import { Donation } from "./Donation"; * Defines the participant interface. */ @Entity() +@TableInheritance({ column: { name: "type", type: "varchar" } }) export abstract class Participant { /** * Autogenerated unique id (primary key). @@ -36,7 +37,7 @@ export abstract class Participant { * The participant's middle name. * Optional */ - @Column({nullable: true}) + @Column({ nullable: true }) @IsOptional() @IsString() middlename?: string; @@ -60,7 +61,7 @@ export abstract class Participant { * The participant's phone number. * Optional */ - @Column({nullable: true}) + @Column({ nullable: true }) @IsOptional() @IsPhoneNumber("DE") phone?: string; @@ -69,7 +70,7 @@ export abstract class Participant { * The participant's email address. * Optional */ - @Column({nullable: true}) + @Column({ nullable: true }) @IsOptional() @IsEmail() email?: string; diff --git a/src/models/Runner.ts b/src/models/Runner.ts index 7423c22..e4d3ff7 100644 --- a/src/models/Runner.ts +++ b/src/models/Runner.ts @@ -1,5 +1,5 @@ -import { Entity, Column, OneToMany, ManyToOne } from "typeorm"; -import { IsInt, IsNotEmpty,} from "class-validator"; +import { Entity, Column, OneToMany, ManyToOne, ChildEntity } from "typeorm"; +import { IsInt, IsNotEmpty, } from "class-validator"; import { Participant } from "./Participant"; import { RunnerGroup } from "./RunnerGroup"; import { DistanceDonation } from "./DistanceDonation"; @@ -9,7 +9,7 @@ import { Scan } from "./Scan"; /** * Defines a runner. */ -@Entity() +@ChildEntity() export class Runner extends Participant { /** * The runner's associated group. @@ -17,7 +17,7 @@ export class Runner extends Participant { @IsNotEmpty() @ManyToOne(() => RunnerGroup, group => group.runners, { nullable: true }) group: RunnerGroup; - + /** * Used to link runners to donations. */ @@ -36,9 +36,9 @@ export class Runner extends Participant { @OneToMany(() => Scan, scan => scan.runner, { nullable: true }) scans: Scan[]; - @IsInt() - public get distance() : number { + @IsInt() + public get distance(): number { return this.scans.filter(scan => scan.valid === true).reduce((sum, current) => sum + current.distance, 0); } - + } diff --git a/src/models/RunnerGroup.ts b/src/models/RunnerGroup.ts index 2cd3694..8142754 100644 --- a/src/models/RunnerGroup.ts +++ b/src/models/RunnerGroup.ts @@ -1,4 +1,4 @@ -import { PrimaryGeneratedColumn, Column, OneToMany, ManyToOne, Entity } from "typeorm"; +import { PrimaryGeneratedColumn, Column, OneToMany, ManyToOne, Entity, TableInheritance } from "typeorm"; import { IsInt, IsNotEmpty, @@ -13,6 +13,7 @@ import { RunnerTeam } from "./RunnerTeam"; * Defines the runnerGroup interface. */ @Entity() +@TableInheritance({ column: { name: "type", type: "varchar" } }) export abstract class RunnerGroup { /** * Autogenerated unique id (primary key). diff --git a/src/models/RunnerOrganisation.ts b/src/models/RunnerOrganisation.ts index 4245fa0..b0a7220 100644 --- a/src/models/RunnerOrganisation.ts +++ b/src/models/RunnerOrganisation.ts @@ -1,5 +1,5 @@ -import { Entity, Column, ManyToOne, OneToMany } from "typeorm"; -import { IsOptional,} from "class-validator"; +import { Entity, Column, ManyToOne, OneToMany, ChildEntity } from "typeorm"; +import { IsOptional, } from "class-validator"; import { RunnerGroup } from "./RunnerGroup"; import { Address } from "./Address"; import { RunnerTeam } from "./RunnerTeam"; @@ -7,7 +7,7 @@ import { RunnerTeam } from "./RunnerTeam"; /** * Defines a runner organisation (business or school for example). */ -@Entity() +@ChildEntity() export class RunnerOrganisation extends RunnerGroup { /** @@ -18,9 +18,9 @@ export class RunnerOrganisation extends RunnerGroup { @ManyToOne(() => Address, address => address.groups, { nullable: true }) address?: Address; - /** - * Used to link teams to runner groups. - */ + /** + * Used to link teams to runner groups. + */ @OneToMany(() => RunnerTeam, team => team.parentGroup, { nullable: true }) teams: RunnerTeam[]; } \ No newline at end of file diff --git a/src/models/RunnerTeam.ts b/src/models/RunnerTeam.ts index 5adc60d..a9fb2f0 100644 --- a/src/models/RunnerTeam.ts +++ b/src/models/RunnerTeam.ts @@ -1,4 +1,4 @@ -import { Entity, Column, ManyToOne } from "typeorm"; +import { Entity, Column, ManyToOne, ChildEntity } from "typeorm"; import { IsNotEmpty } from "class-validator"; import { RunnerGroup } from "./RunnerGroup"; import { RunnerOrganisation } from "./RunnerOrganisation"; @@ -6,7 +6,7 @@ import { RunnerOrganisation } from "./RunnerOrganisation"; /** * Defines a runner team (class or deparment for example). */ -@Entity() +@ChildEntity() export class RunnerTeam extends RunnerGroup { /** diff --git a/src/models/Scan.ts b/src/models/Scan.ts index 5e8cbf9..75ec65d 100644 --- a/src/models/Scan.ts +++ b/src/models/Scan.ts @@ -1,4 +1,4 @@ -import { PrimaryGeneratedColumn, Column, ManyToOne, Entity } from "typeorm"; +import { PrimaryGeneratedColumn, Column, ManyToOne, Entity, TableInheritance } from "typeorm"; import { IsBoolean, IsInt, @@ -12,6 +12,7 @@ import { Runner } from "./Runner"; * Defines the scan interface. */ @Entity() +@TableInheritance({ column: { name: "type", type: "varchar" } }) export abstract class Scan { /** * Autogenerated unique id (primary key). diff --git a/src/models/TrackScan.ts b/src/models/TrackScan.ts index ae0467c..f7bee32 100644 --- a/src/models/TrackScan.ts +++ b/src/models/TrackScan.ts @@ -1,4 +1,4 @@ -import { PrimaryGeneratedColumn, Column, ManyToOne, Entity } from "typeorm"; +import { PrimaryGeneratedColumn, Column, ManyToOne, Entity, ChildEntity } from "typeorm"; import { IsBoolean, IsDateString, @@ -16,7 +16,7 @@ import { ScanStation } from "./ScanStation"; /** * Defines the scan interface. */ -@Entity() +@ChildEntity() export class TrackScan extends Scan { /** * The associated track. diff --git a/tsconfig.json b/tsconfig.json index 0f2192a..dfd4d15 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,12 +1,20 @@ { "compilerOptions": { - "target": "es2017", + "target": "ES2020", "module": "commonjs", "rootDir": "./src", "outDir": "./build", "esModuleInterop": true, "strict": false, "experimentalDecorators": true, - "emitDecoratorMetadata": true - } + "emitDecoratorMetadata": true, + "sourceMap": false + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules", + "**/*.spec.ts" + ] } \ No newline at end of file