Skip to content

Instantly share code, notes, and snippets.

'[:find ?e
:where
[?e :db/ident ?i]
[(namespace ?i) ?ns]
[(ground "dustingetz.gender") ?ns]]

This is probably going to be the next iteration of the declarative CRUD metamodel that powers Hyperfiddle. It's just a design sketch, the current metamodel in prod is different. Hyperfiddle is an easy way to make a CRUD app. Hyperfiddle is based on Datomic, a simple graph database with the goal of "enabling declarative data programming in applications."

CRUD UI definition

This extends Datomic pull syntax into something that composes in richer ways. The key idea is that Pull notation expresses implicit joins and thus can be used to declare data dependencies implicitly, without needing to name them. We also handle tempids, named transactions, and hyperlinks to other pages. We satisfy the hypermedia constraint, like HTML and the web.

{identity                                                   ; Pass through URL params to query
 [{:dustingetz/event-registration                           ; virtual attribute identif
; CRUD UI
{identity ; pass through query params, decoded from URL
[{:hfnet/domains ; virtual attribute, resolves to a collection queried
[(:domain/ident {:hf/a :domains/edit}) ; :hf/a means hyperlink to a detail view, not specified here
{:domain/fiddle-database
[:database/uri]}]}
{(hf/new $domains) ; allocates a tempid for a new entity to be created in database $domains
[:db/id
:domain/ident
{:domain/fiddle-database
@dustingetz
dustingetz / datomic-reset-attributes.clj
Created September 19, 2019 00:58
via Francis Avila
(def tx-fns
[{:db/ident :db.fn/reset-attribute-values
:db/doc "Transaction function which accepts an entity identifier, attribute identifier
and set of values and expands to any additions and retractions necessary to
make the final post-transaction value of the attribute match the provided
values. Attribute values must be scalars.
If multiple values are provided on a cardinality-one attribute you will get a
datom conflict exception at transaction time."
:db/fn (d/function
@dustingetz
dustingetz / ordering.clj
Created May 30, 2019 12:46 — forked from joinr/ordering.clj
examples of composeable ordering functions
(ns ordering)
;;We want to pack some information along with
;;our functions so that when our interpreter picks them
;;up, we can determine if the function should be applied
;;directly as a comparator, or if we need to "lift"
;;it into the comparator domain.
(defn ordering? [x] (get (meta x) :ordering))
;;convenience macro to help us create functions with
;;ordering specified in meta
@dustingetz
dustingetz / .cljs
Created May 12, 2019 03:11
react virtualized data grid clojurescript
(defn row [ctx k]
^{:key (pr-str k)}
[:> js/ReactVirtualized.Column
{:label (reagent.core/as-element [hyperfiddle.ui/field [k] ctx])
:dataKey (hypercrud.transit/encode k)
:cellDataGetter
(fn [m]
(let [k (hypercrud.transit/decode (aget m "dataKey"))
ctx (aget m "rowData")
#_#_ctx (hypercrud.browser.context/attribute ctx k)]
[[:db/add "-1000001" :district/region :region/e]
[:db/add "-1000001" :district/name "East"]
[:db/add "-1000002" :neighborhood/name "Capitol Hill"]
[:db/add "-1000002" :neighborhood/district "-1000001"]
[:db/add "-1000003" :community/category "15th avenue residents"]
[:db/add "-1000003" :community/orgtype :community.orgtype/community]
[:db/add "-1000003" :community/type :community.type/email-list]
[:db/add "-1000003" :community/name "15th Ave Community"]
[:db/add "-1000003" :community/url "http://groups.yahoo.com/group/15thAve_Community/"]
[:db/add "-1000003" :community/neighborhood "-1000002"]
[[:db/add "-700968933" :db/ident :community/name]
[:db/add "-700968933" :db/valueType :db.type/string]
[:db/add "-700968933" :db/cardinality :db.cardinality/one]
[:db/add "-700968933" :db/fulltext true]
[:db/add "-700968933" :db/doc "A community's name"]
[:db/add "43126449" :db/ident :community/url]
[:db/add "43126449" :db/valueType :db.type/string]
[:db/add "43126449" :db/cardinality :db.cardinality/one]
[:db/add "43126449" :db/doc "A community's url"]
[:db/add "-1305932792" :db/ident :community/neighborhood]
;; Because in formal logic, ∀x.P(x) = ¬∃x.¬P(x)
(d/q '[:find ?id
:in $ [?interest ...]
:where
[?a :account/id ?id]
(not-join [?a ?interest]
[?a :account/interest ?i]
(not [(= ?i ?interest)]))])
;; It is harder to understand when you bind interest as above if you
(def players-roster-rules
"Rules to test if a collection of players are a subset of the players
in a roster.
Usage Constraints:
- ?players must always be bound
- ?roster may be bound or unbound
Valid Uses:
- test if a specific ?roster contains all ?players