Fork me on GitHub
#om
<
2015-12-02
>
joshfrench01:12:58

just wondering if anyone else has a clean solution for serializing and/or cleaning the results of remote mutations, since the new :result key may include things that transit doesn’t know how to serialize (in our case this is a bunch of Datomic tx info)

dnolen02:12:40

@joshfrench: it’s trivial to elide, just elide it

joshfrench02:12:55

@dnolen: I’m stripping it at the server layer, is it possible to do the same from within the parser itself?

noonian02:12:01

@eguneys: yes, the parser impl in om.next.server is for parsing on the server. :value on the server I believe doesn’t do anything (except for tempids but dont worry about it) except to give a clue to developers about which keys might have changes as a result of the mutation

noonian02:12:19

I also think that is an old style for the :value result. I think the new style is supposed to be a map.

dnolen02:12:02

@joshfrench: I could imagine putting the behavior behind a flag, we can look at later when the more pressing things are sorted out

dnolen02:12:09

until then just handle it yourself

dnolen02:12:11

after parse

dnolen02:12:31

yes om-next-demo is probably out of date now

noonian02:12:55

@eguneys: and about remotes, in @dnolen's example the default read wouldn’t refetch the key automatically. Usually if you caused the change on the client with a transaction you would include the key to be read afterward in the transaction. If the server changed because some other user did something for example you would need a way to push data to the client to tell it to read (for example with websockets or long-polling).

simonb03:12:50

I'm using DataScript. Rendering data as a table. The query and component structure from the root is as below: {:app {:table [{:table-row [...]} {:table-row [...]}] }} I have it setup so I can click on an element in a row and modify the text. The mutate works, the DataScript db is updated. But when the render method of the row is called, it is called with the full props all the way from the root i.e. all of the below: {:app {:table [{:table-row [...]} {:table-row [...]}] }} I was expecting it just to get the props for the row, i.e. like this: {:table-row [...]} All the rows have idents. It seems like there is a missing link between the query and the row, so Om defaults to passing props from the root. Is this right? Anyone have any pointers? Thanks!

codonnell05:12:37

Anyone know how I can interface om.next with a library like Chartist, which does its magic with commands like new Chartist.Line('.ct-line', data)? Is there some way to execute code after a part of the DOM has already been rendered?

tony.kay05:12:07

look at react lifecycle methods...componentDidUpdate

tony.kay05:12:29

but if Chartist messes with the DOM, it is a bad idea

tony.kay05:12:43

(depending on how it messes with the dom)

codonnell05:12:35

Do you have suggestions for other chart libraries that may behave better?

tony.kay05:12:13

not saying you cannot use Chartist...just that your idea about how to integrate needs to be careful

tony.kay05:12:52

remember that react wants to own the DOM, and Om tries to manage the app state and re-rendering

tony.kay05:12:09

so, look for tutorials on integrating that kind of thing with plain React

codonnell05:12:11

I'll do that; thanks.

snufkon08:12:54

Does anyone know how to add a list item(person) for this tutorial? https://github.com/omcljs/om/wiki/Components%2C-Identity-%26-Normalization

snufkon08:12:20

I added a button for RootView and a mutate function.

(defui RootView
  static om/IQuery
  (query [this]
    (let [subquery (om/get-query Person)]
      `[{:list/one ~subquery} {:list/two ~subquery}]))
  Object
  (render [this]
    (println "Render RootView")
    (let [{:keys [list/one list/two]} (om/props this)]
      (apply dom/div nil
             [;; add --------------------------------------------------------
              (dom/button #js {:onClick
                               (fn [e]
                                 (om/transact! this `[(list/add)]))} "add")
              ;; ------------------------------------------------------------
              (dom/h2 nil "List A")
              (list-view one)
              (dom/h2 nil "List B")
              (list-view two)]))))

(defmethod mutate 'list/add
  [{:keys [state]} _ _]
  (let [name "Mike"
        new-person {:name name :points 0}]
    {:action
     (fn []
       (swap! state update :person/by-name assoc name new-person)
       (swap! state update :list/one conj [:person/by-name name]))}))

snufkon08:12:09

When I clicked the button, mutate function is called, but view is not changed. I want to know correct action code to add a person for :list/one.

artemyarulin08:12:56

transact! accept the list of dependent keys that has to be re-read after the mutation, maybe this is a case for that

danielstockton08:12:25

Do I have to implement migrate to update tempids from the server?

danielstockton08:12:45

Just want to make sure I'm on the right track

danielstockton08:12:25

Bonus points if anyone has this stuff already figured out with datascript. I'm not datomic/datascript expert, curious if my implementations are 'correct'

danielstockton08:12:22

my merge-tree looks like :merge-tree (fn [_ data] (doseq [t (vals data)] (d/transact! conn t)) @conn)

griffio10:12:27

@snufkon: You shouldn’t need to do anything else…render will occur as you are transacting from root. Your add person will only work once though due to same identity being created. I have created a gist with a working version. Well works for me! So it must be something else in your code that you didn’t post. https://gist.github.com/griffio/87e3ff9f88d9d8fbc7a5

txus10:12:22

is there a way to use om.next master in a project? I realized after alpha24 David might be aiming for beta 1 and not releasing any more alphas?

griffio10:12:52

@txus I think it was mentioned somewhere but clone the om repo and and then lein install. Add 1.0.0-alpha25-SNAPSHOT to your project deps. If that is what you need to get the latest cut.

griffio10:12:21

@txus don’t forget to do a clean or delete of your js build when upgrading versions 😭

snufkon11:12:24

@griffio: both your and my code didn't work. But after I upgrade om and clojurescript versions both works!

snufkon11:12:42

;; not work 
[org.clojure/clojurescript "1.7.170"]
[org.omcljs/om "1.0.0-alpha22"]

;; work
[org.clojure/clojurescript "1.7.189"]
[org.omcljs/om "1.0.0-alpha24"]

snufkon11:12:06

@griffio: Thank you for your suggestion.

danielstockton13:12:13

Everyone is using atoms over datascript? Wonder why, seeing as although they're easier to understand initially, when you have to introduce all the db->tree and tree->db stuff, they're no longer just atoms.

dnolen13:12:13

@danielstockton: no people are using DataScript but some things are less obvious with DataScript

danielstockton13:12:20

And there doesn't seem to be a good story for using other remotes than datomic yet, anyone tried?

danielstockton13:12:36

Seems atoms may also be easier if you're getting json back from a remote

dnolen13:12:45

Om Next doesn’t require any backend at all

dnolen13:12:54

and can work with REST backends just fine

danielstockton13:12:23

I know but there is more to implement on your own with other backends and i haven't seen any attempts yet

danielstockton13:12:30

Not saying it's difficult, it just isn't the easiest route to 'having something', which is where most people probably are at the moment (experimenting)

dnolen13:12:05

people will figure it out eventually and I doubt it will be much more work over plugging in Datomic

dnolen13:12:23

if you’re programming against microservices a la Falcor - trivial

danielstockton13:12:45

Did I figure out correctly, that implementing a custom migrate is what's needed to update tempids in the datascript case?

danielstockton13:12:42

Do you think there are advantages to using atoms other than they're easier to understand for newcomers?

dnolen13:12:01

looking forward to somebody spending a long weekend coming up with a simple acceptable solution for SQL stores

danielstockton13:12:12

I wonder why you didn't push datascript more, I have a feeling that the query syntax and easy integration with datomic will bring a lot of new people to using datomic (i seem to be one of them)

dnolen13:12:31

@danielstockton: because I don’t care about DataScript or Datomic

dnolen13:12:39

these things are irrelevant to the overall design

dnolen13:12:49

they are just convenient to integrate if you choose to do so

dnolen13:12:43

@danielstockton: yes someone will need to sort through a standard way for dealing with tempid transition in DataScript

dnolen13:12:06

similarly the link feature, but I wrote up a quick prototype with with-db and it seems to work fine

danielstockton13:12:12

I understand it's not relevant to the design but you could have gone with a different 'default'

dnolen13:12:51

integrating with another project is generally never a good default

danielstockton13:12:00

Fair point, I guess i'm thinking that a lot of the normalization stuff could have been omitted and then it's more natural fit than being integrated

danielstockton13:12:44

The normalization stuff didn't need to be core to om, you could have told people that the store needs to be normalized and left it to them

dnolen13:12:58

the normalization stuff is already completely optional

danielstockton14:12:34

Anyone using datascript can give some high level pointers on how things can work? I'm not sure how to 'update' the tempid on the client? Or should I generate a 'real id' in advance that get's sent to the remote?

danielstockton14:12:22

I suppose I could bypass this problem by losing optimistic updates..

danielstockton14:12:36

Only transact on the client once receiving things from the server...

dnolen14:12:35

@danielstockton: or use lookup refs, DataScript supports those

danielstockton14:12:58

Aha, thanks for the tip. This looks like it matches very closely the idea of idents in om

dnolen14:12:27

in fact stolen

danielstockton14:12:53

I sometimes feel confused between ident and lookup ref, in datomic it seems that ident is just the keyword part of a lookup ref

danielstockton14:12:08

In om, do we call them lookup refs or idents? Or what is the clear separation

dnolen14:12:22

lookup refs are Datomic/DataScript thing

dnolen14:12:28

ident is an Om thing

dnolen14:12:58

it just happens to map simply to lookup refs … on purpose

danielstockton14:12:20

so merge-refs is more like merge-idents, or the two terms are interchangeable in om land

dnolen14:12:39

yes should probably fix that, old terminology

dnolen14:12:44

in fact will do so now

chris-andrews15:12:43

@danielstockton: FWIW I experimented a bit with om.next and rethinkdb, and the two were a pretty great fit. The syntax for “plucking” in rethinkdb is basically the datomic/om.next pull syntax

dnolen15:12:01

@danielstockton: fixed in master thanks for pointing that out

dnolen15:12:27

@chris-andrews: that’s cool to hear!

dnolen15:12:48

@danielstockton: the only place where ref is should be used outside of React ref terminology is ref->any and ref->components

danielstockton15:12:19

ok, glad my questions actually help create some clarity

txus15:12:00

I’m observing something strange

dnolen15:12:14

@txus hopefully there will be more information simple_smile

txus15:12:02

I have a RootView component, and a couple of nested components. When transacting a delete from one of the nested components (deleting a record from :app/users), @reconciler seems to have all the expected data after the delete, no problem, but RootView, which is querying it, it gets all the props EXCEPT that :app/users is an empty seq

txus15:12:41

if the @reconciler has the right data, that means the read is somehow failing, right?

dnolen15:12:47

sounds like you might have a bug in your own code

dnolen15:12:58

if you don’t think so then make something minimal that demonstrates the problem

txus15:12:21

yeah, I’m debugging the read. Weird is, it always works before deleting, but not after.

dnolen15:12:28

before doing all that though

dnolen15:12:34

just test parsing

dnolen15:12:59

the whole point of parsing being an a l carte thing is you can test data consistency issues via normal REPL evaluation and normal tests

dnolen15:12:45

whatever the bug maybe I doubt it has anything to do w/ the UI bits or the reconciler

txus15:12:02

yeah, I’ve definitely isolated it in my read function

txus15:12:22

the only thing that I can think of is maybe I’m messing with the data tree in the mutate and after that the read no longer works

txus15:12:25

let’s see

txus15:12:06

actually the only difference between when the read works and when it doesn't

txus15:12:18

is that :app/users is first a vector, and then a seq

txus15:12:22

works with the vector, but not with the seq

dnolen15:12:31

right you can’t put seqs into app state

dnolen15:12:39

the old Om rules apply

dnolen15:12:48

only maps only vectors for the collection types

txus15:12:48

aha! nice, then I just change the mutate to return a vector simple_smile

txus15:12:02

perfect. How come, though? out of curiosity

dnolen15:12:15

because just not interested in supporting them at all

dnolen15:12:38

maps and vectors are also crazy fast and could be amenable to optimization things

txus15:12:26

makes sense

dnolen15:12:03

once you seen that transduction with a vector is nearly as fast as a for loop over a mutable array

dnolen15:12:23

supporting seqs is just … not going to happen

txus15:12:55

that’s okay. just three letters more, vec, after seq operations

txus15:12:59

it worked! yay thanks @dnolen

danielstockton15:12:02

@txus in case you didn't know, some things have vector equivalents mapv, filterv ...

danielstockton15:12:15

i end up using them a lot in cases like this

danielstockton15:12:29

so it may be only 1 more letter

dnolen15:12:08

@danielstockton: those things are less useful now that into takes transducers and generalizes those

danielstockton15:12:57

yeah, i haven't quite grasped the power of transducers yet

txus15:12:06

@danielstockton: oh I didn’t know! Thank you

txus15:12:14

@dnolen: for a single seq / vector pass, into + transducers is still the same as th usual seq / vector operations on their own right?

dnolen15:12:01

seq ops on vectors create chunked seq

dnolen15:12:26

transduction on vectors happens in a for loop on the internal nodes

txus15:12:22

oh, okay

txus15:12:55

also, just in case, does what you mentioned about only maps / vectors in Om apply to sets?

danielstockton15:12:51

txus, think it needs to be associative so that it can know what to rerender

danielstockton15:12:55

so that rules out sets too

txus16:12:40

oh, okay

txus16:12:44

thank you simple_smile

dnolen16:12:38

just maps and vectors for now

dnolen16:12:16

I don’t see any compelling need for sets … could be persuaded but would have demonstrate something that isn’t just about convenience

dnolen16:12:07

note this is just about the data structures involved in query

dnolen16:12:27

you can use sets, whatever as scalar values

pyr16:12:35

hi everyone!

hmadelaine16:12:08

Hi Pierre-Yves !

pyr16:12:19

I must confess I haven't followed om too closely lately

pyr16:12:37

Are there any projects with public code out there that use REST backends with om next

pyr16:12:31

I know it's not perfect to shoot for REST but in plenty of cases it would provide a good transition path

noonian16:12:22

I’d imagine you might make a specific remote for each REST endpoint, and in your send function have different implementations for each one. The endpoint specific code would then take the Om query, translate it into api params for the REST endpoint, hit the endpoint, then translate the response data into something that can be merged into your app state and call the callback passed to send with the transformed data.

pyr16:12:57

this makes sense

noonian16:12:16

I don’t know of any public code examples though

dnolen17:12:17

the remote tutorial does this simple_smile

dnolen17:12:24

Wikipedia is not built on Datomic

dnolen17:12:27

as awesome as that would be

pyr17:12:44

thanks!!

tony.kay19:12:17

I'm reworking the sections on app database and queries in om-tutorial. I'd appreciate feedback if anyone has time to look it over. Note the instructions for startup may have changed. Check the README. https://github.com/awkay/om-tutorial

artemyarulin19:12:16

C_App_Database_Exercises.cljs?

artemyarulin19:12:58

I’ll have a look

Tim19:12:33

is there something in react analogous to get-state and set-state!?

tony.kay19:12:43

@artemyarulin: thanks that and queries...the queries part now has interactive cards for running queries against a real db...I think it is a lot more effective

hmadelaine19:12:55

@tmtwd: yes you can access and set the local state in Om.Now

Tim19:12:04

oops I mean is there something in react analogous to get-state and set-state!

hmadelaine19:12:20

@tmtwd: of course, this is not an Om feature, this is React’s feature. It is well explained on their site

Tim19:12:43

ok, fair enough

hmadelaine19:12:51

@tmtwd: you are welcome

jetmind21:12:27

Hey ! I wonder what is a purpose of path in the env passed to read/mutate functions. Seems like it's always [].

thosmos21:12:28

@dnolen: you wrote that you made a quick prototype (with-db) for making links work with datascript's :db/id. Is this online anywhere we can see it?

dnolen21:12:39

but it’s trivial

dnolen21:12:53

include the relationship in your schema but never populate

dnolen21:12:00

create the data you want to associate on the fly

dnolen21:12:03

query that

thosmos22:12:27

the schema relationship as in the datascript schema? so something like: :some/refs {:db/valueType :db.type/ref :db/cardinality :db.cardinality/many}? And rather than populate the :some/refs field with a vector of ids, compute a vector of om links dynamically and query that?

thosmos22:12:22

what about a config switch in Om to say that when it sees a link like [:db/id 1] to just use 1 instead?

thosmos22:12:57

i suppose that's more of an implementation detail that should be done at the edge between Om on the data store