mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-02-12 20:47:42 +01:00
Add db api to query summary of all the files
This commit is contained in:
parent
99c8448bde
commit
97b3e99aa7
5 changed files with 173 additions and 0 deletions
|
@ -126,6 +126,31 @@ class DbLocationGroupResult {
|
||||||
final List<DbLocationGroup> countryCode;
|
final List<DbLocationGroup> countryCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@toString
|
||||||
|
class DbFilesSummaryItem {
|
||||||
|
const DbFilesSummaryItem({
|
||||||
|
required this.count,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => _$toString();
|
||||||
|
|
||||||
|
final int count;
|
||||||
|
}
|
||||||
|
|
||||||
|
@toString
|
||||||
|
class DbFilesSummary {
|
||||||
|
const DbFilesSummary({
|
||||||
|
required this.items,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => _$toString();
|
||||||
|
|
||||||
|
@Format(r"{length: ${$?.length}}")
|
||||||
|
final Map<DateTime, DbFilesSummaryItem> items;
|
||||||
|
}
|
||||||
|
|
||||||
@npLog
|
@npLog
|
||||||
abstract class NpDb {
|
abstract class NpDb {
|
||||||
factory NpDb() => NpDbSqlite();
|
factory NpDb() => NpDbSqlite();
|
||||||
|
@ -321,9 +346,23 @@ abstract class NpDb {
|
||||||
String? location,
|
String? location,
|
||||||
bool? isFavorite,
|
bool? isFavorite,
|
||||||
List<String>? mimes,
|
List<String>? mimes,
|
||||||
|
int? offset,
|
||||||
int? limit,
|
int? limit,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/// Summarize files matching some specific requirements
|
||||||
|
///
|
||||||
|
/// See [getFileDescriptors]
|
||||||
|
///
|
||||||
|
/// Returned data are sorted by [DbFileDescriptor.bestDateTime] in descending
|
||||||
|
/// order
|
||||||
|
Future<DbFilesSummary> getFilesSummary({
|
||||||
|
required DbAccount account,
|
||||||
|
List<String>? includeRelativeRoots,
|
||||||
|
List<String>? excludeRelativeRoots,
|
||||||
|
List<String>? mimes,
|
||||||
|
});
|
||||||
|
|
||||||
Future<DbLocationGroupResult> groupLocations({
|
Future<DbLocationGroupResult> groupLocations({
|
||||||
required DbAccount account,
|
required DbAccount account,
|
||||||
List<String>? includeRelativeRoots,
|
List<String>? includeRelativeRoots,
|
||||||
|
|
|
@ -37,3 +37,17 @@ extension _$DbLocationGroupResultToString on DbLocationGroupResult {
|
||||||
return "DbLocationGroupResult {name: [length: ${name.length}], admin1: [length: ${admin1.length}], admin2: [length: ${admin2.length}], countryCode: [length: ${countryCode.length}]}";
|
return "DbLocationGroupResult {name: [length: ${name.length}], admin1: [length: ${admin1.length}], admin2: [length: ${admin2.length}], countryCode: [length: ${countryCode.length}]}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension _$DbFilesSummaryItemToString on DbFilesSummaryItem {
|
||||||
|
String _$toString() {
|
||||||
|
// ignore: unnecessary_string_interpolations
|
||||||
|
return "DbFilesSummaryItem {count: $count}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension _$DbFilesSummaryToString on DbFilesSummary {
|
||||||
|
String _$toString() {
|
||||||
|
// ignore: unnecessary_string_interpolations
|
||||||
|
return "DbFilesSummary {items: {length: ${items.length}}}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -40,6 +40,14 @@ class FileDescriptor {
|
||||||
final DateTime bestDateTime;
|
final DateTime bestDateTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class CountFileGroupsByDateResult {
|
||||||
|
const CountFileGroupsByDateResult({
|
||||||
|
required this.dateCount,
|
||||||
|
});
|
||||||
|
|
||||||
|
final Map<DateTime, int> dateCount;
|
||||||
|
}
|
||||||
|
|
||||||
extension SqliteDbFileExtension on SqliteDb {
|
extension SqliteDbFileExtension on SqliteDb {
|
||||||
/// Return files located inside [dir]
|
/// Return files located inside [dir]
|
||||||
Future<List<CompleteFile>> queryFilesByDirKey({
|
Future<List<CompleteFile>> queryFilesByDirKey({
|
||||||
|
@ -574,6 +582,62 @@ extension SqliteDbFileExtension on SqliteDb {
|
||||||
return query.map((r) => r.read(files.fileId)!).getSingleOrNull();
|
return query.map((r) => r.read(files.fileId)!).getSingleOrNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Count number of files per date
|
||||||
|
Future<CountFileGroupsByDateResult> countFileGroupsByDate({
|
||||||
|
required ByAccount account,
|
||||||
|
List<String>? includeRelativeRoots,
|
||||||
|
List<String>? excludeRelativeRoots,
|
||||||
|
List<String>? mimes,
|
||||||
|
}) async {
|
||||||
|
_log.info(
|
||||||
|
"[countFileGroupsByDate] "
|
||||||
|
"includeRelativeRoots: $includeRelativeRoots, "
|
||||||
|
"excludeRelativeRoots: $excludeRelativeRoots, "
|
||||||
|
"mimes: $mimes",
|
||||||
|
);
|
||||||
|
|
||||||
|
final count = countAll();
|
||||||
|
final localDate = accountFiles.bestDateTime
|
||||||
|
.modify(const DateTimeModifier.localTime())
|
||||||
|
.date;
|
||||||
|
final query = _queryFiles().let((q) {
|
||||||
|
q
|
||||||
|
..setQueryMode(
|
||||||
|
FilesQueryMode.expression,
|
||||||
|
expressions: [localDate, count],
|
||||||
|
)
|
||||||
|
..setAccount(account);
|
||||||
|
if (includeRelativeRoots != null) {
|
||||||
|
if (includeRelativeRoots.none((p) => p.isEmpty)) {
|
||||||
|
for (final r in includeRelativeRoots) {
|
||||||
|
q.byOrRelativePathPattern("$r/%");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return q.build();
|
||||||
|
});
|
||||||
|
if (excludeRelativeRoots != null) {
|
||||||
|
for (final r in excludeRelativeRoots) {
|
||||||
|
query.where(accountFiles.relativePath.like("$r/%").not());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mimes != null) {
|
||||||
|
query.where(files.contentType.isIn(mimes));
|
||||||
|
} else {
|
||||||
|
query.where(files.isCollection.isNotValue(true));
|
||||||
|
}
|
||||||
|
query
|
||||||
|
..orderBy([OrderingTerm.desc(accountFiles.bestDateTime)])
|
||||||
|
..groupBy([localDate]);
|
||||||
|
final results = await query
|
||||||
|
.map((r) => MapEntry<DateTime, int>(
|
||||||
|
DateTime.parse(r.read(localDate)!),
|
||||||
|
r.read(count)!,
|
||||||
|
))
|
||||||
|
.get();
|
||||||
|
return CountFileGroupsByDateResult(dateCount: results.toMap());
|
||||||
|
}
|
||||||
|
|
||||||
/// Update Db files
|
/// Update Db files
|
||||||
///
|
///
|
||||||
/// Return a list of files that are not yet inserted to the DB (thus not
|
/// Return a list of files that are not yet inserted to the DB (thus not
|
||||||
|
|
|
@ -461,6 +461,27 @@ class NpDbSqlite implements NpDb {
|
||||||
return sqlObjs.toDbFileDescriptors();
|
return sqlObjs.toDbFileDescriptors();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<DbFilesSummary> getFilesSummary({
|
||||||
|
required DbAccount account,
|
||||||
|
List<String>? includeRelativeRoots,
|
||||||
|
List<String>? excludeRelativeRoots,
|
||||||
|
List<String>? mimes,
|
||||||
|
}) async {
|
||||||
|
final result = await _db.use((db) async {
|
||||||
|
return await db.countFileGroupsByDate(
|
||||||
|
account: ByAccount.db(account),
|
||||||
|
includeRelativeRoots: includeRelativeRoots,
|
||||||
|
excludeRelativeRoots: excludeRelativeRoots,
|
||||||
|
mimes: mimes,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return DbFilesSummary(
|
||||||
|
items: result.dateCount
|
||||||
|
.map((key, value) => MapEntry(key, DbFilesSummaryItem(count: value))),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<DbLocationGroupResult> groupLocations({
|
Future<DbLocationGroupResult> groupLocations({
|
||||||
required DbAccount account,
|
required DbAccount account,
|
||||||
|
|
|
@ -8,6 +8,7 @@ import '../test_util.dart' as util;
|
||||||
void main() {
|
void main() {
|
||||||
group("database.SqliteDbFileExtension", () {
|
group("database.SqliteDbFileExtension", () {
|
||||||
test("cleanUpDanglingFiles", _cleanUpDanglingFiles);
|
test("cleanUpDanglingFiles", _cleanUpDanglingFiles);
|
||||||
|
test("countFileGroupsByDate", _countFileGroupsByDate);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,3 +47,37 @@ Future<void> _cleanUpDanglingFiles() async {
|
||||||
[0, 1],
|
[0, 1],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _countFileGroupsByDate() async {
|
||||||
|
final account = util.buildAccount();
|
||||||
|
final files = (util.FilesBuilder()
|
||||||
|
..addDir("admin")
|
||||||
|
..addJpeg(
|
||||||
|
"admin/test1.jpg",
|
||||||
|
lastModified: DateTime(2024, 1, 2, 3, 4, 5),
|
||||||
|
)
|
||||||
|
..addJpeg(
|
||||||
|
"admin/test2.jpg",
|
||||||
|
lastModified: DateTime(2024, 1, 2, 4, 5, 6),
|
||||||
|
)
|
||||||
|
..addJpeg(
|
||||||
|
"admin/test3.jpg",
|
||||||
|
lastModified: DateTime(2024, 1, 3, 4, 5, 6),
|
||||||
|
))
|
||||||
|
.build();
|
||||||
|
final db = util.buildTestDb();
|
||||||
|
addTearDown(() => db.close());
|
||||||
|
await db.transaction(() async {
|
||||||
|
await db.insertAccounts([account]);
|
||||||
|
await util.insertFiles(db, account, files);
|
||||||
|
});
|
||||||
|
|
||||||
|
final result = await db.countFileGroupsByDate(account: ByAccount.db(account));
|
||||||
|
expect(
|
||||||
|
result.dateCount,
|
||||||
|
{
|
||||||
|
DateTime(2024, 1, 2): 2,
|
||||||
|
DateTime(2024, 1, 3): 1,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue