96 switch from azure table storage to sqlite #97
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,3 +6,4 @@ node_modules
|
|||||||
.dapr
|
.dapr
|
||||||
**/**/secrets.json
|
**/**/secrets.json
|
||||||
.prod
|
.prod
|
||||||
|
database
|
||||||
@@ -22,7 +22,13 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
FROM node:18-slim AS base
|
FROM node:22-slim AS base
|
||||||
|
|
||||||
|
FROM base AS migrate
|
||||||
|
WORKDIR migrations
|
||||||
|
COPY ./migrations .
|
||||||
|
RUN npm i -g pnpm
|
||||||
|
RUN pnpm install
|
||||||
|
|
||||||
FROM base AS api
|
FROM base AS api
|
||||||
WORKDIR api
|
WORKDIR api
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
"@nestjs/core": "^10.0.0",
|
"@nestjs/core": "^10.0.0",
|
||||||
"@nestjs/passport": "^10.0.3",
|
"@nestjs/passport": "^10.0.3",
|
||||||
"@nestjs/platform-express": "^10.0.0",
|
"@nestjs/platform-express": "^10.0.0",
|
||||||
|
"@nestjs/typeorm": "^11.0.0",
|
||||||
"@noahspan/azure-database": "^3.1.2",
|
"@noahspan/azure-database": "^3.1.2",
|
||||||
"@noahspan/noahspan-modules": "^1.1.5",
|
"@noahspan/noahspan-modules": "^1.1.5",
|
||||||
"@schematics/angular": "^17.3.7",
|
"@schematics/angular": "^17.3.7",
|
||||||
@@ -34,6 +35,8 @@
|
|||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
"reflect-metadata": "^0.2.2",
|
"reflect-metadata": "^0.2.2",
|
||||||
"rxjs": "^7.8.1",
|
"rxjs": "^7.8.1",
|
||||||
|
"sqlite3": "^5.1.7",
|
||||||
|
"typeorm": "^0.3.25",
|
||||||
"uuid": "^10.0.0",
|
"uuid": "^10.0.0",
|
||||||
"uuidv4": "^6.2.13"
|
"uuidv4": "^6.2.13"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { HttpExceptionFilter } from './filters/http-exception.filter';
|
|||||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
import { AuthGuard, AuthModule, UserModule } from '@noahspan/noahspan-modules';
|
import { AuthGuard, AuthModule, UserModule } from '@noahspan/noahspan-modules';
|
||||||
import configuration from './config/configuration';
|
import configuration from './config/configuration';
|
||||||
|
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -27,6 +28,15 @@ import configuration from './config/configuration';
|
|||||||
FeatureFlagModule,
|
FeatureFlagModule,
|
||||||
LogModule,
|
LogModule,
|
||||||
PilotModule,
|
PilotModule,
|
||||||
|
TypeOrmModule.forRootAsync({
|
||||||
|
inject: [ConfigService],
|
||||||
|
useFactory: (configService: ConfigService) => ({
|
||||||
|
type: 'sqlite',
|
||||||
|
database: configService.get<string>('dbPath'),
|
||||||
|
entities: [__dirname + "/**/*.entity{.ts,.js}"],
|
||||||
|
synchronize: false
|
||||||
|
})
|
||||||
|
}),
|
||||||
UserModule.registerAsync({
|
UserModule.registerAsync({
|
||||||
inject: [ConfigService],
|
inject: [ConfigService],
|
||||||
imports: [ConfigModule],
|
imports: [ConfigModule],
|
||||||
|
|||||||
21
api/src/certificate/certificate.entity.ts
Normal file
21
api/src/certificate/certificate.entity.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
|
||||||
|
import { PilotEntity } from '../pilot/pilot.entity';
|
||||||
|
|
||||||
|
@Entity({ name: 'certificates'})
|
||||||
|
export class CertificateEntity {
|
||||||
|
@PrimaryGeneratedColumn('uuid')
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
number: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
issueDate: Date
|
||||||
|
|
||||||
|
@ManyToOne(() => PilotEntity, (pilot: PilotEntity) => pilot.certificates)
|
||||||
|
@JoinColumn({ name: 'pilotId' })
|
||||||
|
pilot: PilotEntity;
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
export default () => ({
|
export default () => ({
|
||||||
azureStorageConnectionString: process.env.AZURE_STORAGE_CONNECTION_STRING,
|
azureStorageConnectionString: process.env.AZURE_STORAGE_CONNECTION_STRING,
|
||||||
|
dbPath: process.env.DB_PATH,
|
||||||
clientId: process.env.CLIENT_ID,
|
clientId: process.env.CLIENT_ID,
|
||||||
clientSecret: process.env.CLIENT_SECRET,
|
clientSecret: process.env.CLIENT_SECRET,
|
||||||
tenantId: process.env.TENANT_ID
|
tenantId: process.env.TENANT_ID
|
||||||
|
|||||||
18
api/src/endorsement/endorsement.entity.ts
Normal file
18
api/src/endorsement/endorsement.entity.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { PilotEntity } from 'src/pilot/pilot.entity';
|
||||||
|
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
|
||||||
|
|
||||||
|
@Entity({ name: 'endorsements' })
|
||||||
|
export class EndorsementEntity {
|
||||||
|
@PrimaryGeneratedColumn('uuid')
|
||||||
|
id: string
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
issueDate: Date;
|
||||||
|
|
||||||
|
@ManyToOne(() => PilotEntity, (pilot: PilotEntity) => pilot.endorsements)
|
||||||
|
@JoinColumn({ name: 'pilotId' })
|
||||||
|
pilot: PilotEntity
|
||||||
|
}
|
||||||
@@ -27,3 +27,82 @@ export class Log {
|
|||||||
tracks?: string[];
|
tracks?: string[];
|
||||||
notes?: string;
|
notes?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
import { PilotEntity } from 'src/pilot/pilot.entity';
|
||||||
|
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
|
||||||
|
|
||||||
|
@Entity({ name: 'logs' })
|
||||||
|
export class LogEntity {
|
||||||
|
@PrimaryGeneratedColumn('uuid')
|
||||||
|
id: string
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
date: Date;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
aircraftMakeModel: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
aircraftIdentity: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
routeFrom: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
routeTo: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
durationOfFlight: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
singleEngineLand: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
simulatorAtd: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
landingsDay: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
landingsNight: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
groundTrainingReceived: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
flightTrainingReceived: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
crossCountry: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
night: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
solo: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
pilotInCommand: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
instrumentActual: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
instrumentSimulated: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
instrumentApproaches: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
instrumentHolds: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
instrumentNavTrack: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
notes: string;
|
||||||
|
|
||||||
|
@ManyToOne(() => PilotEntity, (pilot: PilotEntity) => pilot.logs)
|
||||||
|
@JoinColumn({ name: 'pilotId' })
|
||||||
|
pilot: PilotEntity;
|
||||||
|
}
|
||||||
18
api/src/medical/medical.entity.ts
Normal file
18
api/src/medical/medical.entity.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import { PilotEntity } from 'src/pilot/pilot.entity';
|
||||||
|
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm';
|
||||||
|
|
||||||
|
@Entity({ name: 'medical' })
|
||||||
|
export class MedicalEntity {
|
||||||
|
@PrimaryGeneratedColumn('uuid')
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
class: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
expirationDate: Date;
|
||||||
|
|
||||||
|
@ManyToOne(() => PilotEntity, (pilot: PilotEntity) => pilot.medical)
|
||||||
|
@JoinColumn({ name: 'pilotId' })
|
||||||
|
pilot: PilotEntity;
|
||||||
|
}
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
export class Certificate {
|
|
||||||
type: string;
|
|
||||||
issueDate: string;
|
|
||||||
number: string;
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
export class Endorsement {
|
|
||||||
type: string;
|
|
||||||
issueDate: Date;
|
|
||||||
}
|
|
||||||
@@ -1,18 +1,63 @@
|
|||||||
import { EntityString } from '@noahspan/azure-database';
|
// import { EntityString } from '@noahspan/azure-database';
|
||||||
|
|
||||||
export class Pilot {
|
// export class Pilot {
|
||||||
@EntityString() partitionKey: string;
|
// @EntityString() partitionKey: string;
|
||||||
@EntityString() rowKey: string;
|
// @EntityString() rowKey: string;
|
||||||
@EntityString() id: string;
|
// @EntityString() id: string;
|
||||||
@EntityString() name: string;
|
// @EntityString() name: string;
|
||||||
@EntityString() address?: string;
|
// @EntityString() address?: string;
|
||||||
@EntityString() city?: string;
|
// @EntityString() city?: string;
|
||||||
@EntityString() state?: string;
|
// @EntityString() state?: string;
|
||||||
@EntityString() postalCode?: string;
|
// @EntityString() postalCode?: string;
|
||||||
@EntityString() email?: string;
|
// @EntityString() email?: string;
|
||||||
@EntityString() phone?: string;
|
// @EntityString() phone?: string;
|
||||||
@EntityString() medicalClass?: string;
|
// @EntityString() medicalClass?: string;
|
||||||
@EntityString() medicalExpiration: string;
|
// @EntityString() medicalExpiration: string;
|
||||||
@EntityString() certificates: string;
|
// @EntityString() certificates: string;
|
||||||
@EntityString() endorsements: string;
|
// @EntityString() endorsements: string;
|
||||||
|
// }
|
||||||
|
|
||||||
|
import { LogEntity } from 'src/log/log.entity';
|
||||||
|
import { Entity, PrimaryGeneratedColumn, Column, OneToMany } from 'typeorm';
|
||||||
|
import { CertificateEntity } from '../certificate/certificate.entity';
|
||||||
|
import { EndorsementEntity } from 'src/endorsement/endorsement.entity';
|
||||||
|
import { MedicalEntity } from 'src/medical/medical.entity';
|
||||||
|
|
||||||
|
@Entity({ name: 'pilots' })
|
||||||
|
export class PilotEntity {
|
||||||
|
@PrimaryGeneratedColumn('uuid')
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
address: string
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
city: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
state: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
postalCode: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
email: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
phone: string;
|
||||||
|
|
||||||
|
@OneToMany(() => LogEntity, (log: LogEntity) => log.pilot, {onDelete: 'CASCADE', onUpdate: 'CASCADE'})
|
||||||
|
logs: LogEntity[];
|
||||||
|
|
||||||
|
@OneToMany(() => CertificateEntity, (certificate: CertificateEntity) => certificate.pilot, { onDelete: 'CASCADE', onUpdate: 'CASCADE' })
|
||||||
|
certificates: CertificateEntity[];
|
||||||
|
|
||||||
|
@OneToMany(() => EndorsementEntity, (endorsement: EndorsementEntity) => endorsement.pilot, { onDelete: 'CASCADE', onUpdate: 'CASCADE' })
|
||||||
|
endorsements: EndorsementEntity[];
|
||||||
|
|
||||||
|
@OneToMany(() => MedicalEntity, (medical: MedicalEntity) => medical.pilot, { onDelete: 'CASCADE', onUpdate: 'CASCADE' })
|
||||||
|
medical: MedicalEntity[];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,63 @@
|
|||||||
version: '3.8'
|
version: '3.8'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
azurite:
|
# azurite:
|
||||||
container_name: azurite-flying
|
# container_name: azurite-flying
|
||||||
image: mcr.microsoft.com/azure-storage/azurite
|
# image: mcr.microsoft.com/azure-storage/azurite
|
||||||
ports:
|
# ports:
|
||||||
- '10000:10000'
|
# - '10000:10000'
|
||||||
- '10001:10001'
|
# - '10001:10001'
|
||||||
- '10002:10002'
|
# - '10002:10002'
|
||||||
command: 'azurite --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 --loose --skipApiVersionCheck'
|
# command: 'azurite --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 --loose --skipApiVersionCheck'
|
||||||
|
# volumes:
|
||||||
|
# - ./azurite-flying:/data
|
||||||
|
|
||||||
|
restore:
|
||||||
|
container_name: restore
|
||||||
|
image: litestream/litestream:0.3.13
|
||||||
volumes:
|
volumes:
|
||||||
- ./azurite-flying:/data
|
- ./database/flying.db:/var/lib/flying/flying.db
|
||||||
|
- ./database/litestream_dev.yml:/etc/litestream.yml
|
||||||
|
- backup:/var/lib/backup
|
||||||
|
- data:/var/lib/flying
|
||||||
|
command: restore -if-db-not-exists -if-replica-exists /var/lib/flying/flying.db
|
||||||
|
|
||||||
api:
|
# api:
|
||||||
container_name: flying-api
|
# container_name: flying-api
|
||||||
build:
|
# build:
|
||||||
context: .
|
# context: .
|
||||||
target: api
|
# target: api
|
||||||
ports:
|
# ports:
|
||||||
- '3000:3000'
|
# - '3000:3000'
|
||||||
env_file:
|
# env_file:
|
||||||
- ./api/.env.compose
|
# - ./api/.env.compose
|
||||||
|
# volumes:
|
||||||
|
# - data:/var/lib/flying
|
||||||
|
# depends_on:
|
||||||
|
# migrate:
|
||||||
|
# condition: service_completed_successfully
|
||||||
|
|
||||||
app:
|
# replicate:
|
||||||
container_name: flying-app
|
# container_name: replicate
|
||||||
build:
|
# image: litestream/litestream:0.3.13
|
||||||
context: .
|
# volumes:
|
||||||
target: app
|
# - ./database/litestream_dev.yml:/etc/litestream.yml
|
||||||
ports:
|
# - backup:/var/lib/backup
|
||||||
- '8080:8080'
|
# - data:/var/lib/flying
|
||||||
|
# command: replicate
|
||||||
|
# depends_on:
|
||||||
|
# migrate:
|
||||||
|
# condition: service_completed_successfully
|
||||||
|
|
||||||
|
# app:
|
||||||
|
# container_name: flying-app
|
||||||
|
# build:
|
||||||
|
# context: .
|
||||||
|
# target: app
|
||||||
|
# ports:
|
||||||
|
# - '8080:8080'
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
azurite-flying:
|
# azurite-flying:
|
||||||
|
backup:
|
||||||
|
data:
|
||||||
998
pnpm-lock.yaml
generated
998
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user