// Deletes all entries that have an outdated timestamp dbmtime. Also cleans up // entries in Artist and Album table that are not referenced anymore in the // Track-table. // // Returns the number of deleted rows and an error. func deleteDanglingEntries(db *database.Database) (int64, error) { r, err := db.Execute("DELETE FROM Track WHERE dbmtime <> ?", db.Mtime()) deletedTracks, _ := r.RowsAffected() if err != nil { return deletedTracks, err } if _, err := db.Execute("DELETE FROM Album WHERE ID IN " + "(SELECT Album.ID FROM Album LEFT JOIN Track ON " + "Album.ID = Track.album_id WHERE Track.album_id " + "IS NULL);"); err != nil { return deletedTracks, err } if _, err := db.Execute("DELETE FROM Artist WHERE ID IN " + "(SELECT Artist.ID FROM Artist LEFT JOIN Album ON " + "Artist.ID = Album.artist_id WHERE Album.artist_id " + "IS NULL);"); err != nil { return deletedTracks, err } return deletedTracks, nil }
// Updates or adds tracks that are received at the tracks channel. // // For every track a status update UpdateStatus is emitted to the status // channel. If the method finishes, the overall result is emitted on the result // channel. func updateDatabase(db *database.Database, tracks <-chan source.TrackInfo, status chan<- *UpdateStatus) *UpdateResult { err := db.BeginTransaction() if err != nil { close(status) return &UpdateResult{Err: err} } defer db.EndTransaction() var trackAction uint8 tm := &trackMtime{} martists := mod.New(db, "artist") malbums := mod.New(db, "album") mtracks := mod.New(db, "track") // traverse all catched pathes and update or add database entries for ti := range tracks { var statusErr error trackAction = TRACK_NOUPDATE // check if mtime has changed and decide what to do err := query.New(db, "track").Where("path =", ti.Path()).Exec(tm) switch { case err == nil: // track is in database // check if track has changed since the last time if ti.Mtime() != tm.Mtime { trackAction = TRACK_UPDATE } else { tdbm := &trackDBMtime{db.Mtime()} statusErr = mtracks.Update(tm.ID, tdbm) } case err == sql.ErrNoRows: // track is not in database trackAction = TRACK_ADD tag, err := ti.Tags() if err != nil { statusErr = err break } artist := &artist.Artist{ Name: tag.Artist, } res, err := martists.InsertIgnore(artist) if err != nil { statusErr = err break } aff, _ := res.RowsAffected() var artist_id int64 // if entry exists if aff == 0 { err = query.New(db, "artist"). Where("name =", tag.Artist).Limit(1).Exec(artist) if err != nil { statusErr = err break } artist_id = artist.Id } else { artist_id, _ = res.LastInsertId() } album := &album.Album{ Name: tag.Album, ArtistID: artist_id, } res, err = malbums.InsertIgnore(album) if err != nil { statusErr = err break } aff, _ = res.RowsAffected() var album_id int64 // if entry exists if aff == 0 { err = query.New(db, "album"). Where("name =", tag.Album). Where("artist_id =", artist_id). Limit(1).Exec(album) if err != nil { statusErr = err break } album_id = album.Id } else { album_id, _ = res.LastInsertId() } track := &track.RawTrack{ Path: ti.Path(), Title: tag.Title, Tracknumber: tag.Track, Year: tag.Year, Length: tag.Length, Genre: tag.Genre, AlbumID: album_id, Filemtime: ti.Mtime(), DBMtime: db.Mtime(), } _, err = mtracks.Insert(track) if err != nil { statusErr = err break } statusErr = nil default: // if something is wrong update timestamp, so track is not // deleted the next time tdbm := &trackDBMtime{db.Mtime()} mtracks.Update(tm.ID, tdbm) statusErr = err } status <- &UpdateStatus{ Path: ti.Path(), Action: trackAction, Err: statusErr} } // clean up del, err := deleteDanglingEntries(db) close(status) return &UpdateResult{Err: err, Deleted: del} }