Retrofit POST with two multidimenional arrays, how to send? - retrofit

I have this API and I need to send some data to it as follows:
www.abc.com/orders/new?items[][id]=1001&items[][quantity]=2
So I have to pass in these arrays
items[][id]=1001
items[][quantity]=2
If there are multiple items, it should look like this
items[][id]=1001 & items[][quantity]=2
& items[][id]=1002 & items[][quantity]=3
So this is the problem I am having because I am aware that #Query can accept arrays but the arrangement needs to be element of ids first and then element of quantities. I cannot have all ids first and then quantities which is what happens.
#POST("/orders/new")
void send(#Query("items[][id]") String...ids, #Query("items[][quantity") String...quantity)
Please note I omitted the callback for simplicity.
I have also tried with lists, whereby the entire list contains all the needed information in the correct arrangement but then came the problem of only having a single #Query annotation i.e. "items[][id]" and "items[][quantity]"

Use #QueryMap. It is like a HashMap. From retrofit documentation, we have this:
For complex query parameter combinations a Map can be used.
#GET("/group/{id}/users")
List<User> groupList(#QueryMap Map<String, String> options);
So, in your case, the key of the map will be the id, and the value will be the quantity.

Related

How to merge List of two objects based on unique id?

I have a class
class Topic {
Integer id
String name
Integer numberPosts
}
and another one
class TopicDetails {
Integer id
Integer numberPosts
}
The second is actually a container for query results that's why the similarity.
I have two lists List<Topic> and List<TopicDetails>. Objects will be unique by id in both the lists. The second one will have at most all the ids as the first list.
I want to merge the data from second list to first list. I understand that there are simple ways like
to iterate over both and check for ids and merge the details
Using a map for the details.
But is there some better way to do this? Collection framework has many new methods so I was thinking that there may be some elegant way to do this in groovy instead of doing the above mentioned methods.
EDIT I forgot to mention that the first one initially does not have the information regarding the numberPosts. That is why the second one is present i.e. as a container for information from the database.
A List is still just a list. You can use lambda expressions and "find" the ID each time, but you gain nothing in efficiency. A map is the way to go, at least for one of the lists.

modify field value in a crossfilter after insertion

I need to modify a field value for all records in a crossfilter before inserting new records.
The API doesn't say anything about it. Is there a way to do that ?
Even if it's a hack that would be really useful to me.
Looking at the code, the data array is held as a private local variable inside the crossfilter function so there's no way to get at it directly.
With that said, it looks like Crossfilter really tries to minimize the number of copies of the data it makes. So callback functions like the ones passed into crossfilter.dimension or dimension.filter are passed the actual records themselves from the data array (using the native Array.map) so any changes to make to the records will be made to the main records.
With that said, you obviously need to be very careful that you're not changing anything that is relied on by the existing dimensions, filters or groups. Otherwise you'll end up with data that doesn't agree with the internal Crossfilter structures and chaos will ensue.
The cool thing about .remove is it only removes entries that match the currently applied filters. So if you create a 'unique dimension' that returns a unique value for every entry in your dataset (like an ID column), you can have a function like this:
function editEntry(id, changes) {
uniqueDimension.filter(id); // filter to the item you want to change
var selectedEntry = uniqueDimension.top(1)[0]; // get the item
_.extend(selectedEntry, changes); // apply changes to it
ndx.remove(); // remove all items that pass the current filter (which will just be the item we are changing
ndx.add([selectedEntry]); // re-add the item
uniqueDimension.filter(null); // clear the filter
dc.redrawAll(); // redraw the UI
}
At the least you could do a cf.remove() then readd the adjusted data with cf.add().

How does one convert string to number in JDOQL?

I have a JDOQL/DataNucleus storage layer which stores values that can have multiple primitive types in a varchar field. Some of them are numeric, and I need to compare (</>/...) them with numeric constants. How does one achieve that? I was trying to use e.g. (java.lang.)Long.parse on the field or value (e.g. java.lang.Long.parseLong(field) > java.lang.Long.parseLong(string_param)), supplying a parameter of type long against string field, etc. but it doesn't work. In fact, I very rarely get any errors, for various combinations it would return all values or no values for no easily discernible reasons.
Is there documentation for this?
Clarification: the field is of string type (actually a string collection from which I do a get). For some subset of values they may store ints, e.g. "3" string, and I need to do e.g. value >= 2 filters.
I tried using casts, but not much, they do produce errors, let me investigate some more
JDO has a well documented set of methods that are valid for use with JDOQL, upon which DataNucleus JDO adds some additional ones and allows users to add on support for others as per
http://www.datanucleus.org/products/accessplatform_3_3/jdo/jdoql.html#methods
then you also can use JDOQL casts (on the same page as that link).

dynamodb creating a string set

I have a lot of objects with unique IDs. Every object can have several labels associated to it, like this:
123: ['a', 'hello']
456: ['dsajdaskldjs']
789: (no labels associated yet)
I'm not planning to store all objects in DynamoDB, only these sets of labels. So it would make sense to add labels like that:
find a record with (id = needed_id)
if there is one, and it has a set named label_set, add a label to this set
if there is no record with such id, or the existing record doesn't have an attribute named label_set, create a record and an attribute, and initialize the attribute with a set consisting of the label
if I used sets of numbers, I could use just ADD operation of UPDATE command. This command does exactly what I described. However, this does not work with sets of strings:
If no item matches the specified primary key:
ADD— Creates an item with supplied primary key and number (or set of numbers) for the attribute value. Not valid for a string type.
so I have to use a PUT operation with Expected set to {"label_set":{"Exists":false}}, followed (in case it fails) by an ADD operation. These are two operations, and it kinda sucks (since you pay per operation, the costs of this will be 2 times more than they could be).
This limitations seems really weird to me. Why are something what works with numbers sets would not work with string sets? Maybe I'm doing something wrong.
Using many records like (123, 'a'), (123, 'hello') instead of one record per object with a set is not a solutions: I want to get all the values from the set at once, without any scans.
I use string sets from the Java SDK the way you describe all the time and it works for me. Perhaps it has changed? I basically follow the pattern in this doc:
http://docs.amazonwebservices.com/amazondynamodb/latest/developerguide/API_UpdateItem.html
ADD— Only use the add action for numbers or if the target attribute is
a set (including string sets). ADD does not work if the target
attribute is a single string value or a scalar binary value. The
specified value is added to a numeric value (incrementing or
decrementing the existing numeric value) or added as an additional
value in a string set. If a set of values is specified, the values are
added to the existing set. For example if the original set is [1,2]
and supplied value is [3], then after the add operation the set is
[1,2,3], not [4,5]. An error occurs if an Add action is specified for
a set attribute and the attribute type specified does not match the
existing set type.
If you use ADD for an attribute that does not exist, the attribute and
its values are added to the item.
When your set is empty, it means the attribute isn't present. You can still ADD to it. In fact, a pattern that I've found useful is to simply ADD without even checking for the item. If it doesn't exist, it will create a new item using the specified key and create the attribute set with the value(s) I am adding. If the item exists but the attribute doesn't, it creates the attribute set and adds the value(s). If they both exist, it just adds the value(s).
The only piece that caught me up at first was that the value I had to add was a SS (String set) even if it was only one string value. From DynamoDB's perspective, you are always merging sets, even if the existing set is an empty set (missing) or the new set only contains one value.
IMO, from the way you've described your intent, you would be better off not specifying an existing condition at all. You are having to do two steps because you are enforcing two different situations but you are trying to perform the same action in both. So might as well just blindly add the label and let DynamoDB handle the rest.
Maybe you could: (pseudo code)
try:
add_with_update_item(hash_key=42, "label")
except:
element = new Element(hash_key=42, labels=["label"])
element.save()
With this graceful recovery approach, you need 1 call in the general case, 2 otherwise.
You are unable to use sets to do what you want because Dynamo Db doesn't support empty sets. I would suggest just using a string with a custom schema and building the set from that yourself.
To avoid two operations, you can add a "ConditionExpression" to your item.
For example, add this field/value to your item:
"ConditionExpression": "attribute_not_exists(RecordID) and attribute_not_exists(label_set)"
Source documentation.
Edit: I found a really good guide about how to use the conditional statements

Passing Lists as a QueryString - should I use JSON

Lets say I've got an online dating site, users can filter the user list based on various criteria, Height, Age, BodyType, Ethnic Origin....
I want to pass the criteria to the pager, via QueryString. Height and Age are easy as these are ranges, and I would use
MinHeight=3&MaxHeight=12&MinAge=21&MaxAge=30
However other Criteria like BodyType and Ethnic orgins are Lists of ForeignKey values e.g:
Ethnitity:2,3,5
What is the best way to pass these as a QueryString? Should I convert it to a Json string eg:
www.site.com?filterjson={\"minage\":0,\"maxage\":0,\"minheight\":0,\"maxheight\":0,\"bodytypelist\":[1,2,3],"ethnicitylist\":[2,3,4],\"eyecolorlist\":[],\"haircolorlist\":[],\"orientationlist\":[]}
Or is this not-valid/overkill/too complex?
Maybe something like this:
MinHeight=3&MaxHeight=12&bodytypes=1,2,3&
and parse the list values by splitting the ','?????
I don't know the ups and downs of all these ideas. So how would you pass a list of values in a querystring?
Using comma-separated values is the most pragmatic approach in my opinion. You can use this code to split values:
if (!string.IsNullOrEmpty(Request.QueryString["bodytypes"]))
{
string[] rgs = Request.QueryString["bodytypes"].Split(new char[] { ',' });
}
Both will work, though querystring is much easier to be 'hacked'. However if you have it well protected from malicious/unexpected values, I say it's fine.
Consuming data via querystring is relatively more straightforward than from JSON.

Resources