Specmonstah
  • Introduction
  • Infomercial
  • Tutorial
    • Concepts
    • 01: ent db
    • 02: schemas
    • 03: queries
    • 04: refs
    • 05: progressive construction
    • 06: spec-gen
    • 07: spec gen customization and omission
    • 08: visiting functions
    • 09: performing inserts
    • 10: uniqueness constraint
    • 11: collection constraint (vector of foreign keys)
    • 12: what about cycles?
Powered by GitBook
On this page

Was this helpful?

  1. Tutorial

10: uniqueness constraint

If you're building a forum and want people to be able to like posts, you probably don't want to allow people to like the same post twice. If your schema is something like this:

like

post-id

user-id

Then you probably have a constraint such that you can't have two records with the same post-id and user-id. How do you model this in Specmonstah? So far, we've seen schemas like this:

(ns reifyhealth.specmonstah-tutorial.10
  (:require [reifyhealth.specmonstah.core :as sm]))
  
(def bad-schema
  {:user {:prefix :u}
   :post {:prefix :p}
   :like {:prefix      :l
          :spec        ::like
          :relations   {:post-id       [:post :id]
                        :created-by-id [:user :id]}}})

If you use this to generate ents, you'll end up in a disappointing situation:

(defn ex-01
  []
  (sm/view (sm/add-ents {:schema bad-schema} {:like [[3]]})))
(ex-01)

All the likes reference the same :post (:p0) and :user (:u0). This happens because Specmonstah generates the minimal data needed to satisfy a query.

To get Specmonstah to generate data that your database will accept, you introduce a uniqueness constraint in the schema:

(def good-schema
  {:user {:prefix :u}
   :post {:prefix :p}
   :like {:prefix      :l
          :spec        ::like
          :relations   {:post-id       [:post :id]
                        :created-by-id [:user :id]}
          :constraints {:created-by-id #{:uniq}}}})

Notice the :constraints key at the bottom of the schema. This tells Specmonstah, "The :created-by-id relation of every :like should refer to a unique :user. If you generate multiple :likes, generate new :users too until each like refers to a differ :user."

This schema will generate a graph that will satisfy your database's constraints:

(defn ex-02
  []
  (sm/view (sm/add-ents {:schema good-schema} {:like [[3]]})))
(ex-02)

You could have instead added the :uniq constraint to :post-id, and it would have generated new :posts instead of :users. Give it a try :) Or, try adding the constraint to both :post-id and :created-by-id.

Previous09: performing insertsNext11: collection constraint (vector of foreign keys)

Last updated 5 years ago

Was this helpful?

likes all reference the same post and user
a happy graph