mirror of
https://gitlab.com/nkming2/nc-photos.git
synced 2025-01-22 08:46:18 +01:00
Generate code to help sorting db rows
This commit is contained in:
parent
18f5a49db0
commit
9b3a755add
9 changed files with 211 additions and 2 deletions
|
@ -1,3 +1,4 @@
|
|||
library np_codegen;
|
||||
|
||||
export 'src/drift_table_sort_annotations.dart';
|
||||
export 'src/np_log_annotations.dart';
|
||||
|
|
6
codegen/lib/src/drift_table_sort_annotations.dart
Normal file
6
codegen/lib/src/drift_table_sort_annotations.dart
Normal file
|
@ -0,0 +1,6 @@
|
|||
class DriftTableSort {
|
||||
const DriftTableSort(this.dbClass);
|
||||
|
||||
final String dbClass;
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
builders:
|
||||
np_log_build:
|
||||
import: "package:np_codegen_build/builder.dart"
|
||||
builder_factories: ["npLogBuilder"]
|
||||
builder_factories: ["driftTableSortBuilder", "npLogBuilder"]
|
||||
# The `partId` argument to `SharedPartBuilder` is "some_cool_builder"
|
||||
build_extensions: {".dart": [".np_log.g.part"]}
|
||||
build_extensions: {".dart": [".np_codegen.g.part"]}
|
||||
auto_apply: dependents
|
||||
build_to: cache
|
||||
# To copy the `.g.part` content into `.g.dart` in the source tree
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import 'package:build/build.dart';
|
||||
import 'package:np_codegen_build/src/drift_table_sort_generator.dart';
|
||||
import 'package:np_codegen_build/src/np_log_generator.dart';
|
||||
import 'package:source_gen/source_gen.dart';
|
||||
|
||||
Builder driftTableSortBuilder(BuilderOptions options) =>
|
||||
SharedPartBuilder([DriftTableSortGenerator()], "drift_table_sort");
|
||||
|
||||
Builder npLogBuilder(BuilderOptions options) =>
|
||||
SharedPartBuilder([NpLogGenerator()], "np_log");
|
||||
|
|
71
codegen_build/lib/src/drift_table_sort_generator.dart
Normal file
71
codegen_build/lib/src/drift_table_sort_generator.dart
Normal file
|
@ -0,0 +1,71 @@
|
|||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:build/build.dart';
|
||||
import 'package:np_codegen/np_codegen.dart';
|
||||
import 'package:source_gen/source_gen.dart';
|
||||
|
||||
/// Generate a enum class with all columns to define sorting without exposing
|
||||
/// drift internals
|
||||
class DriftTableSortGenerator extends GeneratorForAnnotation<DriftTableSort> {
|
||||
const DriftTableSortGenerator();
|
||||
|
||||
@override
|
||||
dynamic generateForAnnotatedElement(
|
||||
Element element,
|
||||
ConstantReader annotation,
|
||||
BuildStep buildStep,
|
||||
) {
|
||||
if (element is! ClassElement) {
|
||||
print("Not a class");
|
||||
return null;
|
||||
}
|
||||
final driftTableSort =
|
||||
DriftTableSort(annotation.read("dbClass").stringValue);
|
||||
final clazz = element;
|
||||
if (!clazz.allSupertypes.any((t) => t.element2.name == "Table")) {
|
||||
print("Not a drift table");
|
||||
return null;
|
||||
}
|
||||
final columns = clazz.fields.where((f) => _shouldIncludeField(f)).toList();
|
||||
if (columns.isEmpty) {
|
||||
print("No columns");
|
||||
return null;
|
||||
}
|
||||
|
||||
final sortEnumName =
|
||||
"${clazz.name.substring(0, clazz.name.length - 1)}Sort";
|
||||
final enumValues = columns
|
||||
.map((f) => "${f.name}Asc, ${f.name}Desc, ")
|
||||
.reduce((a, b) => a + b);
|
||||
final cases = columns.map((f) {
|
||||
return """
|
||||
case $sortEnumName.${f.name}Asc:
|
||||
return OrderingTerm.asc(db.${clazz.name.replaceRange(0, 1, clazz.name[0].toLowerCase())}.${f.name});
|
||||
case $sortEnumName.${f.name}Desc:
|
||||
return OrderingTerm.desc(db.${clazz.name.replaceRange(0, 1, clazz.name[0].toLowerCase())}.${f.name});
|
||||
""";
|
||||
}).reduce((a, b) => a + b);
|
||||
return """
|
||||
enum $sortEnumName { $enumValues }
|
||||
|
||||
extension ${sortEnumName}IterableExtension on Iterable<$sortEnumName> {
|
||||
Iterable<OrderingTerm> toOrderingItem(${driftTableSort.dbClass} db) {
|
||||
return map((s) {
|
||||
switch (s) { $cases }
|
||||
});
|
||||
}
|
||||
}
|
||||
""";
|
||||
}
|
||||
|
||||
bool _shouldIncludeField(FieldElement field) {
|
||||
if (!field.isSynthetic) {
|
||||
// columns are getters
|
||||
return false;
|
||||
}
|
||||
// it's a very rough way but well...
|
||||
if (field.type.element2?.name?.endsWith("Column") ?? false) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -17,6 +17,7 @@ dependencies:
|
|||
dev_dependencies:
|
||||
build_test: ^2.1.5
|
||||
lints: any
|
||||
path: any
|
||||
test: any
|
||||
code_gen_tester:
|
||||
git:
|
||||
|
|
88
codegen_build/test/drift_table_sort_test.dart
Normal file
88
codegen_build/test/drift_table_sort_test.dart
Normal file
|
@ -0,0 +1,88 @@
|
|||
import 'package:np_codegen_build/src/drift_table_sort_generator.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import 'util.dart';
|
||||
|
||||
void main() {
|
||||
resolveCompilationUnit("test/src/drift_table_sort.dart");
|
||||
tearDown(() {
|
||||
// Increment this after each test so the next test has it's own package
|
||||
_pkgCacheCount++;
|
||||
});
|
||||
|
||||
test("DriftTableSort", () {
|
||||
final src = _genSrc("""
|
||||
@DriftTableSort("Database")
|
||||
class Tests extends Table {
|
||||
IntColumn get test1 => integer()();
|
||||
TextColumn get test2 => text()();
|
||||
}
|
||||
|
||||
class Table {}
|
||||
|
||||
class IntColumn {}
|
||||
|
||||
class TextColumn {}
|
||||
|
||||
IntColumn Function() integer() => () => IntColumn();
|
||||
|
||||
TextColumn Function() text() => () => TextColumn();
|
||||
""");
|
||||
final expected = _genExpected(r"""
|
||||
enum TestSort {
|
||||
test1Asc,
|
||||
test1Desc,
|
||||
test2Asc,
|
||||
test2Desc,
|
||||
}
|
||||
|
||||
extension TestSortIterableExtension on Iterable<TestSort> {
|
||||
Iterable<OrderingTerm> toOrderingItem(Database db) {
|
||||
return map((s) {
|
||||
switch (s) {
|
||||
case TestSort.test1Asc:
|
||||
return OrderingTerm.asc(db.tests.test1);
|
||||
case TestSort.test1Desc:
|
||||
return OrderingTerm.desc(db.tests.test1);
|
||||
case TestSort.test2Asc:
|
||||
return OrderingTerm.asc(db.tests.test2);
|
||||
case TestSort.test2Desc:
|
||||
return OrderingTerm.desc(db.tests.test2);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
""");
|
||||
return _buildTest(src, expected);
|
||||
});
|
||||
}
|
||||
|
||||
String _genSrc(String src) {
|
||||
return """
|
||||
import 'package:np_codegen/np_codegen.dart';
|
||||
part 'test.g.dart';
|
||||
$src
|
||||
""";
|
||||
}
|
||||
|
||||
String _genExpected(String src) {
|
||||
return """// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'test.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// DriftTableSortGenerator
|
||||
// **************************************************************************
|
||||
|
||||
$src""";
|
||||
}
|
||||
|
||||
Future _buildTest(String src, String expected) => buildTest(
|
||||
generators: [DriftTableSortGenerator()],
|
||||
pkgName: _pkgName,
|
||||
src: src,
|
||||
expected: expected,
|
||||
);
|
||||
|
||||
String get _pkgName => 'pkg$_pkgCacheCount';
|
||||
int _pkgCacheCount = 1;
|
4
codegen_build/test/src/drift_table_sort.dart
Normal file
4
codegen_build/test/src/drift_table_sort.dart
Normal file
|
@ -0,0 +1,4 @@
|
|||
import 'package:np_codegen/np_codegen.dart';
|
||||
|
||||
@DriftTableSort("")
|
||||
class Foo {}
|
34
codegen_build/test/util.dart
Normal file
34
codegen_build/test/util.dart
Normal file
|
@ -0,0 +1,34 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:build/build.dart';
|
||||
import 'package:build_test/build_test.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:source_gen/source_gen.dart';
|
||||
|
||||
// Taken from source_gen_test, unclear why this is needed...
|
||||
Future<void> resolveCompilationUnit(String filePath) async {
|
||||
final assetId = AssetId.parse('a|lib/${p.basename(filePath)}');
|
||||
final files =
|
||||
Directory(p.dirname(filePath)).listSync().whereType<File>().toList();
|
||||
|
||||
final fileMap = Map<String, String>.fromEntries(files.map(
|
||||
(f) => MapEntry('a|lib/${p.basename(f.path)}', f.readAsStringSync())));
|
||||
|
||||
await resolveSources(fileMap, (item) async {
|
||||
return await item.libraryFor(assetId);
|
||||
}, resolverFor: 'a|lib/${p.basename(filePath)}');
|
||||
}
|
||||
|
||||
Future buildTest({
|
||||
required List<Generator> generators,
|
||||
required String pkgName,
|
||||
required String src,
|
||||
required String expected,
|
||||
}) {
|
||||
return testBuilder(
|
||||
PartBuilder(generators, ".g.dart"),
|
||||
{"$pkgName|lib/test.dart": src},
|
||||
generateFor: {'$pkgName|lib/test.dart'},
|
||||
outputs: {"$pkgName|lib/test.g.dart": decodedMatches(expected)},
|
||||
);
|
||||
}
|
Loading…
Reference in a new issue