@@ -653,8 +653,8 @@ class PuddySqlQuery {
653653 return `${ col } IN (${ inList } )` ;
654654 } ) ;
655655 cases . push ( `WHEN ${ conditions . join ( ' OR ' ) } THEN ${ weight } ` ) ;
656- }
657-
656+ }
657+
658658 // Other modes
659659 else {
660660 if ( typeof value !== 'string' )
@@ -2056,12 +2056,10 @@ class PuddySqlQuery {
20562056 * @param {SelectQuery } [searchData.select='*'] - Which columns to select. Set to null to skip item data.
20572057 * @param {string } [searchData.order] - SQL ORDER BY clause. Defaults to configured order.
20582058 * @param {string|JoinObj|JoinObj[] } [searchData.join] - JOIN definitions with table, compare, and optional type.
2059- * @returns {Promise<FindResult | null> }
2059+ * @returns {{ query: string; values: any[] | undefined; perPage: number; selectValue: SelectQuery; } }
20602060 * @throws {Error } If searchData has invalid structure or values.
20612061 */
2062- async find ( searchData = { } ) {
2063- const db = this . getDb ( ) ;
2064-
2062+ findQuery ( searchData = { } ) {
20652063 // --- Validate searchData types ---
20662064 if ( ! isJsonObject ( searchData ) ) throw new TypeError ( `'searchData' must be a object` ) ;
20672065 const criteria = searchData . q || { } ;
@@ -2154,7 +2152,31 @@ class PuddySqlQuery {
21542152 WHERE rn = 1
21552153 ` . trim ( ) ;
21562154
2157- const row = await db . get ( query , pCache . values , 'find' ) ;
2155+ return { query, values : pCache . values , perPage, selectValue } ;
2156+ }
2157+
2158+ /**
2159+ * Finds the first item matching the filter, along with its position, page, and total info.
2160+ * Uses a single SQL query to calculate everything efficiently.
2161+ *
2162+ * If selectValue is null, it only returns the pagination/position data, not the item itself.
2163+ *
2164+ * @param {Object } [searchData={}] - Main search configuration.
2165+ * @param {QueryGroup } [searchData.q={}] - Nested criteria object.
2166+ * @param {TagCriteria[]|TagCriteria|null } [searchData.tagCriteria] - One or multiple tag criteria groups.
2167+ * @param {string[] } [searchData.tagCriteriaOps] - Optional logical operators between tag groups (e.g., ['AND', 'OR']).
2168+ * @param {number } [searchData.perPage] - Number of items per page.
2169+ * @param {SelectQuery } [searchData.select='*'] - Which columns to select. Set to null to skip item data.
2170+ * @param {string } [searchData.order] - SQL ORDER BY clause. Defaults to configured order.
2171+ * @param {string|JoinObj|JoinObj[] } [searchData.join] - JOIN definitions with table, compare, and optional type.
2172+ * @returns {Promise<FindResult | null> }
2173+ * @throws {Error } If searchData has invalid structure or values.
2174+ */
2175+ async find ( searchData = { } ) {
2176+ const db = this . getDb ( ) ;
2177+ const { query, values, perPage, selectValue } = this . findQuery ( searchData ) ;
2178+
2179+ const row = await db . get ( query , values , 'find' ) ;
21582180 if ( ! row ) return null ;
21592181
21602182 const total = parseInt ( row . total ) ;
@@ -2198,7 +2220,7 @@ class PuddySqlQuery {
21982220 * @param {string|JoinObj|JoinObj[] } [searchData.join] - A string for single join or array of objects for multiple joins.
21992221 * Each object should contain `{ table: 'name', compare: 'ON clause' }`.
22002222 * @param {number } [searchData.limit] - Max number of results to return (ignored when `perPage` is used).
2201- * @returns {Promise<FreeObj[]|PaginationResult> } - Result rows matching the query.
2223+ * @returns {{ query: string; perPage: number | null; values: any[]; page: number; } }
22022224 * @throws {Error } If searchData has invalid structure or values.
22032225 *
22042226 * @example
@@ -2235,9 +2257,7 @@ class PuddySqlQuery {
22352257 * order: 'created_at DESC'
22362258 * });
22372259 */
2238-
2239- async search ( searchData = { } ) {
2240- const db = this . getDb ( ) ;
2260+ searchQuery ( searchData = { } ) {
22412261 if ( ! isJsonObject ( searchData ) ) throw new TypeError ( `'searchData' must be a object` ) ;
22422262 const order = searchData . order || this . #settings. order ;
22432263 const join = searchData . join || this . #settings. join ;
@@ -2340,6 +2360,34 @@ class PuddySqlQuery {
23402360 ${ orderClause }
23412361 ${ limitClause } ` . trim ( ) ;
23422362
2363+ return { query, perPage, values, page } ;
2364+ }
2365+
2366+ /**
2367+ * Perform a filtered search with advanced nested criteria, pagination, and customizable settings.
2368+ *
2369+ * Supports complex logical groupings (AND/OR), flat condition style, custom ordering, and single or multiple joins.
2370+ * Pagination can be enabled using `perPage`, and additional settings like `order`, `join`, and `limit` can be passed inside `searchData`.
2371+ *
2372+ * @param {Object } [searchData={}] - Main search configuration.
2373+ * @param {QueryGroup } [searchData.q={}] - Nested criteria object.
2374+ * Can be a flat object style or grouped with `{ group: 'AND'|'OR', conditions: [...] }`.
2375+ * @param {TagCriteria[]|TagCriteria|null } [searchData.tagsQ] - One or multiple tag criteria groups.
2376+ * @param {string[] } [searchData.tagsOpsQ] - Optional logical operators between tag groups (e.g., ['AND', 'OR']).
2377+ * @param {SelectQuery } [searchData.select='*'] - Defines which columns or expressions should be selected in the query.
2378+ * @param {number|null } [searchData.perPage=null] - Number of results per page. If set, pagination is applied.
2379+ * @param {number } [searchData.page=1] - Page number to retrieve when `perPage` is used.
2380+ * @param {string } [searchData.order] - Custom `ORDER BY` clause (e.g. `'created_at DESC'`).
2381+ * @param {string|JoinObj|JoinObj[] } [searchData.join] - A string for single join or array of objects for multiple joins.
2382+ * Each object should contain `{ table: 'name', compare: 'ON clause' }`.
2383+ * @param {number } [searchData.limit] - Max number of results to return (ignored when `perPage` is used).
2384+ * @returns {Promise<FreeObj[]|PaginationResult> } - Result rows matching the query.
2385+ * @throws {Error } If searchData has invalid structure or values.
2386+ */
2387+ async search ( searchData = { } ) {
2388+ const db = this . getDb ( ) ;
2389+ const { query, values, perPage, page } = this . searchQuery ( searchData ) ;
2390+
23432391 // Results
23442392 let results ;
23452393
0 commit comments