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

Metadata schema #23

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open

Conversation

ianmcorvidae
Copy link
Member

This is not complete, but I was instructed to timebox it to the end of today. I think that these changes should all still be acceptable, but without finishing the remaining namespaces we won't be able to use the merged DB. One possible exception: I suspect that if anything I've changed uses transactions from other parts of the code (i.e. outside the persistence namespaces), those transactions will no longer apply. I was planning to do those after finishing the persistence namespace changes.

(dissoc :select) ;; change to select distinct
(h/select-distinct cols)
(h/where [:in :target_id target-ids]
[:in :target_type (map jtypes/as-other target-types)]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First common change: jtypes/as-other is how we make things with our enums work properly; we don't need our ->enum-val any more.

Comment on lines +12 to +17
(def avu-columns [:id :attribute :value :unit :target_id :target_type :created_by :modified_by :created_on :modified_on])

(defn- avus-base-query
[cols]
(-> (apply h/select cols)
(h/from (t "avus"))))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been doing a pattern like these two definitions in a bunch of places. Basically, have a plain def with the most common setup of columns, plus a whatever-base-query function that takes a list of columns and selects them from the appropriate table. I'm not sure if it's super useful, but it does cut down a little bit at least. May be worth generalizing, idk

[:in :target_type (map jtypes/as-other target-types)]
[:in :attribute attributes]
[:in :value values]))]
(plan/select! ds cols (sql/format q))))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line means:

  • turn the query into SQL + parameters
  • fetch results from the DB defined by ds
  • on each row, run select-keys cols, and return a collection of the results. Or, if the cols slot is not a vector of keywords, it will be applied as a function (which also means, passing a single keyword will extract just that column)

(first (select :avus (where {:id id}))))
(let [q (-> (avus-base-query avu-columns)
(h/where [:= :id id]))]
(plan/select-one! ds avu-columns (sql/format q))))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is exactly like select! but only does it for the first result row, and doesn't return a collection as a result.

Or basically it's the same as running first on the output of the same call with select!. except probably more efficient I guess

Comment on lines +74 to +77
(jsql/insert-multi! ds
(t "avus")
cols
(map fmt-avu avus))))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The format for these bulk inserts is different than korma. For this, we pass a collection of columns, plus a collection-of-collections, where each entry should be a collection corresponding to the columns listed before.

i.e. (:id :attribute ...) and then [("4609ef48-...." "some-attribute" ...), ...]

Comment on lines +100 to +105
(let [insert-vals (jsql/insert! ds
(t "comments")
{:owner_id owner
:target_id target-id
:target_type (jtypes/as-other target-type)
:value comment})]
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unlike the multi-insert, the single insert still takes a map of columns to values.

Comment on lines +137 to +141
(jsql/update! ds
(t "comments")
{:retracted false
:retracted_by nil}
{:id comment-id})
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hopefully fairly self-explanatory how the update works. After DB and table is updates, then conditions.

(aggregate (count :*) :cnt)
(where {:target_id target-id :owner_id user}))
first :cnt pos?))
(let [q (-> (h/select [[:> :%count.* 0] :is_favorite])
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit of a change. I made it do SELECT count(*) > 0 AS is_favorite rather than doing the pos? in clojureland.

Comment on lines 73 to +79
(defn search-classes-subselect
[ontology-version search-term]
(-> (search-classes-base ontology-version search-term)
(subselect (fields :iri))))
(let [search-term (str "%" (format-query-wildcards search-term) "%")]
(-> (h/select :iri)
(h/from (t "ontology_classes"))
(h/where [:= :ontology_version ontology-version]
[:ilike :label search-term]))))
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We weren't using search-classes-base anywhere else, and I think it was an artifact of the select* vs. select vs subselect distinction in korma due to it handling both query generation and execution. With honeysql + next.jdbc they're already separate, so h/select handles all three.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also used ilike instead of lowercasing both sides, which is inconsistent with one other spot. I guess we should check if that affects indexing and maybe use the lowercasing if that's better, but dunno

@@ -198,7 +198,7 @@
(defn update-permanent-id-request
"Records the Permanent ID for a given Request."
[request-id permanent-id]
(sql/update :permanent_id_requests
(ksql/update :permanent_id_requests
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These updates are the bits in progress. I've been changing things over to use the ksql name, since jsql I'm using for next.jdbc. Should go away ultimately anyway.

Copy link
Member

@psarando psarando left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So far so good 👍

:owner_id user})))
(-> (h/select :target_id)
(h/from (t "favorites"))
(h/where [:in :target_type [:inline target-types]]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the avu namespace [:in :target_type (map jtypes/as-other target-types)] was used.
Is it not needed here, or is this an alternative expression?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm... actually not sure. I did this namespace first, so it could be that I actually have it wrong in the other namespace. I think they might work as alternates though -- jtypes/as-other will mark them correctly to be included as bound parameters, while :inline will inline them in the expression rather than using bind parameters at all. I think that since in raw SQL without bind parameters you can basically treat enums like strings, it might just work out the same.

I think this inline version is a bit cleaner, so when I get a chance to get back to this and test it out, I might just use that everywhere I can.

(where {:owner_id user
:target_type [in (map db/->enum-val target-types)]})))
(let [q (-> (h/delete-from (t "favorites"))
(h/where [:in :target_type [:inline target-types]]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question about [:in :target_type (map jtypes/as-other target-types)] here.

Comment on lines +61 to +65
(let [new-values (mapv #(vector (:ontology_version %) (:iri %) (:label %) (:description %)) class-values)]
(jsql/insert-multi! ds
(t "ontology_classes")
[:ontology_version :iri :label :description]
new-values)))))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This LGTM as-is, but alternatively, if we wanted to define the set of update columns only once:

Suggested change
(let [new-values (mapv #(vector (:ontology_version %) (:iri %) (:label %) (:description %)) class-values)]
(jsql/insert-multi! ds
(t "ontology_classes")
[:ontology_version :iri :label :description]
new-values)))))
(let [update-cols [:ontology_version :iri :label :description]
new-values (mapv #(mapv (partial get %) update-cols) class-values)]
(jsql/insert-multi! ds
(t "ontology_classes")
update-cols
new-values)))))

I'm not sure if this way is more confusing, though 🤔

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I think I like your version a bit more. I was trying to avoid having the same lists multiple times, but I think I was also getting a bit hurried by the time I was doing ontologies and didn't think of doing it that particular way.

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

Successfully merging this pull request may close these issues.

2 participants