Skip to content

Commit

Permalink
feat: add planetary events and joint operations (#6)
Browse files Browse the repository at this point in the history
* feat: add type definitions for `planetEvents` and `jointOperations`

* feat: add `Order` model to database

* refractor: incorporate the order model into generation service

* feat: add dedicated routes for order model

* feat: add related routes for order model

* fix: rename route collection

* feat: add order route collection to routes

* refractor: updated postman collection
  • Loading branch information
fabio-nettis authored Mar 19, 2024
1 parent f02acf6 commit c5d45bb
Show file tree
Hide file tree
Showing 13 changed files with 965 additions and 5 deletions.
702 changes: 700 additions & 2 deletions postman.json

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions prisma/migrations/20240319081538_orders/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
-- CreateTable
CREATE TABLE "Order" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"index" INTEGER NOT NULL,
"planetId" INTEGER,
"factionId" INTEGER,
"campaignId" INTEGER,
"eventType" TEXT NOT NULL,
"health" INTEGER NOT NULL,
"maxHealth" INTEGER NOT NULL,
"hqNodeIndex" INTEGER,
"startTime" DATETIME NOT NULL,
"expireTime" DATETIME NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "Order_planetId_fkey" FOREIGN KEY ("planetId") REFERENCES "Planet" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "Order_factionId_fkey" FOREIGN KEY ("factionId") REFERENCES "Faction" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "Order_campaignId_fkey" FOREIGN KEY ("campaignId") REFERENCES "Campaign" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);

-- CreateIndex
CREATE UNIQUE INDEX "Order_index_key" ON "Order"("index");
22 changes: 22 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ model Faction {
id Int @id @default(autoincrement())
index Int @unique
name String
orders Order[] @relation("Order")
planets Planet[] @relation(name: "owner")
initialPlanets Planet[] @relation(name: "initialOwner")
globalEvents GlobalEvent[]
Expand Down Expand Up @@ -59,6 +60,7 @@ model Planet {
positionY Float
globalEvent GlobalEvent? @relation("GlobalEvent", fields: [globalEventId], references: [id])
globalEventId Int?
orders Order[] @relation("Order")
campaign Campaign[] @relation("Campaign")
homeWorld HomeWorld[] @relation("HomeWorld")
attacking Attack[] @relation("Attack")
Expand All @@ -84,6 +86,7 @@ model Campaign {
type Int
index Int @unique
count Int
order Order[] @relation("Order")
planet Planet @relation("Campaign", fields: [planetId], references: [id])
planetId Int
createdAt DateTime @default(now())
Expand All @@ -100,6 +103,25 @@ model HomeWorld {
updatedAt DateTime @updatedAt
}

model Order {
id Int @id @default(autoincrement())
index Int @unique
planet Planet? @relation("Order", fields: [planetId], references: [id])
planetId Int?
faction Faction? @relation("Order", fields: [factionId], references: [id])
factionId Int?
campaign Campaign? @relation("Order", fields: [campaignId], references: [id])
campaignId Int?
eventType String
health Int
maxHealth Int
hqNodeIndex Int?
startTime DateTime
expireTime DateTime
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}

model Attack {
id Int @id @default(autoincrement())
target Planet @relation("Attack", fields: [targetId], references: [id])
Expand Down
35 changes: 35 additions & 0 deletions src/controllers/factions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -185,3 +185,38 @@ export const getFactionOrigin = await witCache(async (ctx: Context) => {
});
}
});

export const getFactionOrders = await witCache(async (ctx: Context) => {
try {
const id = parseIntParam(ctx, "id");
const query = await parseQueryParams(ctx);

const [count, orders] = await Promise.all([
prisma.order.count({
where: { ...(query.where ?? {}), factionId: id },
}),
prisma.order.findMany({
...query,
where: { ...(query.where ?? {}), factionId: id },
}),
]);

return ctx.json({
data: orders,
error: null,
pagination: {
page: query.skip / query.take + 1,
pageSize: query.take,
pageCount: Math.ceil((count as number) / query.take),
total: count,
},
});
} catch (error: any) {
console.error(error);
ctx.status(500);
return ctx.json({
data: null,
error: { details: [error.message] },
});
}
});
72 changes: 72 additions & 0 deletions src/controllers/orders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import type { Context } from "hono";
import { PrismaClient } from "@prisma/client";

import witCache from "utils/cache";
import parseIntParam from "utils/params";
import parseQueryParams from "utils/query";

const prisma = new PrismaClient();

export const getOrderById = await witCache(async (ctx: Context) => {
try {
const id = parseIntParam(ctx, "id");
const query = await parseQueryParams(ctx);

delete query.orderBy;
delete query.where;
delete query.orderBy;
delete (query as any).skip;
delete (query as any).take;

const order = await prisma.order.findUnique({
...(query as any),
where: { id },
});

if (!order) {
ctx.status(404);
return ctx.json({
data: null,
error: { details: [`Order with id (${id}) not found`] },
});
}

return ctx.json({ data: order, error: null });
} catch (error: any) {
console.error(error);
ctx.status(500);
return ctx.json({
data: null,
error: { details: [error.message] },
});
}
});

export const getAllOrders = await witCache(async (ctx: Context) => {
try {
const query = await parseQueryParams(ctx);

const [count, orders] = await Promise.all([
prisma.order.count({ where: query.where }),
prisma.order.findMany(query),
]);

return ctx.json({
data: orders,
error: null,
pagination: {
page: query.skip / query.take + 1,
pageSize: query.take,
pageCount: Math.ceil((count as number) / query.take),
total: count,
},
});
} catch (error: any) {
console.error(error);
ctx.status(500);
return ctx.json({
data: null,
error: { details: [error.message] },
});
}
});
35 changes: 35 additions & 0 deletions src/controllers/planets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,3 +193,38 @@ export const getPlanetCampaigns = await witCache(async (ctx: Context) => {
});
}
});

export const getPlanetOrders = await witCache(async (ctx: Context) => {
try {
const id = parseIntParam(ctx, "id");
const query = await parseQueryParams(ctx);

const [count, orders] = await Promise.all([
prisma.order.count({
where: { planetId: id },
}),
prisma.order.findMany({
...(query ?? {}),
where: { ...(query.where as any), planetId: id },
}),
]);

return ctx.json({
data: orders,
error: null,
pagination: {
page: query.skip / query.take + 1,
pageSize: query.take,
pageCount: Math.ceil((count as number) / query.take),
total: count,
},
});
} catch (error: any) {
console.error(error);
ctx.status(500);
return ctx.json({
data: null,
error: { details: [error.message] },
});
}
});
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import cache from "middleware/cache";
import rateLimit from "middleware/rate-limit";

import wars from "routes/war";
import orders from "routes/orders";
import events from "routes/events";
import planets from "routes/planets";
import sectors from "routes/sectors";
Expand All @@ -18,7 +19,7 @@ app.use(rateLimit);
app.use(cache);

// routes for the api
const routes = [planets, sectors, wars, factions, attacks, events];
const routes = [planets, sectors, wars, factions, attacks, events, orders];
for (const route of routes) await route(app);

export default app;
1 change: 1 addition & 0 deletions src/routes/factions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as Factions from "controllers/factions";
export default async function factions(app: Hono) {
app.get("/factions", Factions.getAllFactions);
app.get("/factions/:id", Factions.getFactionById);
app.get("/factions/:id/orders", Factions.getFactionOrders);
app.get("/factions/:id/origins", Factions.getFactionOrigin);
app.get("/factions/:id/planets", Factions.getFactionPlanets);
app.get("/factions/:id/pushbacks", Factions.getFactionPushbacks);
Expand Down
8 changes: 8 additions & 0 deletions src/routes/orders.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import type { Hono } from "hono";

import * as Orders from "controllers/orders";

export default async function orders(app: Hono) {
app.get("/orders", Orders.getAllOrders);
app.get("/orders/:id", Orders.getOrderById);
}
1 change: 1 addition & 0 deletions src/routes/planets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as Planets from "controllers/planets";
export default async function planets(app: Hono) {
app.get("/planets", Planets.getAllPlanets);
app.get("/planets/:id", Planets.getPlanetById);
app.get("/planets/:id/orders", Planets.getPlanetOrders);
app.get("/planets/:id/owners", Planets.getPlanetOwners);
app.get("/planets/:id/attacks", Planets.getPlanetAttacks);
app.get("/planets/:id/campaigns", Planets.getPlanetCampaigns);
Expand Down
23 changes: 21 additions & 2 deletions src/types/source.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,25 @@ export interface HomeWorld {
planetIndices: number[];
}

export interface JointOperation {
id: number;
planetIndex: number;
hqNodeIndex: number;
}

export interface PlanetEvent {
id: number;
planetIndex: number;
eventType: number;
race: number;
health: number;
maxHealth: number;
startTime: number;
expireTime: number;
campaignId: number;
jointOperationIds: number[];
}

export interface WarStatus {
warId: number;
time: number;
Expand All @@ -65,8 +84,8 @@ export interface WarStatus {
planetAttacks: PlanetAttack[];
campaigns: Campaign[];
communityTargets: never[];
jointOperations: never[];
planetEvents: never[];
jointOperations: JointOperation[];
planetEvents: PlanetEvent[];
planetActiveEffects: never[];
activeElectionPolicyEffects: never[];
globalEvents: GlobalEvent[];
Expand Down
23 changes: 23 additions & 0 deletions src/utils/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ export async function transformAndStoreSourceData() {
return warStatus.campaigns.map(c => c.planetIndex).includes(p.index);
});

// generate the campaign data
for (const campaign of warStatus.campaigns) {
const planet = campaignPlanets.find(p => p.index === campaign.planetIndex);

Expand All @@ -201,6 +202,28 @@ export async function transformAndStoreSourceData() {
});
}

// generate the planet event data (attack/defend orders)
for (const event of warStatus.planetEvents) {
const planet = planets.find(p => p.index === event.planetIndex);
const faction = factions.find(f => f.index === event.race);
const jointOp = warStatus.jointOperations.find(j => j.id === event.id);

await prisma.order.create({
data: {
index: event.id,
eventType: event.eventType === 1 ? "DEFEND" : "ATTACK",
health: event.health,
maxHealth: event.maxHealth,
hqNodeIndex: jointOp?.hqNodeIndex,
startTime: new Date(event.startTime),
expireTime: new Date(event.expireTime),
campaign: { connect: { index: event.campaignId } },
planet: planet ? { connect: { index: planet.index } } : undefined,
faction: faction ? { connect: { index: faction.index } } : undefined,
},
});
}

// generate the global event data
for (const globals of warStatus.globalEvents) {
const faction = factions.find(f => f.index === globals.race);
Expand Down
23 changes: 23 additions & 0 deletions src/utils/refresh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,29 @@ export async function refreshAndStoreSourceData() {
});
}

// generate the planet event data (attack/defend orders)
await prisma.order.deleteMany();
for (const event of warStatus.planetEvents) {
const planet = planets.find(p => p.index === event.planetIndex);
const faction = factions.find(f => f.index === event.race);
const jointOp = warStatus.jointOperations.find(j => j.id === event.id);

await prisma.order.create({
data: {
index: event.id,
eventType: event.eventType === 1 ? "DEFEND" : "ATTACK",
health: event.health,
maxHealth: event.maxHealth,
hqNodeIndex: jointOp?.hqNodeIndex,
startTime: new Date(event.startTime),
expireTime: new Date(event.expireTime),
campaign: { connect: { index: event.campaignId } },
planet: planet ? { connect: { index: planet.index } } : undefined,
faction: faction ? { connect: { index: faction.index } } : undefined,
},
});
}

// generate the global event data
await prisma.globalEvent.deleteMany();
for (const globals of warStatus.globalEvents) {
Expand Down

0 comments on commit c5d45bb

Please sign in to comment.