sync doc to database

This commit is contained in:
Julian Krauser 2025-03-09 09:54:56 +01:00
parent b5a67d27fa
commit cc811717e1
21 changed files with 379 additions and 40 deletions

30
package-lock.json generated
View file

@ -20,6 +20,8 @@
"ics": "^3.8.1",
"ip": "^2.0.1",
"jsonwebtoken": "^9.0.2",
"lodash.differencewith": "^4.5.0",
"lodash.isequal": "^4.5.0",
"lodash.uniqby": "^4.7.0",
"moment": "^2.30.1",
"morgan": "^1.10.0",
@ -46,6 +48,8 @@
"@types/express": "^4.17.17",
"@types/ip": "^1.1.3",
"@types/jsonwebtoken": "^9.0.6",
"@types/lodash.differencewith": "^4.5.9",
"@types/lodash.isequal": "^4.5.8",
"@types/lodash.uniqby": "^4.7.9",
"@types/morgan": "^1.9.9",
"@types/ms": "^0.7.34",
@ -392,6 +396,26 @@
"dev": true,
"license": "MIT"
},
"node_modules/@types/lodash.differencewith": {
"version": "4.5.9",
"resolved": "https://registry.npmjs.org/@types/lodash.differencewith/-/lodash.differencewith-4.5.9.tgz",
"integrity": "sha512-nMaREKoe7J3WvnsO7HDRxvnPT3mWmZD3EAECpy7gBGJ6S5nQ66uVlkRe+ZXs6261ZNb2fH9Ny4oUUiSOCmTnLw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/lodash": "*"
}
},
"node_modules/@types/lodash.isequal": {
"version": "4.5.8",
"resolved": "https://registry.npmjs.org/@types/lodash.isequal/-/lodash.isequal-4.5.8.tgz",
"integrity": "sha512-uput6pg4E/tj2LGxCZo9+y27JNyB2OZuuI/T5F+ylVDYuqICLG2/ktjxx0v6GvVntAf8TvEzeQLcV0ffRirXuA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/lodash": "*"
}
},
"node_modules/@types/lodash.uniqby": {
"version": "4.7.9",
"resolved": "https://registry.npmjs.org/@types/lodash.uniqby/-/lodash.uniqby-4.7.9.tgz",
@ -2370,6 +2394,12 @@
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
"license": "MIT"
},
"node_modules/lodash.differencewith": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.differencewith/-/lodash.differencewith-4.5.0.tgz",
"integrity": "sha512-/8JFjydAS+4bQuo3CpLMBv7WxGFyk7/etOAsrQUCu0a9QVDemxv0YQ0rFyeZvqlUD314SERfNlgnlqqHmaQ0Cg==",
"license": "MIT"
},
"node_modules/lodash.includes": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",

View file

@ -35,6 +35,8 @@
"ics": "^3.8.1",
"ip": "^2.0.1",
"jsonwebtoken": "^9.0.2",
"lodash.differencewith": "^4.5.0",
"lodash.isequal": "^4.5.0",
"lodash.uniqby": "^4.7.0",
"moment": "^2.30.1",
"morgan": "^1.10.0",
@ -61,6 +63,8 @@
"@types/express": "^4.17.17",
"@types/ip": "^1.1.3",
"@types/jsonwebtoken": "^9.0.6",
"@types/lodash.differencewith": "^4.5.9",
"@types/lodash.isequal": "^4.5.8",
"@types/lodash.uniqby": "^4.7.9",
"@types/morgan": "^1.9.9",
"@types/ms": "^0.7.34",

View file

@ -1,4 +1,4 @@
export interface UpdateMissionCommand {
export interface SyncMissionCommand {
id: string;
title: string;
commandId?: string | null;
@ -11,6 +11,7 @@ export interface UpdateMissionCommand {
rescued: number;
recovered: number;
description: string;
last_update: number;
}
export interface DeleteMissionCommand {

View file

@ -1,7 +1,7 @@
import { dataSource } from "../../../data-source";
import { mission } from "../../../entity/operation/mission";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import { DeleteMissionCommand, UpdateMissionCommand } from "./missionCommand";
import { DeleteMissionCommand, SyncMissionCommand } from "./missionCommand";
export default abstract class MissionCommandHandler {
/**
@ -27,10 +27,10 @@ export default abstract class MissionCommandHandler {
/**
* @description update mission
* @param {UpdateMissionCommand} updateMission
* @param {SyncMissionCommand} updateMission
* @returns {Promise<void>}
*/
static async sync(updateMission: UpdateMissionCommand): Promise<void> {
static async sync(updateMission: SyncMissionCommand): Promise<void> {
return await dataSource
.createQueryBuilder()
.update(mission)

View file

@ -0,0 +1,14 @@
export interface SyncMissionContactCommand {
contactId: string;
missionId: string;
firstname: string;
lastname: string;
phone: string;
address: string;
note: string;
}
export interface DeleteMissionContactCommand {
contactId: string;
missionId: string;
}

View file

@ -0,0 +1,43 @@
import { dataSource } from "../../../data-source";
import { mission_contact } from "../../../entity/operation/mission_contact";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import { DeleteMissionContactCommand, SyncMissionContactCommand } from "./missionContactCommand";
export default abstract class MissionContactCommandHandler {
/**
* @description update mission_contact
* @param {Array<SyncMissionCommand>} updateMissionContact
* @returns {Promise<void>}
*/
static async sync(updateMissionContact: Array<SyncMissionContactCommand>): Promise<void> {
return await dataSource
.createQueryBuilder()
.insert()
.into(mission_contact)
.values(updateMissionContact)
.orUpdate(["firstname", "lastname", "phone", "address", "note"], ["missionId", "contactId"])
.execute()
.then(() => {})
.catch((err) => {
throw new DatabaseActionException("UPDATE", "mission_contact", err);
});
}
/**
* @description delete mission_contact
* @param {Array<DeleteMissionCommand>} deleteMissionContact
* @returns {Promise<void>}
*/
static async delete(deleteMissionContact: Array<DeleteMissionContactCommand>): Promise<void> {
return await dataSource
.createQueryBuilder()
.delete()
.from(mission_contact)
.whereInIds(deleteMissionContact)
.execute()
.then(() => {})
.catch((err) => {
throw new DatabaseActionException("DELETE", "mission_contact", err);
});
}
}

View file

@ -0,0 +1,10 @@
export interface SyncMissionEquipmentCommand {
equipmentId: string;
missionId: string;
note: string;
}
export interface DeleteMissionEquipmentCommand {
equipmentId: string;
missionId: string;
}

View file

@ -0,0 +1,43 @@
import { dataSource } from "../../../data-source";
import { mission_equipment } from "../../../entity/operation/mission_equipment";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import { DeleteMissionEquipmentCommand, SyncMissionEquipmentCommand } from "./missionEquipmentCommand";
export default abstract class MissionEquipmentCommandHandler {
/**
* @description update mission_equipment
* @param {Array<SyncMissionCommand>} updateMissionEquipment
* @returns {Promise<void>}
*/
static async sync(updateMissionEquipment: Array<SyncMissionEquipmentCommand>): Promise<void> {
return await dataSource
.createQueryBuilder()
.insert()
.into(mission_equipment)
.values(updateMissionEquipment)
.orUpdate(["note"], ["missionId", "equipmentId"])
.execute()
.then(() => {})
.catch((err) => {
throw new DatabaseActionException("UPDATE", "mission_equipment", err);
});
}
/**
* @description delete mission_equipment
* @param {Array<DeleteMissionCommand>} deleteMissionEquipment
* @returns {Promise<void>}
*/
static async delete(deleteMissionEquipment: Array<DeleteMissionEquipmentCommand>): Promise<void> {
return await dataSource
.createQueryBuilder()
.delete()
.from(mission_equipment)
.whereInIds(deleteMissionEquipment)
.execute()
.then(() => {})
.catch((err) => {
throw new DatabaseActionException("DELETE", "mission_equipment", err);
});
}
}

View file

@ -0,0 +1,9 @@
export interface SyncMissionPresenceCommand {
forceId: string;
missionId: string;
}
export interface DeleteMissionPresenceCommand {
forceId: string;
missionId: string;
}

View file

@ -0,0 +1,44 @@
import { dataSource } from "../../../data-source";
import { mission_presence } from "../../../entity/operation/mission_presence";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import { DeleteMissionPresenceCommand, SyncMissionPresenceCommand } from "./missionPresenceCommand";
export default abstract class MissionPresenceCommandHandler {
/**
* @description update mission-presence
* @param {Array<SyncMissionCommand>} updateMissionpresence
* @returns {Promise<void>}
*/
static async sync(updateMissionpresence: Array<SyncMissionPresenceCommand>): Promise<void> {
return await dataSource
.createQueryBuilder()
.insert()
.into(mission_presence)
.values(updateMissionpresence)
.orIgnore()
// .orUpdate([], ["missionId", "forceId"])
.execute()
.then(() => {})
.catch((err) => {
throw new DatabaseActionException("UPDATE", "mission-presence", err);
});
}
/**
* @description delete mission-presence
* @param {Array<DeleteMissionCommand>} deleteMissionpresence
* @returns {Promise<void>}
*/
static async delete(deleteMissionpresence: Array<DeleteMissionPresenceCommand>): Promise<void> {
return await dataSource
.createQueryBuilder()
.delete()
.from(mission_presence)
.whereInIds(deleteMissionpresence)
.execute()
.then(() => {})
.catch((err) => {
throw new DatabaseActionException("DELETE", "mission-presence", err);
});
}
}

View file

@ -0,0 +1,13 @@
export interface SyncMissionVehicleCommand {
vehicleId: string;
missionId: string;
driverId: string | null;
leaderId: string | null;
mileage_start: number | null;
mileage_end: number | null;
}
export interface DeleteMissionVehicleCommand {
vehicleId: string;
missionId: string;
}

View file

@ -0,0 +1,43 @@
import { dataSource } from "../../../data-source";
import { mission_vehicle } from "../../../entity/operation/mission_vehicle";
import DatabaseActionException from "../../../exceptions/databaseActionException";
import { DeleteMissionVehicleCommand, SyncMissionVehicleCommand } from "./missionVehicleCommand";
export default abstract class MissionVehicleCommandHandler {
/**
* @description update mission_vehicle
* @param {Array<SyncMissionCommand>} updateMissionVehicle
* @returns {Promise<void>}
*/
static async sync(updateMissionVehicle: Array<SyncMissionVehicleCommand>): Promise<void> {
return await dataSource
.createQueryBuilder()
.insert()
.into(mission_vehicle)
.values(updateMissionVehicle)
.orUpdate(["driverId", "leaderId", "mileage_start", "mileage_end"], ["missionId", "vehicleId"])
.execute()
.then(() => {})
.catch((err) => {
throw new DatabaseActionException("UPDATE", "mission_vehicle", err);
});
}
/**
* @description delete mission_vehicle
* @param {Array<DeleteMissionCommand>} deleteMissionVehicle
* @returns {Promise<void>}
*/
static async delete(deleteMissionVehicle: Array<DeleteMissionVehicleCommand>): Promise<void> {
return await dataSource
.createQueryBuilder()
.delete()
.from(mission_vehicle)
.whereInIds(deleteMissionVehicle)
.execute()
.then(() => {})
.catch((err) => {
throw new DatabaseActionException("DELETE", "mission_vehicle", err);
});
}
}

View file

@ -1,7 +1,7 @@
import { Request, Response } from "express";
import MissionService from "../../../service/operation/missionService";
import MissionFactory from "../../../factory/admin/operation/mission";
import { DeleteMissionCommand, UpdateMissionCommand } from "../../../command/operation/mission/missionCommand";
import { DeleteMissionCommand, SyncMissionCommand } from "../../../command/operation/mission/missionCommand";
import MissionCommandHandler from "../../../command/operation/mission/missionCommandHandler";
import SocketServer from "../../../websocket";

View file

@ -16,7 +16,7 @@ import { CreateSchema1739697068682 } from "./migrations/1739697068682-CreateSche
import { vehicle } from "./entity/configuration/vehicle";
import { equipment } from "./entity/configuration/equipment";
import { mission } from "./entity/operation/mission";
import { mission_force } from "./entity/operation/mission_force";
import { mission_presence } from "./entity/operation/mission_presence";
import { mission_equipment } from "./entity/operation/mission_equipment";
import { mission_vehicle } from "./entity/operation/mission_vehicle";
import { mission_contact } from "./entity/operation/mission_contact";
@ -43,7 +43,7 @@ const dataSource = new DataSource({
vehicle,
equipment,
mission,
mission_force,
mission_presence,
mission_equipment,
mission_vehicle,
mission_contact,

View file

@ -1,6 +1,6 @@
import { Column, CreateDateColumn, Entity, ManyToOne, OneToMany, PrimaryColumn } from "typeorm";
import { force } from "../configuration/force";
import { mission_force } from "./mission_force";
import { mission_presence } from "./mission_presence";
import { mission_vehicle } from "./mission_vehicle";
import { mission_equipment } from "./mission_equipment";
import { mission_contact } from "./mission_contact";
@ -43,6 +43,9 @@ export class mission {
@Column({ type: "text", default: "[]" })
description: string;
@Column({ type: "bigint", default: 0 })
last_update: number;
@CreateDateColumn()
createdAt: Date;
@ -58,8 +61,8 @@ export class mission {
})
secretary: force;
@OneToMany(() => mission_force, (mf) => mf.mission, { cascade: ["insert"] })
forces: mission_force[];
@OneToMany(() => mission_presence, (mf) => mf.mission, { cascade: ["insert"] })
presence: mission_presence[];
@OneToMany(() => mission_vehicle, (mv) => mv.mission, { cascade: ["insert"] })
vehicles: mission_vehicle[];

View file

@ -3,7 +3,7 @@ import { force } from "../configuration/force";
import { mission } from "./mission";
@Entity()
export class mission_force {
export class mission_presence {
@PrimaryColumn({ type: "varchar", length: 36 })
missionId: string;

View file

@ -1,8 +1,14 @@
import * as Y from "yjs";
import { MissionMap } from "../storage/missionMap";
import MissionService from "../service/operation/missionService";
import { UpdateMissionCommand } from "../command/operation/mission/missionCommand";
import { SyncMissionCommand } from "../command/operation/mission/missionCommand";
import MissionCommandHandler from "../command/operation/mission/missionCommandHandler";
import MissionVehicleCommandHandler from "../command/operation/mission/missionVehicleCommandHandler";
import MissionEquipmentCommandHandler from "../command/operation/mission/missionEquipmentCommandHandler";
import MissionContactCommandHandler from "../command/operation/mission/missionContactCommandHandler";
import MissionPresenceCommandHandler from "../command/operation/mission/missionPresenceCommandHandler";
import differenceWith from "lodash.differencewith";
import isEqual from "lodash.isequal";
export default abstract class MissionDocHelper {
public static async populateDoc(missionId: string) {
@ -19,14 +25,15 @@ export default abstract class MissionDocHelper {
doc.getMap("form").set("others", mission.others);
doc.getMap("form").set("rescued", mission.rescued.toString());
doc.getMap("form").set("recovered", mission.recovered.toString());
doc.getText("editor").applyDelta(JSON.parse(mission.description)); //.insert(0, mission.description);
doc.getText("editor").applyDelta(JSON.parse(mission.description));
for (const vehicle of mission.vehicles) {
doc.getMap<Y.Map<number | string>>("vehicle").set(vehicle.vehicleId, new Y.Map<string | number>());
for (const key of ["driverId", "leaderId", "mileage_start", "mileage_end"] as (keyof typeof vehicle)[]) {
doc
.getMap<Y.Map<number | string>>("vehicle")
.get(vehicle.vehicleId)
.set<string | number>(key, vehicle[key].toString());
.set<string | number>(key.replace("Id", ""), (vehicle[key] ?? "").toString());
}
}
for (const equipment of mission.equipments) {
@ -35,7 +42,7 @@ export default abstract class MissionDocHelper {
doc
.getMap<Y.Map<number | string>>("equipment")
.get(equipment.equipmentId)
.set<string | number>(key, equipment[key].toString());
.set<string | number>(key, (equipment[key] ?? "").toString());
}
}
for (const contact of mission.contacts) {
@ -44,10 +51,10 @@ export default abstract class MissionDocHelper {
doc
.getMap<Y.Map<number | string>>("contact")
.get(contact.contactId)
.set<string | number>(key, contact[key].toString());
.set<string | number>(key, (contact[key] ?? "").toString());
}
}
for (const force of mission.forces) {
for (const force of mission.presence) {
doc.getMap<boolean>("presence").set(force.forceId, true);
}
@ -56,7 +63,7 @@ export default abstract class MissionDocHelper {
doc,
editors: new Map(),
editorStates: new Map(),
timestamp: 0,
timestamp: mission.last_update,
});
console.log(`created local doc ${missionId}`);
}
@ -86,13 +93,45 @@ export default abstract class MissionDocHelper {
return Array.from(mission.editors.entries());
}
public static async saveDoc(missionId: string, update: Uint8Array) {
public static async saveDoc(missionId: string, update: Uint8Array, timestamp: number) {
const oldMission = MissionMap.read(missionId);
const oldVehicles = Array.from(oldMission.doc.getMap("presence").keys());
const oldEquipments = Array.from(oldMission.doc.getMap("presence").keys());
const oldContact = Array.from(oldMission.doc.getMap("presence").keys());
const oldPresence = Array.from(oldMission.doc.getMap("presence").keys());
const oldMissionVehicles = oldMission.doc.getMap<Y.Map<string | number>>("vehicle").toJSON();
const oldMissionEquipment = oldMission.doc.getMap<Y.Map<string | number>>("equipment").toJSON();
const oldMissionContact = oldMission.doc.getMap<Y.Map<string | number>>("contact").toJSON();
const oldMissionPresence = oldMission.doc.getMap<Y.Map<string | number>>("presence").toJSON();
const oldMissionVehiclesArray = Object.keys(oldMissionVehicles).map((mv) => ({
missionId: missionId,
vehicleId: mv,
driverId: oldMissionVehicles[mv]?.driver || null,
leaderId: oldMissionVehicles[mv]?.leader || null,
mileage_start: parseInt(oldMissionVehicles[mv]?.mileage_start) || null,
mileage_end: parseInt(oldMissionVehicles[mv]?.mileage_end) || null,
}));
const oldMissionEquipmentArray = Object.keys(oldMissionEquipment).map((me) => ({
missionId: missionId,
equipmentId: me,
note: oldMissionEquipment[me]?.note ?? "",
}));
const oldMissionContactArray = Object.keys(oldMissionContact).map((mc) => ({
missionId: missionId,
contactId: mc,
firstname: oldMissionContact[mc]?.firstname ?? "",
lastname: oldMissionContact[mc]?.lastname ?? "",
phone: oldMissionContact[mc]?.phone ?? "",
address: oldMissionContact[mc]?.address ?? "",
note: oldMissionContact[mc]?.note ?? "",
}));
const oldMissionPresenceArray = Object.keys(oldMissionPresence).map((mc) => ({
missionId: missionId,
forceId: mc,
}));
MissionMap.updateState(missionId, update);
const mission = MissionMap.read(missionId);
@ -106,8 +145,7 @@ export default abstract class MissionDocHelper {
const removedContacts = oldContact.filter((item) => !contact.includes(item));
const removedPresence = oldPresence.filter((item) => !presence.includes(item));
//editor.setContents(mission.doc.getText("editor").toDelta()); //new QuillDeltaToHtmlConverter(mission.doc.getText("editor").toDelta()).convert(),
const missionDetails: UpdateMissionCommand = {
const missionDetails: SyncMissionCommand = {
id: missionId,
title: mission.doc.getMap("form").toJSON().title,
...(mission.doc.getMap("form").toJSON().command != ""
@ -122,25 +160,68 @@ export default abstract class MissionDocHelper {
...(mission.doc.getMap("form").get("end") != ""
? { mission_end: new Date(mission.doc.getMap("form").get("end") as string) }
: { mission_end: null }),
keyword: mission.doc.getMap("form").toJSON().mission_short,
location: mission.doc.getMap("form").toJSON().location,
others: mission.doc.getMap("form").toJSON().others,
rescued: parseInt(mission.doc.getMap("form").toJSON().rescued),
recovered: parseInt(mission.doc.getMap("form").toJSON().recovered),
keyword: mission.doc.getMap("form").toJSON().mission_short ?? "",
location: mission.doc.getMap("form").toJSON().location ?? "",
others: mission.doc.getMap("form").toJSON().others ?? "",
rescued: parseInt(mission.doc.getMap("form").toJSON().rescued) || 0,
recovered: parseInt(mission.doc.getMap("form").toJSON().recovered) || 0,
description: JSON.stringify(mission.doc.getText("editor").toDelta()),
last_update: timestamp,
};
const missionVehicles = mission.doc.getMap<Y.Map<string | number>>("vehicle").toJSON();
const missionEquipment = mission.doc.getMap<Y.Map<string | number>>("equipment").toJSON();
const missionContact = mission.doc.getMap<Y.Map<string | number>>("contact").toJSON();
const missionPresence = mission.doc.getMap<Y.Map<string | number>>("presence").toJSON();
// store Data to database
// Object.keys(tmp).map(t => ({
// id:t,
// ...tmp[t]
// }))
const missionVehiclesArray = Object.keys(missionVehicles).map((mv) => ({
missionId: missionId,
vehicleId: mv,
driverId: missionVehicles[mv]?.driver || null,
leaderId: missionVehicles[mv]?.leader || null,
mileage_start: parseInt(missionVehicles[mv]?.mileage_start) || null,
mileage_end: parseInt(missionVehicles[mv]?.mileage_end) || null,
}));
const missionEquipmentArray = Object.keys(missionEquipment).map((me) => ({
missionId: missionId,
equipmentId: me,
note: missionEquipment[me]?.note ?? "",
}));
const missionContactArray = Object.keys(missionContact).map((mc) => ({
missionId: missionId,
contactId: mc,
firstname: missionContact[mc]?.firstname ?? "",
lastname: missionContact[mc]?.lastname ?? "",
phone: missionContact[mc]?.phone ?? "",
address: missionContact[mc]?.address ?? "",
note: missionContact[mc]?.note ?? "",
}));
const missionPresenceArray = Object.keys(missionPresence).map((mc) => ({
missionId: missionId,
forceId: mc,
}));
await MissionCommandHandler.sync(missionDetails);
if (differenceWith(missionVehiclesArray, oldMissionVehiclesArray, isEqual).length != 0)
await MissionVehicleCommandHandler.sync(differenceWith(missionVehiclesArray, oldMissionVehiclesArray, isEqual));
if (removedVehicles.length != 0)
await MissionVehicleCommandHandler.delete(removedVehicles.map((rv) => ({ missionId, vehicleId: rv })));
if (differenceWith(missionEquipmentArray, oldMissionEquipmentArray, isEqual).length != 0)
await MissionEquipmentCommandHandler.sync(
differenceWith(missionEquipmentArray, oldMissionEquipmentArray, isEqual)
);
if (removedEquipments.length != 0)
await MissionEquipmentCommandHandler.delete(removedEquipments.map((re) => ({ missionId, equipmentId: re })));
if (differenceWith(missionContactArray, oldMissionContactArray, isEqual).length != 0)
await MissionContactCommandHandler.sync(differenceWith(missionContactArray, oldMissionContactArray, isEqual));
if (removedContacts.length != 0)
await MissionContactCommandHandler.delete(removedContacts.map((rc) => ({ missionId, contactId: rc })));
if (differenceWith(missionPresenceArray, oldMissionPresenceArray, isEqual).length != 0)
await MissionPresenceCommandHandler.sync(differenceWith(missionPresenceArray, oldMissionPresenceArray, isEqual));
if (removedPresence.length != 0)
await MissionPresenceCommandHandler.delete(removedPresence.map((mp) => ({ missionId, forceId: mp })));
}
}

View file

@ -13,7 +13,7 @@ import { equipment_table, force_table, vehicle_table } from "./baseSchemaTables/
import {
mission_contact_table,
mission_equipment_table,
mission_force_table,
mission_presence_table,
mission_table,
mission_vehicle_table,
} from "./baseSchemaTables/operation";
@ -36,7 +36,7 @@ export class CreateSchema1739697068682 implements MigrationInterface {
await queryRunner.createTable(vehicle_table, true, true, true);
await queryRunner.createTable(mission_table, true, true, true);
await queryRunner.createTable(mission_force_table, true, true, true);
await queryRunner.createTable(mission_presence_table, true, true, true);
await queryRunner.createTable(mission_vehicle_table, true, true, true);
await queryRunner.createTable(mission_equipment_table, true, true, true);
await queryRunner.createTable(mission_contact_table, true, true, true);
@ -46,7 +46,7 @@ export class CreateSchema1739697068682 implements MigrationInterface {
await queryRunner.dropTable("mission_contact", true, true, true);
await queryRunner.dropTable("mission_equipment", true, true, true);
await queryRunner.dropTable("mission_vehicle", true, true, true);
await queryRunner.dropTable("mission_force", true, true, true);
await queryRunner.dropTable("mission_presence", true, true, true);
await queryRunner.dropTable("mission", true, true, true);
await queryRunner.dropTable("vehicle", true, true, true);

View file

@ -16,12 +16,13 @@ export const mission_table = new Table({
{ name: "rescued", ...getTypeByORM("int"), default: getDefaultByORM("number", 0) },
{ name: "recovered", ...getTypeByORM("int"), default: getDefaultByORM("number", 0) },
{ name: "description", ...getTypeByORM("text"), default: getDefaultByORM("string", "[]") },
{ name: "last_update", ...getTypeByORM("bigint"), default: getDefaultByORM("number", 0) },
{ name: "createdAt", ...getTypeByORM("datetime", false, 6), default: getDefaultByORM("currentTimestamp") },
],
});
export const mission_force_table = new Table({
name: "mission_force",
export const mission_presence_table = new Table({
name: "mission_presence",
columns: [
{ name: "missionId", ...getTypeByORM("uuid"), isPrimary: true },
{ name: "forceId", ...getTypeByORM("uuid"), isPrimary: true },

View file

@ -64,8 +64,8 @@ export default abstract class MissionService {
.createQueryBuilder("mission")
.leftJoinAndSelect("mission.command", "command")
.leftJoinAndSelect("mission.secretary", "secretary")
.leftJoinAndSelect("mission.forces", "forces")
.leftJoinAndSelect("forces.force", "force")
.leftJoinAndSelect("mission.presence", "presence")
.leftJoinAndSelect("presence.force", "force")
.leftJoinAndSelect("mission.vehicles", "vehicles")
.leftJoinAndSelect("vehicles.driver", "driver")
.leftJoinAndSelect("vehicles.leader", "leader")

View file

@ -98,7 +98,7 @@ export default (io: Server, socket: Socket) => {
async (data: { update: Array<number>; timestamp: number }) => {
const socketRooms = Array.from(socket.rooms).filter((room) => room !== socket.id && room !== "home");
try {
MissionDocHelper.saveDoc(socketRooms[0], new Uint8Array(data.update));
MissionDocHelper.saveDoc(socketRooms[0], new Uint8Array(data.update), data.timestamp);
return {
type: "package-sync",