ferry
ferry copied to clipboard
[Feature Request] Access properties using Maps (ferry_generator)
Accessing generated code members via a Map should be feasible. For example, in my current project, I'm utilizing 'proto_grid' for table management. This tool enables column filtering using various criteria such as "Greater than", "Contains", "Equals to", etc. Consequently, for each column that is available, I find myself manually scripting a filter like so:
Future<PlutoInfinityScrollRowsResponse> _fetch(
PlutoInfinityScrollRowsRequest request,
) async {
final filterBuilder = GVehiclesBoolExpBuilder();
if (request.lastRow != null) {
filterBuilder.id.G_gt = int.tryParse(request.lastRow?.cells['id']?.value);
}
if (request.filterRows.isNotEmpty) {
final filters = FilterHelper.convertRowsToMap(request.filterRows);
if (filters.containsKey('name')) {
filterBuilder.name.G_eq = v[PlutoFilterTypeEquals.name];
final containsValue = v[PlutoFilterTypeContains.name];
final startsWithValue = v[PlutoFilterTypeStartsWith.name];
final endsWithValue = v[PlutoFilterTypeEndsWith.name];
if (containsValue != null) {
filterBuilder.name.G_ilike = '%$containsValue%';
} else if (startsWithValue != null) {
filterBuilder.name.G_ilike = '$startsWithValue%';
} else if (endsWithValue != null) {
filterBuilder.name.G_ilike = '%$endsWithValue';
}
filterBuilder.name.G_gt = v[PlutoFilterTypeGreaterThan.name];
filterBuilder.name.G_gte = v[PlutoFilterTypeGreaterThanOrEqualTo.name];
filterBuilder.name.G_lt = v[PlutoFilterTypeLessThan.name];
filterBuilder.name.G_lte = v[PlutoFilterTypeLessThanOrEqualTo.name];
}
if(filters.containsKey('companyOwner')) {
// Same code as before but with filterBuilder.companyOwner
}
}
final req = gqlClient.request(GVehicleListReq(
(b) => b
..requestId = 'VehicleListReq'
..vars.where = filterBuilder
..vars.limit = 20
..fetchPolicy = FetchPolicy.NetworkOnly,
));
final result = await req.first;
final vehicles = result.data?.vehicles ?? BuiltList();
return PlutoInfinityScrollRowsResponse(
isLast: vehicles.length < 20,
rows: vehicles.map(_createRowFromData).toList(),
);
}
Hence, the feature request aims to provide a Map<String, TComparisonExpBuilder> or a similar construct (like overriding the [] operator with a set of if-else statements) to enable this kind of access:
for (final filter in filters) {
filterBuilder[filter].G_eq = filters[filter][PlutoFilterTypeEquals.name];
filterBuilder[filter].G_gt = filters[filter][PlutoFilterTypeGreaterThan.name];
// etc.
}
I understand this approach might lead to some type errors, but I am willing to consider a dynamic type and perform manual casting, like this:
for (final filter in filters) {
filterBuilder.get<GStringComparisonExpBuilder>(filter).G_eq = filters[filter][PlutoFilterTypeEquals.name];
filterBuilder.get<GStringComparisonExpBuilder>(filter).G_gt = filters[filter][PlutoFilterTypeGreaterThan.name];
// etc.
}
An alternative, albeit less elegant, solution I've considered is the following, which aims to avoid manually setting all the fields:
extension GStringComparisonExpBuilderX on GStringComparisonExpBuilder {
void buildFromMap(List<Map<String, String>>? map) {
if (map == null) {
return;
}
for (final v in map) {
G_eq = v[PlutoFilterTypeEquals.name];
final containsValue = v[PlutoFilterTypeContains.name];
final startsWithValue = v[PlutoFilterTypeStartsWith.name];
final endsWithValue = v[PlutoFilterTypeEndsWith.name];
if (containsValue != null) {
G_ilike = '%$containsValue%';
} else if (startsWithValue != null) {
G_ilike = '$startsWithValue%';
} else if (endsWithValue != null) {
G_ilike = '%$endsWithValue';
}
G_gt = v[PlutoFilterTypeGreaterThan.name];
G_gte = v[PlutoFilterTypeGreaterThanOrEqualTo.name];
G_lt = v[PlutoFilterTypeLessThan.name];
G_lte = v[PlutoFilterTypeLessThanOrEqualTo.name];
}
}
}
However, this method still requires manual verification of each filter's existence, similar to the first example. I think it's possible to better use code generation for those use-cases. Thank you!