Here is one possible solution for the other questions, with additional comments:
3A
Creating SQL tables is relatively straightforward. Check an SQL reference for the
right keywords and be careful of composite keys.
CREATE TABLE Tracks(
trackId INTEGER PRIMARY KEY,
title TEXT,
length INTEGER CHECK (length > 0)
);
CREATE TABLE Artists(
artistId INTEGER PRIMARY KEY,
name TEXT
);
CREATE TABLE Albums(
albumId INTEGER PRIMARY KEY,
title TEXT,
yearReleased INTEGER
);
CREATE TABLE TracksOnAlbum(
album INTEGER REFERENCES Albums(albumId),
trackNr INTEGER CHECK (trackNr > 0),
track INTEGER REFERENCES Tracks(trackId),
PRIMARY KEY (album,trackNr),
UNIQUE (album, track)
);
CREATE TABLE Participates(
track INTEGER REFERENCES Tracks(trackId),
artist INTEGER REFERENCES Artists(artistId)
);
CREATE TABLE Users(
username TEXT PRIMARY KEY,
email TEXT UNIQUE,
name TEXT
);
CREATE TABLE Playlists(
user_ TEXT REFERENCES Users(username),
playlistName TEXT,
PRIMARY KEY (user_, playlistName)
);
CREATE TABLE InList(
user_ TEXT,
playlist TEXT,
number INTEGER,
track INTEGER REFERENCES Tracks(trackId),
PRIMARY KEY (user_, playlist, number),
FOREIGN KEY (user_, playlist) REFERENCES Playlists (user_,playlistName)
);
CREATE TABLE PlayLog(
user_ TEXT REFERENCES Users(username),
time TIMESTAMP,
track INTEGER REFERENCES Tracks(trackId),
UNIQUE (user_,time)
)
3C
Let's first step through the queries the interface needs to execute on the
database in order to perform this "microinteraction". First, the web interface
needs to load the user's playlists in case she wants to add the song to an
existing playlist::
SELECT playlistName FROM Playlists WHERE user = ...;
Next, if the user choose to create a new playlist, the interface will need to
add it to the database::
INSERT INTO Playlists(user_, playlistName)
VALUES (<username>, <new playlist's name>);
Finally, in order to add the song to the playlist, we need insert a row in the
InList table::
INSERT INTO InList(user_, playlist, track)
VALUES (<username>, <playlist name>, <track id>)
Most of the constraint we would like the data to follow will already be enforced
by our schema (e.g. unique playlist name for a user, existing playlist, existing
track id...) But there is one thing that we need to take care of: the interface
doesn't ask the user to assign a number to the track added to the playlist, so
we need to make this happen automatically. One possible solution is to use a
BEFORE INSERT trigger on the InList track. The trigger will assign to
NEW.number the next available number::
NEW.number := SELECT MAX(NUMBER) + 1 FROM InList
WHERE user = ... AND playlist = ...
So the needed permissions, for this interaction only, (the interface might need
other permissions to do other things, like play a track or browse collection)
SELECT, INSERT ON Playlists
INSERT ON InList