(entries, currentDir)
| 4030 | function compileSearchTokensToSQL(tokens, params, filters) { |
| 4031 | const t = sanitizeSearchTokensForCompile(tokens); |
| 4032 | if (t.length === 0) return null; |
| 4033 | try { |
| 4034 | const [sql, end] = parseSearchOr(t, 0, params, filters); |
| 4035 | if (end !== t.length) return null; |
| 4036 | return sql; |
| 4037 | } catch (e) { |
| 4038 | console.warn('compileSearchTokensToSQL failed:', e.message); |
| 4039 | return null; |
| 4040 | } |
| 4041 | } |
| 4042 | |
| 4043 | /** Multi-value designer / parentModel / license (matches legacy single-value SQL for invert + NULL). */ |
| 4044 | function pushEqualityListCondition(conditions, params, column, values, combineOp, inverted, useLowerTrim) { |
| 4045 | if (!values.length) return; |
| 4046 | const posJoin = combineOp === 'AND' ? ' AND ' : ' OR '; |
| 4047 | if (!inverted) { |
| 4048 | const posParts = []; |
| 4049 | for (const v of values) { |
| 4050 | if (v === '__none__') { |
| 4051 | posParts.push(`(${column} IS NULL OR ${column} = '')`); |
| 4052 | } else if (useLowerTrim) { |
| 4053 | params.push(v); |
| 4054 | posParts.push(`LOWER(TRIM(${column})) = LOWER(TRIM(?))`); |
| 4055 | } else { |
| 4056 | params.push(v); |
| 4057 | posParts.push(`${column} = ?`); |
| 4058 | } |
| 4059 | } |
| 4060 | conditions.push(posParts.length === 1 ? posParts[0] : `(${posParts.join(posJoin)})`); |
| 4061 | return; |
| 4062 | } |
| 4063 | const negJoin = combineOp === 'OR' ? ' AND ' : ' OR '; |
| 4064 | const negParts = []; |
| 4065 | for (const v of values) { |
| 4066 | if (v === '__none__') { |
| 4067 | negParts.push(`(${column} IS NOT NULL AND ${column} != '')`); |
| 4068 | } else if (useLowerTrim) { |
| 4069 | params.push(v); |
| 4070 | negParts.push(`(${column} IS NULL OR ${column} = '' OR LOWER(TRIM(${column})) != LOWER(TRIM(?)))`); |
| 4071 | } else { |
| 4072 | params.push(v); |
| 4073 | negParts.push(`(${column} IS NULL OR ${column} = '' OR ${column} != ?)`); |
| 4074 | } |
| 4075 | } |
| 4076 | conditions.push(negParts.length === 1 ? negParts[0] : `(${negParts.join(negJoin)})`); |
| 4077 | } |
| 4078 | |
| 4079 | function pushTagListSQL(conditions, params, filters) { |
| 4080 | const tagNames = normalizeTagNameList(filters); |
| 4081 | if (!tagNames.length) return false; |
| 4082 | const combine = filters.tagCombine === 'AND' ? 'AND' : 'OR'; |
| 4083 | const inverted = !!filters.tagInverted; |
| 4084 | let inner; |
| 4085 | if (combine === 'OR') { |
no test coverage detected