完整注册表示例
使用两个表“forums”和“messages”的简单模式的注册表可能如下所示;有关详细信息,请参阅编解码器、资源(包括执行器)和关系文档。
请记住:您可以自动生成此内容。
import { sql } from "pg-sql2";
import { context, object } from "grafast";
import {
PgExecutor,
TYPES,
makePgResourceOptions,
makeRegistry,
makeRegistryBuilder,
recordCodec,
} from "@dataplan/pg";
// The executor is responsible for talking to the database. If you have
// multiple databases, you will have multiple executors (one per database).
const executor = new PgExecutor({
name: "default",
context() {
return object({ withPgClient: context().get("withPgClient") });
},
});
// Represents the type of the 'forums' table:
const forumsCodec = recordCodec({
name: "forums",
identifier: sql`forums`,
attributes: {
id: {
codec: TYPES.uuid,
notNull: true,
hasDefault: true,
},
name: {
codec: TYPES.citext,
notNull: true,
},
},
});
// Represents the 'forums' table, including knowledge of its primary key:
const forumsResourceOptions = makePgResourceOptions({
name: "forums",
executor,
codec: forumsCodec,
from: sql`forums`,
uniques: [{ attributes: ["id"], isPrimary: true }],
});
// Represents the type of the 'messages' table:
const messagesCodec = recordCodec({
name: "messages",
identifier: sql`messages`,
attributes: {
id: {
codec: TYPES.int,
notNull: true,
hasDefault: true,
},
forum_id: {
codec: TYPES.int,
notNull: true,
},
message: {
codec: TYPES.text,
notNull: true,
},
},
});
// Represents the 'messages' table:
const messagesResourceOptions = makePgResourceOptions({
name: "messages",
executor,
codec: messagesCodec,
from: sql`messages`,
uniques: [{ isPrimary: true, attributes: ["id"] }],
});
// The builder tracks all the types so you end up with a strongly-typed registry
const builder = makeRegistryBuilder()
// First add our codecs
.addCodec(forumsCodec)
.addCodec(messagesCodec)
// Then add our resources
.addResource(forumsResourceOptions)
.addResource(messagesResourceOptions)
// A message relates to a single forum:
.addRelation(messagesCodec, "forum", forumsResourceOptions, {
localAttributes: ["forum_id"],
remoteAttributes: ["id"],
isUnique: true,
})
// A forum can have many messages:
.addRelation(forumsCodec, "messages", messagesResourceOptions, {
localAttributes: ["id"],
remoteAttributes: ["forum_id"],
// The foreign key reference is defined on 'messages', so we're the one
// that's referenced by a foreign key
isReferencee: true,
});
// Finally build the registry:
const registry = makeRegistry(builder.getRegistryConfig());
示例模式
鉴于上述注册表,您可以创建类似于以下计划的模式
const { forums, messages } = registry.pgResources;
const typeDefs = /* GraphQL */ `
type Query {
forumById(id: Int!): Forum
}
type Forum {
id: Int!
name: String!
messages: [Message!]!
}
type Message {
id: Int!
message: String!
forum: Forum!
}
`;
const plans = {
Query: {
forumById(_, { $id }) {
return forums.get({ id: $id });
},
},
Forum: {
messages($forum) {
return messages.find({ forum_id: $forum.get("id") });
// OR: return $forum.manyRelation("messages");
},
},
Message: {
forum($message) {
return forums.get({ id: $message.get("forum_id") });
// OR: return $message.singleRelation("forum");
},
},
};
import { makeGrafastSchema } from "grafast";
const schema = makeGrafastSchema({ typeDefs, plans });
注意
虽然这种简单的 ORM 风格外观看起来会触发多个 SQL 语句,但在大多数情况下,Grafast 和 @dataplan/pg
协同工作将导致计划被分析,并且请求会通过联接和/或子查询自动组合,以生成高效的 SQL 查询
(待办事项:测试此功能是否有效。)