Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions apps/backend/controllers/flowsheet.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Request, RequestHandler } from 'express';
import { Mutex } from 'async-mutex';
import { NewFSEntry, FSEntry, Show, ShowDJ, library } from '@wxyc/database';
import { FSEntry, Show, ShowDJ, library } from '@wxyc/database';
import * as flowsheet_service from '../services/flowsheet.service.js';
import { fetchAndCacheMetadata } from '../services/metadata/index.js';

Expand Down Expand Up @@ -159,7 +159,7 @@ export const addEntry: RequestHandler = async (req: Request<object, object, FSEn
albumInfo.record_label = body.record_label;
}

const fsEntry: NewFSEntry = {
const fsEntry = {
album_id: body.album_id,
...albumInfo,
track_title: body.track_title,
Expand Down Expand Up @@ -191,7 +191,7 @@ export const addEntry: RequestHandler = async (req: Request<object, object, FSEn
console.error('Bad Request, Missing Flowsheet Parameters: album_title, artist_name, track_title');
res.status(400).send('Bad Request, Missing Flowsheet Parameters: album_title, artist_name, track_title');
} else {
const fsEntry: NewFSEntry = {
const fsEntry = {
...body,
show_id: latestShow.id,
};
Expand Down Expand Up @@ -220,7 +220,7 @@ export const addEntry: RequestHandler = async (req: Request<object, object, FSEn
}
} else {
//we're just throwing the message in there (whatever it may be): dj join event, psa event, talk set event, break-point
const fsEntry: NewFSEntry = {
const fsEntry = {
artist_name: '',
album_title: '',
track_title: '',
Expand Down
28 changes: 25 additions & 3 deletions apps/backend/services/flowsheet.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { sql, desc, eq, and, lte, gte, inArray } from 'drizzle-orm';
import { sql, desc, eq, and, lte, gte, inArray, max } from 'drizzle-orm';
import {
db,
FSEntry,
Expand Down Expand Up @@ -40,6 +40,12 @@ const updateLastModified = () => {
}
};

/** Get the next play_order value (global max + 1, or 1 if no entries exist) */
export const getNextPlayOrder = async (): Promise<number> => {
const result = await db.select({ maxOrder: max(flowsheet.play_order) }).from(flowsheet);
return (result[0]?.maxOrder ?? 0) + 1;
};

// SQL query fields (flat structure from database)
const FSEntryFieldsRaw = {
id: flowsheet.id,
Expand Down Expand Up @@ -174,7 +180,7 @@ export const getEntriesByShow = async (...show_ids: number[]): Promise<IFSEntry[
return raw.map(transformToIFSEntry);
};

export const addTrack = async (entry: NewFSEntry): Promise<FSEntry> => {
export const addTrack = async (entry: Omit<NewFSEntry, 'play_order'> & { play_order?: number }): Promise<FSEntry> => {
/*
TODO: logic for updating album playcount
*/
Expand Down Expand Up @@ -202,7 +208,15 @@ export const addTrack = async (entry: NewFSEntry): Promise<FSEntry> => {
// }
// }

const response = await db.insert(flowsheet).values(entry).returning();
// Compute play_order if not already set
if (entry.show_id != null && !entry.play_order) {
entry = { ...entry, play_order: await getNextPlayOrder() };
}

const response = await db
.insert(flowsheet)
.values(entry as NewFSEntry)
.returning();
updateLastModified();
return response[0];
};
Expand Down Expand Up @@ -291,8 +305,10 @@ export const startShow = async (dj_id: string, show_name?: string, specialty_id?
})
.returning();

const startPlayOrder = await getNextPlayOrder();
await db.insert(flowsheet).values({
show_id: new_show[0].id,
play_order: startPlayOrder,
entry_type: 'show_start',
message: `Start of Show: DJ ${dj_info.djName || dj_info.name} joined the set at ${new Date().toLocaleString(
'en-US',
Expand Down Expand Up @@ -352,10 +368,12 @@ const createJoinNotification = async (id: string, show_id: number): Promise<FSEn

const message = `${dj_name} joined the set!`;

const joinPlayOrder = await getNextPlayOrder();
const notification = await db
.insert(flowsheet)
.values({
show_id: show_id,
play_order: joinPlayOrder,
entry_type: 'dj_join',
message: message,
})
Expand Down Expand Up @@ -388,8 +406,10 @@ export const endShow = async (currentShow: Show): Promise<Show> => {
const dj_information = (await db.select().from(user).where(eq(user.id, primary_dj_id)).limit(1))[0];
const dj_name = dj_information?.djName || dj_information?.name || 'A DJ';

const endPlayOrder = await getNextPlayOrder();
await db.insert(flowsheet).values({
show_id: currentShow.id,
play_order: endPlayOrder,
entry_type: 'show_end',
message: `End of Show: ${dj_name} left the set at ${new Date().toLocaleString('en-US', {
timeZone: 'America/New_York',
Expand Down Expand Up @@ -431,10 +451,12 @@ const createLeaveNotification = async (dj_id: string, show_id: number): Promise<

const message = `${dj_name} left the set!`;

const leavePlayOrder = await getNextPlayOrder();
const notification = await db
.insert(flowsheet)
.values({
show_id: show_id,
play_order: leavePlayOrder,
entry_type: 'dj_leave',
message: message,
})
Expand Down
2 changes: 1 addition & 1 deletion shared/database/src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ export const flowsheet = wxyc_schema.table('flowsheet', {
album_title: varchar('album_title', { length: 128 }),
artist_name: varchar('artist_name', { length: 128 }),
record_label: varchar('record_label', { length: 128 }),
play_order: serial('play_order').notNull(),
play_order: integer('play_order').notNull(),
request_flag: boolean('request_flag').default(false).notNull(),
message: varchar('message', { length: 250 }),
add_time: timestamp('add_time').defaultNow().notNull(),
Expand Down
13 changes: 13 additions & 0 deletions tests/unit/database/schema.flowsheet.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { readFileSync } from 'fs';
import { resolve } from 'path';

describe('flowsheet schema', () => {
const schemaSource = readFileSync(resolve(__dirname, '../../../shared/database/src/schema.ts'), 'utf-8');

it('play_order should not use serial (it is manually managed)', () => {
const playOrderLine = schemaSource.split('\n').find((line) => line.includes('play_order'));

expect(playOrderLine).toBeDefined();
expect(playOrderLine).not.toMatch(/serial\s*\(\s*['"]play_order['"]\s*\)/);
});
});
Loading