123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- namespace Invercargill {
- public delegate TProp PropertyGetter<TClass, TProp>(TClass object) throws Error;
- public delegate bool PropertyPredicate<TClass>(TClass object);
- public delegate void PropertySetter<TClass, TProp>(TClass object, TProp value) throws Error;
- public delegate void PropertyDefaultSetter<TClass>(TClass object);
- public delegate Tout PropertyGetterTransformer<Tin, Tout>(Tin object);
- public delegate Tout PropertySetterTransformer<Tin, Tout>(Tin object) throws Error;
- public delegate T ObjectConstructor<T>();
- public class PropertyMapper<T> : Mapper<T, Properties> {
- private Vector<PropertyMapping<T>> mappings;
- private ObjectConstructor<T> constructor;
- public static PropertyMapper<T> build_for<T>(Func<PropertyMapperBuilder<T>> func) {
- int location = (int)func;
- return keyed_once<PropertyMapper<T>>(location, () => {
- var builder = new PropertyMapperBuilder<T>();
- func(builder);
- return builder.build();
- });
- }
- internal PropertyMapper(Vector<PropertyMapping<T>> mappings, ObjectConstructor<T> constructor) {
- this.mappings = mappings;
- this.constructor = constructor;
- }
- public void map_into(T object, ReadOnlyAssociative<string, Element> properties) throws Error {
- foreach (var mapping in mappings) {
- var exists = properties.has(mapping.name);
- if(mapping.undefined_setter != null && !exists) {
- mapping.undefined_setter(object);
- continue;
- }
- if(mapping.undefined_setter == null && !exists){
- throw new IndexError.KEY_NOT_FOUND(@"Failed to map into $(typeof(T).name()): Property \"$(mapping.name)\" does not have an undefined setter and no matching property was found");
- }
- var element = properties[mapping.name];
- if(mapping.null_setter != null && element.is_null()) {
- mapping.null_setter(object);
- continue;
- }
- if(mapping.null_setter == null && element.is_null()) {
- throw new ElementError.INVALID_CONVERSION(@"Failed to map into $(typeof(T).name()): Property \"$(mapping.name)\" does not have a null setter and a null value was found");
- }
- mapping.setter(object, properties[mapping.name]);
- }
- }
- public override T materialise(Properties properties) throws Error {
- var obj = constructor();
- map_into(obj, properties);
- return obj;
- }
- public override Properties map_from(T object) throws Error {
- var properties = new PropertiesDictionary();
- foreach (var mapping in mappings) {
- // Check undefined
- if(mapping.undefined_check != null && mapping.undefined_check(object)){
- continue;
- }
- // Check null
- if(mapping.null_check != null && mapping.null_check(object)) {
- properties[mapping.name] = new NullElement();
- continue;
- }
- // Assign value
- var val = mapping.getter(object);
- properties[mapping.name] = val;
- }
- return properties;
- }
- }
- private class PropertyMapping<T> {
- public string name;
- public PropertyGetter<T, Element> getter;
- public PropertySetter<T, Element> setter;
- public PropertyPredicate<T>? null_check;
- public PropertyPredicate<T>? undefined_check;
- public PropertyDefaultSetter<T>? null_setter;
- public PropertyDefaultSetter<T>? undefined_setter;
- }
- public class PropertyMapperBuilder<T> {
- private Vector<PropertyMapping<T>> mappings;
- private ObjectConstructor<T> constructor;
- public PropertyMapperBuilder() {
- mappings = new Vector<PropertyMapping<T>>();
- constructor = () => Object.new(typeof(T));
- }
- public virtual PropertyMappingBuilder<T> map<TProp>(string name, owned PropertyGetter<T, TProp> getter, owned PropertySetter<T, TProp> setter) {
- PropertyMapping<T> mapping;
- if(typeof(TProp).is_a(typeof(Element))) {
- mapping = new PropertyMapping<T>() {
- name = name,
- getter = (owned)getter,
- setter = (owned)setter,
- };
- }
- else {
- mapping = new PropertyMapping<T>() {
- name = name,
- getter = (o) => new NativeElement<TProp>(getter(o)),
- setter = (o,d) => setter(o, d.as<TProp>())
- };
- }
- add_mapping(mapping);
- return new PropertyMappingBuilder<T>(this, mapping);
- }
- public virtual PropertyMappingBuilder<T> map_properties_with<TObj>(string name, owned PropertyGetter<T, TObj> getter, owned PropertySetter<T, TObj> setter, PropertyMapper<TObj> mapper) {
- return map_with<TObj, Properties>(name, getter, setter, mapper);
- }
- public virtual PropertyMappingBuilder<T> map_with<TNative, TElement>(string name, owned PropertyGetter<T, TNative> getter, owned PropertySetter<T, TNative> setter, Mapper<TNative, TElement> mapper) {
- var mapping = new PropertyMapping<T>() {
- name = name,
- getter = (o) => new NativeElement<TElement>(mapper.map_from(getter(o))),
- setter = (o,d) => setter(o, mapper.materialise(d.as<TElement>()))
- };
- add_mapping(mapping);
- return new PropertyMappingBuilder<T>(this, mapping);
- }
- public virtual PropertyMappingBuilder<T> map_many<TObj>(string name, owned PropertyGetter<T, Enumerable<TObj>> getter, owned PropertySetter<T, Enumerable<TObj>> setter) {
- var mapping = new PropertyMapping<T>() {
- name = name,
- getter = (o) => new NativeElement<Elements>(getter(o).to_elements()),
- setter = (o,d) => setter(o, d.as<Elements>().elements_as<TObj>())
- };
- add_mapping(mapping);
- return new PropertyMappingBuilder<T>(this, mapping);;
- }
- public virtual PropertyMappingBuilder<T> map_property_groups_with<TObj>(string name, owned PropertyGetter<T, Enumerable<TObj>> getter, owned PropertySetter<T, Enumerable<TObj>> setter, PropertyMapper<TObj> mapper) {
- return map_many_with<TObj, Properties>(name, getter, setter, mapper);
- }
- public virtual PropertyMappingBuilder<T> map_many_with<TNative, TElement>(string name, owned PropertyGetter<T, Enumerable<TNative>> getter, owned PropertySetter<T, Enumerable<TNative>> setter, Mapper<TNative, TElement> mapper) {
- var mapping = new PropertyMapping<T>() {
- name = name,
- getter = (o) => new NativeElement<Elements>(getter(o).attempt_select<TElement>(i => mapper.map_from(i)).to_elements()),
- setter = (o,d) => {
- var collection = new Series<TNative>();
- foreach (var properties in d.as<Elements>().elements_as<TElement>()) {
- collection.add(mapper.materialise(properties));
- }
- setter(o, collection.seal());
- }
- };
- return new PropertyMappingBuilder<T>(this, mapping);;
- }
- public virtual PropertyMapperBuilder<T> set_constructor(ObjectConstructor<T> constructor) {
- this.constructor = constructor;
- return this;
- }
- public virtual PropertyMapper<T> build() {
- return new PropertyMapper<T>(mappings, constructor);
- }
- private void add_mapping(PropertyMapping<T> mapping) {
- mappings.add(mapping);
- }
- }
- public class PropertyMappingBuilder<T> : PropertyMapperBuilder<T> {
- private PropertyMapperBuilder<T> inner;
- private PropertyMapping<T> mapping;
- internal PropertyMappingBuilder(PropertyMapperBuilder<T> builder, PropertyMapping<T> mapping) {
- inner = builder;
- this.mapping = mapping;
- }
- public PropertyMappingBuilder<T> null_when(owned PropertyPredicate<T> predicate) {
- mapping.null_check = predicate;
- return this;
- }
- public PropertyMappingBuilder<T> undefined_when(owned PropertyPredicate<T> predicate) {
- mapping.undefined_check = predicate;
- return this;
- }
- public PropertyMappingBuilder<T> when_null(owned PropertyDefaultSetter<T> setter) {
- mapping.null_setter = setter;
- return this;
- }
-
- public PropertyMappingBuilder<T> when_undefined(owned PropertyDefaultSetter<T> setter) {
- mapping.undefined_setter = setter;
- return this;
- }
- public override PropertyMappingBuilder<T> map<TProp>(string name, owned PropertyGetter<T, TProp> getter, owned PropertySetter<T, TProp> setter) {
- return inner.map<TProp>(name, (owned)getter, (owned)setter);
- }
- public override PropertyMappingBuilder<T> map_properties_with<TObj>(string name, owned PropertyGetter<T, TObj> getter, owned PropertySetter<T, TObj> setter, PropertyMapper<TObj> mapper) {
- return inner.map_properties_with<TObj>(name, (owned)getter, (owned)setter, mapper);
- }
- public override PropertyMappingBuilder<T> map_with<TNative, TElement>(string name, owned PropertyGetter<T, TNative> getter, owned PropertySetter<T, TNative> setter, Mapper<TNative, TElement> mapper) {
- return inner.map_with<TNative, TElement>(name, (owned)getter, (owned)setter, mapper);
- }
- public override PropertyMappingBuilder<T> map_many<TObj>(string name, owned PropertyGetter<T, Enumerable<TObj>> getter, owned PropertySetter<T, Enumerable<TObj>> setter) {
- return inner.map_many<TObj>(name, (owned)getter, (owned)setter);
- }
- public override PropertyMappingBuilder<T> map_property_groups_with<TObj>(string name, owned PropertyGetter<T, Enumerable<TObj>> getter, owned PropertySetter<T, Enumerable<TObj>> setter, PropertyMapper<TObj> mapper) {
- return inner.map_property_groups_with<TObj>(name, getter, setter, mapper);
- }
- public override PropertyMappingBuilder<T> map_many_with<TNative, TElement>(string name, owned PropertyGetter<T, Enumerable<TNative>> getter, owned PropertySetter<T, Enumerable<TNative>> setter, Mapper<TNative, TElement> mapper) {
- return inner.map_many_with<TNative, TElement>(name, (owned)getter, (owned)setter, mapper);
- }
- public override PropertyMapperBuilder<T> set_constructor(ObjectConstructor<T> constructor) {
- return inner.set_constructor(constructor);
- }
- public override PropertyMapper<T> build() {
- return inner.build();
- }
- }
- }
|