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)); }
public async Task <IList <T> > AsListUnpaginated() { var resourceString = await Context.CallRaw(HttpMethod.Get, Context.GetRequestContentType(), Path(), parameters : FullParameters(), requestBody : null); var list = Context.TranslateObject <List <T> >(ShopifyAPIContext.Pluralize(Name), resourceString); foreach (var model in list) { PlaceResourceProxesOnModel(model); } return(list); }
/// <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; } }
public override string Path() { return(ShopifyAPIContext.UriPathJoin(ParentResource.InstanceOrVerbPath(ParentInstance.Id.ToString()), ShopifyAPIContext.Pluralize(Name))); }
public async Task CallAction(T instance, string action) { await Context.CallRaw(HttpMethod.Post, Context.GetRequestContentType(), ShopifyAPIContext.UriPathJoin(InstancePath(instance.Id.Value), action), FullParameters(), null); }
public string InstanceOrVerbPath(string id) { return(ShopifyAPIContext.UriPathJoin(Path(), id)); }
public virtual string Path() { return(ShopifyAPIContext.UriPathJoin(Context.AdminPath(), ShopifyAPIContext.Pluralize(Name))); }
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); }
protected override string ResolvePropertyName(string propertyName) { return(ShopifyAPIContext.Underscoreify(propertyName)); }