diff --git a/packages/components/model-team/package.json b/packages/components/model-team/package.json index 857bc14b1fc49524dbac06487f9007fabe9d1967..74153d8219384de261506db54f5ac173461bedd1 100644 --- a/packages/components/model-team/package.json +++ b/packages/components/model-team/package.json @@ -19,6 +19,7 @@ }, "peerDependencies": { "@pubsweet/model-user": "^2.0.0", + "@pubsweet/models": "^0.1.3", "config": "^3.0.1", "lodash": "^4.17.11", "pubsweet-server": "^11.0.0", diff --git a/packages/components/model-team/src/graphql.js b/packages/components/model-team/src/graphql.js index 2f4034d3273309899d5b33b3afc64ecbed888525..483f6236725e6a9931d5d3760ec6acb912fba135 100644 --- a/packages/components/model-team/src/graphql.js +++ b/packages/components/model-team/src/graphql.js @@ -4,30 +4,6 @@ const resolvers = { return ctx.connectors.Team.fetchOne(id, ctx) }, teams(_, { where }, ctx) { - // A little bit of API sugar to provide querying with e.g. - // where: { - // role: 'test', - // object: { - // objectId: fragment.id, - // objectType: 'fragment', - // }, - // members: [UUID] - // } - // which is then translated into appropriate JSON/relation queries. - if ( - where && - where.object && - where.object.objectId && - where.object.objectType - ) { - const { object } = where - delete where.object - where._json = [ - { ref: 'teams.object:objectId', value: object.objectId }, - { ref: 'teams.object:objectType', value: object.objectType }, - ] - } - if (where.members) { const { members } = where delete where.members @@ -87,6 +63,10 @@ const resolvers = { members(team, vars, ctx) { return ctx.connectors.User.fetchSome(team.members, ctx) }, + object(team, vars, ctx) { + const { objectId, objectType } = team + return objectId && objectType ? { objectId, objectType } : null + }, }, } @@ -123,16 +103,12 @@ const typeDefs = ` input TeamInput { role: String name: String - object: TeamObjectInput + objectId: ID + objectType: String members: [ID!] global: Boolean } - - input TeamObjectInput { - objectId: ID! - objectType: String! - } ` module.exports = { resolvers, typeDefs } diff --git a/packages/components/model-team/src/migrations/1548205276-simplify-object.js b/packages/components/model-team/src/migrations/1548205276-simplify-object.js new file mode 100644 index 0000000000000000000000000000000000000000..f04443c6a26bf553ff9aa5bc01ed950ae89a2386 --- /dev/null +++ b/packages/components/model-team/src/migrations/1548205276-simplify-object.js @@ -0,0 +1,27 @@ +exports.up = async knex => { + const { Team } = require('@pubsweet/models') + const teams = await Team.query() + + const saves = [] + + await knex.schema.table('teams', table => { + table.uuid('object_id') + table.string('object_type') + table.index(['object_id', 'object_type']) + }) + + teams.forEach(team => { + if (team.object && team.object.objectId && team.object.objectType) { + team.objectId = team.object.objectId + team.objectType = team.object.objectType + delete team.object + saves.push(team.save()) + } + }) + + await Promise.all(saves) + + return knex.schema.table('teams', table => { + table.dropColumn('object') + }) +} diff --git a/packages/components/model-team/src/team.js b/packages/components/model-team/src/team.js index 28e0cca60034b4042cf42e5931f26c873330125d..287239daa981d75ee797e8ae1b41fc8919709f63 100644 --- a/packages/components/model-team/src/team.js +++ b/packages/components/model-team/src/team.js @@ -34,7 +34,8 @@ class Team extends BaseModel { static get schema() { return { properties: { - object: { type: ['object', 'null'] }, + objectId: { type: ['string', 'null'], format: 'uuid' }, + objectType: { type: ['string', 'null'] }, name: { type: 'string' }, role: { type: ['string'] }, owners: { diff --git a/packages/components/model-team/test/1548205276-simplify-object_test.js b/packages/components/model-team/test/1548205276-simplify-object_test.js new file mode 100644 index 0000000000000000000000000000000000000000..22ccbd75b41b74ffca5703f86b6fb3fcd34c3b30 --- /dev/null +++ b/packages/components/model-team/test/1548205276-simplify-object_test.js @@ -0,0 +1,41 @@ +process.env.NODE_CONFIG = `{"pubsweet":{ + "components":[ + "@pubsweet/model-user", + "@pubsweet/model-team", + "@pubsweet/model-team-member", + "@pubsweet/model-fragment" + ] +}}` + +const { model: Team } = require('../src') +const { dbCleaner } = require('pubsweet-server/test') +const migrate = require('@pubsweet/db-manager/src/commands/migrate') + +describe('Migration to simplify object storage', () => { + it('successfully migrates from JSONB to separate columns', async () => { + // Clean database and run up until the migration we're testing + await dbCleaner({ to: '1548205275-move-members.js' }) + + // Get a team with the previous members array structure + let team = await new Team({ + name: 'Test', + role: 'test', + }).save() + + // Using id and type 'team' here just for testing + await Team.raw('UPDATE teams SET object = ?::jsonb WHERE id = ?', [ + JSON.stringify({ objectId: team.id, objectType: 'team' }), + team.id, + ]) + + // Do the migration + await migrate({ to: '1548205276-simplify-object.js' }) + + // Check that members have migrated to the relationship + team = await Team.query().findById(team.id) + + expect(team.objectId).toEqual(team.id) + expect(team.objectType).toEqual('team') + expect(team.object).toBeUndefined() + }) +}) diff --git a/packages/components/model-team/test/team_graphql_test.js b/packages/components/model-team/test/team_graphql_test.js index 9d899d4f1b3c5d82ddc4244e2a3cfc26c07bfa9b..7b65377b5c9cdb51d5c6d46012746a69158171fa 100644 --- a/packages/components/model-team/test/team_graphql_test.js +++ b/packages/components/model-team/test/team_graphql_test.js @@ -12,7 +12,7 @@ const { model: Fragment } = require('@pubsweet/model-fragment') const { dbCleaner, api } = require('pubsweet-server/test') -const fixtures = require('pubsweet-server/test/fixtures/fixtures') +const { fixtures } = require('@pubsweet/model-user/test') const authentication = require('pubsweet-server/src/authentication') const Team = require('../src/team') @@ -26,6 +26,10 @@ describe('Team queries', () => { `query($where: TeamInput) { teams(where: $where) { name + object { + objectId + objectType + } } }`, { @@ -43,6 +47,8 @@ describe('Team queries', () => { }) it('creates a team', async () => { + const fragment = await new Fragment({ fragmentType: 'post' }).save() + const { body } = await api.graphql.query( `mutation($input: TeamInput) { createTeam(input: $input) { @@ -50,6 +56,10 @@ describe('Team queries', () => { members { id } + object { + objectId + objectType + } } }`, { @@ -57,6 +67,8 @@ describe('Team queries', () => { name: 'My team', role: 'test', members: [user.id], + objectId: fragment.id, + objectType: 'fragment', }, }, token, @@ -67,6 +79,10 @@ describe('Team queries', () => { createTeam: { name: 'My team', members: [{ id: user.id }], + object: { + objectId: fragment.id, + objectType: 'fragment', + }, }, }, }) @@ -137,10 +153,8 @@ describe('Team queries', () => { { role: 'test', name: 'Test', - object: { - objectId: fragment.id, - objectType: 'fragment', - }, + objectId: fragment.id, + objectType: 'fragment', members: [ { '#dbRef': user.id, @@ -152,10 +166,8 @@ describe('Team queries', () => { const body = await whereQuery({ role: 'test', - object: { - objectId: fragment.id, - objectType: 'fragment', - }, + objectId: fragment.id, + objectType: 'fragment', }) expect(body.data.teams).toHaveLength(1) @@ -176,10 +188,8 @@ describe('Team queries', () => { { role: 'test', name: 'Test', - object: { - objectId: fragment.id, - objectType: 'fragment', - }, + objectId: fragment.id, + objectType: 'fragment', members: [ { '#dbRef': user.id, @@ -196,23 +206,23 @@ describe('Team queries', () => { it('finds a team for 1 member', async () => { const body = await whereQuery({ role: 'test', - object: { - objectId: fragment.id, - objectType: 'fragment', - }, + objectId: fragment.id, + objectType: 'fragment', members: [user.id], }) expect(body.data.teams).toHaveLength(1) + expect(body.data.teams[0].object).toEqual({ + objectId: fragment.id, + objectType: 'fragment', + }) }) it('finds a team for both members', async () => { const body = await whereQuery({ role: 'test', - object: { - objectId: fragment.id, - objectType: 'fragment', - }, + objectId: fragment.id, + objectType: 'fragment', members: [user.id, user2.id], }) @@ -222,10 +232,8 @@ describe('Team queries', () => { it('does not find a team for non-existent member', async () => { const body = await whereQuery({ role: 'test', - object: { - objectId: fragment.id, - objectType: 'fragment', - }, + objectId: fragment.id, + objectType: 'fragment', members: ['54513de6-b473-4b39-8f95-bcbb3ae58a2a'], }) @@ -235,10 +243,8 @@ describe('Team queries', () => { it('does not find a team if missing one of the members', async () => { const body = await whereQuery({ role: 'test', - object: { - objectId: fragment.id, - objectType: 'fragment', - }, + objectId: fragment.id, + objectType: 'fragment', members: [user.id, user2.id, '54513de6-b473-4b39-8f95-bcbb3ae58a2a'], })