Esempio n. 1
0
        public Task CallAction(T instance, Expression <Func <SpecialAction> > actionPropertyLambda)
        {
            var memberExpression = actionPropertyLambda.Body as MemberExpression;

            if (memberExpression == null)
            {
                throw new ShopifyConfigurationException("Please specify a flat expression specifying a SpecialAction property on the IResourceModel.");
            }
            var prop = memberExpression.Member as PropertyInfo;

            if (prop == null)
            {
                throw new ShopifyConfigurationException("Expression specified to CallAction?() did not specify a property.  This probably can't happen (because of type parameter to Func<>)?");
            }
            var type = typeof(T);

            if (type != prop.ReflectedType && !type.IsSubclassOf(prop.ReflectedType))
            {
                throw new ShopifyConfigurationException("Expression specified to CallAction() specified a property on a different class than the IResourceModel type of this RestResource.");
            }
            if (instance.Id == null)
            {
                throw new ShopifyUsageException("Actions can only be called on models with an ID.");
            }
            var action = ShopifyAPIContext.Underscoreify(prop.Name);

            return(CallAction(instance, action));
        }
Esempio n. 2
0
        /// <summary>
        /// Initializes a new instance of the <see
        /// cref="ShopifyAPIAdapterLibrary.RestResource`1"/> class.
        /// </summary>
        /// <param name='name'>
        /// The lowercase resource name, as it would appear in URIs.
        /// Default is underscorized from the model type.
        /// </param>
        // TODO: put name back as an optional
        public RestResource(IShopifyAPIContext context, string name = null)
        {
            Context = context;

            if (name == null)
            {
                Name = ShopifyAPIContext.Underscoreify(typeof(T).Name);
            }
            else
            {
                Name = name;
            }
        }
Esempio n. 3
0
        protected override IList <JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            var properties = new List <JsonProperty>(base.CreateProperties(type, memberSerialization));

            var hasOneAdIdProperties = new List <JsonProperty>();

            properties.RemoveAll((prop) => {
                // do not attempt to (de)serialize IHasManys
                if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(IHasMany <>))
                {
                    return(true);
                }

                // if we're (de)serializing the top-level Container object, perform our wrapper-object
                // name transformation
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Container <>))
                {
                    // our Container type only has one property (the specially named per-resource property),
                    // so, we just presume to match all properties in Container.
                    prop.PropertyName = ResourceName;
                    return(false);
                }

                // is property a HasOne?
                if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(IHasOne <>))
                {
                    var underscorized = ShopifyAPIContext.Underscoreify(prop.PropertyName);

                    // get type argument of IHasOne
                    var hasOneTargetType = prop.PropertyType.GetGenericArguments();

                    // I was really hoping to avoid activator.createinstance... :(

                    Type hasOneInlineConverterType = typeof(HasOneInlineJsonConverter <>).MakeGenericType(hasOneTargetType);
                    var hasOneInlineConverter      = Activator.CreateInstance(hasOneInlineConverterType);

                    Type hasOneAsIdConverterType = typeof(HasOneAsIdJsonConverter <>).MakeGenericType(hasOneTargetType);
                    var hasOneAsIdConverter      = Activator.CreateInstance(hasOneAsIdConverterType);

                    // set the standard HasOneConverter
                    // TODO if we can de-genericify hasOneConverter, just set it up globally and get rid of this dynamic instantiation
                    prop.Converter       = (JsonConverter)hasOneInlineConverter;
                    prop.MemberConverter = (JsonConverter)hasOneInlineConverter;

                    // create an additional property for the as-id deserialization (deserialization *only*) case
                    JsonProperty asIdProperty = new JsonProperty()
                    {
                        PropertyType   = prop.PropertyType,
                        Ignored        = false,
                        PropertyName   = underscorized + "_id",
                        UnderlyingName = prop.UnderlyingName,
                        DeclaringType  = prop.DeclaringType,
                        ValueProvider  = prop.ValueProvider,
                        Readable       = true,
                        Writable       = true,
                        // Use the as-id converter
                        Converter       = (JsonConverter)hasOneAsIdConverter,
                        MemberConverter = (JsonConverter)hasOneAsIdConverter
                    };

                    // make props:

                    // outgoing inline
                    // outgoing as id
                    // incoming inline
                    // incoming as id

                    // the outgoings should have ShouldSerializes that do the HasOne type check IN addition to the usual dirty check
                    // the incomings can be naiive, since the presence of either field in the incoming json makes the selection

                    // we should only serialize such properties as have changed.
                    prop.ShouldSerialize = (obj) =>
                    {
                        // TODO: https://trello.com/card/isfielddirty-if-called-on-inline-hasone-fields-should-return-true-if-the-contained-resource-model-is-at-all-dirty/50a1c9c990c4980e0600178b/58
                        var hasOneInstance = prop.ValueProvider.GetValue(obj);
                        if ((hasOneInstance as IHasOneInlineUntyped) == null)
                        {
                            return(false);
                        }
                        IResourceModel model = (IResourceModel)obj;
                        return(model.IsFieldDirty(prop.UnderlyingName));
                    };

                    asIdProperty.ShouldSerialize = (obj) =>
                    {
                        var hasOneInstance = prop.ValueProvider.GetValue(obj);
                        if ((hasOneInstance as IHasOneAsIdUntyped) == null)
                        {
                            return(false);
                        }
                        IResourceModel model = (IResourceModel)obj;
                        return(model.IsFieldDirty(asIdProperty.UnderlyingName));
                    };

                    // we add all of the created as=id property descriptors after,
                    // in order to avoid modifying the collection while RemoveAll is
                    // running
                    hasOneAdIdProperties.Add(asIdProperty);

                    return(false);
                }

                if (typeof(IGranularDirtiable).IsAssignableFrom(type))
                {
                    // the main ID field should always be included
                    if (prop.PropertyName != "id")
                    {
                        prop.ShouldSerialize = (obj) =>
                        {
                            IGranularDirtiable model = (IGranularDirtiable)obj;
                            return(model.IsFieldDirty(prop.UnderlyingName));
                        };
                    }
                }

                return(false);
            });

            properties.AddRange(hasOneAdIdProperties);
            return(properties);
        }
Esempio n. 4
0
 protected override string ResolvePropertyName(string propertyName)
 {
     return(ShopifyAPIContext.Underscoreify(propertyName));
 }