Можно ли сделать мульти-аренду с Graphql и Sequelize? - PullRequest
0 голосов
/ 30 апреля 2019

выделенный текст У меня довольно сложный вопрос о GraphQl и мультитенантности.

Предположим, есть 3 таблицы: ВЛАДЕЛЕЦ , ДОМ и АРЕНДАТОРЫ .Я опишу их в псевдокоде Sequelize и GraphQl:

Таблица владельцев (имеет несколько домов и несколько арендаторов)

const OWNER = sequelize.define('owner', {
  ownerId: type: Sequelize.INTEGER,
  name: type: Sequelize.STRING
}

OWNER.associate = models => {
  models.owner.hasMany(models.house, {foreignKey: {name: 'ownerId', field: 'ownerId'}})
  models.owner.hasMany(models.tenant, {foreignKey: {name: 'ownerId', field: 'ownerId'}})
}

Таблица домов (принадлежит владельцу и имеет несколько арендаторов)

const HOUSE = sequelize.define('house', {
  houseId: type: Sequelize.INTEGER,
  ownerId: type: Sequelize.INTEGER,
  name: type: Sequelize.STRING
}

HOUSE.associate = models => {
  models.house.belongsTo(models.owner, {foreignKey: {name: 'ownerId', field: 'ownerId'}})
  models.house.hasMany(models.tenant, {foreignKey: {name: 'houseId', field: 'houseId'}})
}

Таблица арендаторов (принадлежит владельцу и дому)

const TENANT = sequelize.define('tenant', {
  tenantId: type: Sequelize.INTEGER,
  ownerId: type: Sequelize.INTEGER,
  houseId: type: Sequelize.INTEGER,
  name: type: Sequelize.STRING
}

TENANT.associate = models => {
  models.tenant.belongsTo(models.owner, {foreignKey: {name: 'ownerId', field: 'ownerId'}})
  models.tenant.belongsTo(models.house, {foreignKey: {name: 'houseId', field: 'houseId'}})
}

Владелец объекта graphql

const OwnerType = new GraphQLObjectType({
  name: 'Owner',
  fields: () => ({
    ownerId: { type: GraphQLInt },
    name: { type: GraphQLString },
    houses: {
      type: GraphQLList(HouseType),
      resolve(owner) {
        return owner.getHouse()
      }
    },
    houseById: {
      type: HouseType,
      args: <args is not defined>
      resolve(owner) {
        return <???>
      }
    },
  })
})

Вот несколько простых запросов GraphQL:

ownerById = {
  type: OwnerType,
  args: {
    ownerId: { type: GraphQLInt },
  },
  resolve(parents, args){
    return models.owner.findOne({ where: args })
  }
}

houses = {
  type: GraphQLList(HouseType),
  resolve(parents, args){
    return models.house.findAll()
  }
}

houseById = {
  type: HouseType,
  args: {
    houseId: { type: GraphQLInt },
  },
  resolve(parents, args){
    return models.house.findOne({ where: args })
  }
}

tenants = {
  type: GraphQLList(TenantType),
  resolve(parents, args){
    return models.tenant.findAll()
  }
}

Эти клиентские запросы работают:

{
  ownerById(ownerId: 1) {
    ownerId
    name
    house {
      houseId
      name
    }
  }
}

{
  houseById(houseId: 2) {
    houseId
    name
    tenant {
      tenantId
      name
    }
  }
}

То, что мне нужно, чтобы многопользовательская работа работала, выглядит примерно так:

{
  ownerById(ownerId: 1) {
    ownerId
    name
    houseById(houseId: 2) {
      houseId
      name
      tenant {
        tenantId
        name
      }
    }
  }
}

Есть ли способ архивировать это илиэто выходит за рамки того, что может сделать GraphQl?

Если да, то как будет выглядеть запрос объекта graphql houseById?

Заранее спасибо.

1 Ответ

1 голос
/ 30 апреля 2019

Если я что-то упустил, похоже, что ваш распознаватель для houseById не будет сильно отличаться от распознавателя для поля houses того же типа.

houseById: {
  type: HouseType,
  args: {
    houseId: { type: GraphQLInt },
  },
  async resolve(owner, { houseId }) {
    const houses = await owner.getHouses({ where: { id: houseId } })
    return houses[0]
  }
},

Для HasMany ассоциация, получатель для целевой модели разрешается в массив экземпляров.Поэтому нам нужно сначала захватить этот массив, а затем вернуть только первый элемент в нем, поскольку наше поле представляет отдельный объект, а не список.Если вы не хотите использовать async / await, вы также можете сделать:

return owner.getHouses({ where: { id: houseId } })
  .then(houses => houses[0])

Также стоит упомянуть, что этот тип шаблона для схемы не соответствует соглашению.Вместо того, чтобы иметь поле houses, поле houseById, поле houseBySomeOtherArg и т. Д., Рассмотрите возможность предоставления одного поля houses с одним или несколькими аргументами, такими как id, name или любым другим критерием фильтрации, который вы используете.хочу предоставить.Ваше поле может затем просто отфильтровать дома на основе любых переданных аргументов или вернуть все результаты, если аргументы фильтра не были предоставлены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...