platform/packages/relations/lib/src/belongs_to.dart
2021-02-16 10:10:09 +08:00

80 lines
2.4 KiB
Dart

import 'dart:async';
import 'dart:mirrors';
import 'package:angel_framework/angel_framework.dart';
import 'plural.dart' as pluralize;
import 'no_service.dart';
/// Represents a relationship in which the current [service] "belongs to"
/// a single member of the service at [servicePath]. Use [as] to set the name
/// on the target object.
///
/// Defaults:
/// * [localKey]: `userId`
/// * [foreignKey]: `id`
HookedServiceEventListener belongsTo(Pattern servicePath,
{String as,
String foreignKey,
String localKey,
getForeignKey(obj),
assignForeignObject(foreign, obj)}) {
String localId = localKey;
var foreignName =
as?.isNotEmpty == true ? as : pluralize.singular(servicePath.toString());
if (localId == null) {
localId = foreignName + 'Id';
// print('No local key provided for belongsTo, defaulting to \'$localId\'.');
}
return (HookedServiceEvent e) async {
var ref = e.getService(servicePath);
if (ref == null) throw noService(servicePath);
_getForeignKey(obj) {
if (getForeignKey != null)
return getForeignKey(obj);
else if (obj is Map)
return obj[localId];
//TODO: Undefined class
//else if (obj is Extensible)
// return obj.properties[localId];
else if (localId == null || localId == 'userId')
return obj.userId;
else
return reflect(obj).getField(new Symbol(localId)).reflectee;
}
_assignForeignObject(foreign, obj) {
if (assignForeignObject != null)
return assignForeignObject(foreign, obj);
else if (obj is Map)
obj[foreignName] = foreign;
//TODO: Undefined class
//else if (obj is Extensible)
// obj.properties[foreignName] = foreign;
else
reflect(obj).setField(new Symbol(foreignName), foreign);
}
_normalize(obj) async {
if (obj != null) {
var id = await _getForeignKey(obj);
var indexed = await ref.index({
'query': {foreignKey ?? 'id': id}
});
if (indexed == null || indexed is! List || indexed.isNotEmpty != true) {
await _assignForeignObject(null, obj);
} else {
var child = indexed.first;
await _assignForeignObject(child, obj);
}
}
}
if (e.result is Iterable) {
await Future.wait(e.result.map(_normalize));
} else
await _normalize(e.result);
};
}