96 switch from azure table storage to sqlite #100
3
.gitignore
vendored
3
.gitignore
vendored
@@ -5,4 +5,5 @@ node_modules
|
||||
.DS_Store
|
||||
.dapr
|
||||
**/**/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
|
||||
WORKDIR api
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"@nestjs/core": "^10.0.0",
|
||||
"@nestjs/passport": "^10.0.3",
|
||||
"@nestjs/platform-express": "^10.0.0",
|
||||
"@nestjs/typeorm": "^11.0.0",
|
||||
"@noahspan/azure-database": "^3.1.2",
|
||||
"@noahspan/noahspan-modules": "^1.1.5",
|
||||
"@schematics/angular": "^17.3.7",
|
||||
@@ -34,6 +35,8 @@
|
||||
"dotenv": "^16.4.7",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"rxjs": "^7.8.1",
|
||||
"sqlite3": "^5.1.7",
|
||||
"typeorm": "^0.3.25",
|
||||
"uuid": "^10.0.0",
|
||||
"uuidv4": "^6.2.13"
|
||||
},
|
||||
|
||||
@@ -7,6 +7,7 @@ import { HttpExceptionFilter } from './filters/http-exception.filter';
|
||||
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||
import { AuthGuard, AuthModule, UserModule } from '@noahspan/noahspan-modules';
|
||||
import configuration from './config/configuration';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@@ -27,6 +28,15 @@ import configuration from './config/configuration';
|
||||
FeatureFlagModule,
|
||||
LogModule,
|
||||
PilotModule,
|
||||
TypeOrmModule.forRootAsync({
|
||||
inject: [ConfigService],
|
||||
useFactory: (configService: ConfigService) => ({
|
||||
type: 'sqlite',
|
||||
database: configService.get<string>('dbPath'),
|
||||
entities: [__dirname + "/**/*.entity{.ts,.js}"],
|
||||
synchronize: false
|
||||
})
|
||||
}),
|
||||
UserModule.registerAsync({
|
||||
inject: [ConfigService],
|
||||
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 () => ({
|
||||
azureStorageConnectionString: process.env.AZURE_STORAGE_CONNECTION_STRING,
|
||||
dbPath: process.env.DB_PATH,
|
||||
clientId: process.env.CLIENT_ID,
|
||||
clientSecret: process.env.CLIENT_SECRET,
|
||||
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[];
|
||||
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 {
|
||||
@EntityString() partitionKey: string;
|
||||
@EntityString() rowKey: string;
|
||||
@EntityString() id: string;
|
||||
@EntityString() name: string;
|
||||
@EntityString() address?: string;
|
||||
@EntityString() city?: string;
|
||||
@EntityString() state?: string;
|
||||
@EntityString() postalCode?: string;
|
||||
@EntityString() email?: string;
|
||||
@EntityString() phone?: string;
|
||||
@EntityString() medicalClass?: string;
|
||||
@EntityString() medicalExpiration: string;
|
||||
@EntityString() certificates: string;
|
||||
@EntityString() endorsements: string;
|
||||
// export class Pilot {
|
||||
// @EntityString() partitionKey: string;
|
||||
// @EntityString() rowKey: string;
|
||||
// @EntityString() id: string;
|
||||
// @EntityString() name: string;
|
||||
// @EntityString() address?: string;
|
||||
// @EntityString() city?: string;
|
||||
// @EntityString() state?: string;
|
||||
// @EntityString() postalCode?: string;
|
||||
// @EntityString() email?: string;
|
||||
// @EntityString() phone?: string;
|
||||
// @EntityString() medicalClass?: string;
|
||||
// @EntityString() medicalExpiration: string;
|
||||
// @EntityString() certificates: 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'
|
||||
|
||||
services:
|
||||
azurite:
|
||||
container_name: azurite-flying
|
||||
image: mcr.microsoft.com/azure-storage/azurite
|
||||
ports:
|
||||
- '10000:10000'
|
||||
- '10001:10001'
|
||||
- '10002:10002'
|
||||
command: 'azurite --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 --loose --skipApiVersionCheck'
|
||||
volumes:
|
||||
- ./azurite-flying:/data
|
||||
# azurite:
|
||||
# container_name: azurite-flying
|
||||
# image: mcr.microsoft.com/azure-storage/azurite
|
||||
# ports:
|
||||
# - '10000:10000'
|
||||
# - '10001:10001'
|
||||
# - '10002:10002'
|
||||
# command: 'azurite --blobHost 0.0.0.0 --queueHost 0.0.0.0 --tableHost 0.0.0.0 --loose --skipApiVersionCheck'
|
||||
# volumes:
|
||||
# - ./azurite-flying:/data
|
||||
|
||||
api:
|
||||
container_name: flying-api
|
||||
build:
|
||||
context: .
|
||||
target: api
|
||||
ports:
|
||||
- '3000:3000'
|
||||
env_file:
|
||||
- ./api/.env.compose
|
||||
restore:
|
||||
container_name: restore
|
||||
image: litestream/litestream:0.3.13
|
||||
volumes:
|
||||
- ./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
|
||||
|
||||
app:
|
||||
container_name: flying-app
|
||||
build:
|
||||
context: .
|
||||
target: app
|
||||
ports:
|
||||
- '8080:8080'
|
||||
# api:
|
||||
# container_name: flying-api
|
||||
# build:
|
||||
# context: .
|
||||
# target: api
|
||||
# ports:
|
||||
# - '3000:3000'
|
||||
# env_file:
|
||||
# - ./api/.env.compose
|
||||
# volumes:
|
||||
# - data:/var/lib/flying
|
||||
# depends_on:
|
||||
# migrate:
|
||||
# condition: service_completed_successfully
|
||||
|
||||
# replicate:
|
||||
# container_name: replicate
|
||||
# image: litestream/litestream:0.3.13
|
||||
# volumes:
|
||||
# - ./database/litestream_dev.yml:/etc/litestream.yml
|
||||
# - backup:/var/lib/backup
|
||||
# - 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:
|
||||
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