////
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
////

[[core-personAuthorityGroupClass]]
=== PersonGroup Class

The typical approach to mapping the relationship between "`person`" and "`group`" is a many-to-many. In a standard implementation, users have multiple roles, and roles are shared by multiple users. In a group implementation, users have multiple groups, and groups are shared by multiple users. For the same reason we would use a join class between "`person`" and "`authority`", we should use one between "`person`" and "`group`". Please note that when using groups, there should not be a join class between "`person`" and "`authority`", since "`group`" resides between the two.

If you run the <<core-s2-quickstart>> script with the group name specified, this class will be generated for you, so you don't need to deal with the details of mapping it. Assuming you choose `com.mycompany.myapp` as your package, and `User` and `RoleGroup` as your class names, you'll generate this class:

[source, groovy]
.`UserRoleGroup.groovy`
----
package com.mycompany.myapp

import grails.gorm.DetachedCriteria
import groovy.transform.ToString
import org.codehaus.groovy.util.HashCodeHelper
import grails.compiler.GrailsCompileStatic

@GrailsCompileStatic
@ToString(cache = true, includeNames = true, includePackage = false)
class UserRoleGroup implements Serializable {

    private static final long serialVersionUID = 1

    User user
    RoleGroup roleGroup

    @Override
    boolean equals(other) {
        if (other instanceof UserRoleGroup) {
            other.userId == user?.id && other.roleGroupId == roleGroup?.id
        }
        false
    }

    @Override
    int hashCode() {
        int hashCode = HashCodeHelper.initHash()
        if (user) {
            hashCode = HashCodeHelper.updateHash(hashCode, user.id)
        }
        if (roleGroup) {
            hashCode = HashCodeHelper.updateHash(hashCode, roleGroup.id)
        }
        hashCode
    }

    static UserRoleGroup get(long userId, long roleGroupId) {
        criteriaFor(userId, roleGroupId).get()
    }

    static boolean exists(long userId, long roleGroupId) {
        criteriaFor(userId, roleGroupId).count()
    }

    private static DetachedCriteria criteriaFor(long userId, long roleGroupId) {
        UserRoleGroup.where {
            user == User.load(userId) &&
            roleGroup == RoleGroup.load(roleGroupId)
        }
    }

    static UserRoleGroup create(User user, RoleGroup roleGroup, boolean flush = false) {
        def instance = new UserRoleGroup(user: user, roleGroup: roleGroup)
        instance.save(flush: flush)
        instance
    }

    static boolean remove(User u, RoleGroup rg) {
        if (u != null && rg != null) {
            UserRoleGroup.where { user == u && roleGroup == rg }.deleteAll()
        }
    }

    static int removeAll(User u) {
        u == null ? 0 : UserRoleGroup.where { user == u }.deleteAll() as int
    }

    static int removeAll(RoleGroup rg) {
        rg == null ? 0 : UserRoleGroup.where { roleGroup == rg }.deleteAll() as int
    }

    static constraints = {
        user validator: { User u, UserRoleGroup ug ->
            if (ug.roleGroup?.id) {
                UserRoleGroup.withNewSession {
                    if (UserRoleGroup.exists(u.id, ug.roleGroup.id)) {
                        return ['userGroup.exists']
                    }
                }
            }
        }
    }

    static mapping = {
        id composite: ['roleGroup', 'user']
        version false
    }
}
----
