在本篇博客中,我们将看到如何使用Prisma和GraphQL构建SQL查询机制,我们将使用Apollo Client和GraphQL Server使用Express使用GraphQL。
这里使用的技术堆栈是:
GraphQL,Prisma PGSQL转储,Express(推断GraphQL后端服务器)。
如果您想要GraphQL查询,请与我们的后端接口进行通信,我们可能需要做我在React下在下面做的事情,这只是一个配置部分,我想从技术上讲,我们如何在前端部分配置GraphQL。
const client = new ApolloClient({
uri: import.meta.env.VITE_APP_GRAPHQL_API,
cache: new InMemoryCache(),
});
然后,我们将使用它像包装应用程序组件一样使用它,因为我们将在整个应用程序中使用客户端。
<ApolloProvider client={client}>
<App />
</ApolloProvider>
上述代码必须在main.tsx文件中或index.ts文件中写入。以上代码在阿波罗的帮助下创建客户端-客户端库用来创建一个用于使用GraphQL的客户端的使用,它需要两个参数URI,不过是GraphQL API的后端推断和我们定义InmemoryCache的缓存参数() 如果在没有网络请求的情况下将查询存储在本地缓存存储中,则阿波罗客户端会立即响应。
现在,我们需要集中精力,以推断GraphQL Server在其中突变和获取我们的帖子数据-GRES数据转储
让我们从graphql的后端设置开始,然后是prisma
在这里,我们看不到要设置的配置的太多,但是只有为服务客户端请求服务的Apollo服务器,我们的主要重点是准确而精确地制作解决方案函数和架构文件,因为有时可能会很混乱。产品代码库变得非常庞大。
在我的 ./index.js
const server = new ApolloServer({
schema, // you executable schema file
context: ({ req }) => ({
db, // your database connection
}),
plugins: [ApolloServerPluginDrainHttpServer({ httpServer })],
});
await server.start();
就我而言,我正在使用Postgres数据库,所以我将使用PG-承诺制作数据库实例并制作连接字符串。我还附加了我们如何从.env文件中使用它,就好像有些新手读取博客一样,他们可能会有意义地开发生产 /行业应用程序。
const pgp = pgPromise();
export const db = pgp({
connectionString: `postgres://${process.env.DB_USER}:${process.env.DB_PASSWORD}@${process.env.DB_HOST}:${process.env.DB_PORT}/${process.env.DB_DATABASE}` ,
});
现在让我们求助于可执行模式文件并赠送给阿波罗服务器
import makeExecutableSchema from "graphql-tools" // also add it into the file
const schema = makeExecutableSchema({ typeDefs, resolvers });
那么什么是Typedef和解析器?
Typedefs不过是一个架构文件,其中提到的字段的数据类型(类似于Typescript中的类型),我将添加一些我们在文件中提到的内容以及一些标量类型,我们如何管理一些标量类型以及如何管理我们是否使用GraphQLScalArtypes创建了一些自定义TypeDEF。还链接了文档 apolagraphql 用于使模式更好,声音。
也在我的 ./schema.js
让我们假设我正在做类似的事情 user_secrets
让我的DB以以下方式诱惑
type sus_users_talez{
id: Int!,
created_at: TimestampWithTimezone!,
updated_at: TimestampWithTimezone,
deleted_at: TimestampWithTimezone,
name: String,
sus_created_at: TimestampWithTimezone,
sus_updated_at: TimestampWithTimezone,
visibility: String,
workflows: [String],
}
在这里,您可以看到我有Timestampwithtimezone,这是一个自定义Typedef,我们将在微型中创建它
但是在此之前,我想展示我们将如何使架构文件更加好,以上只是类型的示例
export const typeDefs = `#graphql
scalar TimestampWithTimezone
scalar JSON
type sus_users_talez{
id: Int!,
created_at: TimestampWithTimezone!,
updated_at: TimestampWithTimezone,
deleted_at: TimestampWithTimezone,
name: String,
sus_created_at: TimestampWithTimezone,
sus_updated_at: TimestampWithTimezone,
visibility: String,
workflows: [String],
}
// this typedef will be responsible for Querying (Remember useQuery in ApolloGraphQL for fetching data from server)
// Note : I have also shown how it will take parameter for Pagination and a id for specifc user data.
type Query {
# Query to get all sus_users_talez
getAllSusUsers(limit:Int, offset:Int): [sus_users_talez]
# Query to get sus_users_talez by ID
getSusUser(id: Int!): sus_users_talez
}
// Similarly we will create a Mutation typedef to accomplish Querying from frontend.
type Mutation {
# mutation endpoint for customSQL queries from frontend
customSQLQuery(limit:Int, offset: Int, sql: String! , user_id: String!): JSON
}`
也让我回到自定义标量类型:) ,我们只需将其添加到我们在同一文件中导出的上述类型中,或从新文件中创建和导出它。
还要注意GraphQL单独支持JSON,上面在突变中,我们将其用作Frontend的用户将发送JSON格式的有效负载。
import { GraphQLScalarType } from "graphql" ;
export const TimestampWithTimezone = new GraphQLScalarType({
name: "TimestampWithTimezone" ,
description: "Timestamp with timezone offset" ,
serialize: (value) => {
// Serialize a timestamp value from your database
return value.toISOString();
},
parseValue: (value) => {
// Parse a timestamp value from a client input
return new Date(value);
},
parseLiteral: (ast) => {
if (ast.kind === Kind.STRING) {
// Parse a timestamp from an AST literal
return new Date(ast.value);
}
return null;
},
});
接下来是解析器功能,我们将如何创建一个解析器函数,该函数根据客户端的用户请求返回数据。
让我们开始从头开始构建我们的Resover文件:)
export const resolvers = {
Query: {
getAllSusUsersTalez: async (parent, { limit, offset }) => {
try {
// Use Prisma to fetch all sus_users_talez
const allUsers = await prisma.sus_users_talez.findMany({
skip: offset,
take: limit,
});
return allUsers;
} catch (error) {
console.error( "Error fetching sus_users_talez:" , error);
throw error;
}
},
}
Mutation: {
customSQLQuery: async (parent, { limit, offset, sql, user_id }) => {
try {
// handling the recent queries
// fetching the user_details for the metaData
const user = await prisma.talez.findUnique({
where: {
user_id: user_id,
},
});
// keeping a track for complete data count without offset
const countQuery = `SELECT COUNT(*) FROM (${sql}) AS total` ;
const totalCount = await prisma.$queryRawUnsafe(countQuery);
const paginatedSQL = `${sql} LIMIT ${limit} OFFSET ${offset}` ;
const result = await prisma.$queryRawUnsafe(paginatedSQL);
// Check if there are more items
const hasMoreItems = offset + limit < totalCount[0]?.count;
return { result: result, hasMoreItems };
} catch (error) {
console.error( "Error executing SQL query:" , error);
return { message: "Error Executing SQL Query, Try Different Query" };
}
},
}
在这里,我创建了一个查询功能,我尝试获取与SUS相关的所有数据_用户_Talez还添加了一个突变功能,如果用户需要按限制和偏移,他们也可以轻松地编写自定义SQL查询。
例如 Select * From sus_users_talez WHERE id="12345"
和Kaboom,您会得到结果。
PS:在Prisma之上构建将做出一些额外的努力,例如Prisma架构文件和迁移,如果您更改任何字段,如果您已经有像我这样的DB转储,则需要使用所有相关的架构的DB拉动,而您只需需要点击一个称为的命令 prisma db pull
您可以找到它的文档 Prisma 。
因此,现在您可以更充分地使用GraphQL从此处创建更多参考-SQL使用Express和任何前端框架。