Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ public boolean hasRelationship(final String relationshipName) {
}

public void addRelationship(final RelationshipVectorDefinition relationship) {
String relationshipName = relationship.getName().toLowerCase();
List<RelationshipVectorDefinition> relationshipsWithThisName =
relationships.get(relationship.getName());
relationships.get(relationshipName);
if (relationshipsWithThisName == null) {
// there is no relationship with this name
relationshipsWithThisName = new ArrayList<>();
relationships.put(relationship.getName(), relationshipsWithThisName);
relationships.put(relationshipName, relationshipsWithThisName);
}

relationshipsWithThisName.add(relationship);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,19 @@ public RelationshipDefinition defineRelationship(
RelationshipDefinition relationship =
RelationshipDefinition.create(
new RelationshipVectorDefinition(from, named, to, of));
relationships.put(named, relationship);
relationships.put(relationshipKey(from, named, to), relationship);
return relationship;
}

public boolean hasRelationshipNamed(final String relationshipName) {
if (relationshipName == null) {
return false;
}
if (relationships.containsKey(relationshipName.toLowerCase())) {
return true;
}

// perhaps it is a reverse relationship?
for (RelationshipDefinition defn : relationships.values()) {
if (defn.getFromRelationship().getName().equalsIgnoreCase(relationshipName)) {
return true;
}
if (defn.isTwoWay()) {
if (defn.getReversedRelationship().getName().equalsIgnoreCase(relationshipName)) {
return true;
Expand All @@ -65,6 +64,16 @@ public boolean hasRelationshipNamed(final String relationshipName) {
return false;
}

private String relationshipKey(
final EntityDefinition from, final String relationshipName, final EntityDefinition to) {
return String.format(
"%s:%s:%s",
from.getName().toLowerCase(),
relationshipName.toLowerCase(),
to.getName().toLowerCase())
.toLowerCase();
}

public List<String> getEntityNames() {
List<String> names = new ArrayList();
names.addAll(entityDefinitions.keySet());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ public class EntityDefinition {
private int maxInstanceCount; // use -ve for no limit
private final String name;
private final String plural;
private String description;

// TODO: consider adding candidate keys e.g. guid or id
// TODO: consider adding composite keys e.g. name and id
private Field primaryKeyField;

private final DefinedFields fields;
private final DefinedRelationships definedRelationships;
private final Map<String, EntityViewDefinition> views;

private static final int NO_INSTANCE_LIMIT = -1;

Expand All @@ -30,7 +32,9 @@ public EntityDefinition(String name, String plural, int maxInstanceCount) {
this.plural = plural;
definedRelationships = new DefinedRelationships();
fields = new DefinedFields();
views = new HashMap<>();
this.maxInstanceCount = maxInstanceCount;
this.description = "";

// todo: add some validation to report against no primary key having been defined

Expand All @@ -55,6 +59,19 @@ public String getPlural() {
return plural;
}

public EntityDefinition withDescription(final String description) {
this.description = description == null ? "" : description;
return this;
}

public boolean hasDescription() {
return description != null && !description.trim().isEmpty();
}

public String getDescription() {
return description;
}

public void addField(Field aField) {
fields.addField(aField);
}
Expand Down Expand Up @@ -136,4 +153,32 @@ public boolean hasAnyOfFieldNamesDefined(List<String> fieldNames) {
}
return false;
}

public EntityViewDefinition defineView(final String viewName) {
final String normalizedName = viewName == null ? "" : viewName.trim();
if (normalizedName.isEmpty()) {
throw new IllegalArgumentException("View name is required");
}
if (views.containsKey(normalizedName)) {
throw new IllegalArgumentException(
String.format(
"View %s is already defined for entity %s", normalizedName, getName()));
}

final EntityViewDefinition view = new EntityViewDefinition(this, normalizedName);
views.put(normalizedName, view);
return view;
}

public boolean hasViewNamed(final String viewName) {
return views.containsKey(viewName);
}

public EntityViewDefinition getViewNamed(final String viewName) {
return views.get(viewName);
}

public Collection<EntityViewDefinition> getViews() {
return Collections.unmodifiableCollection(views.values());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package uk.co.compendiumdev.thingifier.core.domain.definitions;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public final class EntityViewDefinition {

private final EntityDefinition entity;
private final String name;
private final Set<String> requestVisibleFields;
private final Set<String> responseVisibleFields;
private final Set<String> inputAllowedFields;

EntityViewDefinition(final EntityDefinition entity, final String name) {
this.entity = entity;
this.name = name;
this.requestVisibleFields = new HashSet<>(entity.getFieldNames());
this.responseVisibleFields = new HashSet<>(entity.getFieldNames());
this.inputAllowedFields = new HashSet<>(entity.getFieldNames());
}

public String getName() {
return name;
}

public EntityDefinition getEntity() {
return entity;
}

public EntityViewDefinition showFields(final String... fieldNames) {
showRequestFields(fieldNames);
showResponseFields(fieldNames);
return this;
}

public EntityViewDefinition hideFields(final String... fieldNames) {
hideRequestFields(fieldNames);
hideResponseFields(fieldNames);
return this;
}

public EntityViewDefinition showRequestFields(final String... fieldNames) {
for (String fieldName : validFieldNames(fieldNames)) {
requestVisibleFields.add(fieldName);
}
return this;
}

public EntityViewDefinition hideRequestFields(final String... fieldNames) {
for (String fieldName : validFieldNames(fieldNames)) {
requestVisibleFields.remove(fieldName);
}
return this;
}

public EntityViewDefinition showResponseFields(final String... fieldNames) {
for (String fieldName : validFieldNames(fieldNames)) {
responseVisibleFields.add(fieldName);
}
return this;
}

public EntityViewDefinition hideResponseFields(final String... fieldNames) {
for (String fieldName : validFieldNames(fieldNames)) {
responseVisibleFields.remove(fieldName);
}
return this;
}

public EntityViewDefinition allowInputFields(final String... fieldNames) {
for (String fieldName : validFieldNames(fieldNames)) {
inputAllowedFields.add(fieldName);
}
return this;
}

public EntityViewDefinition disallowInputFields(final String... fieldNames) {
for (String fieldName : validFieldNames(fieldNames)) {
inputAllowedFields.remove(fieldName);
}
return this;
}

public boolean isRequestVisible(final String fieldName) {
return requestVisibleFields.contains(fieldName);
}

public boolean isResponseVisible(final String fieldName) {
return responseVisibleFields.contains(fieldName);
}

public boolean isInputAllowed(final String fieldName) {
return inputAllowedFields.contains(fieldName);
}

public Set<String> requestVisibleFields() {
return Collections.unmodifiableSet(requestVisibleFields);
}

public Set<String> responseVisibleFields() {
return Collections.unmodifiableSet(responseVisibleFields);
}

public Set<String> inputAllowedFields() {
return Collections.unmodifiableSet(inputAllowedFields);
}

private Set<String> validFieldNames(final String... fieldNames) {
if (fieldNames == null) {
return Set.of();
}
final Set<String> validNames = new HashSet<>();
for (String fieldName : fieldNames) {
if (!entity.hasFieldNameDefined(fieldName)) {
throw new IllegalArgumentException(
String.format(
"Field %s is not defined for entity %s",
fieldName, entity.getName()));
}
validNames.add(fieldName);
}
return validNames;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.ArrayList;
import java.util.List;
import uk.co.compendiumdev.thingifier.core.domain.definitions.EntityDefinition;
import uk.co.compendiumdev.thingifier.core.domain.definitions.relationship.RelationshipVectorDefinition;
import uk.co.compendiumdev.thingifier.core.domain.instances.EntityInstance;
import uk.co.compendiumdev.thingifier.core.repository.EntityInstanceQuery;
import uk.co.compendiumdev.thingifier.core.repository.RelationshipRepository;
Expand Down Expand Up @@ -60,12 +61,29 @@ public RepositoryQuery performQuery(final QueryFilterParams queryParams) {

if (spec.hasRelationship()) {
wasIntentToMatchInstance = true;
isCollection = true;
foundItems =
new ArrayList<>(
relationshipRepository.listRelated(
currentInstance, spec.relationshipName(), queryParams));
resultContainsDefinition = relatedEntityFor(currentInstance, spec.relationshipName());

if (shouldReturnRelationshipAsSingleInstance(
currentInstance, spec.relationshipName())) {
isCollection = false;
if (foundItems.isEmpty()) {
currentInstance = null;
lastMatchWasNothing = true;
lastMatchWasInstance = false;
return this;
}

currentInstance = foundItems.get(0);
lastMatchWasNothing = false;
lastMatchWasInstance = true;
return this;
}

isCollection = true;
lastMatchWasNothing = false;
lastMatchWasInstance = false;
return this;
Expand Down Expand Up @@ -120,4 +138,25 @@ private EntityDefinition relatedEntityFor(
}
return instance.getEntity().related().getRelationships(relationshipName).get(0).getTo();
}

private boolean shouldReturnRelationshipAsSingleInstance(
final EntityInstance instance, final String relationshipName) {
if (!spec.singleTargetRelationshipsAsInstances()) {
return false;
}

final RelationshipVectorDefinition relationship =
relationshipDefinitionFor(instance, relationshipName);
return relationship != null
&& relationship.getCardinality().hasMaximumLimit()
&& relationship.getCardinality().maximumLimit() == 1;
}

private RelationshipVectorDefinition relationshipDefinitionFor(
final EntityInstance instance, final String relationshipName) {
if (instance.getEntity().related().getRelationships(relationshipName).isEmpty()) {
return null;
}
return instance.getEntity().related().getRelationships(relationshipName).get(0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,40 @@ public final class RepositoryQuerySpec {
private final EntityDefinition entity;
private final String identifier;
private final String relationshipName;
private final boolean singleTargetRelationshipsAsInstances;

private RepositoryQuerySpec(
final EntityDefinition entity, final String identifier, final String relationshipName) {
final EntityDefinition entity,
final String identifier,
final String relationshipName,
final boolean singleTargetRelationshipsAsInstances) {
this.entity = entity;
this.identifier = identifier;
this.relationshipName = relationshipName;
this.singleTargetRelationshipsAsInstances = singleTargetRelationshipsAsInstances;
}

public static RepositoryQuerySpec collection(final EntityDefinition entity) {
return new RepositoryQuerySpec(entity, null, null);
return new RepositoryQuerySpec(entity, null, null, true);
}

public static RepositoryQuerySpec instance(
final EntityDefinition entity, final String identifier) {
return new RepositoryQuerySpec(entity, identifier, null);
return new RepositoryQuerySpec(entity, identifier, null, true);
}

public static RepositoryQuerySpec relationship(
final EntityDefinition entity, final String identifier, final String relationshipName) {
return new RepositoryQuerySpec(entity, identifier, relationshipName);
return relationship(entity, identifier, relationshipName, true);
}

public static RepositoryQuerySpec relationship(
final EntityDefinition entity,
final String identifier,
final String relationshipName,
final boolean singleTargetRelationshipsAsInstances) {
return new RepositoryQuerySpec(
entity, identifier, relationshipName, singleTargetRelationshipsAsInstances);
}

public EntityDefinition entity() {
Expand All @@ -48,4 +62,8 @@ public boolean hasIdentifier() {
public boolean hasRelationship() {
return relationshipName != null;
}

public boolean singleTargetRelationshipsAsInstances() {
return singleTargetRelationshipsAsInstances;
}
}
Loading
Loading