open-source-ideas / ideas

💡 Looking for inspiration for your next open source project? Or perhaps you've got a brilliant idea you can't wait to share with others? Open Source Ideas is a community built specifically for this! 👋
6.56k stars 221 forks source link

GraphQL Syntax for selecting data in a Immutable.js Structure #4

Open mikaelbr opened 7 years ago

mikaelbr commented 7 years ago

Project description

I often use Immutable.js as a datastructure for my applications. Destructuring doesn't work to well with it and I can see some added value in being able to do GraphQL-type querying for the nested datastructure. There are projects such as vacuumlabs/babel-plugin-extensible-destructuring, and you can destructure an immutable structure that has been .toObject()-ed or .toJS()-ed. But neither of those solve the problem I've been thinking of, and they seem pretty non-performant.

By supporting something like GraphQL querying, you could do things like fragments that you can't do with destructuring. You could also make it much more performant, only selecting the data you want.

I was thinking one could do an API such as

const data = select(`{
  person {
    firstName,
    lastName
  }
}`, immutableStructure);

And that can also be used for component based libraries/frameworks such as React.js:

const MyConnectedComponent = connectData(`{
  person {
    firstName,
    lastName
  }
}`, MyExistingComponent);

... and that'll select the data in the current schema from the props passed to MyExistingComponent. This would probably be it's own library. So this issue can be for two projects.

Maybe something like https://www.npmjs.com/package/graphql-parser can be used for this project.

Relevant Technology

JavaScript, GraphQL, Immutable.js, Possibly React.js (but that should probably exist in it's own project).

Who is this for

This requires some knowledge of GraphQL or Immutable.js. Both isn't that hard to get an understanding of, but it's something to consider. I think this can be more advanced and take some time considering you have to have some knowledge of existing technologies. But it's not too big of a project code line-wise.

priithaamer commented 7 years ago

Interesting idea. Being a heavy user of both Immutable.js and GraphQL, i'd like to tinker around with this.

mikaelbr commented 7 years ago

Cool! Interested in seeing how it works out. I haven't done a proof of concept or anything, just an idea I've been having.

tomlagier commented 6 years ago

I think I'm going to work on this. I'm going to start with a higher order function that takes a graphql query string, parses it with graphql-tag, and returns a function that accepts an immutable map. It will use the parsed representation of graphql to select state out of the map. You can use it as a way to generate mapStateToProps functions, something like:

class UserAvatar extends Component { ... }
const CURRENT_USER = 'query { currentUser { id name avatar }}';
componentWithUser = connect(graphqlImmutableSelector(CURRENT_USER))(UserAvatar);
tomlagier commented 6 years ago

Finished a quick POC project. Check it out here: https://github.com/tomlagier/graphql-immutable-selector

bowbahdoe commented 6 years ago

Curious as to the use of this. Since presumably, this selector DSL wouldn't change the structure of the data, what is the benefit of doing this over simply having your component only read the data it is interested in versus explicitly making a smaller map?

The big benefit of graphql is that it can decouple how a service provides data and optimize the data that needs to be fetched. When you are inside of a React component and you are passed data in the form of an Immutable.js data structure, there really shouldn't be a reason to further decouple data providing (the data has already been computed by whatever means by the time it gets to the component, there are no more steps to abstract over), and I doubt that there are optimization concerns that are addressed by "shrinking" your data structure in this way.

That being said, I am open to being convinced.

Edit: Ignore me and my negativity.

Heres some clojure code I wrote to accomplish something similar with just data structures instead of a graphql dsl that I wrote in response to this that I am a little proud of.

(defn select [selections ds]
  (into {}
    (for [selection selections]
      (if (vector? selection)
        [(first selection)
         (select (second selection) 
                 (get ds (first selection)))]
        [selection (get ds selection)]))))

(println 
  (select [:a :b [:c [:c1 :c2]]] 
          {:a 1
           :b 2
           :c {:c1 3
               :c2 4}
           :d 10
           :f {:f1 10
               :f2 20}}))

;; {:a 1, :b 2, :c {:c1 3, :c2 4}}

In general, if just data will do, its worth taking time to consider if you really need a macro/dsl.