2021-02-08 10:30:30 +00:00
package query
import (
"context"
2022-01-20 14:40:25 +00:00
"database/sql"
errs "errors"
"time"
2021-12-14 07:19:02 +00:00
2022-01-20 14:40:25 +00:00
sq "github.com/Masterminds/squirrel"
"github.com/lib/pq"
"golang.org/x/text/language"
"github.com/caos/zitadel/internal/domain"
"github.com/caos/zitadel/internal/errors"
2021-12-14 07:19:02 +00:00
"github.com/caos/zitadel/internal/query/projection"
)
2022-01-20 14:40:25 +00:00
type Users struct {
SearchResponse
Users [ ] * User
}
type User struct {
ID string
CreationDate time . Time
ChangeDate time . Time
ResourceOwner string
Sequence uint64
State domain . UserState
Type domain . UserType
Username string
LoginNames [ ] string
PreferredLoginName string
Human * Human
Machine * Machine
}
type Human struct {
FirstName string
LastName string
NickName string
DisplayName string
AvatarKey string
PreferredLanguage language . Tag
Gender domain . Gender
Email string
IsEmailVerified bool
Phone string
IsPhoneVerified bool
}
type Profile struct {
ID string
CreationDate time . Time
ChangeDate time . Time
ResourceOwner string
Sequence uint64
FirstName string
LastName string
NickName string
DisplayName string
AvatarKey string
PreferredLanguage language . Tag
Gender domain . Gender
}
type Email struct {
ID string
CreationDate time . Time
ChangeDate time . Time
ResourceOwner string
Sequence uint64
Email string
IsVerified bool
}
type Phone struct {
ID string
CreationDate time . Time
ChangeDate time . Time
ResourceOwner string
Sequence uint64
Phone string
IsVerified bool
}
type Machine struct {
Name string
Description string
}
type UserSearchQueries struct {
SearchRequest
Queries [ ] SearchQuery
}
2021-12-14 07:19:02 +00:00
var (
userTable = table {
name : projection . UserTable ,
}
UserIDCol = Column {
name : projection . UserIDCol ,
table : userTable ,
}
UserCreationDateCol = Column {
name : projection . UserCreationDateCol ,
table : userTable ,
}
UserChangeDateCol = Column {
name : projection . UserChangeDateCol ,
table : userTable ,
}
UserResourceOwnerCol = Column {
name : projection . UserResourceOwnerCol ,
table : userTable ,
}
UserStateCol = Column {
name : projection . UserStateCol ,
table : userTable ,
}
UserSequenceCol = Column {
name : projection . UserSequenceCol ,
table : userTable ,
}
UserUsernameCol = Column {
name : projection . UserUsernameCol ,
table : userTable ,
}
2022-01-14 09:45:50 +00:00
UserTypeCol = Column {
name : projection . UserTypeCol ,
table : userTable ,
}
2022-02-02 07:21:54 +00:00
userLoginNamesTable = loginNameTable . setAlias ( "login_names" )
userLoginNamesUserIDCol = LoginNameUserIDCol . setTable ( userLoginNamesTable )
userLoginNamesNameCol = LoginNameNameCol . setTable ( userLoginNamesTable )
userLoginNamesListCol = Column {
name : "loginnames" ,
table : userLoginNamesTable ,
}
2022-01-20 14:40:25 +00:00
userPreferredLoginNameTable = loginNameTable . setAlias ( "preferred_login_name" )
userPreferredLoginNameUserIDCol = LoginNameUserIDCol . setTable ( userPreferredLoginNameTable )
userPreferredLoginNameCol = LoginNameNameCol . setTable ( userPreferredLoginNameTable )
userPreferredLoginNameIsPrimaryCol = LoginNameIsPrimaryCol . setTable ( userPreferredLoginNameTable )
2021-12-14 07:19:02 +00:00
)
var (
humanTable = table {
name : projection . UserHumanTable ,
}
// profile
HumanUserIDCol = Column {
name : projection . HumanUserIDCol ,
table : humanTable ,
}
HumanFirstNameCol = Column {
name : projection . HumanFirstNameCol ,
table : humanTable ,
}
HumanLastNameCol = Column {
name : projection . HumanLastNameCol ,
table : humanTable ,
}
HumanNickNameCol = Column {
name : projection . HumanNickNameCol ,
table : humanTable ,
}
HumanDisplayNameCol = Column {
name : projection . HumanDisplayNameCol ,
table : humanTable ,
}
HumanPreferredLanguageCol = Column {
name : projection . HumanPreferredLanguageCol ,
table : humanTable ,
}
HumanGenderCol = Column {
name : projection . HumanGenderCol ,
table : humanTable ,
}
2022-01-20 14:40:25 +00:00
HumanAvatarURLCol = Column {
name : projection . HumanAvatarURLCol ,
2021-12-14 07:19:02 +00:00
table : humanTable ,
}
// email
HumanEmailCol = Column {
name : projection . HumanEmailCol ,
table : humanTable ,
}
HumanIsEmailVerifiedCol = Column {
name : projection . HumanIsEmailVerifiedCol ,
table : humanTable ,
}
// phone
HumanPhoneCol = Column {
name : projection . HumanPhoneCol ,
table : humanTable ,
}
HumanIsPhoneVerifiedCol = Column {
name : projection . HumanIsPhoneVerifiedCol ,
table : humanTable ,
}
)
var (
machineTable = table {
name : projection . UserMachineTable ,
}
MachineUserIDCol = Column {
name : projection . MachineUserIDCol ,
table : machineTable ,
}
MachineNameCol = Column {
name : projection . MachineNameCol ,
table : machineTable ,
}
MachineDescriptionCol = Column {
name : projection . MachineDescriptionCol ,
table : machineTable ,
}
2021-02-08 10:30:30 +00:00
)
2022-01-20 14:40:25 +00:00
func ( q * Queries ) GetUserByID ( ctx context . Context , userID string , queries ... SearchQuery ) ( * User , error ) {
query , scan := prepareUserQuery ( )
for _ , q := range queries {
query = q . toQuery ( query )
}
stmt , args , err := query . Where (
sq . Eq {
UserIDCol . identifier ( ) : userID ,
} ) . ToSql ( )
if err != nil {
return nil , errors . ThrowInternal ( err , "QUERY-FBg21" , "Errors.Query.SQLStatment" )
}
row := q . client . QueryRowContext ( ctx , stmt , args ... )
return scan ( row )
}
func ( q * Queries ) GetUser ( ctx context . Context , queries ... SearchQuery ) ( * User , error ) {
query , scan := prepareUserQuery ( )
for _ , q := range queries {
query = q . toQuery ( query )
}
stmt , args , err := query . ToSql ( )
if err != nil {
return nil , errors . ThrowInternal ( err , "QUERY-Dnhr2" , "Errors.Query.SQLStatment" )
}
row := q . client . QueryRowContext ( ctx , stmt , args ... )
return scan ( row )
}
func ( q * Queries ) GetHumanProfile ( ctx context . Context , userID string , queries ... SearchQuery ) ( * Profile , error ) {
query , scan := prepareProfileQuery ( )
for _ , q := range queries {
query = q . toQuery ( query )
}
stmt , args , err := query . Where (
sq . Eq {
UserIDCol . identifier ( ) : userID ,
} ) . ToSql ( )
if err != nil {
return nil , errors . ThrowInternal ( err , "QUERY-Dgbg2" , "Errors.Query.SQLStatment" )
}
row := q . client . QueryRowContext ( ctx , stmt , args ... )
return scan ( row )
}
func ( q * Queries ) GetHumanEmail ( ctx context . Context , userID string , queries ... SearchQuery ) ( * Email , error ) {
query , scan := prepareEmailQuery ( )
for _ , q := range queries {
query = q . toQuery ( query )
}
stmt , args , err := query . Where (
sq . Eq {
UserIDCol . identifier ( ) : userID ,
} ) . ToSql ( )
if err != nil {
return nil , errors . ThrowInternal ( err , "QUERY-BHhj3" , "Errors.Query.SQLStatment" )
}
row := q . client . QueryRowContext ( ctx , stmt , args ... )
return scan ( row )
}
func ( q * Queries ) GetHumanPhone ( ctx context . Context , userID string , queries ... SearchQuery ) ( * Phone , error ) {
query , scan := preparePhoneQuery ( )
for _ , q := range queries {
query = q . toQuery ( query )
}
stmt , args , err := query . Where (
sq . Eq {
UserIDCol . identifier ( ) : userID ,
} ) . ToSql ( )
if err != nil {
return nil , errors . ThrowInternal ( err , "QUERY-Dg43g" , "Errors.Query.SQLStatment" )
}
row := q . client . QueryRowContext ( ctx , stmt , args ... )
return scan ( row )
}
func ( q * Queries ) SearchUsers ( ctx context . Context , queries * UserSearchQueries ) ( * Users , error ) {
query , scan := prepareUsersQuery ( )
stmt , args , err := queries . toQuery ( query ) . ToSql ( )
if err != nil {
return nil , errors . ThrowInternal ( err , "QUERY-Dgbg2" , "Errors.Query.SQLStatment" )
}
rows , err := q . client . QueryContext ( ctx , stmt , args ... )
if err != nil {
return nil , errors . ThrowInternal ( err , "QUERY-AG4gs" , "Errors.Internal" )
}
users , err := scan ( rows )
if err != nil {
return nil , err
}
users . LatestSequence , err = q . latestSequence ( ctx , userTable )
return users , err
}
func ( q * Queries ) IsUserUnique ( ctx context . Context , username , email , resourceOwner string ) ( bool , error ) {
query , scan := prepareUserUniqueQuery ( )
queries := make ( [ ] SearchQuery , 0 , 3 )
if username != "" {
usernameQuery , err := NewUserUsernameSearchQuery ( username , TextEquals )
if err != nil {
return false , err
}
queries = append ( queries , usernameQuery )
}
if email != "" {
emailQuery , err := NewUserEmailSearchQuery ( email , TextEquals )
if err != nil {
return false , err
}
queries = append ( queries , emailQuery )
}
if resourceOwner != "" {
resourceOwnerQuery , err := NewUserResourceOwnerSearchQuery ( resourceOwner , TextEquals )
if err != nil {
return false , err
}
queries = append ( queries , resourceOwnerQuery )
}
for _ , q := range queries {
query = q . toQuery ( query )
}
stmt , args , err := query . ToSql ( )
if err != nil {
return false , errors . ThrowInternal ( err , "QUERY-Dg43g" , "Errors.Query.SQLStatment" )
}
row := q . client . QueryRowContext ( ctx , stmt , args ... )
return scan ( row )
}
func ( q * UserSearchQueries ) toQuery ( query sq . SelectBuilder ) sq . SelectBuilder {
query = q . SearchRequest . toQuery ( query )
for _ , q := range q . Queries {
query = q . toQuery ( query )
}
return query
}
func ( r * UserSearchQueries ) AppendMyResourceOwnerQuery ( orgID string ) error {
query , err := NewUserResourceOwnerSearchQuery ( orgID , TextEquals )
if err != nil {
return err
}
r . Queries = append ( r . Queries , query )
return nil
}
func NewUserResourceOwnerSearchQuery ( value string , comparison TextComparison ) ( SearchQuery , error ) {
return NewTextQuery ( UserResourceOwnerCol , value , comparison )
}
func NewUserUsernameSearchQuery ( value string , comparison TextComparison ) ( SearchQuery , error ) {
return NewTextQuery ( UserUsernameCol , value , comparison )
}
func NewUserFirstNameSearchQuery ( value string , comparison TextComparison ) ( SearchQuery , error ) {
return NewTextQuery ( HumanFirstNameCol , value , comparison )
}
func NewUserLastNameSearchQuery ( value string , comparison TextComparison ) ( SearchQuery , error ) {
return NewTextQuery ( HumanLastNameCol , value , comparison )
}
func NewUserNickNameSearchQuery ( value string , comparison TextComparison ) ( SearchQuery , error ) {
return NewTextQuery ( HumanNickNameCol , value , comparison )
}
func NewUserDisplayNameSearchQuery ( value string , comparison TextComparison ) ( SearchQuery , error ) {
return NewTextQuery ( HumanDisplayNameCol , value , comparison )
}
func NewUserEmailSearchQuery ( value string , comparison TextComparison ) ( SearchQuery , error ) {
return NewTextQuery ( HumanEmailCol , value , comparison )
}
func NewUserStateSearchQuery ( value int32 ) ( SearchQuery , error ) {
return NewNumberQuery ( UserStateCol , value , NumberEquals )
}
func NewUserTypeSearchQuery ( value int32 ) ( SearchQuery , error ) {
return NewNumberQuery ( UserTypeCol , value , NumberEquals )
}
func NewUserPreferredLoginNameSearchQuery ( value string , comparison TextComparison ) ( SearchQuery , error ) {
return NewTextQuery ( userPreferredLoginNameCol , value , comparison )
}
func NewUserLoginNamesSearchQuery ( value string ) ( SearchQuery , error ) {
2022-02-02 07:21:54 +00:00
return NewTextQuery ( userLoginNamesListCol , value , TextListContains )
2022-01-20 14:40:25 +00:00
}
func prepareUserQuery ( ) ( sq . SelectBuilder , func ( * sql . Row ) ( * User , error ) ) {
loginNamesQuery , _ , err := sq . Select (
userLoginNamesUserIDCol . identifier ( ) ,
2022-02-02 07:21:54 +00:00
"ARRAY_AGG(" + userLoginNamesNameCol . identifier ( ) + ") as " + userLoginNamesListCol . name ) .
2022-01-20 14:40:25 +00:00
From ( userLoginNamesTable . identifier ( ) ) .
GroupBy ( userLoginNamesUserIDCol . identifier ( ) ) .
ToSql ( )
if err != nil {
return sq . SelectBuilder { } , nil
}
preferredLoginNameQuery , preferredLoginNameArgs , err := sq . Select (
userPreferredLoginNameUserIDCol . identifier ( ) ,
userPreferredLoginNameCol . identifier ( ) ) .
From ( userPreferredLoginNameTable . identifier ( ) ) .
Where (
sq . Eq {
userPreferredLoginNameIsPrimaryCol . identifier ( ) : true ,
} ) . ToSql ( )
if err != nil {
return sq . SelectBuilder { } , nil
}
return sq . Select (
UserIDCol . identifier ( ) ,
UserCreationDateCol . identifier ( ) ,
UserChangeDateCol . identifier ( ) ,
UserResourceOwnerCol . identifier ( ) ,
UserSequenceCol . identifier ( ) ,
UserStateCol . identifier ( ) ,
UserTypeCol . identifier ( ) ,
UserUsernameCol . identifier ( ) ,
2022-02-02 07:21:54 +00:00
userLoginNamesListCol . identifier ( ) ,
2022-01-20 14:40:25 +00:00
userPreferredLoginNameCol . identifier ( ) ,
HumanUserIDCol . identifier ( ) ,
HumanFirstNameCol . identifier ( ) ,
HumanLastNameCol . identifier ( ) ,
HumanNickNameCol . identifier ( ) ,
HumanDisplayNameCol . identifier ( ) ,
HumanPreferredLanguageCol . identifier ( ) ,
HumanGenderCol . identifier ( ) ,
HumanAvatarURLCol . identifier ( ) ,
HumanEmailCol . identifier ( ) ,
HumanIsEmailVerifiedCol . identifier ( ) ,
HumanPhoneCol . identifier ( ) ,
HumanIsPhoneVerifiedCol . identifier ( ) ,
MachineUserIDCol . identifier ( ) ,
MachineNameCol . identifier ( ) ,
MachineDescriptionCol . identifier ( ) ,
) .
From ( userTable . identifier ( ) ) .
LeftJoin ( join ( HumanUserIDCol , UserIDCol ) ) .
LeftJoin ( join ( MachineUserIDCol , UserIDCol ) ) .
2022-02-02 07:21:54 +00:00
LeftJoin ( "(" + loginNamesQuery + ") as " + userLoginNamesTable . alias + " on " + userLoginNamesUserIDCol . identifier ( ) + " = " + UserIDCol . identifier ( ) ) .
LeftJoin ( "(" + preferredLoginNameQuery + ") as " + userPreferredLoginNameTable . alias + " on " + userPreferredLoginNameUserIDCol . identifier ( ) + " = " + UserIDCol . identifier ( ) , preferredLoginNameArgs ... ) .
2022-01-20 14:40:25 +00:00
PlaceholderFormat ( sq . Dollar ) ,
func ( row * sql . Row ) ( * User , error ) {
u := new ( User )
loginNames := pq . StringArray { }
preferredLoginName := sql . NullString { }
humanID := sql . NullString { }
firstName := sql . NullString { }
lastName := sql . NullString { }
nickName := sql . NullString { }
displayName := sql . NullString { }
preferredLanguage := sql . NullString { }
gender := sql . NullInt32 { }
avatarKey := sql . NullString { }
email := sql . NullString { }
isEmailVerified := sql . NullBool { }
phone := sql . NullString { }
isPhoneVerified := sql . NullBool { }
machineID := sql . NullString { }
name := sql . NullString { }
description := sql . NullString { }
err := row . Scan (
& u . ID ,
& u . CreationDate ,
& u . ChangeDate ,
& u . ResourceOwner ,
& u . Sequence ,
& u . State ,
& u . Type ,
& u . Username ,
& loginNames ,
& preferredLoginName ,
& humanID ,
& firstName ,
& lastName ,
& nickName ,
& displayName ,
& preferredLanguage ,
& gender ,
& avatarKey ,
& email ,
& isEmailVerified ,
& phone ,
& isPhoneVerified ,
& machineID ,
& name ,
& description ,
)
if err != nil {
if errs . Is ( err , sql . ErrNoRows ) {
return nil , errors . ThrowNotFound ( err , "QUERY-Dfbg2" , "Errors.User.NotFound" )
}
return nil , errors . ThrowInternal ( err , "QUERY-Bgah2" , "Errors.Internal" )
}
u . LoginNames = loginNames
if preferredLoginName . Valid {
u . PreferredLoginName = preferredLoginName . String
}
if humanID . Valid {
u . Human = & Human {
FirstName : firstName . String ,
LastName : lastName . String ,
NickName : nickName . String ,
DisplayName : displayName . String ,
AvatarKey : avatarKey . String ,
PreferredLanguage : language . Make ( preferredLanguage . String ) ,
Gender : domain . Gender ( gender . Int32 ) ,
Email : email . String ,
IsEmailVerified : isEmailVerified . Bool ,
Phone : phone . String ,
IsPhoneVerified : isPhoneVerified . Bool ,
}
} else if machineID . Valid {
u . Machine = & Machine {
Name : name . String ,
Description : description . String ,
}
}
return u , nil
}
}
func prepareProfileQuery ( ) ( sq . SelectBuilder , func ( * sql . Row ) ( * Profile , error ) ) {
return sq . Select (
UserIDCol . identifier ( ) ,
UserCreationDateCol . identifier ( ) ,
UserChangeDateCol . identifier ( ) ,
UserResourceOwnerCol . identifier ( ) ,
UserSequenceCol . identifier ( ) ,
HumanUserIDCol . identifier ( ) ,
HumanFirstNameCol . identifier ( ) ,
HumanLastNameCol . identifier ( ) ,
HumanNickNameCol . identifier ( ) ,
HumanDisplayNameCol . identifier ( ) ,
HumanPreferredLanguageCol . identifier ( ) ,
HumanGenderCol . identifier ( ) ,
HumanAvatarURLCol . identifier ( ) ) .
From ( userTable . identifier ( ) ) .
LeftJoin ( join ( HumanUserIDCol , UserIDCol ) ) .
PlaceholderFormat ( sq . Dollar ) ,
func ( row * sql . Row ) ( * Profile , error ) {
p := new ( Profile )
humanID := sql . NullString { }
firstName := sql . NullString { }
lastName := sql . NullString { }
nickName := sql . NullString { }
displayName := sql . NullString { }
preferredLanguage := sql . NullString { }
gender := sql . NullInt32 { }
avatarKey := sql . NullString { }
err := row . Scan (
& p . ID ,
& p . CreationDate ,
& p . ChangeDate ,
& p . ResourceOwner ,
& p . Sequence ,
& humanID ,
& firstName ,
& lastName ,
& nickName ,
& displayName ,
& preferredLanguage ,
& gender ,
& avatarKey ,
)
if err != nil {
if errs . Is ( err , sql . ErrNoRows ) {
return nil , errors . ThrowNotFound ( err , "QUERY-HNhb3" , "Errors.User.NotFound" )
}
return nil , errors . ThrowInternal ( err , "QUERY-Rfheq" , "Errors.Internal" )
}
if ! humanID . Valid {
return nil , errors . ThrowPreconditionFailed ( nil , "QUERY-WLTce" , "Errors.User.NotHuman" )
}
p . FirstName = firstName . String
p . LastName = lastName . String
p . NickName = nickName . String
p . DisplayName = displayName . String
p . AvatarKey = avatarKey . String
p . PreferredLanguage = language . Make ( preferredLanguage . String )
p . Gender = domain . Gender ( gender . Int32 )
return p , nil
}
}
func prepareEmailQuery ( ) ( sq . SelectBuilder , func ( * sql . Row ) ( * Email , error ) ) {
return sq . Select (
UserIDCol . identifier ( ) ,
UserCreationDateCol . identifier ( ) ,
UserChangeDateCol . identifier ( ) ,
UserResourceOwnerCol . identifier ( ) ,
UserSequenceCol . identifier ( ) ,
HumanUserIDCol . identifier ( ) ,
HumanEmailCol . identifier ( ) ,
HumanIsEmailVerifiedCol . identifier ( ) ) .
From ( userTable . identifier ( ) ) .
LeftJoin ( join ( HumanUserIDCol , UserIDCol ) ) .
PlaceholderFormat ( sq . Dollar ) ,
func ( row * sql . Row ) ( * Email , error ) {
e := new ( Email )
humanID := sql . NullString { }
email := sql . NullString { }
isEmailVerified := sql . NullBool { }
err := row . Scan (
& e . ID ,
& e . CreationDate ,
& e . ChangeDate ,
& e . ResourceOwner ,
& e . Sequence ,
& humanID ,
& email ,
& isEmailVerified ,
)
if err != nil {
if errs . Is ( err , sql . ErrNoRows ) {
return nil , errors . ThrowNotFound ( err , "QUERY-Hms2s" , "Errors.User.NotFound" )
}
return nil , errors . ThrowInternal ( err , "QUERY-Nu42d" , "Errors.Internal" )
}
if ! humanID . Valid {
return nil , errors . ThrowPreconditionFailed ( nil , "QUERY-pt7HY" , "Errors.User.NotHuman" )
}
e . Email = email . String
e . IsVerified = isEmailVerified . Bool
return e , nil
}
}
func preparePhoneQuery ( ) ( sq . SelectBuilder , func ( * sql . Row ) ( * Phone , error ) ) {
return sq . Select (
UserIDCol . identifier ( ) ,
UserCreationDateCol . identifier ( ) ,
UserChangeDateCol . identifier ( ) ,
UserResourceOwnerCol . identifier ( ) ,
UserSequenceCol . identifier ( ) ,
HumanUserIDCol . identifier ( ) ,
HumanPhoneCol . identifier ( ) ,
HumanIsPhoneVerifiedCol . identifier ( ) ) .
From ( userTable . identifier ( ) ) .
LeftJoin ( join ( HumanUserIDCol , UserIDCol ) ) .
PlaceholderFormat ( sq . Dollar ) ,
func ( row * sql . Row ) ( * Phone , error ) {
e := new ( Phone )
humanID := sql . NullString { }
phone := sql . NullString { }
isPhoneVerified := sql . NullBool { }
err := row . Scan (
& e . ID ,
& e . CreationDate ,
& e . ChangeDate ,
& e . ResourceOwner ,
& e . Sequence ,
& humanID ,
& phone ,
& isPhoneVerified ,
)
if err != nil {
if errs . Is ( err , sql . ErrNoRows ) {
return nil , errors . ThrowNotFound ( err , "QUERY-DAvb3" , "Errors.User.NotFound" )
}
return nil , errors . ThrowInternal ( err , "QUERY-Bmf2h" , "Errors.Internal" )
}
if ! humanID . Valid {
return nil , errors . ThrowPreconditionFailed ( nil , "QUERY-hliQl" , "Errors.User.NotHuman" )
}
e . Phone = phone . String
e . IsVerified = isPhoneVerified . Bool
return e , nil
}
}
func prepareUserUniqueQuery ( ) ( sq . SelectBuilder , func ( * sql . Row ) ( bool , error ) ) {
return sq . Select (
UserIDCol . identifier ( ) ,
UserStateCol . identifier ( ) ,
UserUsernameCol . identifier ( ) ,
HumanUserIDCol . identifier ( ) ,
HumanEmailCol . identifier ( ) ,
HumanIsEmailVerifiedCol . identifier ( ) ) .
From ( userTable . identifier ( ) ) .
LeftJoin ( join ( HumanUserIDCol , UserIDCol ) ) .
PlaceholderFormat ( sq . Dollar ) ,
func ( row * sql . Row ) ( bool , error ) {
userID := sql . NullString { }
state := sql . NullInt32 { }
username := sql . NullString { }
humanID := sql . NullString { }
email := sql . NullString { }
isEmailVerified := sql . NullBool { }
err := row . Scan (
& userID ,
& state ,
& username ,
& humanID ,
& email ,
& isEmailVerified ,
)
if err != nil {
if errs . Is ( err , sql . ErrNoRows ) {
return true , nil
}
return false , errors . ThrowInternal ( err , "QUERY-Cxces" , "Errors.Internal" )
}
return ! userID . Valid , nil
}
}
func prepareUsersQuery ( ) ( sq . SelectBuilder , func ( * sql . Rows ) ( * Users , error ) ) {
loginNamesQuery , _ , err := sq . Select (
userLoginNamesUserIDCol . identifier ( ) ,
2022-02-02 07:21:54 +00:00
"ARRAY_AGG(" + userLoginNamesNameCol . identifier ( ) + ") as " + userLoginNamesListCol . name ) .
2022-01-20 14:40:25 +00:00
From ( userLoginNamesTable . identifier ( ) ) .
GroupBy ( userLoginNamesUserIDCol . identifier ( ) ) .
ToSql ( )
if err != nil {
return sq . SelectBuilder { } , nil
}
preferredLoginNameQuery , preferredLoginNameArgs , err := sq . Select (
userPreferredLoginNameUserIDCol . identifier ( ) ,
userPreferredLoginNameCol . identifier ( ) ) .
From ( userPreferredLoginNameTable . identifier ( ) ) .
Where (
sq . Eq {
userPreferredLoginNameIsPrimaryCol . identifier ( ) : true ,
} ) . ToSql ( )
if err != nil {
return sq . SelectBuilder { } , nil
}
return sq . Select (
UserIDCol . identifier ( ) ,
UserCreationDateCol . identifier ( ) ,
UserChangeDateCol . identifier ( ) ,
UserResourceOwnerCol . identifier ( ) ,
UserSequenceCol . identifier ( ) ,
UserStateCol . identifier ( ) ,
UserTypeCol . identifier ( ) ,
UserUsernameCol . identifier ( ) ,
2022-02-02 07:21:54 +00:00
userLoginNamesListCol . identifier ( ) ,
2022-01-20 14:40:25 +00:00
userPreferredLoginNameCol . identifier ( ) ,
HumanUserIDCol . identifier ( ) ,
HumanFirstNameCol . identifier ( ) ,
HumanLastNameCol . identifier ( ) ,
HumanNickNameCol . identifier ( ) ,
HumanDisplayNameCol . identifier ( ) ,
HumanPreferredLanguageCol . identifier ( ) ,
HumanGenderCol . identifier ( ) ,
HumanAvatarURLCol . identifier ( ) ,
HumanEmailCol . identifier ( ) ,
HumanIsEmailVerifiedCol . identifier ( ) ,
HumanPhoneCol . identifier ( ) ,
HumanIsPhoneVerifiedCol . identifier ( ) ,
MachineUserIDCol . identifier ( ) ,
MachineNameCol . identifier ( ) ,
MachineDescriptionCol . identifier ( ) ,
countColumn . identifier ( ) ) .
From ( userTable . identifier ( ) ) .
LeftJoin ( join ( HumanUserIDCol , UserIDCol ) ) .
LeftJoin ( join ( MachineUserIDCol , UserIDCol ) ) .
2022-02-02 07:21:54 +00:00
LeftJoin ( "(" + loginNamesQuery + ") as " + userLoginNamesTable . alias + " on " + userLoginNamesUserIDCol . identifier ( ) + " = " + UserIDCol . identifier ( ) ) .
LeftJoin ( "(" + preferredLoginNameQuery + ") as " + userPreferredLoginNameTable . alias + " on " + userPreferredLoginNameUserIDCol . identifier ( ) + " = " + UserIDCol . identifier ( ) , preferredLoginNameArgs ... ) .
2022-01-20 14:40:25 +00:00
PlaceholderFormat ( sq . Dollar ) ,
func ( rows * sql . Rows ) ( * Users , error ) {
users := make ( [ ] * User , 0 )
var count uint64
for rows . Next ( ) {
u := new ( User )
loginNames := pq . StringArray { }
preferredLoginName := sql . NullString { }
humanID := sql . NullString { }
firstName := sql . NullString { }
lastName := sql . NullString { }
nickName := sql . NullString { }
displayName := sql . NullString { }
preferredLanguage := sql . NullString { }
gender := sql . NullInt32 { }
avatarKey := sql . NullString { }
email := sql . NullString { }
isEmailVerified := sql . NullBool { }
phone := sql . NullString { }
isPhoneVerified := sql . NullBool { }
machineID := sql . NullString { }
name := sql . NullString { }
description := sql . NullString { }
err := rows . Scan (
& u . ID ,
& u . CreationDate ,
& u . ChangeDate ,
& u . ResourceOwner ,
& u . Sequence ,
& u . State ,
& u . Type ,
& u . Username ,
& loginNames ,
& preferredLoginName ,
& humanID ,
& firstName ,
& lastName ,
& nickName ,
& displayName ,
& preferredLanguage ,
& gender ,
& avatarKey ,
& email ,
& isEmailVerified ,
& phone ,
& isPhoneVerified ,
& machineID ,
& name ,
& description ,
& count ,
)
if err != nil {
return nil , err
}
u . LoginNames = loginNames
if preferredLoginName . Valid {
u . PreferredLoginName = preferredLoginName . String
}
if humanID . Valid {
u . Human = & Human {
FirstName : firstName . String ,
LastName : lastName . String ,
NickName : nickName . String ,
DisplayName : displayName . String ,
AvatarKey : avatarKey . String ,
PreferredLanguage : language . Make ( preferredLanguage . String ) ,
Gender : domain . Gender ( gender . Int32 ) ,
Email : email . String ,
IsEmailVerified : isEmailVerified . Bool ,
Phone : phone . String ,
IsPhoneVerified : isPhoneVerified . Bool ,
}
} else if machineID . Valid {
u . Machine = & Machine {
Name : name . String ,
Description : description . String ,
}
}
users = append ( users , u )
}
if err := rows . Close ( ) ; err != nil {
return nil , errors . ThrowInternal ( err , "QUERY-frhbd" , "Errors.Query.CloseRows" )
}
return & Users {
Users : users ,
SearchResponse : SearchResponse {
Count : count ,
} ,
} , nil
}
}