Skip to content

redux-model/graphql

Folders and files

NameName
Last commit message
Last commit date

Latest commit

601bb4d · Apr 10, 2021

History

51 Commits
Mar 9, 2021
Sep 16, 2020
Sep 29, 2020
Apr 10, 2021
Apr 10, 2021
Sep 16, 2020
Sep 29, 2020
Sep 16, 2020
Sep 16, 2020
Mar 9, 2021
Apr 10, 2021
Sep 18, 2020
Apr 10, 2021

Repository files navigation

redux-model-graphql

Graphql模板运行时工具,自动生成标准模板和Typescript类型, 配合Redux-Model实现graphql请求。

License GitHub Workflow Status (branch) Codecov

特性

  • 只需写一次,Graphql语法和Typescript同时拥有
  • 自动收集参数
  • 自动识别参数基础类型
  • 单一职责,只生成标准graphql字符串
  • 支持所有graphql语法

安装

yarn add @redux-model/graphql

基础用法

import { Model } from '@redux-model/react';
import { types, graphql } from '@redux-model/graphql';

const getUserTpl = graphql.query({
  getUser: {
    id: types.number,   // number
    name: types.string, // string
    bankAccount: {     // object
      id: types.number,
      branch: types.string.number,   // string | number
    },
  }
});

// console.log(getUserTpl.toString());

// 生成模板:
// query GetUser {
//   getUser {
//     id
//     name
//     bankAccount {
//       id
//       branch
//     }
//   }
// }

type Response = {
  data: typeof getUserTpl.type;
};

interface Data {
  list?: Response['data'];
};

class TestModel extends Model<Data> {
  getUser = $api.action(() => {
    return this
      .post<Response>('/graphql')
      .graphql(getUserTpl)
      .onSuccess((state, action) => {
        state.list = action.response.data;
      });
  });

  protected initialState(): Data {
    return {};
  }
}

函数

const tpl = graphql.query({
  getUser: {
    id: types.number,
    logs: types.fn(['page: Int!', 'pageSize as size: Int'], types.array({
      id: types.number,
      title: types.string,
    })),
  }
});

// 生成模板:
// query GetUser ($page: Int!, $size: Int) {
//   getUser: {
//     id
//     logs (page: $page, pageSize: $size) {
//       id
//       title
//     }
//   }
// }

// 在模型中使用
type Response = {
  data: typeof tpl.type;
};

type Data = Response['data'];

class TestModel extends Model<Data> {
  getUser = $api.action((page: number, size: number = 10) => {
    return this
      .post<Response>('/graphql')
      .graphql(tpl({
        page,
        size,
      }))
      .onSuccess((state, action) => {
        return action.response.data;
      });
  });

  protected initialState(): Data {
    return {};
  }
}

片段

const fragment1 = graphql.fragment('User', {
  name: types.string,
});

const tpl = graphql.query({
  getUser: {
    id: types.number,
    ...fragment1,
  }
});

// 生成模板:
// query GetUser {
//   getUser: {
//     id
//     ...UserFragment
//   }
// }
//
// fragment UserFragment on User {
//   name
// }

内联片段

const tpl = graphql.query({
  getUser: {
    id: types.number,
    ...types.on('User', {
      name: types.string,
    }),
    ...types.on(['Hero', 'Thief'], {
      age: types.number,
    }),
  }
});

// 生成模板:
// query GetUser {
//   getUser: {
//     id
//     ... on User {
//       name
//     }
//     ... on Hero {
//       age
//     }
//     ... on Thief {
//       age
//     }
//   }
// }

互斥内联片段

生成的模板和内联片段一样,但是在类型上是互斥的

const tpl = graphql.query({
  getUser: {
    id: types.number,
    ...types.union(
      types.on('User', {
        kind: types.custom<'User'>(),
        name: types.string,
        age: types.number,
      }),
      types.on('Admin', {
        kind: types.custom<'Admin'>(),
        name1: types.string,
        age1: types.number,
      }),
    )
  }
});

// 生成模板:
// query GetUser {
//   getUser: {
//     id
//     ... on User {
//       kind
//       name
//       age
//     }
//     ... on Admin {
//       kind
//       name1
//       age1
//     }
//   }
// }

您可以通过判断来确定哪个字段存在

if (getUser.kind === 'User') {
  // getUser.name
  // getUser.age
} else if (getUser.kind === 'Admin') {
  // getUser.name1
  // getUser.age1
}

if ('age' in getUser) {
  // getUser.name
  // getUser.age
} else if ('age1' in getUser) {
  // getUser.name1
  // getUser.age1
}

⚠️注意:互斥内联片段中互斥的字段无法收集函数参数名

指令

const tpl = graphql.query({
  getUser: {
    id: types.number.include('test: Boolean'),   // number | undefined
    logs: types.skip('other: Boolean').object({  // object | undefined
      id: types.number,
      title: types.string,
    }),
  }
});

// 生成模板:
// query GetUser ($test: Boolean, $other: Boolean) {
//   getUser: {
//     id @include(if: $test)
//     logs @skip(if: $other) {
//       id
//       title
//     }
//   }
// }