1+
12import db from '../data/db.js' ;
23import { FIELD_MAP , toDomain , toPersistence } from './mappers/personMapper.js' ;
34import { withSettingsInclude , saveSettings } from './utils/settings.js' ;
45import { resolveAttributesFromFields } from './utils/repoUtils.js' ;
56import { chapterJudgeInclude } from './chapterJudge.js' ;
7+ import { judgeInclude } from './judgeRepo.js' ;
68
79async function buildPersonQuery ( opts = { } ) {
810
@@ -16,95 +18,68 @@ async function buildPersonQuery(opts = {}) {
1618 attributes . exclude . push ( 'password' ) ;
1719 }
1820 }
21+
1922 const query = {
2023 where : { } ,
2124 attributes,
2225 include : [ ] ,
2326 } ;
2427
25- // Exclude banned persons
28+ // Build tag filters for settings include
29+ let settingsTags = [ ] ;
30+ if ( opts . settings === true ) {
31+ settingsTags = true ;
32+ } else if ( Array . isArray ( opts . settings ) ) {
33+ settingsTags = [ ...opts . settings ] ;
34+ }
35+
36+ const settingsInclude = withSettingsInclude ( {
37+ model : db . personSetting ,
38+ as : 'person_settings' ,
39+ settings : settingsTags ,
40+ } ) [ 0 ] ;
41+
2642 if ( opts . excludeBanned ) {
27- if ( ! query . where [ db . Sequelize . Op . and ] ) {
28- query . where [ db . Sequelize . Op . and ] = [ ] ;
29- }
43+ query . where [ db . Sequelize . Op . and ] = query . where [ db . Sequelize . Op . and ] || [ ] ;
3044 query . where [ db . Sequelize . Op . and ] . push (
31- db . sequelize . where (
32- db . sequelize . literal ( `NOT EXISTS (
33- SELECT 1 FROM person_setting banned
34- WHERE banned.person = person.id
35- AND banned.tag = 'banned'
36- )` ) ,
37- db . Sequelize . Op . eq ,
38- db . sequelize . literal ( '1' )
39- )
45+ db . Sequelize . literal ( `NOT EXISTS (SELECT 1 FROM person_setting ps WHERE ps.person = person.id AND ps.tag = 'banned')` )
4046 ) ;
4147 }
4248
43- // Exclude persons with unconfirmed emails
4449 if ( opts . excludeUnconfirmedEmail ) {
45- if ( ! query . where [ db . Sequelize . Op . and ] ) {
46- query . where [ db . Sequelize . Op . and ] = [ ] ;
47- }
50+ query . where [ db . Sequelize . Op . and ] = query . where [ db . Sequelize . Op . and ] || [ ] ;
4851 query . where [ db . Sequelize . Op . and ] . push (
49- db . sequelize . where (
50- db . sequelize . literal ( `NOT EXISTS (
51- SELECT 1 FROM person_setting email_unconfirmed
52- WHERE email_unconfirmed.person = person.id
53- AND email_unconfirmed.tag = 'email_unconfirmed'
54- AND email_unconfirmed.value = '1'
55- )` ) ,
56- db . Sequelize . Op . eq ,
57- db . sequelize . literal ( '1' )
58- )
52+ db . Sequelize . literal ( `NOT EXISTS (SELECT 1 FROM person_setting ps WHERE ps.person = person.id AND ps.tag = 'email_unconfirmed')` )
5953 ) ;
6054 }
61-
62- // Require a person to have a valid paradigm setting, and have been updated since the last paradigm review cutoff
63- if ( opts . hasValidParadigm ) {
64- const now = opts . now || new Date ( ) ;
65- const reviewSettings = await db . tabroomSetting . findAll ( {
66- where : {
67- tag : {
68- [ db . Sequelize . Op . in ] : [ 'paradigm_review_cutoff' , 'paradigm_review_start' ] ,
69- } ,
70- } ,
71- } ) ;
72- const reviewCutoff = reviewSettings . find ( setting => setting . tag === 'paradigm_review_cutoff' ) ;
73- const reviewStart = reviewSettings . find ( setting => setting . tag === 'paradigm_review_start' ) ;
74- const reviewClause = ( reviewCutoff ?. value_date
75- && reviewStart ?. value_date
76- && reviewCutoff . value_date < now )
77- ? ` AND paradigm.timestamp > ${ db . sequelize . escape ( reviewStart . value_date ) } `
78- : '' ;
79- if ( ! query . where [ db . Sequelize . Op . and ] ) {
80- query . where [ db . Sequelize . Op . and ] = [ ] ;
81- }
55+ if ( opts . hasValidParadigm ) {
56+ query . where [ db . Sequelize . Op . and ] = query . where [ db . Sequelize . Op . and ] || [ ] ;
57+ query . where [ db . Sequelize . Op . and ] . push (
58+ db . Sequelize . literal ( `EXISTS (SELECT 1 FROM person_setting ps WHERE ps.person = person.id AND ps.tag = 'paradigm')` )
59+ ) ;
60+ }
61+ if ( opts . hasJudged ) {
62+ query . where [ db . Sequelize . Op . and ] = query . where [ db . Sequelize . Op . and ] || [ ] ;
8263 query . where [ db . Sequelize . Op . and ] . push (
83- db . sequelize . where (
84- db . sequelize . literal ( `EXISTS (
85- SELECT 1 FROM person_setting paradigm
86- WHERE paradigm.person = person.id
87- AND paradigm.tag = 'paradigm'
88- ${ reviewClause }
89- )` ) ,
90- db . Sequelize . Op . eq ,
91- db . sequelize . literal ( '1' )
92- )
64+ db . Sequelize . literal ( `EXISTS (SELECT 1 FROM judge j WHERE j.person = person.id)` )
9365 ) ;
9466 }
9567
96- query . include . push (
97- ...withSettingsInclude ( {
98- model : db . personSetting ,
99- as : 'person_settings' ,
100- settings : opts . settings ,
101- } )
102- ) ;
68+ if ( settingsInclude ) {
69+ query . include . push ( settingsInclude ) ;
70+ }
10371
10472 // Add chapter join when requested
10573 if ( opts . include ?. chapterJudges ) {
10674 query . include . push ( chapterJudgeInclude ( opts . include . chapterJudges ) ) ;
10775 }
76+ if ( opts . include ?. judges ) {
77+ query . include . push ( {
78+ ...judgeInclude ( opts . include . judges ) ,
79+ as : 'judges' ,
80+ required : false ,
81+ } ) ;
82+ }
10883
10984 if ( Number . isInteger ( opts . limit ) ) {
11085 query . limit = opts . limit ;
@@ -152,32 +127,28 @@ async function personSearch(searchTerm = '', opts = {}) {
152127 const cleanTerm = sanitize ( searchTerm ) ;
153128 const words = cleanTerm . split ( / \s + / ) . filter ( w => w . length > 0 ) ;
154129
130+ if ( words . length === 0 ) {
131+ return [ ] ;
132+ }
133+
134+ // Use buildPersonQuery for all filters and includes
155135 const query = await buildPersonQuery ( opts ) ;
156- query . order = [ [ 'last' , 'ASC' ] , [ 'first' , 'ASC' ] ] ;
157- query . attributes = [
158- 'id' ,
159- 'first' ,
160- 'last' ,
161- ] ;
162-
163- // Build name search conditions that handle multi-word search
164- // "john smith", "smith john", "john", "smith" should all match person with firstName=john, lastName=smith
165- if ( words . length > 0 ) {
166- const nameConditions = words . map ( word => ( {
136+
137+ // Add name search to where clause
138+ query . where = query . where || { } ;
139+ query . where [ db . Sequelize . Op . and ] = query . where [ db . Sequelize . Op . and ] || [ ] ;
140+ for ( const word of words ) {
141+ query . where [ db . Sequelize . Op . and ] . push ( {
167142 [ db . Sequelize . Op . or ] : [
168143 { first : { [ db . Sequelize . Op . like ] : `${ word } %` } } ,
169144 { last : { [ db . Sequelize . Op . like ] : `${ word } %` } } ,
170145 ] ,
171- } ) ) ;
172-
173- query . where = {
174- ...query . where ,
175- [ db . Sequelize . Op . and ] : nameConditions ,
176- } ;
146+ } ) ;
177147 }
178148
179- query . limit = opts . limit || 75 ;
180- query . subQuery = false ;
149+ query . order = [ [ 'last' , 'ASC' ] , [ 'first' , 'ASC' ] ] ;
150+ //query.subQuery = false;
151+ //query.distinct = true;
181152
182153 const results = await db . person . findAll ( query ) ;
183154 return results . map ( toDomain ) ;
0 commit comments