gpt4 book ai didi

sequelize.js - 如何使用 Sequelize 和 GraphQL 正确设置多态模型

转载 作者:行者123 更新时间:2023-12-03 16:18:42 26 4
gpt4 key购买 nike

我目前正在尝试通过为自己开发一个膳食计划应用程序来学习 React。来自传统的商业编程世界,我决定使用 MySQL 作为后端,并使用 Sequelize/GraphQL 作为我的数据接口(interface)。

我有一个数据模型如下:
-用户吃饭
-膳食具有日期、类型(早餐、午餐等)和“MealItems”的属性
-MealItems 可以是 FoodItem 或 Recipe
-Recipes 基本上是 FoodItems 的集合

我用这个数据模式实现了这个想法(在 Access 中完成了非常快速的模型):Meal Planner Model

我设法编写了一个 Sequelize 模型,该模型完全按照我的意愿创建表和约束。我使用官方 Sequelize 文档中的 n:m 关联示例来创建 MealItems 查找表,该表应该允许模型根据范围(“ItemType”)动态返回 FoodItem 或 Recipe。 (但我不知道我是否正确地完成了该部分,因为我无法通过原始 SQL 查询以外的任何方式实际提取数据。)

我的项目的完整源代码可以在这里找到:(相关的数据组件在'./src/data'下)
https://github.com/philspins/NourishMe

Sequelize 模型:

//
// Model definitions
// -----------------------------------------------------------------------------
import DataType from "sequelize";
import Model from "../sequelize";

const FoodItem = Model.define("FoodItem",
{

Name: { type: DataType.STRING(100) },
Quantity: { type: DataType.STRING(32) },
Weight: { type: DataType.INTEGER },
Calories: { type: DataType.INTEGER },
Protein: { type: DataType.DOUBLE },
Carbs: { type: DataType.DOUBLE },
Fat: { type: DataType.DOUBLE },
Fibre: { type: DataType.DOUBLE },
ImageURL: { type: DataType.TEXT }
});

const Recipe = Model.define("Recipe",
{
Name: { type: DataType.STRING(100) },
Instructions: { type: DataType.TEXT },
ImageURL: { type: DataType.TEXT }
});

const Ingredient = Model.define("Ingredient");

const Meal = Model.define("Meal",
{
Day: { type: DataType.DATE }
});

const MealType = Model.define("MealType",
{
Name: { type: DataType.STRING(100) }
});

const MealItem = Model.define("MealItem",
{
id: {type: DataType.INTEGER, primaryKey: true, autoIncrement: true},
ItemType: { type: DataType.STRING(100) },
ItemID: { type: DataType.STRING(100) },
Quantity: { type: DataType.DOUBLE }
},
{
instanceMethods: {
getItem: function() {
return this["get" + this.get("ItemType").substr(0,1).toUpperCase() + this.get("ItemType").substr(1)]();
}
}
});

//
// Recipe and FoodItem relations
// -----------------------------------------------------------------------------
Recipe.FoodItems = Recipe.belongsToMany(FoodItem, {
through: Ingredient,
as: "FoodItems"
});
FoodItem.Recipes = FoodItem.belongsToMany(Recipe, {
through: Ingredient,
as: "Recipes"
});


//
// Meals relationships with Recipe and FoodItem
// -----------------------------------------------------------------------------
Meal.belongsToMany(Recipe, {
through: MealItem,
foreignKey: "ItemID",
constraints: false,
scope: {
ItemType: "Recipe"
}
});
Recipe.belongsToMany(Meal, {
through: MealItem,
foreignKey: "ItemID",
constraints: false,
as: "Recipe"
});
Meal.belongsToMany(FoodItem, {
through: MealItem,
foreignKey: "ItemID",
constraints: false,
scope: {
ItemType: "FoodItem"
}
});
FoodItem.belongsToMany(Meal, {
through: MealItem,
foreignKey: "ItemID",
constraints: false,
as: "FoodItem"
});


//
// Other Meal relationships
// -----------------------------------------------------------------------------
Meal.MealItems = Meal.hasMany(MealItem, {foreignKey: {allowNull: false}, onDelete: "CASCADE"});
Meal.User = User.hasMany(Meal, {foreignKey: {allowNull: false}, onDelete: "CASCADE"});
Meal.MealType = MealType.hasMany(Meal, {foreignKey: {allowNull: false}, onDelete: "CASCADE"});

我有 GraphQL 类型和查询设置来返回除 Meal 之外的所有数据。除了 MealItem 表中实际存在的值之外,我无法让它返回任何内容。我能够将 FoodItem 链接到 Recipe 没有问题,并检索在 Recipes 中嵌入了 FoodItems 的 JSON 包,但无法弄清楚如何用 MealItems 做同样的事情。这是我现在使用的模型:[GraphQL 模型的可视化][3]
但我希望 Meals 能够在输出中嵌入 FoodItems 或 Recipes 而不是 MealItems。

这是我的 GraphQL 代码,因为我正在使用它:
import {GraphQLObjectType,
GraphQLList,
GraphQLNonNull,
GraphQLID,
GraphQLString} from "graphql";
import {resolver, attributeFields} from "graphql-sequelize";
import {Meal,
Recipe,
FoodItem as
FoodModel,
MealItem as MealItemModel} from "../models";

const FoodType = new GraphQLObjectType({
name: "FoodItem",
fields: attributeFields(FoodModel),
resolve: resolver(FoodModel)
});

const RecipeType = new GraphQLObjectType({
name: "Recipe",
fields: {
id: { type: new GraphQLNonNull(GraphQLID) },
Name: { type: GraphQLString },
Instructions: { type: GraphQLString },
ImageURL: { type: GraphQLString },
Ingredients: {
type: new GraphQLList(FoodType),
resolve: resolver(Recipe.FoodItems) }
}
});

const MealTypeType = new GraphQLObjectType({
name: "MealType",
fields: attributeFields(MealType)
});

const MealItemType = new GraphQLObjectType({
name: "MealItem",
fields: attributeFields(MealItemModel),
resolve: resolver(MealItemModel)
});

const MealType = new GraphQLObjectType({
name: "Meal",
fields: {
id: { type: new GraphQLNonNull(GraphQLID) },
Day: { type: DateType },
UserId: { type: GraphQLID },
MealTypeId: { type: GraphQLID },
MealItems: {
type: new GraphQLList(MealItemType),
resolve: resolver(Meal.MealItems)
}
}
});

const Meals = {
type: new GraphQLList(MealType),
resolve: resolver(Meal)
};

const schema = new Schema({
query: new ObjectType({
name: "Root",
fields: {
Meals
}
})
});

我认为我需要做的是,为了让 MealType 动态返回 FoodType 或 RecipeType 而不是 MealItemType,这与此类似。但这是我无法开始工作的地方,也是这个极其冗长的问题的原因。
function resolveMealItemType(value){
if(value.ItemType == "Recipe"){return RecipeType;}else{return FoodType;}
}

const MealItemType = new GraphQLUnionType({
name: "MealItem",
types: [RecipeType, FoodType],
resolveType: resolveMealItemType
});

const MealType = new GraphQLObjectType({
name: "Meal",
fields: {
id: { type: new GraphQLNonNull(GraphQLID) },
Day: { type: DateType },
UserId: { type: GraphQLID },
MealTypeId: { type: GraphQLID },
MealItems: {
type: new GraphQLList(MealItemType),
resolve: resolver(Meal.MealItems)
}
}
});

当前查询和输出:
{
Meal {
Day
MealTypeId
UserId
MealItems {
ItemType
ItemID
}
}
}

{
"data": {
"Meal": {
"Day": "2017-02-07T16:18:47.000Z",
"MealTypeId": "1",
"UserId": "1",
"MealItems": [
{
"ItemType": "Recipe",
"ItemID": 1
},
{
"ItemType": "FoodItem",
"ItemID": 25
}
]
}
}
}

所需的查询和输出:
{
Meal {
Day
MealTypeId
UserId
MealItems {
... on FoodItem {
Name
Quantity
Weight
Calories
Carbs
Protein
Fat
Fibre
}
... on Recipe {
Name
Instructions
Ingredients {
Name
Quantity
Weight
Calories
Carbs
Protein
Fat
Fibre
}
}
}
}
}


{
"data": {
"Meal": {
"Day": "2017-02-07T15:30:10.000Z",
"MealTypeId": "1",
"UserId": "1",
"MealItems": [
{
"Name": "Fish, Halibut, Pacific",
"Quantity": "4 oz uncooked",
"Weight": 113,
"Calories": 124,
"Carbs": 0,
"Protein": 24,
"Fat": 3,
"Fibre": 0
},
{
"Name": "Test Recipe 1",
"Instructions": "Recipe instructions go here...",
"Ingredients": [
{
"Name": "Fish, Halibut, Pacific",
"Quantity": "4 oz uncooked",
"Weight": 113,
"Calories": 124,
"Carbs": 0,
"Protein": 24,
"Fat": 3,
"Fibre": 0
},
{
"Name": "Sardines (herring), canned in olive oil",
"Quantity": "1 can (3.2 oz)",
"Weight": 91,
"Calories": 191,
"Carbs": 0,
"Protein": 23,
"Fat": 11,
"Fibre": 0
}
}
]
}
}
}

最佳答案

不要设置 key resolver直接在 GraphQLObjectType 内:

...
const FoodType = new GraphQLObjectType({
name: "FoodItem",
fields: attributeFields(FoodModel),
resolve: resolver(FoodModel), // <--- this is wrong, it won't be used
// Only set resolvers inside fields, not on the root of the object
});
...

那么您使用 GraphQLUnionType 是对的.
但是在 MealType 的解析函数中,您应该返回 FoodItems 和食谱的合并数组而不是 MealItems 的条目 table 。您在与工会说“我要返回 FoodItem 或 Recipe 的列表”,所以这就是您应该做的。

所以,
const MealType = new GraphQLObjectType({
...
fields: {
...
MealItems: {
type: new GraphQLList(MealItemType),
resolve: (meal, args, context) => {
return Promise.all([
Meal.getFoodItems(), // pseudo-code
Meal.getRecipes(), // pseudo-code
])
.then(([ foodItems, recipes ]) => foodItems.concat(recipes));
},
},
...
},
});

关于sequelize.js - 如何使用 Sequelize 和 GraphQL 正确设置多态模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42095114/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com