Skip to content

Instantly share code, notes, and snippets.

@danilaplee
Created August 22, 2023 11:21
Show Gist options
  • Select an option

  • Save danilaplee/2a67f80d25683e892fd4dda8508c74c5 to your computer and use it in GitHub Desktop.

Select an option

Save danilaplee/2a67f80d25683e892fd4dda8508c74c5 to your computer and use it in GitHub Desktop.

Revisions

  1. danilaplee created this gist Aug 22, 2023.
    172 changes: 172 additions & 0 deletions data-source-join.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,172 @@
    /*
    Feature: Data Source Join and Mapping
    Scenario: Joining and mapping data from third-party API and local DB query in execute()
    GIVEN two different data sources, one from a third-party API (call3partyAPI) and one from a local DB query (dbQuery)
    AND the call3partyAPI() returns static "curriculum" data
    AND the dbQuery() returns user learning progress data from our DB
    WHEN the execute() function is called
    THEN it should return an array of [{lessonName, readableStatus}]
    AND the readableStatus for each lesson is defined as follows:
    1: pending
    2: submitted
    3: passed
    4: failed
    definition of response:
    [
    {
    userId: number
    userName: string
    lessons: {
    lessonName: string
    readableStatus: string
    curriculumId: number
    lessonId: number
    }[]
    }
    ]
    */

    const StatusMap = {
    1: "pending",
    2: "submitted",
    3: "passed",
    4: "failed"
    }

    async function call3partyAPI() { //not enought data cases for unit testing
    return {
    status: 200, // could be 400 or 500 sometimes
    data: [ // data property may or may not exist
    {
    curriculum: {
    id: 1,
    title: 'Technology and Sustainability',
    lessons: [
    {
    id: 28,
    name: 'Multiple Choice',
    },
    {
    id: 76,
    name: 'True or False Questions',
    },
    ]
    }
    },
    {
    curriculum: {
    id: 2,
    title: 'Technology and Sustainability',
    lessons: [
    {
    id: 120,
    name: 'Chaos',
    },
    {
    id: 160,
    name: 'Order',
    },
    ]
    }
    },

    ]
    };
    };

    // Assume only one user will ever get returned
    async function dbQuery() { //not enought data cases for unit testing
    return [
    {
    user: { id: 1, name: 'Tom' },
    progress: {
    lessons: [
    {
    lesson_id: 28,
    status: 2,
    },
    {
    lesson_id: 76,
    status: 1
    }
    ]
    },
    },
    {
    user: { id: 2, name: 'Dan' },
    progress: {
    lessons: [
    {
    lesson_id: 76,
    status: 1
    },
    {
    lesson_id: 120,
    status: 1
    }
    ]
    }
    }
    ]
    }

    async function execute() {
    const [client_response, students] = await Promise.all([call3partyAPI(), dbQuery()])
    const curriculums = client_response.data
    const curriculumIds = []
    const curriculumsMap = curriculums.reduce((a, curriculum)=>{
    const curriculumId = curriculum.curriculum.id;
    curriculumIds.push(curriculumId)
    const lessons = curriculum.curriculum.lessons
    a[curriculumId] = {
    lessons:lessons.reduce((aggr, lesson)=>{
    aggr[lesson.id] = lesson.name
    return aggr
    }, {}),
    set: new Set(lessons.map(lesson=>lesson.id))
    }
    return a
    }, {})
    // console.info("curriculumsMap", curriculumsMap)
    const Response = [];
    if (client_response) {

    students.map(student => {
    const studentResult = {
    userId: student.user.id,
    userName: student.user.name,
    lessons: []
    }
    const studentLessonIds = []
    const studentLessonMap = student.progress.lessons.reduce((a,i)=>{
    studentLessonIds.push(i.lesson_id)
    a[i.lesson_id] = i.status
    return a
    }, {})

    // console.info("studentLessonMap", studentLessonMap)
    curriculumIds.map((curriculumId) => {
    const intersection = studentLessonIds.filter((x) => curriculumsMap[parseInt(curriculumId)].set.has(x));
    // console.info("intersection", intersection, studentLessonIds, curriculumIds)
    intersection.map(lessonId => {
    studentResult.lessons.push({
    lessonName: curriculumsMap[curriculumId].lessons[lessonId],
    readableStatus: StatusMap[studentLessonMap[lessonId]],
    curriculumId,
    lessonId
    });
    })
    })

    Response.push(studentResult)
    })
    }

    return Response;
    }


    execute().then((res) => console.log(JSON.stringify(res, 0, 2)))