From 309e9ac8b3cea73f371e1a20e39d50df8765cb98 Mon Sep 17 00:00:00 2001 From: Prince Yadav <66916296+prince-0408@users.noreply.github.com> Date: Sat, 25 Apr 2026 16:46:36 +0530 Subject: [PATCH] feat: use nouns table for alphabetical autocompletions (#596) - Add queryNounAutocompletions(word:) to LanguageDBManager that queries all singular (key) columns from the language data contract numbers section using a UNION ALL across those columns with LIKE prefix% - Update queryAutocompletions(word:) to fall back to noun-based completions when the autocomplete_lexicon returns no results - Results are deduplicated, sorted COLLATE NOCASE ASC, limited to 3 Closes #596 --- Keyboards/DataManager/LanguageDBManager.swift | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/Keyboards/DataManager/LanguageDBManager.swift b/Keyboards/DataManager/LanguageDBManager.swift index 9816438f..ad928099 100644 --- a/Keyboards/DataManager/LanguageDBManager.swift +++ b/Keyboards/DataManager/LanguageDBManager.swift @@ -237,6 +237,7 @@ extension LanguageDBManager { } /// Returns the next three words in the `autocomplete_lexicon` that follow a given word. + /// Falls back to noun-based alphabetical autocompletions when the lexicon returns no results. /// /// - Parameters /// - word: the word that autosuggestions should be returned for. @@ -260,9 +261,52 @@ extension LanguageDBManager { let outputCols = ["word"] let args = ["\(word.lowercased())%"] - return queryDBRows( + let lexiconResults = queryDBRows( query: autocompletionsQuery, outputCols: outputCols, args: StatementArguments(args) ) + + // If the lexicon has results, return them; otherwise fall back to noun-based completions. + if !lexiconResults.isEmpty, !lexiconResults[0].isEmpty { + return lexiconResults + } + + return queryNounAutocompletions(word: word) + } + + /// Returns up to three alphabetically-ordered words from the nouns table that start with the given prefix. + /// Searches across all singular (key) columns defined in the language's data contract numbers section. + /// + /// - Parameters + /// - word: the prefix to match against noun columns. + func queryNounAutocompletions(word: String) -> [String] { + let language = getControllerLanguageAbbr() + let contract = ContractManager.shared.loadContract(language: language) + + guard let numbers = contract.numbers, !numbers.isEmpty else { + return [""] + } + + // Use all singular (key) columns from the numbers contract. + let singularColumns = Array(numbers.keys) + let prefix = word.lowercased() + + // Build a UNION query across all singular columns so we get a deduplicated, + // alphabetically sorted list of up to 3 matching nouns. + let unionParts = singularColumns.map { col in + "SELECT `\(col)` AS word FROM nouns WHERE LOWER(`\(col)`) LIKE ?" + } + let unionQuery = """ + SELECT DISTINCT word + FROM (\(unionParts.joined(separator: " UNION ALL "))) + WHERE word IS NOT NULL AND word != '' + ORDER BY word COLLATE NOCASE ASC + LIMIT 3 + """ + + // One `prefix%` argument per UNION part. + let args = StatementArguments(Array(repeating: "\(prefix)%", count: singularColumns.count)) + + return queryDBRows(query: unionQuery, outputCols: ["word"], args: args) } /// Query the suggestion of word in `autosuggestions`.