search: let radical search API take RadkfileRadical inputs
Build and test / build (push) Successful in 5m11s

This commit is contained in:
2026-06-03 19:32:52 +09:00
parent f3dba3ffab
commit a46d61c335
4 changed files with 36 additions and 28 deletions
+6
View File
@@ -1,3 +1,5 @@
import 'package:collection/collection.dart';
class RadkfileRadical {
/// The formal variant of the radical
///
@@ -302,3 +304,7 @@ const Map<int, List<RadkfileRadical>> radicals = {
],
17: [RadkfileRadical(formalVariant: '', strokeCount: 17)],
};
final Map<String, RadkfileRadical> radicalsByFormalVariant = {
for (final r in radicals.values.flattened) r.formalVariant: r,
};
+7 -4
View File
@@ -1,3 +1,4 @@
import 'package:jadb/const_data/radicals.dart';
import 'package:jadb/models/kanji_search/kanji_search_result.dart';
import 'package:jadb/models/verify_tables.dart';
import 'package:jadb/models/word_search/word_search_result.dart';
@@ -63,13 +64,15 @@ extension JaDBConnection on DatabaseExecutor {
/// of the radicals, find their other radicals, and return those.
/// This is used to figure out which remaining combinations of radicals
/// the user can search for without getting zero results.
Future<List<String>> jadbSearchRemainingRadicals(List<String> radicals) =>
searchRemainingRadicalsWithDbConnection(this, radicals);
Future<List<RadkfileRadical>> jadbSearchRemainingRadicals(
List<RadkfileRadical> radicals,
) => searchRemainingRadicalsWithDbConnection(this, radicals);
/// Given a list of radicals, search which kanji contains all
/// of the radicals, and return those.
Future<List<String>> jadbSearchKanjiByRadicals(List<String> radicals) =>
searchKanjiByRadicalsWithDbConnection(this, radicals);
Future<List<String>> jadbSearchKanjiByRadicals(
List<RadkfileRadical> radicals,
) => searchKanjiByRadicalsWithDbConnection(this, radicals);
/// Retrieve the version information for all datasources in the database.
Future<DatasourceVersions> jadbGetDatasourceVersions() =>
+9 -5
View File
@@ -1,3 +1,4 @@
import 'package:jadb/const_data/radicals.dart';
import 'package:jadb/table_names/radkfile.dart';
import 'package:sqflite_common/sqlite_api.dart';
@@ -7,9 +8,9 @@ import 'package:sqflite_common/sqlite_api.dart';
///
/// This can be used to limit the choices of additional radicals provided to a user,
/// so that any choice they make will still yield at least one kanji.
Future<List<String>> searchRemainingRadicalsWithDbConnection(
Future<List<RadkfileRadical>> searchRemainingRadicalsWithDbConnection(
DatabaseExecutor connection,
List<String> radicals,
List<RadkfileRadical> radicals,
) async {
final distinctRadicals = radicals.toSet();
@@ -25,11 +26,14 @@ Future<List<String>> searchRemainingRadicalsWithDbConnection(
HAVING COUNT(DISTINCT "radical") = ?
)
''',
[...distinctRadicals, distinctRadicals.length],
[...distinctRadicals.map((r) => r.formalVariant), distinctRadicals.length],
);
final remainingRadicals = queryResult
.map((row) => row['radical'] as String)
// TODO: maybe we should do some runtime checking here, just to throw a sensible error
// if something goes horribly wrong?
.map((r) => radicalsByFormalVariant[r]!)
.toList();
return remainingRadicals;
@@ -38,7 +42,7 @@ Future<List<String>> searchRemainingRadicalsWithDbConnection(
/// Returns a list of kanji that contain all of the input radicals.
Future<List<String>> searchKanjiByRadicalsWithDbConnection(
DatabaseExecutor connection,
List<String> radicals,
List<RadkfileRadical> radicals,
) async {
final distinctRadicals = radicals.toSet();
@@ -50,7 +54,7 @@ Future<List<String>> searchKanjiByRadicalsWithDbConnection(
GROUP BY "kanji"
HAVING COUNT(DISTINCT "radical") = ?
''',
[...distinctRadicals, distinctRadicals.length],
[...distinctRadicals.map((r) => r.formalVariant), distinctRadicals.length],
);
final kanji = queryResult.map((row) => row['kanji'] as String).toList();
+14 -19
View File
@@ -58,31 +58,26 @@ void main() {
},
);
test(
'All constant radicals are located in the correct stroke count group',
() {
for (final mapEntry in radicals.entries) {
final strokeCount = mapEntry.key;
final radicalsInGroup = mapEntry.value;
for (final radical in radicalsInGroup) {
expect(
strokeCount,
radical.strokeCount,
reason:
'Radical ${radical.formalVariant} should have stroke count $strokeCount but has ${radical.strokeCount}',
);
}
test('All constant radicals are located in the correct stroke count group', () {
for (final mapEntry in radicals.entries) {
final strokeCount = mapEntry.key;
final radicalsInGroup = mapEntry.value;
for (final radical in radicalsInGroup) {
expect(
strokeCount,
radical.strokeCount,
reason:
'Radical ${radical.formalVariant} should have stroke count $strokeCount but has ${radical.strokeCount}',
);
}
},
);
}
});
group('All radicals should return results', () {
for (final radical in radicals.values.flattened) {
test(' - $radical', () async {
final connection = await setupDatabaseConnection();
final result = await connection.jadbSearchKanjiByRadicals([
radical.formalVariant,
]);
final result = await connection.jadbSearchKanjiByRadicals([radical]);
expect(result, isNotEmpty);
});
}