nuxt-community / nuxt-class-component

ES / TypeScript decorator for class-style Nuxt/Vue components
MIT License
113 stars 15 forks source link

[RFC] Decorators for vue-apollo #20

Closed stevefan1999-personal closed 3 years ago

stevefan1999-personal commented 6 years ago

What problem does this feature solve?

Right now, the smart query/subscrition of vue-apollo must be put into the class decorator of Component, and there're a lot of typing Catch-22s we had to turn off type checking temporarily to get it to stop redding our IDE.

Is there any decorators for vue-apollo? I believe there can also be some decorator sugars around it too, it would be much better.

What does the proposed changes look like?

We could have decorators like this:


@Component()
export default class HelloComponent extends Vue {
  world: string = "world"

  // Type I: Tag only (Can this be computed🤔)
  @SmartQuery(gql`query { hello }`)
  hello?: { data: hello }

  // Type II: With options
  @SmartQuery({
    query: gql`query { hello }`,
    fetchPolicy: 'cache-and-network'
  })
  hello2?: { data: hello }

  // Type III: Functional variable
  @SmartQuery(gql`query Hello($name: String!) {
    hello(name: $name)
  }`)
  hello3(name: string = this.world): any {
    return async (query: (variables?: any) => Promise<any>): Promise<any> => {
      return await query({ name })
    }
  }

  // Type III variant: Functional variable with options and default variable and scoped variable
  @SmartQuery({
    query: gql`query Hello($name: String!) {
      hello(name: $name)
    }`,
    /* !! This should be prohibited for all decorators !!
    variables: {
      message: 'Meow'
    },
    */
    skip: false
  })
  'hello3.5'(name: string = this.world): any {
    return async (query: (variables?: any) => Promise<any>): Promise<any> => {
      return await query({ name })
    }
  }

  // Type IV: Mutation
  @Mutation(gql`
    mutation {
      store(key: "123", value: "456") {
        key,
        value
      }
    }
  `)
  hello4(): any { // Sorry but I'm too lazy to type 😣
    return async (mutate: (variables?: any) => Promise<any>): Promise<void> => {
      const data = await mutate() // no variables supplied
      // ...update..., e.g. write to local storage etc.
    }
  }

  // Type V: Mutation with options and variables
  @SmartMutation({
    mutation: gql`
      mutation Store($key: String!, $value: String!) {
        store(key: $key, value: $value) {
          key,
          value
        }
      }
    `,
    optimisticResponse: {
      __typename: 'Mutation'
    }
  })
  hello5({ key, value }: { key: string, value: string }): any {
    return async (mutate: (variables?: any) => Promise<any>) => Promise<void> {
      const data = await mutate(variables) // with variables supplied
      // ...update..., e.g. write to local storage etc.
    }
  }

  // Type VI: Subscription
  @SmartSubscription(gql`subscription {
    hello
  }`)
  onHello({ hello }: { hello: string }): void { // corresponds to updateQuery
    // XXX: should this really be auto wrapped upon the true model? (see below Type VII)
    this.handleOnHello({ hello })
  }

  @Emit('hello')
  handleOnHello({ hello }: { hello: string }) {}

  // Type VII: Subscription with variables
  @SmartSubscription({
    document: gql`subscription Hello($name) {
      hello(name: $name)
    }`
  })
  onHello2(name: string): any {
    // XXX: Async iterator or observable?
    // Observable is more fitted to Vue philosophy,
    // but async iterator is much easier to implement
    return async (pullData: (variables?: any) => Promise<any>): Promise<void> => {
      // So we are not appending to local variables, instead we remap this into an event and do it there

      // XXX again: Some darker sides of async iterator
      // https://github.com/tc39/proposal-async-iteration/issues/126
      for await (const { data: { hello }, unsubscribe } of pullData({ name })) {
        this.handleOnHello({ hello }) 
        if (hello === 'world') await unsubscribe() // This is my proposed way to stop, but then it degenerates to observable...
      }
    }
  }
}

Consensus

This feature request is available on Nuxt community (#c10)