Fork me on GitHub
#om
<
2017-06-22
>
carter.andrewj11:06:29

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?

danielstockton11:06:17

I think tree->db is what you want, with a true third argument.

danielstockton11:06:41

and (swap! state update merge result)

cjmurphy11:06:11

@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?

carter.andrewj11:06:26

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

carter.andrewj11:06:36

Will try now with the true arg

danielstockton11:06:42

What's the full ISeqable error?

cjmurphy11:06:35

(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].

carter.andrewj11:06:29

@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).

carter.andrewj11:06:36

No joy with tree->db. Which query should I be providing it? The root, the parent component, or the normalized component?

danielstockton11:06:22

The parent component I think (one with the join).

carter.andrewj11:06:16

Hmmm, that's what I'm currently trying

carter.andrewj11:06:37

Let me throw a few print statements in - make sure I've not cocked something else up while changing things around

carter.andrewj12:06:54

None of the inputs seem obviously wrong

carter.andrewj12:06:06

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?

carter.andrewj12:06:50

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 #{}}

danielstockton12:06:16

Do you mean [:foo :bar {:normalized-thing [:more :fields]}]?

danielstockton12:06:27

And you should be passing tree->db {:normalized-thing [{...} {...} ...]}

carter.andrewj12:06:48

Yes, sorry - that is the correct and current form of the query

carter.andrewj12:06:18

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

carter.andrewj12:06:37

However - the output has two main keys - :view-map and :view/by-id which are the non-normalized and normalized fields respectively

carter.andrewj12:06:18

:view-map is now a vector of idents, as expected; and :view/by-id is the normalized input, also as expected

carter.andrewj12:06:20

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

carter.andrewj12:06:19

So presumably I cannot just use (swap! state update merge result) with this output...?

carter.andrewj12:06:41

(Well, I know I can't, because that's what it's still unsuccessfully set to try)

danielstockton12:06:09

You'll have to merge it into app-state wherever your parser expects it to be.

danielstockton12:06:35

I think :om.next/tables #{} should be at the root of the appstate though

carter.andrewj12:06:59

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

carter.andrewj12:06:31

Do I need to merge the new :view-map into the app state, then pass that to tree->db with the root query...?

carter.andrewj12:06:35

(Seems like overkill)

carter.andrewj12:06:02

Or should I deconstruct the output of tree->db (and perform two merges)? Which seems brittle...

danielstockton12:06:02

It sounds like you might want to rethink the queries to avoid duplicating the list in multiple places.

carter.andrewj12:06:23

Duplicating the list?

carter.andrewj12:06:29

Not sure I follow

carter.andrewj12:06:42

The list only appears in one place in the raw app-state

carter.andrewj12:06:49

The multiple places is done by om's normalization

danielstockton12:06:54

I thought :view-map was the list of idents.

carter.andrewj12:06:02

Only after normalization

danielstockton12:06:12

does (merge-with merge app-state result) help merge both parts in a single merge?

carter.andrewj12:06:26

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]

carter.andrewj12:06:28

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...)

danielstockton12:06:13

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.

carter.andrewj12:06:59

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 {...}}} ...?

carter.andrewj12:06:38

Should :view/by-id not end up in the root? (i.e. have I got something wrong with my idents, etc... elsewhere)

danielstockton12:06:02

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?

carter.andrewj12:06:17

Yes, that is correct

danielstockton12:06:45

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.

carter.andrewj12:06:04

Okay, that shouldn't be an issue

carter.andrewj12:06:30

It doesn't feel right, but I get that a lot with om

carter.andrewj13:06:22

Cheers, @danielstockton - that's working now

carter.andrewj13:06:14

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

carter.andrewj13:06:51

i.e. If there are 2 entries in the original data and 4 in the new, componentWillMount only fires for 3 and 4

carter.andrewj13:06:59

Is this the expected behaviour?

danielstockton13:06:33

The other components (existing idents) are probably already mounted so they'll fire componentWillUpdate instead?

carter.andrewj13:06:59

Except the idents are changing

carter.andrewj13:06:35

1 and 2 have completely different data (with the same shape) after the mutate

carter.andrewj13:06:46

And they re-render with the new data

carter.andrewj13:06:33

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)

carter.andrewj13:06:05

I could get round this via WillUpdate, but I suspect it's a symptom of me having done something wrong elsewhere

danielstockton13:06:02

Can't say I've come across this.

danielstockton13:06:26

Where is the new data coming from and how are you merging it in? Also, is the parent component being re-read?

carter.andrewj13:06:41

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.

carter.andrewj13:06:02

(If you mean the data from the remote, that's coming down from an external postgresDB)

carter.andrewj13:06:15

No worries for now - I need to go and grab some lunch anyway

carter.andrewj13:06:20

Thanks for taking the time

claudiu14:06:29

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)

danielstockton14:06:02

(extends? om/IQuery Item) @claudiu ?

danielstockton14:06:40

satisfies? expects an instance, not a class.

danielstockton14:06:28

There is also an (om/iquery? Item) function for this in om core.

claudiu14:06:22

@danielstockton thank you. Will try it out.