Search code examples
javascriptarraystypescript

Can I use the 'this' argument within the typescript Array.map() function to increment a counter?


Here's the code I'm trying to get to work:

const playlist = {
  playlist_idea_uri: uri.toString(),
  type: 'master'
}
const insertedPlaylistIdResponse = await db
  .insertInto('playlist')
  .values(playlist)
  .onConflict((oc) => oc.doNothing())
  .returning('id')
  .executeTakeFirst()
let songs = masterPlaylist.songs.map((song) => {
  return {
    track_name: song.trackName,
    track_mb_id: song.trackMbId,
    album_artwork_ref: song.albumArtwork?.ref.toString(),
    created_at: song.createdAt
  }
})
const insertedSongIdsResponse = await db
  .insertInto('song')
  .values(songs)
  .onConflict((oc) => oc.doNothing())
  .returning('id')
  .execute()
var position = 0
if (insertedPlaylistIdResponse?.id) {
  const playlistItems = insertedSongIdsResponse.map((songIdResponse) => {
    if (this !== undefined) {
      return undefined
    } else {
      const newPosition = this + 1
      return {
        playlist_id: insertedPlaylistIdResponse.id,
        song_id: songIdResponse.id,
        position: newPosition
      }
    }
  }, position)
  await db
    .insertInto('playlist_item')
    .values(playlistItems)
    .execute()
}

So basically I want to insert an object into the playlist table, insert song objects into the song table, take the resulting ids of those inserted songs and the inserted playlist and for each song's id map to a kind of object that I can then insert into another table called playlist_item, like this:

const playlistItems = insertedSongIdsResponse.map((songIdResponse) => {
  if (this !== undefined) {
    return undefined
  } else {
    const newPosition = this + 1
    return {
      playlist_id: insertedPlaylistIdResponse.id,
      song_id: songIdResponse.id,
      position: newPosition
    }
  }
}, position)

The playlist_item table has this schema:

export interface PlaylistItemTable {
  id: Generated<number>
  playlist_id: number
  song_id: number
  position: number
}

Basically a PlaylistItem is a song within the playlist, at a certain position (like the first song in the playlist will have position = 1, the next would have position = 2, etc.

The thing to focus on is the position variable, and whether I can use the thisArg parameter of the Array.map() function as a kind of iterator that each time it maps it will increment, based on the way I've used it. Is that possible, or will it not work? Currently I'm getting the error that the variable this could be undefined, but I'm not sure why because I've checked for that right before attempting to use it.

Any help is appreciated!


Solution

  • There are many reasons why the use of this in this context is not valid (especially since you're in an arrow function).

    A more common approach would be to use filter and map, or even reduce.

    Using filter and map

    const playlistItems = insertedSongIdsResponse
      .filter(songIdResponse => songIdResponse !== undefined)
      .map((songIdResponse, index) => ({
        playlist_id: insertedPlaylistIdResponse.id,
        song_id: songIdResponse.id,
        position: index + 1 // use the index provided
      }));
    

    Using reduce

    const playlistItems = insertedSongIdsResponse
      .reduce((acc, songIdResponse) => {
        if (songIdResponse !== undefined) {
          acc.push({
            playlist_id: insertedPlaylistIdResponse.id,
            song_id: songIdResponse.id,
            position: acc.length + 1 // use the accumulator length
          });
        }
        return acc;
      }, []);