Advertisement
Chame

TS Functional format of data

Jan 28th, 2022
1,368
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import { z } from 'zod'
  2. import { pipe, flow } from 'fp-ts/function'
  3. import { RequestFp } from '@helpers/Request'
  4. import * as T from 'fp-ts/lib/Task'
  5. import * as TE from 'fp-ts/lib/TaskEither'
  6. import { map, reduce, sort, last } from 'fp-ts/lib/Array'
  7. import { Ord } from 'fp-ts/Date'
  8. import { Option } from 'fp-ts/Option'
  9.  
  10. const USERS_INDEX_API = `${process.env.MIX_APP_ENDPOINT}/api/v1/users`
  11.  
  12. export type UserType = {
  13.   id: number
  14.   email: string
  15.   lastAccess: Option<Date>
  16.   microservices: MicroserviceRoleMinistryType[]
  17. }
  18.  
  19. type MicroserviceRoleMinistryType = {
  20.   microserviceName: string
  21.   roles: {
  22.     roleName: string
  23.     ministryName: string[]
  24.   }[]
  25. }
  26.  
  27. const UsersResponseSchema = z.object({
  28.   users: z.array(
  29.     z.object({
  30.       id: z.number(),
  31.       email: z.string(),
  32.       user_access_logs: z.array(
  33.         z.object({
  34.           created_at: z.string(),
  35.         })
  36.       ),
  37.       accounts: z.array(
  38.         z.object({
  39.           ministry: z.object({
  40.             name: z.string(),
  41.           }),
  42.           microservice_role: z.object({
  43.             role: z.object({
  44.               name: z.string(),
  45.             }),
  46.             microservice: z.object({
  47.               name: z.string(),
  48.             }),
  49.           }),
  50.         })
  51.       ),
  52.     })
  53.   ),
  54. })
  55.  
  56. type UsersResponseType = {
  57.   users: {
  58.     id: number
  59.     email: string
  60.     user_access_logs: {
  61.       created_at: string
  62.     }[]
  63.     accounts: {
  64.       ministry: {
  65.         name: string
  66.       }
  67.       microservice_role: {
  68.         role: {
  69.           name: string
  70.         }
  71.         microservice: {
  72.           name: string
  73.         }
  74.       }
  75.     }[]
  76.   }[]
  77. }
  78.  
  79. const squashUserAccounts = reduce(
  80.   [],
  81.   (acc: MicroserviceRoleMinistryType[], cur: MicroserviceRoleMinistryType) => {
  82.     // first iteration, skip parse
  83.     if (!acc.length) return [cur]
  84.  
  85.     const indexOfExistingMicroservice = acc.findIndex(
  86.       (y) => y.microserviceName === cur.microserviceName
  87.     )
  88.  
  89.     // different microservice
  90.     if (indexOfExistingMicroservice === -1) return [...acc, cur]
  91.  
  92.     // different role, push to roles array
  93.     if (
  94.       !acc[indexOfExistingMicroservice].roles.some(
  95.         (y) => y.roleName === cur.roles[0].roleName
  96.       )
  97.     )
  98.       acc[indexOfExistingMicroservice].roles.push(cur.roles[0])
  99.     // same role, push to ministries array
  100.     else
  101.       acc[indexOfExistingMicroservice].roles[
  102.         acc[indexOfExistingMicroservice].roles.findIndex(
  103.           (y) => y.roleName === cur.roles[0].roleName
  104.         )
  105.       ].ministryName.push(cur.roles[0].ministryName[0])
  106.  
  107.     return acc
  108.   }
  109. )
  110.  
  111. export const GetUsers: T.Task<UserType[]> = pipe(
  112.   RequestFp<UsersResponseType>(USERS_INDEX_API, UsersResponseSchema)(),
  113.   TE.map(
  114.     flow(
  115.       ({ data: { users } }) => users,
  116.       map((user) => ({
  117.         id: user.id,
  118.         email: user.email,
  119.         microservices: pipe(
  120.           user.accounts,
  121.           map((account) => ({
  122.             microserviceName: account.microservice_role.microservice.name,
  123.             roles: [
  124.               {
  125.                 roleName: account.microservice_role.role.name,
  126.                 ministryName: [account.ministry.name],
  127.               },
  128.             ],
  129.           })),
  130.           squashUserAccounts
  131.         ),
  132.         lastAccess: pipe(
  133.           user.user_access_logs,
  134.           map(({ created_at }) => <Date>(<unknown>created_at)),
  135.           sort(Ord),
  136.           last
  137.         ),
  138.       }))
  139.     )
  140.   ),
  141.   TE.getOrElse(
  142.     () => T.of(<UserType[]>{}) // Validation already handled by RequestFp(), just cast to empty object
  143.   )
  144. )
  145.  
Advertisement
Advertisement
Advertisement
RAW Paste Data Copied
Advertisement