Each class or interface should be placed in separate code file


Do not use shortened meaningless variable names like a, b, c, d, p, text, value, data, list


Avoid as much as possible function nesting, use async .. await

Not good

public static async UpdateSession(session: Session): Promise<void> {
      let db = ControllerDatabase.ConnectToDatabase();
      return new Promise((resolve, reject) => {
          if (db) {
              let sql = `UPDATE session SET session_hash = ?, modified = ? WHERE session_id = ?`
              db.run(
                  sql,
                  [session.session_hash, session.modified, session.session_id],
                  function (err) {
                      if (err) {
                          console.log(err)
                          reject(err);
                      } else {
                          console.log(`Updated session with id ${session.session_id}`)
                          resolve();
                      }
                  }
              );
              db.close()
          } else {
              reject(new Error("Unexpected error"))
          }
      });
  }

Better:

public static async UpdateSession(session: Session): Promise<boolean> {
        let is_success = false;
        try {
            let db = await ControllerDatabase.ConnectToDatabase();
            try {
                let sql = `UPDATE session SET session_hash = ?, modified = ? WHERE session_id = ?`
                let result = await db.exec(sql, [session.session_hash, session.modified, session.session_id]);
            }
            catch (exc) {
                UtilsLogger.logException(exc);    
            }
            db.close();
        } catch (exc) {
            UtilsLogger.logException(exc);
        }
        return is_success;
    }

Use for..of instead of forEach. Otherwise you should add try..catch in every scope rather than one common try..catch around everything

Not good

playlists.forEach(p => {
    playlist_ids.push(p.playlist_id);
})

Good