Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Factory model for a Union Type model #302

Open
SalahAdDin opened this issue Mar 21, 2024 · 1 comment
Open

Factory model for a Union Type model #302

SalahAdDin opened this issue Mar 21, 2024 · 1 comment

Comments

@SalahAdDin
Copy link

Right now we have the following definition for our models:

type TArticleBase = {
  /** article's thumbnail */
  thumbnail: TImage;
  /** article's title */
  title: string;
  /** article's category */
  category: TCategory;
  /** article's publication date */
  publishedDate: Date;
  /** article's creation date */
  createdDate: Date;
  /** article's slug for URL path */
  slug: string;
  /** article's editor */
  editor: Array<TUser>;
  /** article's hero */
  hero: TArticleHero;
  /** article's source */
  source?: string;
  /** article's tags */
  tags: Array<string>;
};

export type TArticleType = (typeof ARTICLE_TYPES)[number];

export type TStandardArticle = TArticleBase & {
  /** states this article is a standard article */
  type: "standard";
  /** article's introduction (used also as meta) */
  introduction: string;
  /** article's author */
  author?: Array<TUser>;
  /** article's audio */
  audio?: TAudio;
  /** article's content */
  content: TRichText;
  /** article's continue reading article */
  continue: TContinueReadingArticle;
  /** article's related articles */
  related?: Array<TRelatedArticle>;
};

export type TFeaturedArticle = Omit<TStandardArticle, "related" | "type"> & {
  /** states this article is a featured article */
  type: "featured";
};

export type TLiveArticle = TArticleBase & {
  /** states this article is a live article */
  type: "live";
  /** lists the main ideas of the article */
  ideas: Array<string>;
  /** list of updates on the article */
  content: Map<string, Array<TUpdatedInformation>>;
  /** article's related articles */
  related?: Array<TRelatedArticle>;
};

export type TArticle = TFeaturedArticle | TLiveArticle | TStandardArticle;

And the following factory:


export const articleFactory: ModelDefinition = {
  id: primaryKey(() => _articleId++),
  type: () => chooseOne(ARTICLE_TYPES),
  title: () => baseTitle,
  slug: () => faker.helpers.slugify(baseTitle),
  author: nullable(manyOf("user")),
  editor: nullable(manyOf("user")),
  thumbnail: oneOf("image"),
  category: oneOf("category"),
  createdDate: () => faker.date.anytime(),
  publishedDate: () => faker.date.anytime(),
  introduction: () => faker.lorem.text(),
  content: {
    // TODO: https://github.com/mswjs/data/issues/299
    root: () => mockRichText({}),
  },
  audio: {
    url: () => DEFAULT_AUDIO_URL,
    duration: () => 7264000,
    mimeType: () => chooseOne(AUDIO_MIME_TYPES),
  },
  hero: {
    url: () => faker.image.url({ width: mockWidth, height: mockHeight }),
    alt: () => faker.lorem.text(),
    width: () => mockWidth,
    height: () => mockHeight,
    mimeType: () => chooseOne(IMAGE_MIME_TYPES),
    caption: {
      source: () => faker.lorem.word(),
      description: () => faker.lorem.text(),
    },
  },
  source: nullable(() => faker.lorem.word()),
  tags: () => mockArray(6, () => faker.lorem.word()),
  continue: oneOf("continueArticle"),
  related: nullable(manyOf("relatedArticle")),
};

This factory can create different combinations based on the article type.

We don't want to create a different factory for every article type since it adds unnecessary complexity to querying the entities.

What is the best way to do it? Does it require a new feature?

Thank you

@SalahAdDin
Copy link
Author

Right now we have the following issue:

const targetType = chooseOne(ARTICLE_TYPES);
const targetContent =
  targetType === "live"
    ? mockArray(5, () => mockUpdatedInformation({}))
    : {
        root: mockRichText({}),
      };

export const articleFactory: ModelDefinition = {
  id: primaryKey(() => _articleId++),
  type: () => targetType,
  title: () => baseTitle,
  slug: () => slugify(baseTitle),
  author: nullable(manyOf("user")),
  editor: nullable(manyOf("user")),
  thumbnail: oneOf("image"),
  category: oneOf("category"),
  createdDate: () => faker.date.anytime(),
  publishedDate: () => faker.date.anytime(),
  introduction: () => faker.lorem.text(),
  summary: () => mockArray(3, () => faker.lorem.text()),
  // TODO: https://github.com/mswjs/data/issues/299
  content: () => targetContent,
  audio: {
    url: () => DEFAULT_AUDIO_URL,
    duration: () => 7264000,
    mimeType: () => chooseOne(AUDIO_MIME_TYPES),
  },
  hero: {
    url: () => faker.image.url({ width: mockWidth, height: mockHeight }),
    alt: () => faker.lorem.text(),
    width: () => mockWidth,
    height: () => mockHeight,
    mimeType: () => chooseOne(IMAGE_MIME_TYPES),
    caption: {
      source: () => faker.lorem.word(),
      description: () => faker.lorem.text(),
    },
  },
  source: nullable(() => faker.lorem.word()),
  tags: () => mockArray(6, () => faker.lorem.word()),
  continue: nullable(oneOf("continueArticle")),
  related: manyOf("relatedArticle"),
};

And we are creating the articles like this:

  /** Create an article. Faker will fill in any missing data */
  const createArticle = (article = {}) => db.article.create(article);

  /** Creating an article based on the figma design */
  createArticle({
    ...mockArticle({
      title: STANDARD_ARTICLE_BASE.title,
      introduction: STANDARD_ARTICLE_BASE.introduction,
      hero: {
        ...mockImage({ alt: STANDARD_ARTICLE_BASE.hero.text }),
        caption: mockCaption({
          source: STANDARD_ARTICLE_BASE.hero.source,
          description: STANDARD_ARTICLE_BASE.hero.text,
        }),
      },
      source: STANDARD_ARTICLE_BASE.source,
      tags: STANDARD_ARTICLE_BASE.tags,
    }),
    author: users[2],
    editor: chooseOne(users),
    thumbnail: chooseOne(imageGallery),
    category: figmaCategories[0],
    continue: figmaContinueArticles[0],
    related: figmaRelatedArticles.slice(0, 5),
    content: {
      root: mockArticleContent({ raw: STANDARD_ARTICLE_CONTENT }),
    },
  });

  /** Creating a live article based on the figma design */
  createArticle({
    ...mockLiveArticle({
      title: LIVE_ARTICLE_BASE.title,
      summary: LIVE_ARTICLE_BASE.summary,
      tags: LIVE_ARTICLE_BASE.tags,
    }),
    content: mockBELiveArticleContent(),
    editor: chooseOne(users),
    thumbnail: chooseOne(imageGallery),
    category: figmaCategories[1],
    related: figmaRelatedArticles.slice(4, 10),
  });

  /** Creating a featured article based on the figma design */
  createArticle({
    ...mockFeaturedArticle({
      title: FEATURED_ARTICLE_BASE.title,
      introduction: FEATURED_ARTICLE_BASE.introduction,
    }),
    type: "featured",
    display: chooseOne(DISPLAY_TYPES),
    category: figmaCategories[2],
    author: users[0],
    editor: chooseOne(users),
    thumbnail: chooseOne(imageGallery),
    continue: figmaContinueArticles[1],
    related: figmaRelatedArticles.slice(-2),
    content: {
      root: mockArticleContent({ raw: FEATURED_ARTICLE_CONTENT }),
    },
  });

So for a Live Article, the content should be an array of items, and it is:
image

But for a non Live Article, the content should be a rich-text object, and it does not work:
image

Before we had the content created with the mock function and not the content we passed to the function, that's not what we wanted.

As a solution for getting the right content, we have to set the content directly:

const targetContent = /* targetType === "live"
    ? mockArray(5, () => mockUpdatedInformation({}))
    : */ {
  root: mockRichText({}),
};

*
*
*
content: targetContent,

Yeah, content: () => targetContent, does not work also.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant