What's it called when you have a primary table (le...
# orm-help
m
What's it called when you have a primary table (let's say
posts
) with a column called
type
and if
type
is set to
"public"
you join the
PublicPosts
table and if it's set to
"private"
, it joins another table. I think django has this kind of support. Does Prisma support something like this?
I tried to make my question generic but heres my specific scenario. I have a cron job that goes through a list of websites. Each row in my column has a "processor" enum, with a few options such as:
RSS
,
MetaTags
,
Scrape
, etc. Based on that enum, different code will run. The problem I'm running into is that for each option there are different configuration options. For example, one example would be for
Scrape
, I might have an option called
respectRobotsTxt
. That column wouldn't apply to the other two options. I currently have a JSONB, but it's not very typesafe at all. I was wondering if Prisma has an inbuilt way in the query to somehow manipulate the
include
? Or maybe should my query include all the different columns and based on the enum value, select the correct table?
Is this the idea solution? Psuedo code:
Copy code
const websites = prisma.websites.findMany({
  include: {
    websiteRssSettings: true,
    websiteScraperSettings: true,
    websiteMetaTagsSettings: true,
  }
})

websites.forEach((website) => {
  if (website.processor === 'RSS') {
    website.websiteRssSettings
    // ...
  }
  if (website.processor === 'Scraper') {
    website.websiteScraperSettings
    // ...
  }
  if (website.processor === 'MetaTags') {
    website.websiteMetaTagsSettings
    // ...
  }
})
I wondering if there is any way I can use the referential actions to somehow further increase the integrity? Somehow say that
if processor == rss, there must be a row in websiteRssSettings
i
Sounds like a polymorphic relation, although I'm not sure if that's the common term. Maybe you could invert the dependency relation between websites and rss/scraper/metatags? Introduce some relation table that includes all four entities:
Copy code
model WebsiteProcessor {
  website WebSite @unique
  rss Rss?
  scraper Scraper?
  meta MetaTags?
}

model Website {
   ...
   + processor WebsiteProcessor
}
you can use this pattern to 1:1 relate a website to a configuration. Then when you do:
Copy code
prisma.websites.findMany({
  include: {
    processor: {
      include: { rss: true, meta: true, scraper: true }
    }
  }
});
your resulting websites will each have stored their correct processor content (plus some garbage nulls, but hey) via the inverted processor relation
Additionally, gonna point out
edge-db
real quick, as it has an approach that addresses this precise issue, without being a NoSQL database: https://www.edgedb.com/docs/edgeql/select#polymorphic-queries https://www.edgedb.com/docs/clients/01_js/select#polymorphism https://www.edgedb.com/docs/datamodel/inheritance
m
Hmmm, makes sense. In your example, what is the purpose of
WebsiteProcessor
? i.e. why can't I just directly put the
rss, scraper, meta
onto
websites
itself? Is there some future flexibility I'm missing?
Edgedb actually looks pretty cool! Too late to switch now unfortunately
i
Yeah! I'm really excited about it. But back to putting website processor on website itself
I think that's also a correct solution, as you could just move the relations onto the
website
table.
Copy code
model website {
  ...
  rss Rss?
  scraper Scraper?
  meta MetaTags?
}
m
Yep that was what I was thinking. Just to make sure, you don't see any other benefits with
WebsiteProcessor
other than the organization aspect?
i
Well I'm trying to think if there's anything, but nothing comes to mind. I think it ultimately boils down to preference. There have been a handful of times where I tried to create a model where there are shortcuts around dependencies: For instance, in my case, a Batch -> Document -> File, but also Batch -> File. Because of the way prisma expects us to introduce backlinks whenever we embed a model on another model, that was having some strange effects where I had to, on the
@relation
annotation, specify some update/delete cascade-termination rules, if memory serves.
I'd be interested if you run into such issues, needing to specify
onDelete/onUpdate
in your
@relation
if you go the emedded-on-website route!
m
I actually do want to make use of
onDelete
cascade so that if the website is deleted, its config is also deleted. Seems like it should be an issue but I can always report back and tag you if I regret my choice! 😛
🙌 1
j
There are a bunch of issues about similar things in the Prisma repo - searching for "polymorphic" should help you find them. Additional use cases and voices are always welcome in those.
👀 1
i
Cool, thanks for the tip!
👍 1