public interface Review extends Resource<Review>, Custom, WithKey
If you do not need any approval process, skip this part.
If we have an approval process for a review to be used for a product or a channel, we model the approval process with a state machine.
First of all, once per Project, we create the approved state. Then we create the initial to-approve state, which has a possible transition to the approved state:
public class CreateReviewStates {
public static List<State> createStates(final BlockingSphereClient client) {
final StateDraft approvedStateDraft =
StateDraftDsl.of("approved", StateType.REVIEW_STATE).withRoles(StateRole.REVIEW_INCLUDED_IN_STATISTICS);
final State approvedState = client.executeBlocking(StateCreateCommand.of(approvedStateDraft));
final StateDraft initialStateDraft =
StateDraftDsl.of("to-approve", StateType.REVIEW_STATE)
.withInitial(true)
.withTransitions(singleton(approvedState.toReference()));
final State initialState = client.executeBlocking(StateCreateCommand.of(initialStateDraft));
return asList(initialState, approvedState);
}
}
See the test code.
StateRole.REVIEW_INCLUDED_IN_STATISTICS
makes review ratings count in statistics.
Now we can create a review in the initial state to-approve:
public class CreateReviewToApprove {
public static Review createReview(final BlockingSphereClient client, final Reference<Product> productReference) {
final ReviewDraft reviewDraft = ReviewDraftBuilder
.ofRating(4)
.title("review title")
.target(productReference)
.state(ResourceIdentifier.ofKey("to-approve"))//you know the initial state by key and don't need a ref
.build();
final Review review = client.executeBlocking(ReviewCreateCommand.of(reviewDraft));
assertThat(review.getState()).isNotNull();
assertThat(review.getRating()).isEqualTo(4);
return review;
}
}
See the test code.
public class QueryReviewsToApprove {
public static List<Review> query(final BlockingSphereClient client, final State initialState) {
//this ID can be cached
final String initialStateId = client.executeBlocking(StateQuery.of().byKey("to-approve")).head().get().getId();
final ReviewQuery reviewQuery = ReviewQuery.of()
.withPredicates(m -> m.state().id().is(initialStateId))
.withSort(m -> m.createdAt().sort().asc());//oldest first
final List<Review> reviewsToApprove = client.executeBlocking(reviewQuery).getResults();
assertThat(reviewsToApprove).extracting(review -> review.getTitle()).contains("review title");
return reviewsToApprove;
}
}
See the test code.
public class ApprovingAReview {
public static Review approveReview(final BlockingSphereClient client, final Review reviewToApprove) {
final ResourceIdentifier<State> state = ResourceIdentifier.ofKey("approved");//we know the state by key
final ReviewUpdateCommand cmd = ReviewUpdateCommand.of(reviewToApprove, TransitionState.of(state));
final Review approvedReview = client.executeBlocking(cmd);
assertThat(reviewToApprove.getState()).isNotEqualTo(approvedReview.getState());
return approvedReview;
}
}
See the test code.
We can display all products that:
final List<FacetRange<BigDecimal>> facetRanges = IntStream.range(LOWEST_RATING, HIGHEST_RATING)
.mapToObj(i -> FacetRange.of(new BigDecimal(i), new BigDecimal(i + 1)))
.collect(toList());
assertThat(facetRanges.toString()).isEqualTo("[[0 to 1), [1 to 2), [2 to 3), [3 to 4), [4 to 5)]");
final ProductProjectionSearch searchRequest = ProductProjectionSearch.ofStaged()//in prod it would be current
.withResultFilters(m -> m.reviewRatingStatistics().averageRating().isGreaterThanOrEqualTo(new BigDecimal(2)))
.withFacets(m -> m.reviewRatingStatistics().averageRating().onlyRange(facetRanges))
.withSort(m -> m.reviewRatingStatistics().averageRating().desc());
assertEventually(Duration.ofSeconds(60), Duration.ofMillis(100), () -> {
final PagedSearchResult<ProductProjection> result = client().executeBlocking(searchRequest);
assertThat(result.getResults()).hasSize(2);
final ProductProjection productProjection = result.getResults().get(0);
assertThat(productProjection.getReviewRatingStatistics().getCount()).isEqualTo(REVIEWS_PER_PRODUCT);
final RangeFacetResult facetResult = (RangeFacetResult) result.getFacetResult("reviewRatingStatistics.averageRating");
assertThat(facetResult.getRanges().get(2)).isEqualTo(RangeStats.of("2.0", "3.0", 2L, null, "2.2", "2.7", "4.9", 2.45));
});
See the test code.
final String productId = product.getId();
final ReviewQuery reviewQuery = ReviewQuery.of()
.withPredicates(review -> review.includedInStatistics().is(true).and(review.target().id().is(productId)))
.withSort(m -> m.createdAt().sort().desc())
.withLimit(REVIEWS_PER_PRODUCT);
final List<Review> reviews = client().executeBlocking(reviewQuery).getResults();
assertThat(reviews).hasSize(REVIEWS_PER_PRODUCT);
assertThat(reviews).extracting(r -> r.getTarget().getId()).containsOnlyElementsOf(singletonList(productId));
assertThat(reviews).extracting(r -> r.isIncludedInStatistics()).containsOnlyElementsOf(singletonList(true));
See the test code.
final String productId = product.getId();
final ReviewQuery reviewQuery = ReviewQuery.of()
.withPredicates(m -> m.target().id().is(productId))
.withSort(m -> m.createdAt().sort().desc())
.withLimit(REVIEWS_PER_PRODUCT);
final List<Review> reviews = client().executeBlocking(reviewQuery).getResults();
assertThat(reviews).hasSize(REVIEWS_PER_PRODUCT);
assertThat(reviews).extracting(r -> r.getTarget().getId()).containsOnlyElementsOf(singletonList(productId));
See the test code.
Modifier and Type | Method and Description |
---|---|
String |
getAuthorName()
The name of the author which created this review or null.
|
CustomFields |
getCustom()
Gets the custom fields of this review or null.
|
Reference<Customer> |
getCustomer()
Gets the customer which created this review or null.
|
String |
getKey()
Gets the key assigned to this review or null.
|
Locale |
getLocale()
Gets the locale (language) in which the text and title are or null.
|
Integer |
getRating()
Gets the rating or null.
|
Reference<State> |
getState()
Gets the state of this review or null.
|
Reference<?> |
getTarget()
Identifies the target of the review.
|
String |
getText()
Gets the text of this review or null.
|
String |
getTitle()
Gets the title of this review or null.
|
String |
getUniquenessValue() |
Boolean |
isIncludedInStatistics()
Indicates if this review is taken into account in the ratings statistics of the target.
|
static Reference<Review> |
referenceOfId(String id)
Creates a reference for one item of this class by a known ID.
|
static String |
referenceTypeId()
A type hint for references which resource type is linked in a reference.
|
static String |
resourceTypeId()
An identifier for this resource which supports
CustomFields . |
default Reference<Review> |
toReference()
Creates a reference to this resource, the reference may not be filled.
|
static com.fasterxml.jackson.core.type.TypeReference<Review> |
typeReference()
Creates a container which contains the full Java type information to deserialize this class from JSON.
|
getCreatedAt, getId, getLastModifiedAt, getVersion
hasSameIdAs, toResourceIdentifier
@Nullable String getAuthorName()
SetAuthorName
@Nullable CustomFields getCustom()
getCustom
in interface Custom
SetCustomField
,
SetCustomType
@Nullable Reference<Customer> getCustomer()
SetCustomer
@Nullable Locale getLocale()
@Nullable Integer getRating()
SetRating
@Nullable Reference<State> getState()
TransitionState
@Nullable Reference<?> getTarget()
SetTarget
@Nullable String getText()
SetText
@Nullable String getTitle()
SetTitle
Boolean isIncludedInStatistics()
static String referenceTypeId()
Reference.getTypeId()
static String resourceTypeId()
CustomFields
.TypeDraft.getResourceTypeIds()
,
Custom
static com.fasterxml.jackson.core.type.TypeReference<Review> typeReference()
static Reference<Review> referenceOfId(String id)
An example for categories but this applies for other resources, too:
final String categoryIdFromFormOrSession = "84ac4271-0fec-49d0-9fee-55586c565c58";
final Reference<Category> categoryReference = Category.referenceOfId(categoryIdFromFormOrSession);
assertThat(categoryReference.getId()).isEqualTo(categoryIdFromFormOrSession);
See the test code.
If you already have a resource object, then use toReference()
instead:
final Category category = getCategory1();
final Reference<Category> categoryReference = category.toReference();
assertThat(category.getId()).isEqualTo(categoryReference.getId());
See the test code.
id
- the ID of the resource which should be referenced.default Reference<Review> toReference()
Referenceable
toReference
in interface Referenceable<Review>
toReference
in interface Resource<Review>