142 lines
3.1 KiB
JavaScript
142 lines
3.1 KiB
JavaScript
import knex from './knex';
|
|
import { HttpError } from './errors';
|
|
|
|
function curateDatabaseShelf(shelf) {
|
|
if (!shelf) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
id: shelf.id,
|
|
slug: shelf.slug,
|
|
name: shelf.slug,
|
|
subscribed: !!shelf.subscribed,
|
|
};
|
|
}
|
|
|
|
function identityQuery(builder, shelfId) {
|
|
const id = Number(shelfId);
|
|
|
|
if (Number.isNaN(id)) {
|
|
builder.where('slug', shelfId);
|
|
return;
|
|
}
|
|
|
|
builder.where('id', shelfId);
|
|
}
|
|
|
|
function identitiesQuery(builder, shelfIds) {
|
|
const ids = Array.from(new Set(shelfIds.filter((shelfId) => !Number.isNaN(Number(shelfId)))));
|
|
const slugs = Array.from(new Set(shelfIds.filter((shelfId) => Number.isNaN(Number(shelfId)))));
|
|
|
|
builder
|
|
.whereIn('id', ids)
|
|
.orWhereIn('slug', slugs);
|
|
}
|
|
|
|
function isMemberQuery(builder, user) {
|
|
if (user) {
|
|
builder.select(knex.raw('shelves_subscriptions.id IS NOT NULL as subscribed'));
|
|
|
|
builder.leftJoin('shelves_subscriptions', (joinBuilder) => {
|
|
joinBuilder.on('shelf_id', 'shelves.id');
|
|
joinBuilder.andOnVal('user_id', user.id);
|
|
});
|
|
}
|
|
}
|
|
|
|
async function fetchShelf(shelfId, { user } = {}) {
|
|
const shelfEntry = await knex('shelves')
|
|
.select('shelves.*')
|
|
.modify((builder) => isMemberQuery(builder, user))
|
|
.where((builder) => identityQuery(builder, shelfId))
|
|
.first();
|
|
|
|
return curateDatabaseShelf(shelfEntry);
|
|
}
|
|
|
|
async function fetchAllShelves({ user, limit = 100 } = {}) {
|
|
const shelfEntries = await knex('shelves')
|
|
.select('shelves.*')
|
|
.modify((builder) => isMemberQuery(builder, user))
|
|
.orderBy('slug', 'asc')
|
|
.limit(limit);
|
|
|
|
return shelfEntries.map((shelfEntry) => curateDatabaseShelf(shelfEntry));
|
|
}
|
|
|
|
async function fetchShelves(shelfIds, { user } = {}) {
|
|
const shelfEntries = await knex('shelves')
|
|
.select('shelves.*')
|
|
.where((builder) => identitiesQuery(builder, shelfIds))
|
|
.modify((builder) => isMemberQuery(builder, user));
|
|
|
|
return Object.fromEntries(shelfEntries.map((shelfEntry) => [shelfEntry.id, curateDatabaseShelf(shelfEntry)]));
|
|
}
|
|
|
|
async function createShelf(shelf, user) {
|
|
const [shelfEntry] = await knex('shelves')
|
|
.insert({
|
|
slug: shelf.slug,
|
|
founder_id: user.id,
|
|
})
|
|
.returning('*');
|
|
|
|
return curateDatabaseShelf(shelfEntry);
|
|
}
|
|
|
|
async function subscribe(shelfId, user) {
|
|
const shelf = await fetchShelf(shelfId);
|
|
|
|
if (!shelf) {
|
|
throw new HttpError({
|
|
statusMessage: `Shelf ${shelfId} does not exist`,
|
|
statusCode: 404,
|
|
});
|
|
}
|
|
|
|
try {
|
|
await knex('shelves_subscriptions').insert({
|
|
shelf_id: shelf.id,
|
|
user_id: user.id,
|
|
});
|
|
} catch (error) {
|
|
if (error.code === '23505') {
|
|
throw new HttpError({
|
|
statusMessage: `You are already subscribed to s/${shelf.slug}`,
|
|
statusCode: 409,
|
|
});
|
|
}
|
|
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async function unsubscribe(shelfId, user) {
|
|
const shelf = await fetchShelf(shelfId);
|
|
|
|
if (!shelf) {
|
|
throw new HttpError({
|
|
statusMessage: `Shelf ${shelfId} does not exist`,
|
|
statusCode: 404,
|
|
});
|
|
}
|
|
|
|
await knex('shelves_subscriptions')
|
|
.where({
|
|
shelf_id: shelf.id,
|
|
user_id: user.id,
|
|
})
|
|
.delete();
|
|
}
|
|
|
|
export {
|
|
fetchShelf,
|
|
fetchShelves,
|
|
fetchAllShelves,
|
|
createShelf,
|
|
curateDatabaseShelf,
|
|
subscribe,
|
|
unsubscribe,
|
|
};
|