houdini icon indicating copy to clipboard operation
houdini copied to clipboard

Lazy inline queries

Open fehnomenal opened this issue 2 years ago • 8 comments

With the store api lazy queries are now easily possible by defining them in a separate file. But I would love to be able to define them inline.

My idea to implement this is: We can probably detect whether the query call is part of a variable declaration or standalone, right? I.e. we can differentiate between

const { data, refetch } = query(...);

and

query(...);

If this is the case we could abort the preprocessor logic early to not execute the query in load or on mount.

My thinking is that in the second case the user clearly does not intend to use the query data right now. So it seems logical to defer execution.

What do you think, @aivazis @jycouet?

fehnomenal avatar Jul 10 '22 05:07 fehnomenal

Yea, i agree that we probably want to be able to do this. I wonder if it would be enough to support having a floating graphql tag which would result in a store that you could import as you wanted. Something like

<script>
    import FooStore from '$houdini/stores/Foo'

    graphql`
        query Foo { 
            bar
        }
    `

    // ....
</script>

Thoughts?

AlecAivazis avatar Jul 10 '22 05:07 AlecAivazis

Another option is that we could kind of merge these a bit so that a reference to an inline query returns the store:

<script>
    const FooStore = graphql`
        query Foo { 
            bar
        }
    `
</script>

AlecAivazis avatar Jul 10 '22 06:07 AlecAivazis

I like both approaches, the second one even a bit more. This way there you can immediately see the floating graphql tag has a purpose :sweat_smile:

fehnomenal avatar Jul 10 '22 06:07 fehnomenal

Actually, this 👇

<script>
    import { graphql } from "$houdini";
    
    graphql`
        query Foo { 
            bar
        }
    `
</script>

Is already generating the store GQL_Foo 🎉

But the preprocessor tries to do something with it (and it doesn't work). If you add query(graphql...., everything will work as usual, but then you can't do mazy stuff.

I see 2 ways: 1/ When nothing infront of graphql => Disable preprocessor 2/ Having a function to say: Disable preprocessor. Something like store(graphql... (to ask only for the store creation, nothing more)

Bonus, the cool thing with GQL_Foo is that it's typed without putting the type manually.

jycouet avatar Jul 17 '22 21:07 jycouet

i'm personally not a fan of the floating graphql tag. i think saying const foo = graphql is much more clear instead of having to define a query and then import the store in 2 different lines. One benefit this has is that it's relatively straight forward to support. the preprocessor should just always turn a graphql tag into a reference to the appropriate store and then the inline functions can just look up the information they need from the store reference instead of having an object that contains the store

AlecAivazis avatar Jul 18 '22 00:07 AlecAivazis

I see it as a great opportunity to mix styles (like https://github.com/HoudiniGraphql/houdini/pull/407). If you don't like to define operations in an external document but you want to interact with stores directly 👍

It's almost like a bug today that it's not already working like:

  • graphql is creating the store
  • query(...) doing the preprocessor for query, having SSR & Browser
  • paginatedQuery(...) doing the preprocessor for paginatedQuery, having SSR & Browser & pagination

I have to say that the syntax with the import is also strange because you import something that you define inside the component. 😅 Strange, but enabling this:

<script context="module">
    import { GQL_Foo } from "$houdini";
    
    export async load(event) {
        await GQL_Foo.fetch({ event })
        return {}
    }
</script>
<script>
    import { graphql } from "$houdini";
    
    graphql`
        query Foo { 
            bar
        }
    `
</script>

We don't have to forget that the original question was about lazy. So, maybe the clean & enabling things way is:

<script>
    import { graphql, store } from "$houdini";
    
    const myStoreNameFoo = store(graphql`
        query Foo { 
            bar
        }
    `)
    
    function randomAction() {
      myStoreNameFoo.fetch()
    }
</script>

With store(... giving you GQL_Foo

jycouet avatar Jul 18 '22 03:07 jycouet

hm maybe i'm missing something but i'm not sure what store gets you in that example. What i have in mind would look something like

<script context="module" lang="ts">
   // type is inferred from overloaded definitions of graphql
   const store = graphql`
        query MyQuery { 
        
        }
    `
    
    export async load(event) {
        await store.fetch({ event })
        return {}
    }
</script>
<script>
    $: browser && store.fetch()
</script>

{$store.value}

AlecAivazis avatar Jul 18 '22 03:07 AlecAivazis

Just a heads up, support for this will be added as part of the upcoming work to support the new KitQL api 👍

AlecAivazis avatar Aug 01 '22 21:08 AlecAivazis