diff --git a/packages/panorama-daemon/src/models.ts b/packages/panorama-daemon/src/models.ts index e7c0ad9..803527e 100644 --- a/packages/panorama-daemon/src/models.ts +++ b/packages/panorama-daemon/src/models.ts @@ -2,6 +2,7 @@ import { Column, Entity, Index, + JoinColumn, ManyToOne, OneToMany, PrimaryColumn, @@ -18,7 +19,7 @@ export class PNode { @OneToMany( () => NodeHasAttribute, - (hasAttr) => hasAttr.nodeId, + (hasAttr) => hasAttr.node, ) attributes!: NodeHasAttribute[]; } @@ -29,22 +30,25 @@ export class App { id!: string; @Column() + @Index({}) name!: string; @OneToMany( () => Attribute, - (attr) => attr.appId, + (attr) => attr.app, ) attributes!: Attribute[]; + + @OneToMany( + () => NodeHasAttribute, + (attr) => attr.app, + ) + attributeInstances!: NodeHasAttribute[]; } @Entity() export class Attribute { @PrimaryColumn() - @ManyToOne( - () => App, - (app) => app.id, - ) appId!: string; @PrimaryColumn() @@ -53,20 +57,51 @@ export class Attribute { @Column() @Index({}) type!: string; + + @ManyToOne( + () => App, + (app) => app.attributes, + ) + @JoinColumn({ name: "appId", referencedColumnName: "id" }) + app!: App; + + @OneToMany( + () => NodeHasAttribute, + (attr) => attr.attr, + ) + instances!: NodeHasAttribute[]; } @Entity() export class NodeHasAttribute { - @PrimaryColumn() @ManyToOne( () => PNode, - (node) => node.id, + (node) => node.attributes, ) + @JoinColumn({ name: "nodeId" }) + node!: PNode; + + @PrimaryColumn() nodeId!: string; + @ManyToOne( + () => App, + (app) => app.attributeInstances, + ) + @JoinColumn({ name: "appId", referencedColumnName: "id" }) + app!: App; + @PrimaryColumn() appId!: string; + @ManyToOne( + () => Attribute, + (attr) => attr.instances, + ) + @JoinColumn({ name: "appId", referencedColumnName: "appId" }) + @JoinColumn({ name: "attrName", referencedColumnName: "name" }) + attr!: Attribute; + @PrimaryColumn() attrName!: string; diff --git a/packages/panorama-daemon/src/routes/node.ts b/packages/panorama-daemon/src/routes/node.ts index c129f32..fae71af 100644 --- a/packages/panorama-daemon/src/routes/node.ts +++ b/packages/panorama-daemon/src/routes/node.ts @@ -77,20 +77,86 @@ nodeRouter.put("/", async (ctx) => { nodeRouter.post("/query", async (ctx) => {}); -nodeRouter.get("/:id", async (ctx) => { - const query = dataSource - .createQueryBuilder() - .select("node") - .from(PNode, "node") - .where("node.id = :id", { id: ctx.params.id }); +nodeRouter.get("/recent", async (ctx) => { + const result = await dataSource.query(` + SELECT + node20.id as nodeId, + hasAttr.attrName, + app.name AS appName, + attr.type AS attrType, + hasAttr.nodeRef, + hasAttr.number, + hasAttr.string, + hasAttr.boolean, + hasAttr.instant + FROM node_has_attribute hasAttr + INNER JOIN (SELECT * FROM node ORDER BY lastUpdated DESC LIMIT 20) node20 ON node20.id = hasAttr.nodeId + INNER JOIN app ON app.id = hasAttr.appId + INNER JOIN attribute attr ON attr.appId = hasAttr.appId AND attr.name = hasAttr.attrName + `); - const node = await query.getOne(); - if (node === null) { + console.log("result", result); + + const convertValue = (type: string, row: Partial): any => { + switch (type) { + case "string": + return row.string; + case "datetime": + return new Date(row.instant); + default: + console.error(`unknown type ${type}`); + return ""; + } + }; + + const idAttrs = new Map>(); + + for (const hasAttr of result) { + if (!idAttrs.has(hasAttr.nodeId)) idAttrs.set(hasAttr.nodeId, new Map()); + + idAttrs + .get(hasAttr.nodeId)! + .set( + `${hasAttr.appName}::${hasAttr.attrName}`, + convertValue(hasAttr.attrType, hasAttr), + ); + } + + const result2 = [...idAttrs.entries()].map(([id, attrs]) => ({ + id, + attributes: Object.fromEntries(attrs.entries()), + })); + + // result = result.map((v) => ({ + // id: v.id, + // attributes: new Map( + // v.attr.map((attr) => [ + // `${attr.app.name}::${attr.attrName}`, + // convertValue(attr.attr.type, attr), + // ]), + // ), + // })); + + ctx.body = result2; +}); + +nodeRouter.get("/:id", async (ctx) => { + const result: false | undefined = await dataSource.transaction(async (em) => { + const query = dataSource + .createQueryBuilder() + .select("node") + .from(PNode, "node") + .where("node.id = :id", { id: ctx.params.id }); + + const node = await query.getOne(); + if (node === null) return false; + ctx.body = { node }; + }); + + if (result === false) { ctx.status = 404; ctx.body = { error: "Not found" }; - return; } - ctx.body = { node }; }); nodeRouter.post("/:id", async (ctx) => {});