Hi guys - running into a problem that I'm sure must be easy to solve: I need to mutate (specifically, to entirely replace) a normalized part of the db, but not sure how to go about it. Have tried (swap! state assoc-in [:field-1 :field-2] vector-of-maps)
and (swap! state assoc :normalized/by-id map-of-stuff)
but neither work. Have previously used the latter to successfully mutate fields within the normalized data, but I'm guessing I can't do that here (as it hasn't worked)? Have also experimented with tree->db
, also with no joy. Any pointers?
I think tree->db
is what you want, with a true
third argument.
and (swap! state update merge result)
@carter.andrewj: when you say it doesn't work, have you looked at the state in the REPL to see what it is like before and after the mutation?
Yeah - in each case, the result is:
(swap! state assoc-in [:field-1 :field-2] vector-of-maps)
= [{} {} {}]
(essentially emptying the 3 entries that were there before
(swap! state assoc :normalized/by-id map-of-stuff)
= No change whatsoever
tree->db
(or my previous attempt thereof) = Uncaught Error: ... is not ISeqable
Will try now with the true
arg
What's the full ISeqable error?
(swap! state assoc-in [:normalized/by-id 20] map-of-stuff)
- I would think that would be replacing the whole 'table record' that is held at the ident [:normalized/by-id 20]
.
@danielstockton Are you asking for the full stacktrace? The "..." is part of the error (presumably referring to the recursive part of the query in question).
Oh, I see.
No joy with tree->db. Which query should I be providing it? The root, the parent component, or the normalized component?
The parent component I think (one with the join).
Hmmm, that's what I'm currently trying
Let me throw a few print statements in - make sure I've not cocked something else up while changing things around
None of the inputs seem obviously wrong
If the query in question is [:foo :bar :normalized-thing {:more :fields}]
then I should be passing to tree->db
something like this: {:foo "x" :bar "y" :normalized-thing [:stuff :etc]}
right?
Okay - I'm definitely doing something wrong with tree->db
, the only change that happens to the input is that this gets added: {:om.next/tables #{}}
Do you mean [:foo :bar {:normalized-thing [:more :fields]}]
?
And you should be passing tree->db
{:normalized-thing [{...} {...} ...]}
Yes, sorry - that is the correct and current form of the query
I've fixed the above issue with no change happening in tree->db
(forgot to revert a change I made during the earlier trial and error) and am now getting what looks like the expected result
However - the output has two main keys - :view-map
and :view/by-id
which are the non-normalized and normalized fields respectively
:view-map
is now a vector of idents, as expected; and :view/by-id
is the normalized input, also as expected
But - inspecting the app-state: :view-map
is a child several layers from the root of the app-state, while :view/by-id
sits at the root
So presumably I cannot just use (swap! state update merge result)
with this output...?
(Well, I know I can't, because that's what it's still unsuccessfully set to try)
You'll have to merge it into app-state wherever your parser expects it to be.
I think :om.next/tables #{}
should be at the root of the appstate though
But the output of tree-db is giving me things from different parts of the app state - one from the root, one from 2 levels deep
Do I need to merge the new :view-map
into the app state, then pass that to tree->db
with the root query...?
(Seems like overkill)
Or should I deconstruct the output of tree->db
(and perform two merges)? Which seems brittle...
It sounds like you might want to rethink the queries to avoid duplicating the list in multiple places.
Duplicating the list?
Not sure I follow
The list only appears in one place in the raw app-state
The multiple places is done by om's normalization
I thought :view-map
was the list of idents.
Only after normalization
does (merge-with merge app-state result)
help merge both parts in a single merge?
Not really
The result has both keys at the same level, whereas they need to merge :view/by-id
to the root and :view-map
at [:analytics :dashboards]
I could break both out of the result and merge them independently - but that doesn't seem like it's how this is designed to work (so I'd worry I'm setting myself up for more pain further down the line...)
gotcha, sounds like the new data has a different shape from the old data. I think you'd probably have to pick apart the result and merge yourself. Otherwise, need to redesign the app-state.
Maybe my understanding of normalization is off? - as I understand it you start with {:foo {...} :bar {...} :stuff {:view-map [{...} {...} {...}]}}}
and then get {:foo {...} :bar {...} :stuff {:view-map [ident ident ident]} :view/by-id {id1 {...} id2 {...} id3 {...}}}
...?
Should :view/by-id
not end up in the root? (i.e. have I got something wrong with my idents, etc... elsewhere)
That's right, but if the list of idents is nested under [:analytics :dashboards]
it means that your original data was deeply nested following this structure?
Yes, that is correct
But the novelty you want to merge doesn't have this nesting so I think it's on you to merge it back into app-state in the correct location.
Okay, that shouldn't be an issue
It doesn't feel right, but I get that a lot with om
Cheers, @danielstockton - that's working now
However, it doesn't appear to be treating the new entries in the normalized data as new - but rather as updates to the old entries
i.e. If there are 2 entries in the original data and 4 in the new, componentWillMount
only fires for 3 and 4
Is this the expected behaviour?
The other components (existing idents) are probably already mounted so they'll fire componentWillUpdate
instead?
Except the idents are changing
1 and 2 have completely different data (with the same shape) after the mutate
And they re-render with the new data
But they don't fire WillMount
(which creates a problem, as that's where they set up a lot of initial conditions that then describes and triggers data to be pulled from a remote)
I could get round this via WillUpdate
, but I suspect it's a symptom of me having done something wrong elsewhere
Can't say I've come across this.
Where is the new data coming from and how are you merging it in? Also, is the parent component being re-read?
The parent component is being re-read. If new-data = normalized data from above, that's built in the mutate
from a config stored elsewhere in the app state.
(If you mean the data from the remote, that's coming down from an external postgresDB)
No worries for now - I need to go and grab some lunch anyway
Thanks for taking the time
No worries.
Can anyone help me out with what Iām doing wrong when checking in clj for om next component protocol ? Satisfies? always returns false (on cljs implements? works) ex: (satisfies? om/IQuery Item)
(extends? om/IQuery Item)
@claudiu ?
satisfies?
expects an instance, not a class.
There is also an (om/iquery? Item)
function for this in om core.
https://github.com/omcljs/om/blob/master/src/main/om/next.cljc#L737
@danielstockton thank you. Will try it out.