#1237: MagicFilterProcessor.kt

projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/api/MagicFilterProcessor.kt Object / Filter Processor — Persistence Search Engine, projectforge-business/src/main/kotlin/org/projectforge/framework/persistence/api/MagicFilterProcessor.kt 222 lines · 179 code · 33 comments · 10 blank
Kotlin singleton object that transforms user-facing MagicFilter objects into the database-ready QueryFilter. Interprets each MagicFilterEntry using JPA metamodel reflection (PropUtils) and Hibernate Search metadata (HibernateSearchMeta) to build typed predicates: string LIKE searches, date/numeric ranges, boolean equality, task tree searches, I18nEnum value filters, and Hibernate Envers history queries.

Architecture

Processing Pipeline

MagicFilter  ──►  MagicFilterProcessor.doIt()  ──►  QueryFilter  ──►  DBFilter  ──►  JPA/Hibernate

The processor bridges the gap between the UI-oriented MagicFilter (which can represent filters from React/AG-Grid frontends) and the database-oriented QueryFilter (which builds JPA Criteria API queries and Hibernate Search full-text queries).

Main Entry Point

fun doIt(entityClass: Class<*>, magicFilter: MagicFilter, queryFilter: QueryFilter = QueryFilter()): QueryFilter

Takes an entity class for reflection, a MagicFilter from the user, and optionally an existing QueryFilter to populate. Returns the fully populated QueryFilter.

Processing Steps

  1. Special fields extraction: deleted, searchHistory, MODIFIED_HISTORY_VALUE are extracted from entries and handled directly
  2. Core filter transfer: deleted, maxRows, searchHistory, sortProperties, extended are copied to QueryFilter
  3. Full-text search: If searchString is non-blank, a DBPredicate.FullSearch is added with wildcard support
  4. Field search iteration: Each MagicFilterEntry is classified and transformed in createFieldSearchEntry()

Type-Based Predicate Generation (createFieldSearchEntry)

Field TypePredicate GeneratedNotes
History entrySets modifiedFrom, modifiedTo, modifiedByUserId on QueryFilterUses Hibernate Envers
StringDBPredicate.Like(field, value, autoWildcardSearch)Case-insensitive LIKE
DateQueryFilter.interval() / eq() / isNull()Parsed via PFDateTimeUtils
LocalDateQueryFilter.interval() / eq() / isNull()Parsed via PFDayUtils
IntegerQueryFilter.interval() / eq() / isNull()Parsed via NumberHelper
BooleanQueryFilter.eq(field, value == "true")String-to-boolean conversion
TaskDO subclassQueryFilter.taskSearch()Recursive task tree lookup with descendant IDs
BaseDO subclassQueryFilter.eq() / isNull()Parsed as integer ID
I18nEnum subclassDBPredicate.IsIn(field, enumConstants)Multi-value enum filter via IN clause
Not found (JPA metamodel)Fallback to DBPredicate.FullSearch() with field arrayUses Hibernate Search index metadata for non-persistent fields
Not found (either)Warning logged, entry ignoredGraceful degradation

Helper Methods

MethodPurpose
isHistoryEntry(field)Checks if the field matches any MagicFilterEntry.HistorySearch enum value
isModifiedInterval(field)Specific check for MODIFIED_INTERVAL history field
isModifiedByUserId(field)Specific check for MODIFIED_BY_USER history field

Key Integration Points

Git History

868d6abb7 2025 -> 2026
63081666f Source file headers: 2024-> 2025.
04c38072b AddressDao: select optimized, WIP: pagination.
7957637da Migration stuff in progress... (all tests of all packages: OK).
3264694a8 Migration stuff in progress... (all tests of all packages: OK).
4c04cfd65 MAJOR-CHANGE! Migration of integer id's to Long id's (including fk's etc.)
b6092df09 Copyright 2023 -> 2024
ab45d51fa Copyright 2001-2022 -> 2001-2023.
9c4cc0ae3 WIP: Use AGGrid in list pages.
5f7ef41b8 Copyright 2021 -> 2022
d5dda1711 Bugfix in list search: search for keywords and modified-by-user is now supported in history search.
09bec8f9d UITable and MagicFilterProcessor: support of type Boolean.
ceb63e8a1 Source code header: (C) 2001-2021.
8a2e1215a Support of pageSize added to MagicFilterProcessor.
658d96c77 WIP 93: implementing drop down choices in magic filter entries.
b2657ec3a Vacation list, MagicFilterProcessort supports now I18nEnum values.
0a321235d MagicFilterEntry.synthetic implemented (myFavorites and doublets of address filter are now supported as filter settings).
9709a04cf Address: search for doublets and favorites implemented.
ae7140482 React: MagicCheckboxInput implemented, deleted entries in list are now decorated with line-through.
2ecda305b PFUTCDateTime introduced, parsing dates will no handled by PFDayUtils and PFDateTimeUtils.
611b20d4e WIP: java.sql.Date -> LocalDate.
1f0ceacca MagicFilter: modify searchString automatically as str*
243613fe9 MagicFilter.searchString re-added, translation added.
7c79f1922 Copyright of source header -> 2020.
13cfb0330 WIP: Migration to PFDate and PFDateTime.
1165d1557 WIP Addresses and CustomResultFilter introduced.
3096abc37 MagicFilter.autoWildcardSearch
dc60c1487 MagicFilter.autoWildcardSearch
031b5b380 MagicFilter.autostartWithSearch
bf3d20864 DB.SortProperty fixed.
a9f7fb127 WiP: DBQuery* and QueryFilter...
d32649da3 WIP: DBQuery*, QueryFilter and Predicates refactored....
d651c2d98 MagicFilterEntry.value.str -> value.value. user/ac -> user/aco
619521cf5 MagicFilter: Test: Entry.value -> Entry.value.stringValue.
41bb8904e MagicFilter: Test: Entry.value -> Entry.value.stringValue.
db997435f WIP: MagicFilter...
c0c5e427c WIP: MagicFilter...
aba5af116 BaseDao.contains and BaseDao.getHistoryEntries are now public. WIP: MagicFilter...
5e3bbdfc5 WIP: MagicFilter...
7cefcd6f3 WIP: MagicFilter...
507854213 WIP: MagicFilter...