Giter VIP home page Giter VIP logo

subgraph's People

Contributors

den1k avatar julienfantin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Forkers

p-himik dazld

subgraph's Issues

readme edits

Clarifications

  • make clear that subgraph is based on a fork of mapgraph
  • explain the tradeoffs of decomplecting the component tree from the shape of the data - om.next

Examples

  • interactive tutorial using re-frame and subgraph

Consider using tree structure for entities

Right now SubGraph stores entities directly in app-db under keys that look like [:some-keyword some-key-value]. It makes it incredibly hard to look at app-db with the naked eye or with tools like https://github.com/flexsurfer/re-frisk. I think it would make sense to use a tree structure and store the entities like {:some-keyword {some-key-value some-value}}.
So instead of e.g. this

{[:a/id 1] {:id 1 :name "x"}
 [:a/id 2] {:id 2 :name "y"}}

it would be this

{:a/id {1 {:id 1 :name "x"}
        2 {:id 2 :name "y"}}}

How to nest subgraph db inside reframe's app_db

@julienfantin thank you for this fantastic library. I'm just getting started with it in my re-frame app. I have a certain structure for my re-frame app_db and would like to stick a subgraph db under the :subgraph key like so:

(def default-db
  {
    :ui { ... }
    :subgraph (-> (subgraph/new-db)
                  (subgraph/add-id-attr
                    :user/name
                    :color/hex))
    :server { ... }
  }
)

Is this possible? I managed writing to it with this event handler for :add using re-frame's path interceptor:

(re-frame/reg-event-db
 :add-subgraph
 [(re-frame/path :subgraph)]
 (fn [db-sg [_ & entities]]
   (apply subgraph/add db-sg entities)))

However I'm having trouble with my subscriptions, and I can't pinpoint the cause. Here is my generic query subscription:

(re-frame/reg-sub
 :sg-query
 (fn [db [pattern lookup-ref]]
   (subgraph.reframe/pull (db :subgraph) pattern lookup-ref)))

Do you think this should work?

Thank you for your help.

readme edits

  • make clear that subgraph is based on a fork of mapgraph
  • explain the tradeoffs of decomplecting the component tree from the shape of the data - om.next

Decide on a convention for re-frame handlers registration

  1. Should we provide a registration function that registers the pull handler?
    Yes: nobody likes setup
    No: we'd need to answer the remaining questions

  2. If yes, should we define the sub id?
    Yes: it's good to standardize usage
    No: we'd need to answer the remaining question

  3. If yes, should the sub id be fully-qualified?
    Yes: everything should be, and it forces a require which means we could register as a top-level
    No: Right now it'd be :vimsical.subgraph.re-frame/pull which I can't think of a good alias for

Removing entities

Removing entities can be achieved with (dissoc db (ref-to db my-entity)).

This is undocumented and it is a subtle operation, because:

  • It will leave dangling refs in entities who join my-entity
  • During query parsing pull ignores refs and colls of refs that do not resolve
  • Essentially using pull gives the expected result, but the db is an inconsistent state.

If db-level consistency is desirable, we could maintain an index during add and remove that'd allow a fast reverse lookup on the removed ref, to the refs and attributes pointing to it:

{<ingress-ref> {<egress-ref> <from-attr>}}

This would give us a add and remove operations in time linear to the number of joins.

Pull protocol

The pull api was extend by adding an options map used to parametrize database accessors in the query parser. While this allowed pull to work with ratoms as well as maps, it is not idiomatic and caused our implementation to diverge from MapGraph's.

We could simplify the pull api and bring it closer to its original implementation by defining a pull protocol:

(defprotocol Pull
  (ref? [db x])
  (get-ref [db ref]))

Pros

  • Would simplify the implementation of pull
  • Would make it easier to integrate upstream
  • Would make the api more extensible (though extending the parser is still a non-goal)

Cons

  • Would need to ship 6 implementations: hash and array maps for clj and cljs, plus ratom and atom
  • Last time I checked cljs protocols incurred a non-negligible performance overhead compared to simple functions. We should definitely run some cljs benchmarks before and after these changes.

Notes

  • Quick comparison of fn vs protocol performance in cljs
(def iterations 1e5)

(defn inc-in-map [x {:keys [inc-fn]}] (inc-fn x))

(let [options {:inc-fn inc}]
  (time (dotimes [_ iterations] (inc-in-map 1 options))))

;;  Compare extend-protocol vs. extend-type

(defprotocol IInc
  (inc-extend-protocol [_])
  (inc-extend-type [_]))

(extend-protocol IInc
  js/Number
  (inc-extend-protocol [x] (inc x)))

(extend-type js/Number
  IInc
  (inc-extend-type [x] (inc x)))


(time
 (dotimes [_ iterations]
   (inc-extend-protocol 1)))

(time
 (dotimes [_ iterations]
   (inc-extend-type 1)))

;; Running on node with optimizations :none
;; "Elapsed time: 16.626681 msecs"
;; "Elapsed time: 8.267159 msecs"
;; "Elapsed time: 9.751357 msecs"

;; Running on node with optimizations :advanced
;; "Elapsed time: 27.000000 msecs"
;; "Elapsed time: 8.000000 msecs"
;; "Elapsed time: 8.000000 msecs"

Consider using re-frame's subscription cache in the query parser

The parser implementation for re-frame currently uses reagent's make-reaction thus bypassing the re-frame subscription cache.

We could and probably should leverage the cache by automatically registering our subscription handler and instead use re-frame/subscribe in the parser's implementation.

We also currently don't have benchmarks for the re-frame integration and should write those first in order to compare the performance.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.