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); }; }