What is the preferred way to specify boolean value in the query part of URI? A normal query string looks like
a=foo&b=bar
Say I have a parameter "c" with boolean value, should I state
a=foo&b=bar&c=1
Or
a=foo&b=bar&c=True
Or
a=foo&b=bar&c=true
I checked the query component section of RFC 2396 and it does not specify how to express a boolean parameter. So what I want to know is what is the common (or reasonable) way to do it?
It completely depends on the way you read the query string. All of these that you ask for are valid.
Use key existence for boolean parameter like ?foo
For example, use ?foo instead of ?foo=true.
I prefer this way because I don't need to waste time to think or trace the source code about whether it should be true or 1 or enable or yes or anything that beyond my imagination.
In the case of case sensitivity, should it be true or True or TRUE?
In the case of term stemming, should it be enable or enabled?
IMHO, the form of ?foo is the most elegant way to pass a boolean variable to server because there are only 2 state of it (exist or not exist), which is good for representing a boolean variable.
This is also how Elasticsearch implemented for boolean query parameter, for example:
GET _cat/master?v
In node with an express server, you can add a boolean parser middleware like express-query-boolean.
var boolParser = require('express-query-boolean');
// [...]
app.use(bodyParser.json());
app.use(boolParser());
Without
// ?a=true&b[c]=false
console.log(req.query);
// => { a: 'true', b: { c: 'false' } }
With
// ?a=true&b[c]=false
console.log(req.query);
// => { a: true, b: { c: false } }
Url are strings and all values in a URL are strings,
all the params will be returned as strings.
it depends on how you interpret it in your code.
for the last one where c = true
you can do a JSON.parse(c)
which will change it to a boolean.
Also, you have to be careful not to pass it an empty string, if not it will throw an error.
I managed this with a custom function.
See browser compatibility here: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
function parseQuery(url = window.location.search) {
const urlParams = new URLSearchParams(url);
return Array.from(urlParams.keys()).reduce((acc, key) => {
const value = urlParams.get(key);
if (value) {
switch (value) {
case 'false': {
acc[key] = false;
break;
}
case 'true': {
acc[key] = true;
break;
}
case 'undefined': {
acc[key] = undefined;
break;
}
case 'null': {
acc[key] = null;
break;
}
default: {
acc[key] = value;
}
}
}
return acc;
}, {});
}
The function returns an object with all the parsed query parameters and fallback by default to the original value.
Or you can do this
const queryBool = unwrapTextBoolean({{{A_WAY_TO_GET_THAT_TEXT_BOOLEAN}}})
if(queryBool===null) {return;}
if(queryBool){
/*true-based code*/
}else{
/*false-based code*/
}
function unwrapTextBoolean(tB){
if(tB === 'true') return true;
if(tb === 'false') return false;
return null;
}
Related
I have an ArrayCollection from Hashtag entity (database/table collation both set to utf8_bin_ci) which I want to match on a Criteria but it's not case insensitive.
I've tried 'contains', 'eq', 'startsWith', 'endsWith' expressions, but it returns null on matching, however it has many results without the Criteria matching.
If I add strtolower / strtoupper to $this->name property, it works in the specified case.
How can I make it case-insensitive the Criteria or the matching here?
public function getHashtags($max = null) {
$hashtags = $this->hashtags;
$hashtags->getIterator();
$crit = Criteria::create()
->where(Criteria::expr()->contains('name', $this->name))
if (!empty($max)) {
$crit->setMaxResults($max);
}
return $hashtags->matching($crit);
}
Your code calls getIterator(), which will prevent any database magic from ever happening, because it initializes the collection (which loads all entries), so your collation doesn't matter anyway.
Also, the contains function uses strpos, which obviously is not case-insensitive.
Since your code already pulls in all hashtags, just filter it already:
$hashtags = array_filter(function(Hashtag $hashtag) {
return stripos($this->name, $hashtag->getName());
}, $this->hashtags);
if(!empty($max)) {
$hashtags = array_slice($hashtags, 0, $max, true);
// remove true, if you don't care about keys ^, this preserves them
}
return $hashtags;
regard to #Jakumi correct answer:
$hashtags = array_filter($this->hashtags->toArray(), function (TwitterHashtag $hashtag) use ($fields) {
foreach ($fields as $field) {
if (false !== stripos($hashtag->getName(), $this->$field)) {
return true;
}
}
});
if (!empty($max)) {
$hashtags = array_slice($hashtags, 0, $max, false);
}
I am implementing a method using Vertx to check the existence of certain value in the database and use Handler with AsyncResult.
I would like to know which one is the best practice:
Option 1: When nothing found, Handler is with succeededFuture but with result as FALSE:
public void checkExistence (..., String itemToFind, Handler<AsyncResult<Boolean>> resultHandler) {
// ....
doQuery(..., queryHandler -> {
if (queryHandler.succeeded()) {
List<JsonObject> results = queryHandler.result();
boolean foundIt = false;
for (JsonObject json: results) {
if (json.getString("someKey").equals(itemToFind)) {
foundIt = true;
break;
}
}
resultHandler.handle(Future.succeededFuture(foundIt));
} else {
resultHandler.handle(Future.failedFuture(queryHandler.cause().toString()));
}
});
}
Option 2: When nothing found, Handler is with failedFuture:
public void checkExistence (..., String itemToFind, Handler<AsyncResult<Void>> resultHandler) {
// ....
doQuery(..., queryHandler -> {
if (queryHandler.succeeded()) {
List<JsonObject> results = queryHandler.result();
boolean foundIt = false;
for (JsonObject json: results) {
if (json.getString("someKey").equals(itemToFind)) {
foundIt = true;
break;
}
}
// HERE IS THE DIFFERENCE!!!
if (foundIt) {
resultHandler.handle(Future.succeededFuture());
} else {
resultHandler.handle(Future.failedFuture("Item " + itemToFind + " not found!"));
}
} else {
resultHandler.handle(Future.failedFuture(queryHandler.cause().toString()));
}
});
}
UPDATE:
Let's say I have another example, instead of checking the existence, I would like to get all the results. Do I check the Empty results? Do I treat Empty as failure or success?
Option 1: only output them when it's not null or empty, otherwise, fail it
public void getItems(..., String itemType, Handler<AsyncResult<List<Item>>> resultHandler) {
// ....
doQuery(..., queryHandler -> {
if (queryHandler.succeeded()) {
List<Item> items = queryHandler.result();
if (items != null && !items.empty()) {
resultHandler.handle(Future.succeededFuture(items));
} else {
resultHandler.handle(Future.failedFuture("No items found!"));
}
} else {
resultHandler.handle(Future.failedFuture(queryHandler.cause().toString()));
}
});
}
Option 2: output results I got, even though it could be empty or null
public void getItems(..., String itemType, Handler<AsyncResult<List<Item>>> resultHandler) {
// ....
doQuery(..., queryHandler -> {
if (queryHandler.succeeded()) {
List<Item> items = queryHandler.result();
resultHandler.handle(Future.succeededFuture(items));
} else {
resultHandler.handle(Future.failedFuture(queryHandler.cause().toString()));
}
});
}
The 1st one option is better, because you can clearly say, that checkExistence returned True or False and completed successfully or it failed with some exception (database issue, etc.).
But lets say, you've decided to stick with 2nd option. Then, imagine you have another method:
void getEntity(int id, Handler<AsyncResult<Entity>> resultHandler);
If entity with provided id doesn't exists, will you throw exception (using Future.failedFuture) or return null (using Future.succeededFuture)? I think, you should throw exception to make your methods logic similar to each other. But again, is that exceptional situation?
For case with returning list of entities you can just return empty list, if there are no entities. Same goes to single entity: it's better to return Optional<Entity> instead of Entity, because in this way you avoid NullPointerException and don't have nullable variables in the code. What's better: Optional<List<Entity>> or empty List<Entity>, it's open question.
Particularly if you're writing this as reusable code, then definitely go with your first option. This method is simply determining whether an item exists, and so should simply return whether it does or not. How is this particular method to know whether it's an error condition that the item doesn't exist?
Some caller might determine that it is indeed an error; it that's the case, then it will throw an appropriate exception if the Future returns with false. But another caller might simply need to know whether the item exists before proceeding; in that case, you'll find yourself using exception handling to compose your business logic.
Until now (Swift 2.2) I have been happily using the code from this answer - it's swifty, it's elegant, it worked like a dream.
extension MutableCollectionType where Index : RandomAccessIndexType, Generator.Element : AnyObject {
/// Sort `self` in-place using criteria stored in a NSSortDescriptors array
public mutating func sortInPlace(sortDescriptors theSortDescs: [NSSortDescriptor]) {
sortInPlace {
for sortDesc in theSortDescs {
switch sortDesc.compareObject($0, toObject: $1) {
case .OrderedAscending: return true
case .OrderedDescending: return false
case .OrderedSame: continue
}
}
return false
}
}
}
extension SequenceType where Generator.Element : AnyObject {
/// Return an `Array` containing the sorted elements of `source`
/// using criteria stored in a NSSortDescriptors array.
#warn_unused_result
public func sort(sortDescriptors theSortDescs: [NSSortDescriptor]) -> [Self.Generator.Element] {
return sort {
for sortDesc in theSortDescs {
switch sortDesc.compareObject($0, toObject: $1) {
case .OrderedAscending: return true
case .OrderedDescending: return false
case .OrderedSame: continue
}
}
return false
}
}
}
Swift 3 changes everything.
Using the code migration tool and Proposal SE- 0006 - sort() => sorted(), sortInPlace() => sort() - I have gotten as far as
extension MutableCollection where Index : Strideable, Iterator.Element : AnyObject {
/// Sort `self` in-place using criteria stored in a NSSortDescriptors array
public mutating func sort(sortDescriptors theSortDescs: [SortDescriptor]) {
sort {
for sortDesc in theSortDescs {
switch sortDesc.compare($0, to: $1) {
case .orderedAscending: return true
case .orderedDescending: return false
case .orderedSame: continue
}
}
return false
}
}
}
extension Sequence where Iterator.Element : AnyObject {
/// Return an `Array` containing the sorted elements of `source`
/// using criteria stored in a NSSortDescriptors array.
public func sorted(sortDescriptors theSortDescs: [SortDescriptor]) -> [Self.Iterator.Element] {
return sorted {
for sortDesc in theSortDescs {
switch sortDesc.compare($0, to: $1) {
case .orderedAscending: return true
case .orderedDescending: return false
case .orderedSame: continue
}
}
return false
}
}
}
The 'sorted' function compiles [and works] without problems. For 'sort' I get an error on the line that says 'sort' : "Cannot convert value of type '(_, _) -> _' to expected argument type '[SortDescriptor]'" which has me completely baffled: I do not understand where the compiler is trying to convert anything since I am passing in an array of SortDescriptors, which ought to BE an array of SortDescriptors.
Usually, this type of error means that you're handling optionals where you ought to have definite values, but since this is a function argument - and seems to work without a hitch in func sorted - all I can read from it is that 'something is wrong'. As of now, I have no idea WHAT that something is, and since we're in the early stages of beta, there is no documentation at all.
As a workaround, I have removed the sort (formerly sort-in-place) function from my code and replaced it with a dance of
let sortedArray = oldArray(sorted[...]
oldArray = sortedArray
but I'd be really grateful if I could get my sort-in-place functionality back.
Compare the methods available in Swift 2.2:
with the methods in Swift 3:
Notice that Swift 3 does not have a sort method that accepts an isOrderedBefore closure.
That is why your function won't compile.
This looks like a bug, so I reported it as bug 26857748 at bugreport.apple.com.
let sortedArray = users.sorted { $0.name < $1.name }
Use RandomAccessCollection protocol
extension MutableCollection where Self : RandomAccessCollection {
/// Sort `self` in-place using criteria stored in a NSSortDescriptors array
public mutating func sort(sortDescriptors theSortDescs: [NSSortDescriptor]) {
sort { by:
for sortDesc in theSortDescs {
switch sortDesc.compare($0, to: $1) {
case .orderedAscending: return true
case .orderedDescending: return false
case .orderedSame: continue
}
}
return false
}
}
}
In Swift 3.0
let sortedCapitalArray = yourArray.sorted {($0 as AnyObject).localizedCaseInsensitiveCompare(($1 as AnyObject)as! String) == ComparisonResult.orderedAscending}
Lets say we have a 'Client' object:
(am just mentioning the attributes and the equals method alone of the 'Client' object below!!)
public class Client {
private Long clientId;
private String clientName;
private Integer status;
//getters and setters for above attributes
.....
...
//hashCode method
....
..
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Client other = (Client) obj;
if (clientId == null) {
if (other.clientId != null)
return false;
} else if (!clientId.equals(other.clientId))
return false;
if (clientName == null) {
if (other.clientName != null)
return false;
} else if (!clientName.equals(other.clientName))
return false;
if (status == null) {
if (other.status != null)
return false;
} else if (!status.equals(other.status))
return false;
return true;
}
}
From the above equals method itz clear that 'two' client objects are said to be equal if all the attributes of the two objects are identical.
Now assume a scenario where I need to compare two collections(named say incomingClients and existingClients) of Client objects.
The first collection(Collection incomingClients) was generated after reading the 'client' data from a csv/xls file.
The second collection(Collection existingClients) contains, all the existing clients currently in the system.
I can do the following code (using apache CollectionUtils)to get the 'common' clients.
Collection<Client> commonClients = (Collection<Client>)CollectionUtils.intersection(incomingClients,existingClients);
Now with the below code I can remove these commonClients from both the collections.
incomingClients.removeAll(commonClients);
existingClients.removeAll(commonClients);
The intention of removing the 'common clients objects' was that, we dont need to do 'any processing' for these records,
as we are really not at all interested in those records.
Now how can I figure out which are the entirely 'new clients' in the 'Collection incomingClients' collection?
(When I say 'new' it means a client having a new 'clientId' which doesnt exist in the 'Collection existingClients')
Also, how can I figure out which are the clients which needs 'modification'
(When I say 'modification' it means that the 'Collection incomingClients' and Collection existingClients'
have the same clientId, but, say, different 'clientName')
I know that we can do the normal 'for' loop('check below') to figure out the 'new'/'modification needed' clients.
But I thought of writing 'something new', whether we can achieve this using some classes/function in the 'Apache CollectionUtils' package.
Collection<Client> newClients = new ArrayList<Client>();
Collection<Client> toBeModifiedClients = new ArrayList<Client>();
boolean foundClient = false;
Client client = null;
for(Client incomingClient :incomingClients){
foundClient = false;
for(Client existingClient : existingClients){
if(existingClient.getClientId().equals(incomingClient.getClientId())){
client = existingClient;
foundClient = true;
break;
}
}
if(foundClient){
toBeModifiedClients.add(client);
}else{
//not found in existing. so this is completely new
newClients.add(incomingClient);
}
}
Am I 'complicating' a simple stuff??
Any thoughts??
First, yes, you are complicating "simple stuff". Your entire question could be summarized as follows:
Given collections A and B, how can I get the following using CollectionUtils:
A-B, using a particular function that determines equality
A∩B, using a particular function that determines equality
So, yes. CollectionUtils has what you need. Look at CollectionUtils.select().
What is the preferred way to specify boolean value in the query part of URI? A normal query string looks like
a=foo&b=bar
Say I have a parameter "c" with boolean value, should I state
a=foo&b=bar&c=1
Or
a=foo&b=bar&c=True
Or
a=foo&b=bar&c=true
I checked the query component section of RFC 2396 and it does not specify how to express a boolean parameter. So what I want to know is what is the common (or reasonable) way to do it?
It completely depends on the way you read the query string. All of these that you ask for are valid.
Use key existence for boolean parameter like ?foo
For example, use ?foo instead of ?foo=true.
I prefer this way because I don't need to waste time to think or trace the source code about whether it should be true or 1 or enable or yes or anything that beyond my imagination.
In the case of case sensitivity, should it be true or True or TRUE?
In the case of term stemming, should it be enable or enabled?
IMHO, the form of ?foo is the most elegant way to pass a boolean variable to server because there are only 2 state of it (exist or not exist), which is good for representing a boolean variable.
This is also how Elasticsearch implemented for boolean query parameter, for example:
GET _cat/master?v
In node with an express server, you can add a boolean parser middleware like express-query-boolean.
var boolParser = require('express-query-boolean');
// [...]
app.use(bodyParser.json());
app.use(boolParser());
Without
// ?a=true&b[c]=false
console.log(req.query);
// => { a: 'true', b: { c: 'false' } }
With
// ?a=true&b[c]=false
console.log(req.query);
// => { a: true, b: { c: false } }
Url are strings and all values in a URL are strings,
all the params will be returned as strings.
it depends on how you interpret it in your code.
for the last one where c = true
you can do a JSON.parse(c)
which will change it to a boolean.
Also, you have to be careful not to pass it an empty string, if not it will throw an error.
I managed this with a custom function.
See browser compatibility here: https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams
function parseQuery(url = window.location.search) {
const urlParams = new URLSearchParams(url);
return Array.from(urlParams.keys()).reduce((acc, key) => {
const value = urlParams.get(key);
if (value) {
switch (value) {
case 'false': {
acc[key] = false;
break;
}
case 'true': {
acc[key] = true;
break;
}
case 'undefined': {
acc[key] = undefined;
break;
}
case 'null': {
acc[key] = null;
break;
}
default: {
acc[key] = value;
}
}
}
return acc;
}, {});
}
The function returns an object with all the parsed query parameters and fallback by default to the original value.
Or you can do this
const queryBool = unwrapTextBoolean({{{A_WAY_TO_GET_THAT_TEXT_BOOLEAN}}})
if(queryBool===null) {return;}
if(queryBool){
/*true-based code*/
}else{
/*false-based code*/
}
function unwrapTextBoolean(tB){
if(tB === 'true') return true;
if(tb === 'false') return false;
return null;
}