Commit (old) progress
@ -1 +1 @@
|
||||
{:dev/start-keys [:storage/schema]}
|
||||
{:dev/start-keys []}
|
||||
|
Before Width: | Height: | Size: 502 KiB After Width: | Height: | Size: 1.3 MiB |
Before Width: | Height: | Size: 434 KiB After Width: | Height: | Size: 434 KiB |
@ -1,4 +1,4 @@
|
||||
{:dev/reload-routes? true
|
||||
:jdbc/url "jdbc:pgsql://localhost:55432/souk?user=postgres"
|
||||
:jdbc/admin-url "jdbc:pgsql://localhost:55432/postgres?user=postgres"
|
||||
:instance/domain "dev.squid.casa"}
|
||||
:jdbc/url "jdbc:pgsql://localhost:55432/souk?user=postgres"
|
||||
:jdbc/admin-url "jdbc:pgsql://localhost:55432/postgres?user=postgres"
|
||||
:instance/origin "https://dev.squid.casa"}
|
||||
|
@ -1 +1,99 @@
|
||||
(ns lambdaisland.souk.db)
|
||||
(ns lambdaisland.souk.db
|
||||
(:require
|
||||
[charred.api :as json]
|
||||
[lambdaisland.souk.activitypub :as activitypub]
|
||||
[lambdaisland.souk.sql :as sql]
|
||||
[next.jdbc.result-set :as rs]
|
||||
[next.jdbc :as jdbc]))
|
||||
|
||||
(defn pg-coerce [val]
|
||||
(cond
|
||||
(instance? java.time.ZonedDateTime val)
|
||||
(.toOffsetDateTime val)
|
||||
:else
|
||||
val))
|
||||
|
||||
(defn upsert-sql [table entity props]
|
||||
(into [(sql/sql 'insert-into table
|
||||
(cons :rdf/props
|
||||
(map key entity))
|
||||
'values
|
||||
(repeat (inc (count entity)) '?)
|
||||
'on-conflict [:raw "(\"rdf/id\")"]
|
||||
'do
|
||||
'update-set
|
||||
(into [:bare-list]
|
||||
(map (fn [[k]]
|
||||
[k '= '?]))
|
||||
entity))]
|
||||
(cons
|
||||
(json/write-json-str props)
|
||||
(concat
|
||||
(map (comp pg-coerce val) entity)
|
||||
(map (comp pg-coerce val) entity)))))
|
||||
|
||||
(defn upsert! [{:keys [ds schema] :as conn} entity]
|
||||
(let [rdf-type (:rdf/type entity)
|
||||
{:keys [table properties]} (get schema rdf-type)
|
||||
known-props (keys properties)
|
||||
json-props (apply dissoc entity known-props)
|
||||
_
|
||||
(assert table (str "Don't know how to store "
|
||||
(if rdf-type rdf-type (str "entity " entity))))
|
||||
entity-props (into {}
|
||||
(map (fn [[k v]]
|
||||
[k
|
||||
(let [type (get properties k)]
|
||||
(case type
|
||||
'rdf/iri
|
||||
(activitypub/kw->iri
|
||||
(if (map? v)
|
||||
(do
|
||||
(upsert! conn v)
|
||||
(:rdf/id v))
|
||||
v))
|
||||
v))]))
|
||||
(select-keys entity known-props))]
|
||||
(jdbc/execute! ds (upsert-sql table entity-props json-props))))
|
||||
|
||||
(defrecord MyMapResultSetBuilder [^java.sql.ResultSet rs rsmeta cols]
|
||||
rs/RowBuilder
|
||||
(->row [this] (transient {}))
|
||||
(column-count [this] (count cols))
|
||||
(with-column [this row i]
|
||||
(rs/with-column-value this row (nth cols (dec i))
|
||||
(if (= java.sql.Types/TIMESTAMP_WITH_TIMEZONE (.getColumnType rsmeta i))
|
||||
(.getObject rs ^Integer i ^Class java.time.OffsetDateTime)
|
||||
(rs/read-column-by-index (.getObject rs ^Integer i) rsmeta i))))
|
||||
(with-column-value [this row col v]
|
||||
(assoc! row col v))
|
||||
(row! [this row] (persistent! row))
|
||||
rs/ResultSetBuilder
|
||||
(->rs [this] (transient []))
|
||||
(with-row [this mrs row]
|
||||
(conj! mrs row))
|
||||
(rs! [this mrs] (persistent! mrs)))
|
||||
|
||||
(defn my-builder
|
||||
[rs opts]
|
||||
(let [rsmeta (.getMetaData rs)
|
||||
cols (rs/get-unqualified-column-names rsmeta opts)]
|
||||
(->MyMapResultSetBuilder rs rsmeta cols)))
|
||||
|
||||
(defn retrieve [{:keys [ds schema] :as conn} type iri]
|
||||
(let [{:keys [table]} (get schema type)]
|
||||
(let [{:rdf/keys [props] :as result}
|
||||
(jdbc/execute-one! ds [(sql/sql 'select '* 'from table 'where :rdf/id '= '?)
|
||||
(str iri)]
|
||||
{:builder-fn my-builder})]
|
||||
(when result
|
||||
(merge (dissoc result :rdf/props)
|
||||
(doto (json/read-json props :key-fn keyword) prn))))))
|
||||
|
||||
;; (upsert!
|
||||
;; (user/value :storage/db)
|
||||
;; p)
|
||||
|
||||
;; p
|
||||
|
||||
;; (retrieve (user/value :storage/db) :activitystreams/Actor "http://example.com/users/amber30")
|
||||
|
@ -0,0 +1,60 @@
|
||||
(ns lambdaisland.souk.factories
|
||||
(:require
|
||||
[clojure.string :as str]
|
||||
[lambdaisland.facai :as f]
|
||||
[lambdaisland.faker :as faker]
|
||||
[lambdaisland.uri :as uri]))
|
||||
|
||||
(defn fake [faker]
|
||||
(fn []
|
||||
(faker/fake faker)))
|
||||
|
||||
(def now #(java.time.Instant/now))
|
||||
|
||||
(def ^:dynamic *origin* "http://example.com")
|
||||
|
||||
(defn local-uri [& parts]
|
||||
(str (uri/join *origin* (str "/" (str/join "/" parts)))))
|
||||
|
||||
(f/defactory Person
|
||||
{:rdf/type :activitystreams/Person
|
||||
:souk/origin (fn [] *origin*)
|
||||
:activitystreams/name (fake #{[:simpsons :characters] [:tolkien :characters]})
|
||||
:activitystreams/summary (fake [:lorem :sentence])
|
||||
:activitystreams/published now}
|
||||
|
||||
:after-build
|
||||
(fn [ctx]
|
||||
(f/update-result
|
||||
ctx
|
||||
(fn [{:activitystreams/keys [name] :as res}]
|
||||
(let [username (str (str/lower-case (first (str/split name #" ")))
|
||||
(rand-int 100))]
|
||||
(assoc res
|
||||
:rdf/id (local-uri "users" username)
|
||||
:activitystreams/preferredUsername username
|
||||
:activitystreams/url (local-uri "u" username)
|
||||
:ldp/inbox (local-uri "users" username "inbox")
|
||||
:activitystreams/outbox (local-uri "users" username "outbox")))))))
|
||||
|
||||
(f/defactory Note
|
||||
{:rdf/id (local-uri "/notes/" (rand-int 999999999))
|
||||
:rdf/type :activitystreams/Note
|
||||
:activitystreams/attributedTo Person
|
||||
:activitystreams/content [:lorem :sentence]})
|
||||
|
||||
(binding [*origin* "https://dev.squid.casa"]
|
||||
(Person))
|
||||
|
||||
(Note)
|
||||
|
||||
(binding [*origin* "https://dev.squid.casa"]
|
||||
(lambdaisland.souk.db/upsert!
|
||||
(user/value :storage/db)
|
||||
(Person)
|
||||
))
|
||||
|
||||
@plexus@toot.cat
|
||||
https://toot.cat/users/plexus
|
||||
https://toot.cat/@plexus
|
||||
acct:plexus@toot.cat
|
Before Width: | Height: | Size: 507 KiB After Width: | Height: | Size: 527 KiB |
Before Width: | Height: | Size: 435 KiB After Width: | Height: | Size: 436 KiB |