Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parsing graphql queries #6

Open
agzam opened this issue Sep 24, 2021 · 5 comments
Open

Parsing graphql queries #6

agzam opened this issue Sep 24, 2021 · 5 comments

Comments

@agzam
Copy link

agzam commented Sep 24, 2021

Sean, first of all, let me thank you for this awesome library. I just wanted to make something very small first, and I hope if I'm able to make something useful out of it, maybe I'll eventually turn it into a package. I just started playing with ghub and this package, and indeed it looks very nice.

This is not an issue, more like a question. How do you parse existing graphql queries (text) into lisp structures that later can be fed into (graphql-query)?

@vermiculus
Copy link
Owner

Like a hypothetical graphql-decode? Interesting idea 😄

I might approach it using a two-step process:

  1. Use a stack-based parser to get the overall structure of the query (i.e., matching braces, quotes, and other paired delimiters). For something like query { foo(bar: baz) { qux } }, this might get you the list ("query" (braces "foo" (parens "bar: baz") (braces "qux"))).
  2. Have a recursive function emit the actual graphql.el data structures when given a basic list structure like the above. At this point, you'd be able to use generic pattern-matching tools (pcase and the like) which should make an implementation more straightforward to understand.

The other big option (other than just writing an imperative parser in one pass) is to use a third-party tool to parse the GraphQL into something more consumable, like JSON. I found this with a two-minute google search -- https://www.npmjs.com/package/graphql-query-to-json -- I don't know if it's any good, but I suspect similar tools are out there. Depending on your actual need, that might serve you well 😄

@agzam
Copy link
Author

agzam commented Sep 26, 2021

Thank you for your recommendations. For some reason, I thought there something like this existed already in elisp form. I'm now thinking, maybe it's best to keep the queries in .graphql files and simply parameterize them. But I don't know how exactly to pick up a specific query alongside the fragments from a big file of queries. You see, I don't want to keep a single file per query, I'd rather have multiple (possibly) related queries in a single .graphql file. But I don't see any mechanisms in elisp to pick a named query and compose the full query out of fragments, so it can then passed into (ghub-graphql) function, for example.

@vermiculus
Copy link
Owner

You could define a format delimited by ^L, for instance -- that character is often used as a section separator (IIRC):

^L#some-name and a comment explaining it
query { foo }
^L#some-other-name and a comment explaining this one, too
query { bar }

Nevertheless, I would recommend using separate files. It's just easier, to be honest 😄

Keeping your GraphQL as GraphQL will also allow you to re-use those queries more easily between different platforms. That's come in handy, although admittedly only a few times.

@agzam
Copy link
Author

agzam commented Sep 27, 2021

I think the way how it's done (I've seen in projects talking to graphql back-ends) you store multiple (usually parametrizable) queries alongside with their fragments in a single .graphql file and then to "execute" one of those queries you read the whole text from the file and then specify which one of the queries needs to be [composed and] send to the graphql server, I believe in graphql parlance those are called "operations".

Unfortunately, the existing elisp libraries don't do that (looks like graphql-mode.el does that to a certain extent, but the piece has to be extracted if to be used). And as @tarsius explains, he initially wanted to do things that way, but later he changed his mind https://magit.vc/manual/ghub/Making-GraphQL-Requests.html#Making-GraphQL-Requests.

@dcunited001
Copy link

I know it's not exactly relevant to the thread. I don't really want to create a bug/feature, but i was able to hack elisp symbols to get fragments to work ... at least in a limited manner.

(ghub-graphql
 (graphql-query
  ((search
    :arguments
    ((first . 100)
     (type . REPOSITORY)
     (query . "topic:tutorial org:hashicorp"))
    repositoryCount
    (pageInfo hasNextPage endCursor startCursor)
    repos: (edges
            repo: (node ... on (Repository
                                url name id (owner login)
                                (defaultBranchRef prefix name)
                                updatedAt
                                isArchived)))))))

Unfolds to:

query {
  search(first:100,type:REPOSITORY,query:"topic:tutorial org:hashicorp") {
    repositoryCount
    pageInfo { hasNextPage endCursor startCursor}
    repos: edges {
      repo: node {
        ... on Repository {
          url
          name
          id
          owner{login}
          defaultBranchRef{prefix name}
          updatedAt
          isArchived }}}}}

The docs seem to indicate that fragments aren't covered and I really don't know GraphQL that well, but it looks like it works in some cases, though the elisp objects passed to graphql-query aren't properly structured.

The reason I mention it is because I've had a hard time getting ob-graphql, ob-restclient and curl from babel to run graphql queries. (ghub-graphql (graphql-query ...)) seems to be the only & simplest way to extract data into emacs lisp. I also had a pretty bad time with running GraphQL LSP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants