Java 8 - use stream to match all fields to either one of two values - java-8

I have a list of states (enum: SomeStatus.class). I want to check if all states matches either FINISHED, PENDING, then I want to execute some condition.
public enum SomeStatus {
FINISHED, PENDING, EMPTY, STARTED
}
Eg, this is how I would do for matching all states to one state. But how would I do it for matching it with 2 states (either / or) ?
if(states.stream().allMatch(SomeStatus.FINISHED::equals)) {
// .... custom logic ....
}

for example:
if(states.stream().allMatch(Set.of(SomeStatus.FINISHED, SomeStatus.PENDING)::contains)) {
// .... custom logic ....
}

Related

graphql filter based on internal fragments (gatsbyJS)

Why is this not possible? In the sense that it looks like I have no access to any property accessed through an internal fragment such as ... on File
codebox from gatsby-docs
{
books: allMarkdownRemark(filter: {parent: {sourceInstanceName: {eq: "whatever"}}}) {
totalCount
edges {
node {
parent {
... on File {
sourceInstanceName
}
}
}
}
}
}
Error: Field is not defined by type NodeFilterInput
It's a resolver authors responsibility.
You can compare it to general function arguments and returned result. In graphQL both are strictly defined/typed.
In this case, for query allMarkdownRemark you have
allMarkdownRemark(
filter: MarkdownRemarkFilterInput
limit: Int
skip: Int
sort: MarkdownRemarkSortInput
): MarkdownRemarkConnection!
... so possible arguments are only filter, limit, skip and sort. Argument filter has defined shape, too - it has to be MarkdownRemarkFilterInput type. You can only use properties defined in this type for filter argument.
This is by design, this is how designer created resolver and his intentions about how and what arguments are handled.
It's like pagination - you don't have to use any of result fields as arguments as skip and limit are for record level. This way those arguments are not related to fields at all. They are used for some logic in resolver. filter argument is used for logic, too ... but it's deleveloper decision to choose and cover filtering use cases.
It's impossible to cover all imaginable filters on all processed data layers and properties, ... for parent you can only use children, id, internal and parent properties and subproperties (you can explore them in playground).
Of course it's not enough to extend type definition to make it working with another argument - it's about code to handle it.
If you need onother filtering logic, you can write your own resolver (or modify forked gatsby project) for your file types or other source.

Use Query Result as Argument in Next Level in GraphQL

Hullo everyone,
This has been discussed a bit before, but it's one of those things where there is so much scattered discussion resulting in various proposed "hacks" that I'm having a hard time determining what I should do.
I would like to use the result of a query as an argument for another nested query.
query {
allStudents {
nodes {
courseAssessmentInfoByCourse(courseId: "2b0df865-d7c6-4c96-9f10-992cd409dedb") {
weightedMarkAverage
// getting result for specific course is easy enough
}
coursesByStudentCourseStudentIdAndCourseId {
nodes {
name
// would like to be able to do something like this
// to get a list of all the courses and their respective
// assessment infos
assessmentInfoByStudentId (studentId: student_node.studentId) {
weightedMarkAverage
}
}
}
}
}
}
Is there a way of doing this that is considered to be best practice?
Is there a standard way to do it built into GraphQL now?
Thanks for any help!
The only means to substitute values in a GraphQL document is through variables, and these must be declared in your operation definition and then included alongside your document as part of your request. There is no inherent way to reference previously resolved values within the same document.
If you get to a point where you think you need this functionality, it's generally a symptom of poor schema design in the first place. What follows are some suggestions for improving your schema, assuming you have control over that.
For example, minimally, you could eliminate the studentId argument on assessmentInfoByStudentId altogether. coursesByStudentCourseStudentIdAndCourseId is a field on the student node, so its resolver can already access the student's id. It can pass this information down to each course node, which can then be used by assessmentInfoByStudentId.
That said, you're probably better off totally rethinking how you've got your connections set up. I don't know what your underlying storage layer looks like, or the shape your client needs the data to be in, so it's hard to make any specific recommendations. However, for the sake of example, let's assume we have three types -- Course, Student and AssessmentInfo. A Course has many Students, a Student has many Courses, and an AssessmentInfo has a single Student and a single Course.
We might expose all three entities as root level queries:
query {
allStudents {
# fields
}
allCourses {
# fields
}
allAssessmentInfos {
# fields
}
}
Each node could have a connection to the other two types:
query {
allStudents {
courses {
edges {
node {
id
}
}
}
assessmentInfos {
edges {
node {
id
}
}
}
}
}
If we want to fetch all students, and for each student know what courses s/he is taking and his/her weighted mark average for that course, we can then write a query like:
query {
allStudents {
assessmentInfos {
edges {
node {
id
course {
id
name
}
}
}
}
}
}
Again, this exact schema might not work for your specific use case but it should give you an idea around how you can approach your problem from a different angle. A couple more tips when designing a schema:
Add filter arguments on connection fields, instead of creating separate fields for each scenario you need to cover. A single courses field on a Student type can have a variety of arguments like semester, campus or isPassing -- this is cleaner and more flexible than creating different fields like coursesBySemester, coursesByCampus, etc.
If you're dealing with aggregate values like average, min, max, etc. it might make sense to expose those values as fields on each connection type, in the same way a count field is sometimes available alongside the nodes field. There's a (proposal)[https://github.com/prisma/prisma/issues/1312] for Prisma that illustrates one fairly neat way to do handle these aggregate values. Doing something like this would mean if you already have, for example, an Assessment type, a connection field might be sufficient to expose aggregate data about that type (like grade averages) without needing to expose a separate AssessmentInfo type.
Filtering is relatively straightforward, grouping is a bit tougher. If you do find that you need the nodes of a connection grouped by a particular field, again this may be best done by exposing an additional field on the connection itself, (like Gatsby does it)[https://www.gatsbyjs.org/docs/graphql-reference/#group].

sending input from single spout to multiple bolts with Fields grouping in Apache Storm

builder.setSpout("spout", new TweetSpout());
builder.setBolt("bolt", new TweetCounter(), 2).fieldsGrouping("spout",
new Fields("field1"));
I have an input field "field1" added in fields grouping. By definition of fields grouping, all tweets with same "field1" should go to a single task of TweetCounter. The executors # set for TweetCounter bolt is 2.
However, if "field1" is the same in all the tuples of incoming stream, does this mean that even though I specified 2 executors for TweetCounter, the stream would only be sent to one of them and the other instance remains empty?
To go further with my particular use case, how can I use a single spout and send data to different bolts based on a particular value of an input field (field1)?
It seems one way to solved this problem is to use Direct grouping where the source decides which component will receive the tuple. :
This is a special kind of grouping. A stream grouped this way means that the producer of the tuple decides which task of the consumer will receive this tuple. Direct groupings can only be declared on streams that have been declared as direct streams. Tuples emitted to a direct stream must be emitted using one of the [emitDirect](javadocs/org/apache/storm/task/OutputCollector.html#emitDirect(int, int, java.util.List) methods. A bolt can get the task ids of its consumers by either using the provided TopologyContext or by keeping track of the output of the emit method in OutputCollector (which returns the task ids that the tuple was sent to).
You can see it's example uses here:
collector.emitDirect(getWordCountIndex(word),new Values(word));
where getWordCountIndex returns the index of the component where this tuple will be processes.
An alternative to using emitDirect as described in this answer is to implement your own stream grouping. The complexity is about the same, but it allows you to reuse grouping logic across multiple bolts.
For example, the shuffle grouping in Storm is implemented as a CustomStreamGrouping as follows:
public class ShuffleGrouping implements CustomStreamGrouping, Serializable {
private ArrayList<List<Integer>> choices;
private AtomicInteger current;
#Override
public void prepare(WorkerTopologyContext context, GlobalStreamId stream, List<Integer> targetTasks) {
choices = new ArrayList<List<Integer>>(targetTasks.size());
for (Integer i : targetTasks) {
choices.add(Arrays.asList(i));
}
current = new AtomicInteger(0);
Collections.shuffle(choices, new Random());
}
#Override
public List<Integer> chooseTasks(int taskId, List<Object> values) {
int rightNow;
int size = choices.size();
while (true) {
rightNow = current.incrementAndGet();
if (rightNow < size) {
return choices.get(rightNow);
} else if (rightNow == size) {
current.set(0);
return choices.get(0);
}
} // race condition with another thread, and we lost. try again
}
}
Storm will call prepare to tell you the task ids your grouping is responsible for, as well as some context on the topology. When Storm emits a tuple from a bolt/spout where you're using this grouping, Storm will call chooseTasks which lets you define which tasks the tuple should go to. You would then use the grouping when building your topology as shown:
TopologyBuilder tp = new TopologyBuilder();
tp.setSpout("spout", new MySpout(), 1);
tp.setBolt("bolt", new MyBolt())
.customGrouping("spout", new ShuffleGrouping());
Be aware that groupings need to be Serializable and thread safe.

Spring Data Mongodb - findBy query with OR clause on same field

I'm working on mongo with spring data and using the query "findBy" based on property fields.
My goal will be find same value across multiple properties by OR clause like this:
List<Event> findByCreatorOrOrganizersOrGuests(User user);
this query involves 3 properties: "creator", "organizers" and "guests" that are a single value (creator) and 2 lists (organizers and guests) that contains the same class type (User)
at compile time I receive this error:
org.springframework.data.repository.query.ParameterOutOfBoundsException: Invalid parameter index! You seem to have declare too little query method parameters!
Do I need to repeat the same parameter 3 times? There's no workaround?
thanks
The using of Mongo queries for lists are not so efficient even if you define it with an index.
Another important thing is that the query:
List<Event> findByCreatorOrOrganizersOrGuests(User user);
includes some syntax errors (The MongoDB expects to get 3 parameters as variables int the ( ) relatively to the findBy keys, the return value should be inserted into a list object, and I am not sure that the Or in the find query is legal syntax.
As a concept the DB documents should have a good ability to be searched, cause it is the most expensive action.
When find using OR in MongoDB the direct query should looks like that:
def events = find({ $or: [ { user.username: { $lt: 20 } }, { price: 10 } ] } )
While searching in a list this is should be different, so please follow the links I attached.
When I try to think of the use you are looking for, I would suggest a different aspect. If the events is what interest you please read about the AbstractPersistenceEventListener. By define the appropriate
void onPostInsert(entity) {}
void onPostUpdate(entity) {}
void onPostDelete(entity) {}
You get all the events for each of the objects you want to listen to.
Here are 2 a great examples:
Example 1
Example 2

Java 8 list manipulation

I'm trying to do some basic map/filter operations on a list in a ListChangeListener.onChanged(Change<? extends Place>) method and I can get it working using the old-fashioned "iterate and do some ifs" way, but I wanted to try to write it using the stream() method from java 8. The commented part doesn't give the same result though, it fails to filter out the categories correctly (and yes, I have a working implementation of equals(Object) for Category
for (Place p : change.getAddedSubList()) {
if (!categories.contains(p.getCategory())) {
categories.add(p.getCategory());
}
}
// List<Category> addedCategories = change.getAddedSubList().stream()
//                      .map(Place::getCategory)
//                      .filter((c) -> { return !categories.contains(c); })
//   .collect(Collectors.toList());
// categories.addAll(addedCategories);
That's because in the first version, once you have added a category to the list, a subsequent occurrence of this category isn't added a second time: you have already added it to the list. The second version doesn't do the same thing. So you need to make sure categories are unique in the stream:
change.getAddedSubList().stream()
.map(Place::getCategory)
.distinct()
.filter(c -> !categories.contains(c))
.forEachOrdered(c -> categories.add(c));
Note that you also don't need to collect to a temporary list.
Duplicates in you stream may lead to duplicates in the categories list, when they are not contained in the categories list beforehand, since the filter method is applied for all items, before one of them is inserted.
One solution would be to insert a call to .distinct() in your Stream, another way to collect via Collectors.toSet().

Resources