590 lines
12 KiB
TypeScript
590 lines
12 KiB
TypeScript
import { defineRelations } from "drizzle-orm";
|
|
import {
|
|
boolean,
|
|
index,
|
|
integer,
|
|
json,
|
|
pgEnum,
|
|
pgTable,
|
|
primaryKey,
|
|
text,
|
|
timestamp,
|
|
uniqueIndex,
|
|
uuid,
|
|
} from "drizzle-orm/pg-core";
|
|
import { user } from "./auth-schema";
|
|
|
|
export * from "./auth-schema";
|
|
|
|
export const partyStatus = pgEnum("party_status", [
|
|
"created",
|
|
"started",
|
|
"ended",
|
|
]);
|
|
|
|
export const party = pgTable("party", {
|
|
id: uuid().defaultRandom().primaryKey().notNull(),
|
|
hostId: text()
|
|
.references(() => user.id)
|
|
.notNull(),
|
|
data: json(),
|
|
analysisData: json(),
|
|
createdAt: timestamp().defaultNow().notNull(),
|
|
lastUpdated: timestamp().defaultNow().notNull(),
|
|
status: partyStatus().notNull(),
|
|
});
|
|
|
|
export const memberStatus = pgEnum("member_status", [
|
|
"connected",
|
|
"disconnected",
|
|
]);
|
|
|
|
export const partyMember = pgTable(
|
|
"party_member",
|
|
{
|
|
id: uuid().defaultRandom().primaryKey().notNull(),
|
|
partyId: uuid()
|
|
.references(() => party.id)
|
|
.notNull(),
|
|
userId: text()
|
|
.references(() => user.id)
|
|
.notNull(),
|
|
joinedAt: timestamp().defaultNow().notNull(),
|
|
lastSeen: timestamp().defaultNow().notNull(),
|
|
},
|
|
(partyMember) => [uniqueIndex().on(partyMember.partyId, partyMember.userId)],
|
|
);
|
|
|
|
export const platform = pgEnum("enum_platform", ["spotify", "apple"]);
|
|
|
|
export const artist = pgTable("artist", {
|
|
id: uuid().defaultRandom().primaryKey().notNull(),
|
|
platform_id: text().notNull(),
|
|
platform: platform().notNull(),
|
|
name: text().notNull(),
|
|
type: text(),
|
|
popularity: integer(),
|
|
});
|
|
|
|
export const genre = pgTable("genre", {
|
|
id: uuid().defaultRandom().primaryKey().notNull(),
|
|
name: text().notNull().unique(),
|
|
});
|
|
|
|
export const artistGenre = pgTable(
|
|
"artist_genre",
|
|
{
|
|
artistId: uuid()
|
|
.references(() => artist.id)
|
|
.notNull(),
|
|
genreId: uuid()
|
|
.references(() => genre.id)
|
|
.notNull(),
|
|
},
|
|
(artistGenres) => [
|
|
primaryKey({
|
|
columns: [artistGenres.artistId, artistGenres.genreId],
|
|
}),
|
|
],
|
|
);
|
|
|
|
export const platformImage = pgTable(
|
|
"platform_image",
|
|
{
|
|
id: uuid().defaultRandom().primaryKey().notNull(),
|
|
platform: platform().notNull(),
|
|
url: text(),
|
|
height: integer(),
|
|
width: integer(),
|
|
},
|
|
(platformImage) => [
|
|
uniqueIndex().on(platformImage.platform, platformImage.url),
|
|
index().on(platformImage.url),
|
|
],
|
|
);
|
|
|
|
export const artistImage = pgTable(
|
|
"artist_image",
|
|
{
|
|
artistId: uuid()
|
|
.references(() => artist.id)
|
|
.notNull(),
|
|
imageId: uuid()
|
|
.references(() => platformImage.id)
|
|
.notNull(),
|
|
},
|
|
(artistImages) => [
|
|
primaryKey({
|
|
columns: [artistImages.artistId, artistImages.imageId],
|
|
}),
|
|
],
|
|
);
|
|
|
|
export const album = pgTable("album", {
|
|
id: uuid().defaultRandom().primaryKey().notNull(),
|
|
type: text(),
|
|
name: text(),
|
|
platform: platform(),
|
|
platform_id: text(),
|
|
popularity: integer(),
|
|
release_date: timestamp(),
|
|
label: text(),
|
|
});
|
|
|
|
export const albumImage = pgTable(
|
|
"album_image",
|
|
{
|
|
albumId: uuid()
|
|
.references(() => album.id)
|
|
.notNull(),
|
|
imageId: uuid()
|
|
.references(() => platformImage.id)
|
|
.notNull(),
|
|
},
|
|
(albumImage) => [
|
|
primaryKey({
|
|
columns: [albumImage.albumId, albumImage.imageId],
|
|
}),
|
|
],
|
|
);
|
|
|
|
export const albumArtist = pgTable(
|
|
"album_artist",
|
|
{
|
|
albumId: uuid()
|
|
.references(() => album.id)
|
|
.notNull(),
|
|
artistId: uuid()
|
|
.references(() => artist.id)
|
|
.notNull(),
|
|
},
|
|
(albumArtist) => [
|
|
primaryKey({
|
|
columns: [albumArtist.albumId, albumArtist.artistId],
|
|
}),
|
|
],
|
|
);
|
|
|
|
export const albumGenre = pgTable(
|
|
"album_genre",
|
|
{
|
|
albumId: uuid()
|
|
.references(() => album.id)
|
|
.notNull(),
|
|
genreId: uuid()
|
|
.references(() => genre.id)
|
|
.notNull(),
|
|
},
|
|
(albumGenre) => [
|
|
primaryKey({
|
|
columns: [albumGenre.albumId, albumGenre.genreId],
|
|
}),
|
|
],
|
|
);
|
|
|
|
export const track = pgTable(
|
|
"track",
|
|
{
|
|
id: uuid().defaultRandom().primaryKey().notNull(),
|
|
albumId: uuid()
|
|
.references(() => album.id)
|
|
.notNull(),
|
|
name: text(),
|
|
platform: platform(),
|
|
platform_id: text(),
|
|
popularity: integer(),
|
|
duration: integer(),
|
|
explicit: boolean(),
|
|
disc_number: integer(),
|
|
track_number: integer(),
|
|
},
|
|
(track) => [index().on(track.albumId)],
|
|
);
|
|
|
|
export const trackArtist = pgTable(
|
|
"track_artist",
|
|
{
|
|
trackId: uuid()
|
|
.references(() => track.id)
|
|
.notNull(),
|
|
artistId: uuid()
|
|
.references(() => artist.id)
|
|
.notNull(),
|
|
},
|
|
(trackArtist) => [
|
|
primaryKey({
|
|
columns: [trackArtist.trackId, trackArtist.artistId],
|
|
}),
|
|
index("track_artist_track_id_idx").on(trackArtist.trackId),
|
|
index("track_artist_artist_id_idx").on(trackArtist.artistId),
|
|
],
|
|
);
|
|
|
|
export const topTimeline = pgEnum("top_timeline", [
|
|
"short_term",
|
|
"medium_term",
|
|
"long_term",
|
|
]);
|
|
|
|
export const topTrack = pgTable(
|
|
"top_track",
|
|
{
|
|
trackId: uuid()
|
|
.references(() => track.id)
|
|
.notNull(),
|
|
position: integer().notNull(),
|
|
userId: text()
|
|
.references(() => user.id)
|
|
.notNull(),
|
|
timeline: topTimeline().notNull(),
|
|
},
|
|
(topTrack) => [
|
|
primaryKey({
|
|
columns: [topTrack.trackId, topTrack.userId, topTrack.timeline],
|
|
}),
|
|
index().on(topTrack.userId),
|
|
],
|
|
);
|
|
|
|
export const topArtist = pgTable(
|
|
"top_artist",
|
|
{
|
|
artistId: uuid()
|
|
.references(() => artist.id)
|
|
.notNull(),
|
|
position: integer().notNull(),
|
|
userId: text()
|
|
.references(() => user.id)
|
|
.notNull(),
|
|
timeline: topTimeline().notNull(),
|
|
},
|
|
(topArtist) => [
|
|
primaryKey({
|
|
columns: [topArtist.artistId, topArtist.userId, topArtist.timeline],
|
|
}),
|
|
index().on(topArtist.userId),
|
|
],
|
|
);
|
|
|
|
export const savedAlbum = pgTable(
|
|
"saved_album",
|
|
{
|
|
albumId: uuid()
|
|
.references(() => album.id)
|
|
.notNull(),
|
|
userId: text()
|
|
.references(() => user.id)
|
|
.notNull(),
|
|
saved_at: timestamp("saved_at").defaultNow().notNull(),
|
|
},
|
|
(savedAlbum) => [
|
|
primaryKey({
|
|
columns: [savedAlbum.albumId, savedAlbum.userId],
|
|
}),
|
|
index().on(savedAlbum.userId),
|
|
],
|
|
);
|
|
|
|
export const savedTrack = pgTable(
|
|
"saved_track",
|
|
{
|
|
trackId: uuid()
|
|
.references(() => track.id)
|
|
.notNull(),
|
|
userId: text()
|
|
.references(() => user.id)
|
|
.notNull(),
|
|
saved_at: timestamp("saved_at").defaultNow().notNull(),
|
|
},
|
|
(savedTrack) => [
|
|
primaryKey({
|
|
columns: [savedTrack.trackId, savedTrack.userId],
|
|
}),
|
|
index().on(savedTrack.userId),
|
|
],
|
|
);
|
|
|
|
export const followedArtist = pgTable(
|
|
"followed_artist",
|
|
{
|
|
artistId: uuid()
|
|
.references(() => artist.id)
|
|
.notNull(),
|
|
userId: text()
|
|
.references(() => user.id)
|
|
.notNull(),
|
|
},
|
|
(followedArtist) => [
|
|
primaryKey({
|
|
columns: [followedArtist.artistId, followedArtist.userId],
|
|
}),
|
|
index().on(followedArtist.userId),
|
|
],
|
|
);
|
|
|
|
export const playbackHistory = pgTable(
|
|
"playback_history",
|
|
{
|
|
id: uuid().defaultRandom().primaryKey().notNull(),
|
|
trackId: uuid()
|
|
.references(() => track.id)
|
|
.notNull(),
|
|
userId: text()
|
|
.references(() => user.id)
|
|
.notNull(),
|
|
played_at: timestamp("played_at").defaultNow().notNull(),
|
|
},
|
|
(playbackHistory) => [index().on(playbackHistory.userId)],
|
|
);
|
|
|
|
export const relations = defineRelations(
|
|
{
|
|
album,
|
|
albumImage,
|
|
albumArtist,
|
|
albumGenre,
|
|
artist,
|
|
artistGenre,
|
|
artistImage,
|
|
followedArtist,
|
|
genre,
|
|
party,
|
|
partyMember,
|
|
platformImage,
|
|
playbackHistory,
|
|
savedAlbum,
|
|
savedTrack,
|
|
topArtist,
|
|
topTrack,
|
|
track,
|
|
trackArtist,
|
|
user,
|
|
},
|
|
(r) => ({
|
|
artist: {
|
|
artistGenres: r.many.artistGenre(),
|
|
artistImages: r.many.artistImage(),
|
|
trackArtists: r.many.trackArtist(),
|
|
albumArtists: r.many.albumArtist(),
|
|
topArtists: r.many.topArtist(),
|
|
followedArtists: r.many.followedArtist(),
|
|
genres: r.many.genre({
|
|
from: r.artist.id.through(r.artistGenre.artistId),
|
|
to: r.genre.id.through(r.artistGenre.genreId),
|
|
}),
|
|
images: r.many.platformImage({
|
|
from: r.artist.id.through(r.artistImage.artistId),
|
|
to: r.platformImage.id.through(r.artistImage.imageId),
|
|
}),
|
|
albums: r.many.album({
|
|
from: r.artist.id.through(r.albumArtist.artistId),
|
|
to: r.album.id.through(r.albumArtist.albumId),
|
|
}),
|
|
tracks: r.many.track({
|
|
from: r.artist.id.through(r.trackArtist.artistId),
|
|
to: r.track.id.through(r.trackArtist.trackId),
|
|
}),
|
|
},
|
|
genre: {
|
|
artistGenres: r.many.artistGenre(),
|
|
albumGenres: r.many.albumGenre(),
|
|
artists: r.many.artist({
|
|
from: r.genre.id.through(r.artistGenre.genreId),
|
|
to: r.artist.id.through(r.artistGenre.artistId),
|
|
}),
|
|
albums: r.many.album({
|
|
from: r.genre.id.through(r.albumGenre.genreId),
|
|
to: r.album.id.through(r.albumGenre.albumId),
|
|
}),
|
|
},
|
|
artistGenre: {
|
|
artist: r.one.artist({
|
|
from: r.artistGenre.artistId,
|
|
to: r.artist.id,
|
|
}),
|
|
genre: r.one.genre({
|
|
from: r.artistGenre.genreId,
|
|
to: r.genre.id,
|
|
}),
|
|
},
|
|
platformImage: {
|
|
artistImages: r.many.artistImage(),
|
|
albumImages: r.many.albumImage(),
|
|
artists: r.many.artist({
|
|
from: r.platformImage.id.through(r.artistImage.imageId),
|
|
to: r.artist.id.through(r.artistImage.artistId),
|
|
}),
|
|
albums: r.many.album({
|
|
from: r.platformImage.id.through(r.albumImage.imageId),
|
|
to: r.album.id.through(r.albumImage.albumId),
|
|
}),
|
|
},
|
|
party: {
|
|
members: r.many.partyMember(),
|
|
host: r.one.user({
|
|
from: r.party.hostId,
|
|
to: r.user.id,
|
|
}),
|
|
},
|
|
partyMember: {
|
|
party: r.one.party({
|
|
from: r.partyMember.partyId,
|
|
to: r.party.id,
|
|
}),
|
|
user: r.one.user({
|
|
from: r.partyMember.userId,
|
|
to: r.user.id,
|
|
}),
|
|
},
|
|
artistImage: {
|
|
artist: r.one.artist({
|
|
from: r.artistImage.artistId,
|
|
to: r.artist.id,
|
|
}),
|
|
image: r.one.platformImage({
|
|
from: r.artistImage.imageId,
|
|
to: r.platformImage.id,
|
|
}),
|
|
},
|
|
album: {
|
|
tracks: r.many.track(),
|
|
albumImages: r.many.albumImage(),
|
|
albumArtists: r.many.albumArtist(),
|
|
albumGenres: r.many.albumGenre(),
|
|
savedAlbums: r.many.savedAlbum(),
|
|
images: r.many.platformImage({
|
|
from: r.album.id.through(r.albumImage.albumId),
|
|
to: r.platformImage.id.through(r.albumImage.imageId),
|
|
}),
|
|
artists: r.many.artist({
|
|
from: r.album.id.through(r.albumArtist.albumId),
|
|
to: r.artist.id.through(r.albumArtist.artistId),
|
|
}),
|
|
genres: r.many.genre({
|
|
from: r.album.id.through(r.albumGenre.albumId),
|
|
to: r.genre.id.through(r.albumGenre.genreId),
|
|
}),
|
|
},
|
|
albumImage: {
|
|
album: r.one.album({
|
|
from: r.albumImage.albumId,
|
|
to: r.album.id,
|
|
}),
|
|
image: r.one.platformImage({
|
|
from: r.albumImage.imageId,
|
|
to: r.platformImage.id,
|
|
}),
|
|
},
|
|
albumArtist: {
|
|
album: r.one.album({
|
|
from: r.albumArtist.albumId,
|
|
to: r.album.id,
|
|
}),
|
|
artist: r.one.artist({
|
|
from: r.albumArtist.artistId,
|
|
to: r.artist.id,
|
|
}),
|
|
},
|
|
albumGenre: {
|
|
album: r.one.album({
|
|
from: r.albumGenre.albumId,
|
|
to: r.album.id,
|
|
}),
|
|
genre: r.one.genre({
|
|
from: r.albumGenre.genreId,
|
|
to: r.genre.id,
|
|
}),
|
|
},
|
|
track: {
|
|
album: r.one.album({
|
|
from: r.track.albumId,
|
|
to: r.album.id,
|
|
}),
|
|
trackArtists: r.many.trackArtist(),
|
|
topTracks: r.many.topTrack(),
|
|
savedTracks: r.many.savedTrack(),
|
|
playbackHistory: r.many.playbackHistory(),
|
|
artists: r.many.artist({
|
|
from: r.track.id.through(r.trackArtist.trackId),
|
|
to: r.artist.id.through(r.trackArtist.artistId),
|
|
}),
|
|
},
|
|
trackArtist: {
|
|
track: r.one.track({
|
|
from: r.trackArtist.trackId,
|
|
to: r.track.id,
|
|
}),
|
|
artist: r.one.artist({
|
|
from: r.trackArtist.artistId,
|
|
to: r.artist.id,
|
|
}),
|
|
},
|
|
topTrack: {
|
|
track: r.one.track({
|
|
from: r.topTrack.trackId,
|
|
to: r.track.id,
|
|
}),
|
|
user: r.one.user({
|
|
from: r.topTrack.userId,
|
|
to: r.user.id,
|
|
}),
|
|
},
|
|
topArtist: {
|
|
artist: r.one.artist({
|
|
from: r.topArtist.artistId,
|
|
to: r.artist.id,
|
|
}),
|
|
user: r.one.user({
|
|
from: r.topArtist.userId,
|
|
to: r.user.id,
|
|
}),
|
|
},
|
|
savedAlbum: {
|
|
album: r.one.album({
|
|
from: r.savedAlbum.albumId,
|
|
to: r.album.id,
|
|
}),
|
|
user: r.one.user({
|
|
from: r.savedAlbum.userId,
|
|
to: r.user.id,
|
|
}),
|
|
},
|
|
savedTrack: {
|
|
track: r.one.track({
|
|
from: r.savedTrack.trackId,
|
|
to: r.track.id,
|
|
}),
|
|
user: r.one.user({
|
|
from: r.savedTrack.userId,
|
|
to: r.user.id,
|
|
}),
|
|
},
|
|
followedArtist: {
|
|
artist: r.one.artist({
|
|
from: r.followedArtist.artistId,
|
|
to: r.artist.id,
|
|
}),
|
|
user: r.one.user({
|
|
from: r.followedArtist.userId,
|
|
to: r.user.id,
|
|
}),
|
|
},
|
|
playbackHistory: {
|
|
track: r.one.track({
|
|
from: r.playbackHistory.trackId,
|
|
to: r.track.id,
|
|
}),
|
|
user: r.one.user({
|
|
from: r.playbackHistory.userId,
|
|
to: r.user.id,
|
|
}),
|
|
},
|
|
user: {
|
|
partyMembers: r.many.partyMember(),
|
|
hostedParties: r.many.party({
|
|
from: r.user.id,
|
|
to: r.party.hostId,
|
|
}),
|
|
},
|
|
}),
|
|
);
|