-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Zeke Nierenberg
committed
Nov 13, 2022
1 parent
62d6aa8
commit 9968cba
Showing
24 changed files
with
649 additions
and
60 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ | |
"Signin", | ||
"slonik", | ||
"sunglo", | ||
"timestamptz", | ||
"unbuilt", | ||
"unnest", | ||
"unsign", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,7 @@ | |
"license": "MIT", | ||
"dependencies": { | ||
"@slonik/migrator": "^0.9.0", | ||
"lodash": "^4.17.21", | ||
"slonik": "^27.0.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
const { groupBy } = require("lodash"); | ||
|
||
/** @type {import('@slonik/migrator').Migration} */ | ||
exports.up = async ({ context: { connection, sql } }) => { | ||
await connection.query(sql` | ||
create table "console" ( | ||
id uuid primary key default uuid_generate_v4(), | ||
"createdAt" timestamptz not null default NOW(), | ||
"updatedAt" timestamptz not null default NOW(), | ||
"timestamp" timestamptz not null, | ||
"requestId" uuid, | ||
"stateId" uuid, | ||
"level" varchar(25) not null, | ||
"messages" jsonb not null default '{}', | ||
foreign key("requestId") references request("id"), | ||
foreign key("stateId") references state("id") | ||
) | ||
`); | ||
|
||
const { rows } = await connection.query(sql` | ||
select id, "requestId", console from "state" | ||
where console != '[]' | ||
`); | ||
|
||
for (const row of rows) { | ||
const consoleMessages = row.console; | ||
for (const { messages, level, timestamp } of consoleMessages) { | ||
await connection.query(sql` | ||
insert into "console" | ||
("timestamp", "level", "requestId", "stateId", "messages") | ||
values | ||
(${new Date(timestamp).toISOString()}, ${level}, ${row.requestId}, ${ | ||
row.id | ||
}, ${sql.jsonb(messages)}) | ||
`); | ||
} | ||
} | ||
|
||
await connection.query(sql` | ||
alter table "state" | ||
drop column console | ||
`); | ||
}; | ||
|
||
/** @type {import('@slonik/migrator').Migration} */ | ||
exports.down = async ({ context: { connection, sql } }) => { | ||
await connection.query(sql` | ||
alter table state | ||
add column console jsonb not null default '[]' | ||
`); | ||
|
||
const { rows } = await connection.query(sql` | ||
select * from "console" | ||
`); | ||
|
||
const consoleByState = groupBy(rows, "stateId"); | ||
|
||
for (const stateId of Object.keys(consoleByState)) { | ||
const consoleArr = consoleByState[stateId].map((c) => ({ | ||
level: c.level, | ||
messages: c.messages, | ||
timestamp: new Date(c.timestamp).getTime(), | ||
})); | ||
await connection.query(sql` | ||
update "state" | ||
set "console" = ${sql.json(consoleArr)} | ||
where id = ${stateId} | ||
`); | ||
} | ||
|
||
await connection.query(sql` | ||
drop table "console" | ||
`); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import stateFactory from "../state/state.factory"; | ||
import { bulkInsertConsole, getConsoleByStateIds } from "./console.db"; | ||
import consoleFactory from "./console.factory"; | ||
|
||
describe("console.db", () => { | ||
describe("bulkInsertConsole", () => { | ||
it("inserts multiple console rows", async () => { | ||
const state = await stateFactory.create(); | ||
|
||
await bulkInsertConsole({ | ||
consoleLogs: [ | ||
{ | ||
stateId: state.id, | ||
requestId: state.requestId, | ||
level: "warn", | ||
messages: ["foo", "bar"], | ||
timestamp: new Date(), | ||
}, | ||
{ | ||
stateId: state.id, | ||
requestId: state.requestId, | ||
level: "warn", | ||
messages: ["foo", "bar", "baz"], | ||
timestamp: new Date(), | ||
}, | ||
], | ||
}); | ||
|
||
expect(await getConsoleByStateIds({ stateIds: [state.id] })).toEqual({ | ||
[state.id]: [ | ||
{ | ||
stateId: state.id, | ||
requestId: state.requestId, | ||
level: "warn", | ||
messages: ["foo", "bar"], | ||
timestamp: expect.any(Date), | ||
}, | ||
{ | ||
stateId: state.id, | ||
requestId: state.requestId, | ||
level: "warn", | ||
messages: ["foo", "bar", "baz"], | ||
timestamp: expect.any(Date), | ||
}, | ||
], | ||
}); | ||
}); | ||
}); | ||
|
||
describe("getConsoleByStateIds", () => { | ||
it("gets console logs by state ids", async () => { | ||
const consoles = await consoleFactory | ||
.params({ messages: ["foo", "bar"] }) | ||
.createList(3); | ||
const [c, c1, c2] = consoles; | ||
expect( | ||
await getConsoleByStateIds({ stateIds: consoles.map((c) => c.stateId) }) | ||
).toEqual( | ||
expect.objectContaining({ | ||
[c.stateId]: expect.arrayContaining([ | ||
expect.objectContaining({ messages: ["foo", "bar"] }), | ||
]), | ||
[c1.stateId]: expect.arrayContaining([ | ||
expect.objectContaining({ messages: ["foo", "bar"] }), | ||
]), | ||
[c2.stateId]: expect.arrayContaining([ | ||
expect.objectContaining({ messages: ["foo", "bar"] }), | ||
]), | ||
}) | ||
); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import { groupBy, keyBy, mapValues } from "lodash"; | ||
import { sql } from "slonik"; | ||
import { getPool } from "../db"; | ||
import { ConsoleMessage, ConsoleMessageInsert } from "./console.types"; | ||
|
||
export async function bulkInsertConsole({ | ||
consoleLogs, | ||
}: { | ||
consoleLogs: ConsoleMessageInsert[]; | ||
}) { | ||
if (consoleLogs.length === 0) { | ||
return; | ||
} | ||
const pool = getPool(); | ||
await pool.any(sql` | ||
insert into "console" | ||
("stateId", "requestId", "timestamp", "level", "messages") | ||
select * from ${sql.unnest( | ||
consoleLogs.map((consoleLog) => [ | ||
consoleLog.stateId, | ||
consoleLog.requestId, | ||
new Date(consoleLog.timestamp).toISOString(), | ||
consoleLog.level, | ||
JSON.stringify(consoleLog.messages || []), | ||
]), | ||
["uuid", "uuid", "timestamptz", "varchar", "jsonb"] | ||
)} | ||
returning id | ||
`); | ||
} | ||
|
||
export async function getConsoleByStateIds({ | ||
stateIds, | ||
}: { | ||
stateIds: string[]; | ||
}) { | ||
const consoleRecords = ( | ||
await getPool().any<ConsoleMessage>(sql` | ||
select | ||
messages, | ||
"requestId", | ||
"stateId", | ||
timestamp, | ||
level | ||
from "console" | ||
where "stateId" = ANY(${sql.array(stateIds, "uuid")}) | ||
`) | ||
).map((r) => ({ ...r, timestamp: new Date(r.timestamp) })); | ||
|
||
return groupBy(consoleRecords, "stateId"); | ||
} | ||
|
||
export async function getConsoleByStateId({ | ||
stateId, | ||
}: { | ||
stateId: string; | ||
}): Promise<ConsoleMessageInsert[]> { | ||
const map = await getConsoleByStateIds({ stateIds: [stateId] }); | ||
return map[stateId] || []; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import { Factory } from "fishery"; | ||
import { sql } from "slonik"; | ||
import { getPool } from "../db"; | ||
import stateFactory from "../state/state.factory"; | ||
import { ConsoleRow } from "./console.types"; | ||
import crypto from "crypto"; | ||
|
||
export default Factory.define<ConsoleRow>( | ||
({ associations, onCreate, params }) => { | ||
onCreate(async (row) => { | ||
if (!row.stateId) { | ||
const state = await stateFactory.create(); | ||
row.stateId = state.id; | ||
row.requestId = state.requestId; | ||
} | ||
await getPool().one(sql` | ||
insert into "console" | ||
(id, "level", messages, "timestamp", "requestId", "stateId") | ||
values | ||
( | ||
${row.id}, | ||
${row.level}, | ||
${sql.jsonb(row.messages)}, | ||
${row.timestamp.toISOString()}, | ||
${row.requestId!}, | ||
${row.stateId!} | ||
) | ||
returning id | ||
`); | ||
return row; | ||
}); | ||
return { | ||
id: crypto.randomUUID(), | ||
level: "log", | ||
messages: params.messages || [], | ||
timestamp: new Date(), | ||
requestId: associations.requestId, | ||
stateId: associations.stateId, | ||
} as ConsoleRow; | ||
} | ||
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
export type LogLevels = "warn" | "error" | "log" | "trace" | "debug" | "info"; | ||
|
||
export type ConsoleMessageInsert = { | ||
stateId?: string; | ||
} & ConsoleMessage; | ||
|
||
export type ConsoleMessage = { | ||
level: LogLevels; | ||
messages: string[]; | ||
timestamp: Date; | ||
requestId?: string; | ||
}; | ||
|
||
export type ConsoleRow = { | ||
id: string; | ||
level: LogLevels; | ||
messages: string[]; | ||
timestamp: Date; | ||
requestId?: string; | ||
stateId: string; | ||
}; |
Oops, something went wrong.