Refactor relations ':OWNS' and ':ADMINISTERS' to ':MEMBER_OF' with properties

This commit is contained in:
Wolfgang Huß 2022-08-03 13:12:50 +02:00
parent 520598c897
commit cc44ee8ebc
7 changed files with 94 additions and 88 deletions

View File

@ -30,9 +30,10 @@ export const createGroupMutation = gql`
actionRadius actionRadius
disabled disabled
deleted deleted
owner { myRole
name # Wolle: owner {
} # name
# }
} }
} }
` `

View File

@ -33,15 +33,17 @@ export default {
groupType: { type: 'string', default: 'public' }, groupType: { type: 'string', default: 'public' },
actionRadius: { type: 'string', default: 'regional' }, actionRadius: { type: 'string', default: 'regional' },
myRole: { type: 'string', default: 'pending' },
locationName: { type: 'string', allow: [null] }, locationName: { type: 'string', allow: [null] },
wasSeeded: 'boolean', // Wolle: used or needed? wasSeeded: 'boolean', // Wolle: used or needed?
owner: { // Wolle: owner: {
type: 'relationship', // type: 'relationship',
relationship: 'OWNS', // relationship: 'OWNS',
target: 'User', // target: 'User',
direction: 'in', // direction: 'in',
}, // },
// Wolle: followedBy: { // Wolle: followedBy: {
// type: 'relationship', // type: 'relationship',
// relationship: 'FOLLOWS', // relationship: 'FOLLOWS',

View File

@ -18,63 +18,47 @@ import Resolver from './helpers/Resolver'
// } // }
export default { export default {
// Wolle: Query: { Query: {
// Post: async (object, params, context, resolveInfo) => { // Wolle: Post: async (object, params, context, resolveInfo) => {
// params = await filterForMutedUsers(params, context) // params = await filterForMutedUsers(params, context)
// params = await maintainPinnedPosts(params) // // params = await maintainPinnedPosts(params)
// return neo4jgraphql(object, params, context, resolveInfo) // return neo4jgraphql(object, params, context, resolveInfo)
// }, // },
// findPosts: async (object, params, context, resolveInfo) => { // Group: async (object, params, context, resolveInfo) => {
// params = await filterForMutedUsers(params, context) // // const { email } = params
// return neo4jgraphql(object, params, context, resolveInfo)
// },
// profilePagePosts: async (object, params, context, resolveInfo) => {
// params = await filterForMutedUsers(params, context)
// return neo4jgraphql(object, params, context, resolveInfo)
// },
// PostsEmotionsCountByEmotion: async (object, params, context, resolveInfo) => {
// const { postId, data } = params
// const session = context.driver.session() // const session = context.driver.session()
// const readTxResultPromise = session.readTransaction(async (transaction) => { // const readTxResultPromise = session.readTransaction(async (txc) => {
// const emotionsCountTransactionResponse = await transaction.run( // const result = await txc.run(
// ` // `
// MATCH (post:Post {id: $postId})<-[emoted:EMOTED {emotion: $data.emotion}]-() // MATCH (user:User {id: $userId})-[:MEMBER_OF]->(group:Group)
// RETURN COUNT(DISTINCT emoted) as emotionsCount // RETURN properties(group) AS inviteCodes
// `, // `,
// { postId, data }, // {
// ) // userId: context.user.id,
// return emotionsCountTransactionResponse.records.map( // },
// (record) => record.get('emotionsCount').low,
// ) // )
// return result.records.map((record) => record.get('inviteCodes'))
// }) // })
// if (email) {
// try { // try {
// const [emotionsCount] = await readTxResultPromise // session = context.driver.session()
// return emotionsCount // const readTxResult = await session.readTransaction((txc) => {
// const result = txc.run(
// `
// MATCH (user:User)-[:PRIMARY_EMAIL]->(e:EmailAddress {email: $args.email})
// RETURN user`,
// { args },
// )
// return result
// })
// return readTxResult.records.map((r) => r.get('user').properties)
// } finally { // } finally {
// session.close() // session.close()
// } // }
// },
// PostsEmotionsByCurrentUser: async (object, params, context, resolveInfo) => {
// const { postId } = params
// const session = context.driver.session()
// const readTxResultPromise = session.readTransaction(async (transaction) => {
// const emotionsTransactionResponse = await transaction.run(
// `
// MATCH (user:User {id: $userId})-[emoted:EMOTED]->(post:Post {id: $postId})
// RETURN collect(emoted.emotion) as emotion
// `,
// { userId: context.user.id, postId },
// )
// return emotionsTransactionResponse.records.map((record) => record.get('emotion'))
// })
// try {
// const [emotions] = await readTxResultPromise
// return emotions
// } finally {
// session.close()
// } // }
// return neo4jgraphql(object, args, context, resolveInfo)
// }, // },
// }, },
Mutation: { Mutation: {
CreateGroup: async (_parent, params, context, _resolveInfo) => { CreateGroup: async (_parent, params, context, _resolveInfo) => {
const { categoryIds } = params const { categoryIds } = params
@ -84,12 +68,14 @@ export default {
const writeTxResultPromise = session.writeTransaction(async (transaction) => { const writeTxResultPromise = session.writeTransaction(async (transaction) => {
const categoriesCypher = const categoriesCypher =
CONFIG.CATEGORIES_ACTIVE && categoryIds CONFIG.CATEGORIES_ACTIVE && categoryIds
? `WITH group ? `
WITH group, membership
UNWIND $categoryIds AS categoryId UNWIND $categoryIds AS categoryId
MATCH (category:Category {id: categoryId}) MATCH (category:Category {id: categoryId})
MERGE (group)-[:CATEGORIZED]->(category)` MERGE (group)-[:CATEGORIZED]->(category)
`
: '' : ''
const ownercreateGroupTransactionResponse = await transaction.run( const ownerCreateGroupTransactionResponse = await transaction.run(
` `
CREATE (group:Group) CREATE (group:Group)
SET group += $params SET group += $params
@ -97,14 +83,16 @@ export default {
SET group.updatedAt = toString(datetime()) SET group.updatedAt = toString(datetime())
WITH group WITH group
MATCH (owner:User {id: $userId}) MATCH (owner:User {id: $userId})
MERGE (group)<-[:OWNS]-(owner) MERGE (owner)-[membership:MEMBER_OF]->(group)
MERGE (group)<-[:ADMINISTERS]-(owner) SET membership.createdAt = toString(datetime())
SET membership.updatedAt = toString(datetime())
SET membership.role = 'owner'
${categoriesCypher} ${categoriesCypher}
RETURN group {.*} RETURN group {.*, myRole: membership.role}
`, `,
{ userId: context.user.id, categoryIds, params }, { userId: context.user.id, categoryIds, params },
) )
const [group] = ownercreateGroupTransactionResponse.records.map((record) => const [group] = ownerCreateGroupTransactionResponse.records.map((record) =>
record.get('group'), record.get('group'),
) )
return group return group
@ -205,10 +193,10 @@ export default {
// Wolle: tags: '-[:TAGGED]->(related:Tag)', // Wolle: tags: '-[:TAGGED]->(related:Tag)',
categories: '-[:CATEGORIZED]->(related:Category)', categories: '-[:CATEGORIZED]->(related:Category)',
}, },
hasOne: { // hasOne: {
owner: '<-[:OWNS]-(related:User)', // owner: '<-[:OWNS]-(related:User)',
// Wolle: image: '-[:HERO_IMAGE]->(related:Image)', // // Wolle: image: '-[:HERO_IMAGE]->(related:Image)',
}, // },
// Wolle: count: { // Wolle: count: {
// contributionsCount: // contributionsCount:
// '-[:WROTE]->(related:Post) WHERE NOT related.disabled = true AND NOT related.deleted = true', // '-[:WROTE]->(related:Post) WHERE NOT related.disabled = true AND NOT related.deleted = true',

View File

@ -292,9 +292,10 @@ describe('CreateGroup', () => {
data: { data: {
CreateGroup: { CreateGroup: {
name: 'The Best Group', name: 'The Best Group',
owner: { myRole: 'owner',
name: 'TestUser', // Wolle: owner: {
}, // name: 'TestUser',
// },
}, },
}, },
errors: undefined, errors: undefined,

View File

@ -0,0 +1,6 @@
enum GroupMemberRole {
pending
usual
admin
owner
}

View File

@ -39,10 +39,12 @@ type Group {
categories: [Category] @relation(name: "CATEGORIZED", direction: "OUT") categories: [Category] @relation(name: "CATEGORIZED", direction: "OUT")
myRole: GroupMemberRole # if 'null' then the current user is no member
# Wolle: needed? # Wolle: needed?
# socialMedia: [SocialMedia]! @relation(name: "OWNED_BY", direction: "IN") # socialMedia: [SocialMedia]! @relation(name: "OWNED_BY", direction: "IN")
owner: User @relation(name: "OWNS", direction: "IN") # Wolle: owner: User @relation(name: "OWNS", direction: "IN")
# Wolle: showShoutsPublicly: Boolean # Wolle: showShoutsPublicly: Boolean
# Wolle: sendNotificationEmails: Boolean # Wolle: sendNotificationEmails: Boolean
@ -129,9 +131,12 @@ input _GroupFilter {
AND: [_GroupFilter!] AND: [_GroupFilter!]
OR: [_GroupFilter!] OR: [_GroupFilter!]
name_contains: String name_contains: String
slug_contains: String
about_contains: String about_contains: String
description_contains: String description_contains: String
slug_contains: String groupType_in: [GroupType!]
actionRadius_in: [GroupActionRadius!]
myRole_in: [GroupMemberRole!]
id: ID id: ID
id_not: ID id_not: ID
id_in: [ID!] id_in: [ID!]
@ -161,20 +166,18 @@ input _GroupFilter {
# followedBy_none: _GroupFilter # followedBy_none: _GroupFilter
# followedBy_single: _GroupFilter # followedBy_single: _GroupFilter
# followedBy_every: _GroupFilter # followedBy_every: _GroupFilter
# role_in: [UserRole!]
} }
type Query { type Query {
Group( Group(
id: ID id: ID
email: String # admins need to search for a user sometimes
name: String name: String
slug: String slug: String
createdAt: String
updatedAt: String
locationName: String locationName: String
about: String about: String
description: String description: String
createdAt: String
updatedAt: String
first: Int first: Int
offset: Int offset: Int
orderBy: [_GroupOrdering] orderBy: [_GroupOrdering]

View File

@ -0,0 +1,5 @@
type MEMBER_OF {
createdAt: String!
updatedAt: String!
role: GroupMemberRole!
}