Skip to content

Commit b2e54ca

Browse files
Get Spaces API (#62)
* feat: add update and delete apis for space config * test: add update and delete tests * feat: add query api for current spaces
1 parent db961fe commit b2e54ca

File tree

10 files changed

+418
-0
lines changed

10 files changed

+418
-0
lines changed

hypertrace-graphql-impl/src/main/java/org/hypertrace/graphql/impl/GraphQlModule.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.hypertrace.graphql.impl;
22

33
import com.google.inject.AbstractModule;
4+
import java.time.Clock;
45
import org.hypertrace.core.graphql.attributes.AttributeStoreModule;
56
import org.hypertrace.core.graphql.common.schema.CommonSchemaModule;
67
import org.hypertrace.core.graphql.common.utils.attributes.AttributeUtilsModule;
@@ -43,6 +44,7 @@ protected void configure() {
4344
bind(GraphQlServiceConfig.class).toInstance(this.config);
4445
bind(HypertraceGraphQlServiceConfig.class).toInstance(this.config);
4546
bind(GraphQlServiceLifecycle.class).toInstance(this.serviceLifecycle);
47+
bind(Clock.class).toInstance(Clock.systemUTC());
4648
install(new GraphQlRequestContextModule());
4749
install(new GraphQlGrpcModule());
4850
install(new GraphQlSchemaRegistryModule());

hypertrace-graphql-spaces-schema/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ dependencies {
1818
implementation("org.hypertrace.core.graphql:hypertrace-core-graphql-common-schema")
1919
implementation("org.hypertrace.core.graphql:hypertrace-core-graphql-grpc-utils")
2020
implementation("org.hypertrace.core.graphql:hypertrace-core-graphql-deserialization")
21+
implementation(project(":hypertrace-graphql-explorer-schema"))
2122

2223
testImplementation("org.junit.jupiter:junit-jupiter")
2324
testImplementation("org.mockito:mockito-core")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
package org.hypertrace.graphql.spaces.dao;
2+
3+
import static java.util.Collections.emptyList;
4+
import static java.util.Collections.emptySet;
5+
6+
import io.reactivex.rxjava3.core.Single;
7+
import java.time.Clock;
8+
import java.time.Instant;
9+
import java.util.Collection;
10+
import java.util.List;
11+
import java.util.Objects;
12+
import java.util.Optional;
13+
import java.util.Set;
14+
import java.util.stream.Collectors;
15+
import java.util.stream.Stream;
16+
import javax.inject.Inject;
17+
import lombok.Value;
18+
import lombok.experimental.Accessors;
19+
import org.hypertrace.core.graphql.attributes.AttributeModelMetricAggregationType;
20+
import org.hypertrace.core.graphql.common.request.AttributeAssociation;
21+
import org.hypertrace.core.graphql.common.request.AttributeRequest;
22+
import org.hypertrace.core.graphql.common.request.AttributeRequestBuilder;
23+
import org.hypertrace.core.graphql.common.schema.arguments.TimeRangeArgument;
24+
import org.hypertrace.core.graphql.common.schema.attributes.MetricAggregationType;
25+
import org.hypertrace.core.graphql.common.schema.results.arguments.filter.FilterArgument;
26+
import org.hypertrace.core.graphql.common.schema.results.arguments.order.OrderDirection;
27+
import org.hypertrace.core.graphql.context.GraphQlRequestContext;
28+
import org.hypertrace.graphql.explorer.dao.ExplorerDao;
29+
import org.hypertrace.graphql.explorer.fetcher.ExploreResultMapKey;
30+
import org.hypertrace.graphql.explorer.request.ExploreRequest;
31+
import org.hypertrace.graphql.explorer.schema.ExploreResultSet;
32+
import org.hypertrace.graphql.explorer.schema.Selection;
33+
import org.hypertrace.graphql.explorer.schema.argument.IntervalArgument;
34+
import org.hypertrace.graphql.metric.request.MetricAggregationRequest;
35+
import org.hypertrace.graphql.metric.request.MetricAggregationRequestBuilder;
36+
import org.hypertrace.graphql.metric.schema.argument.AggregatableOrderArgument;
37+
import org.hypertrace.graphql.spaces.schema.query.Space;
38+
import org.hypertrace.graphql.spaces.schema.query.SpaceResultSet;
39+
40+
class ExplorerBackedSpacesDao implements SpacesDao {
41+
42+
private final ExplorerDao explorerDao;
43+
private final AttributeRequestBuilder attributeRequestBuilder;
44+
private final MetricAggregationRequestBuilder metricAggregationRequestBuilder;
45+
private final Clock clock;
46+
47+
@Inject
48+
ExplorerBackedSpacesDao(
49+
ExplorerDao explorerDao,
50+
AttributeRequestBuilder attributeRequestBuilder,
51+
MetricAggregationRequestBuilder metricAggregationRequestBuilder,
52+
Clock clock) {
53+
54+
this.explorerDao = explorerDao;
55+
this.attributeRequestBuilder = attributeRequestBuilder;
56+
this.metricAggregationRequestBuilder = metricAggregationRequestBuilder;
57+
this.clock = clock;
58+
}
59+
60+
@Override
61+
public Single<SpaceResultSet> getAllSpaces(GraphQlRequestContext context) {
62+
return this.buildRequest(context).flatMap(this.explorerDao::explore).map(this::extractResult);
63+
}
64+
65+
private Single<ExploreRequest> buildRequest(GraphQlRequestContext context) {
66+
return this.attributeRequestBuilder
67+
.buildForKey(
68+
context,
69+
ActiveSpaceExploreRequest.SPACE_IDS_SCOPE,
70+
ActiveSpaceExploreRequest.SPACE_IDS_KEY)
71+
.map(
72+
attributeRequest ->
73+
new ActiveSpaceExploreRequest(
74+
context,
75+
new FixedTimeRange(this.clock.instant()),
76+
attributeRequest,
77+
this.metricAggregationRequestBuilder.build(
78+
attributeRequest.attribute(),
79+
AttributeModelMetricAggregationType.COUNT,
80+
emptyList())));
81+
}
82+
83+
private SpaceResultSet extractResult(ExploreResultSet exploreResultSet) {
84+
85+
List<Space> spaces =
86+
exploreResultSet.results().stream()
87+
.map(
88+
exploreResult ->
89+
exploreResult
90+
.selectionMap()
91+
.get(
92+
ExploreResultMapKey.basicAttribute(
93+
ActiveSpaceExploreRequest.SPACE_IDS_KEY)))
94+
.map(Selection::value)
95+
.filter(Objects::nonNull)
96+
.flatMap(
97+
value ->
98+
value instanceof Collection
99+
? ((Collection<?>) value).stream()
100+
: Stream.of(value))
101+
.map(Object::toString)
102+
.map(ExtractedSpace::new)
103+
.collect(Collectors.toList());
104+
105+
return new ExtractedSpaceResultSet(spaces, spaces.size(), spaces.size());
106+
}
107+
108+
@Value
109+
@Accessors(fluent = true)
110+
private static class ExtractedSpaceResultSet implements SpaceResultSet {
111+
List<Space> results;
112+
long count;
113+
long total;
114+
}
115+
116+
@Value
117+
@Accessors(fluent = true)
118+
private static class ExtractedSpace implements Space {
119+
String name;
120+
}
121+
122+
@Value
123+
@Accessors(fluent = true)
124+
private static class FixedTimeRange implements TimeRangeArgument {
125+
private static final Instant FIXED_TIME_RANGE_START = Instant.parse("2021-01-01T00:00:00.00Z");
126+
Instant endTime;
127+
128+
@Override
129+
public Instant startTime() {
130+
return FIXED_TIME_RANGE_START;
131+
}
132+
}
133+
134+
@Value
135+
@Accessors(fluent = true)
136+
private static class ActiveSpaceExploreRequest implements ExploreRequest {
137+
private static final String SPACE_IDS_KEY = "spaceIds";
138+
private static final String SPACE_IDS_SCOPE = "EVENT";
139+
140+
GraphQlRequestContext requestContext;
141+
String scope;
142+
TimeRangeArgument timeRange;
143+
int limit;
144+
int offset;
145+
Set<AttributeRequest> attributeRequests;
146+
Set<MetricAggregationRequest> aggregationRequests;
147+
List<AttributeAssociation<AggregatableOrderArgument>> orderArguments;
148+
List<AttributeAssociation<FilterArgument>> filterArguments;
149+
Set<AttributeRequest> groupByAttributeRequests;
150+
Optional<IntervalArgument> timeInterval;
151+
boolean includeRest;
152+
Optional<String> spaceId;
153+
154+
ActiveSpaceExploreRequest(
155+
GraphQlRequestContext context,
156+
TimeRangeArgument timeRange,
157+
AttributeRequest spaceIdRequest,
158+
MetricAggregationRequest spaceIdCountRequest) {
159+
this.requestContext = context;
160+
this.scope = SPACE_IDS_SCOPE;
161+
this.limit = 100;
162+
this.offset = 0;
163+
this.timeRange = timeRange;
164+
this.attributeRequests = emptySet();
165+
// Aggregation needed to pass explorer validation - a no agg request is not valid
166+
this.aggregationRequests = Set.of(spaceIdCountRequest);
167+
this.orderArguments =
168+
List.of(AttributeAssociation.of(spaceIdRequest.attribute(), new SpaceOrderArgument()));
169+
this.filterArguments = emptyList();
170+
this.groupByAttributeRequests = Set.of(spaceIdRequest);
171+
this.timeInterval = Optional.empty();
172+
this.includeRest = false;
173+
this.spaceId = Optional.empty();
174+
}
175+
}
176+
177+
@Value
178+
@Accessors(fluent = true)
179+
private static class SpaceOrderArgument implements AggregatableOrderArgument {
180+
OrderDirection direction = OrderDirection.DESC;
181+
String key = ActiveSpaceExploreRequest.SPACE_IDS_KEY;
182+
MetricAggregationType aggregation = null;
183+
Integer size = null;
184+
}
185+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package org.hypertrace.graphql.spaces.dao;
2+
3+
import io.reactivex.rxjava3.core.Single;
4+
import org.hypertrace.core.graphql.context.GraphQlRequestContext;
5+
import org.hypertrace.graphql.spaces.schema.query.SpaceResultSet;
6+
7+
public interface SpacesDao {
8+
Single<SpaceResultSet> getAllSpaces(GraphQlRequestContext context);
9+
}

hypertrace-graphql-spaces-schema/src/main/java/org/hypertrace/graphql/spaces/dao/SpacesDaoModule.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,27 @@
22

33
import com.google.inject.AbstractModule;
44
import io.grpc.CallCredentials;
5+
import java.time.Clock;
6+
import org.hypertrace.core.graphql.common.request.AttributeRequestBuilder;
57
import org.hypertrace.core.graphql.context.GraphQlRequestContextBuilder;
68
import org.hypertrace.core.graphql.utils.grpc.GrpcChannelRegistry;
79
import org.hypertrace.graphql.config.HypertraceGraphQlServiceConfig;
10+
import org.hypertrace.graphql.explorer.dao.ExplorerDao;
11+
import org.hypertrace.graphql.metric.request.MetricAggregationRequestBuilder;
812

913
public class SpacesDaoModule extends AbstractModule {
1014

1115
@Override
1216
protected void configure() {
1317
bind(SpacesConfigDao.class).to(ConfigServiceSpacesConfigDao.class);
18+
bind(SpacesDao.class).to(ExplorerBackedSpacesDao.class);
1419
requireBinding(CallCredentials.class);
1520
requireBinding(HypertraceGraphQlServiceConfig.class);
1621
requireBinding(GraphQlRequestContextBuilder.class);
1722
requireBinding(GrpcChannelRegistry.class);
23+
requireBinding(ExplorerDao.class);
24+
requireBinding(AttributeRequestBuilder.class);
25+
requireBinding(MetricAggregationRequestBuilder.class);
26+
requireBinding(Clock.class);
1827
}
1928
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package org.hypertrace.graphql.spaces.fetcher;
2+
3+
import graphql.schema.DataFetcher;
4+
import graphql.schema.DataFetchingEnvironment;
5+
import java.util.concurrent.CompletableFuture;
6+
import javax.inject.Inject;
7+
import org.hypertrace.core.graphql.common.fetcher.InjectableDataFetcher;
8+
import org.hypertrace.graphql.spaces.dao.SpacesDao;
9+
import org.hypertrace.graphql.spaces.schema.query.SpaceResultSet;
10+
11+
public class SpacesFetcher extends InjectableDataFetcher<SpaceResultSet> {
12+
13+
public SpacesFetcher() {
14+
super(SpacesFetcherImpl.class);
15+
}
16+
17+
static final class SpacesFetcherImpl implements DataFetcher<CompletableFuture<SpaceResultSet>> {
18+
private final SpacesDao configDao;
19+
20+
@Inject
21+
SpacesFetcherImpl(SpacesDao configDao) {
22+
this.configDao = configDao;
23+
}
24+
25+
@Override
26+
public CompletableFuture<SpaceResultSet> get(DataFetchingEnvironment environment) {
27+
return this.configDao
28+
.getAllSpaces(environment.getContext())
29+
.toCompletionStage()
30+
.toCompletableFuture();
31+
}
32+
}
33+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package org.hypertrace.graphql.spaces.schema.query;
2+
3+
import graphql.annotations.annotationTypes.GraphQLField;
4+
import graphql.annotations.annotationTypes.GraphQLName;
5+
import graphql.annotations.annotationTypes.GraphQLNonNull;
6+
7+
@GraphQLName(Space.TYPE_NAME)
8+
public interface Space {
9+
String TYPE_NAME = "Space";
10+
String SPACE_NAME_KEY = "name";
11+
12+
@GraphQLField
13+
@GraphQLNonNull
14+
@GraphQLName(SPACE_NAME_KEY)
15+
String name();
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package org.hypertrace.graphql.spaces.schema.query;
2+
3+
import graphql.annotations.annotationTypes.GraphQLField;
4+
import graphql.annotations.annotationTypes.GraphQLName;
5+
import graphql.annotations.annotationTypes.GraphQLNonNull;
6+
import java.util.List;
7+
import org.hypertrace.core.graphql.common.schema.results.ResultSet;
8+
9+
@GraphQLName(SpaceResultSet.TYPE_NAME)
10+
public interface SpaceResultSet extends ResultSet<Space> {
11+
String TYPE_NAME = "SpaceResultSet";
12+
13+
@Override
14+
@GraphQLField
15+
@GraphQLNonNull
16+
@GraphQLName(RESULT_SET_RESULTS_NAME)
17+
List<Space> results();
18+
}

hypertrace-graphql-spaces-schema/src/main/java/org/hypertrace/graphql/spaces/schema/query/SpacesQuerySchema.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,22 @@
55
import graphql.annotations.annotationTypes.GraphQLName;
66
import graphql.annotations.annotationTypes.GraphQLNonNull;
77
import org.hypertrace.graphql.spaces.fetcher.SpaceConfigRuleFetcher;
8+
import org.hypertrace.graphql.spaces.fetcher.SpacesFetcher;
89

910
public interface SpacesQuerySchema {
1011

1112
String SPACE_CONFIG_RULES_KEY = "spaceConfigRules";
13+
String SPACES_KEY = "spaces";
1214

1315
@GraphQLField
1416
@GraphQLNonNull
1517
@GraphQLName(SPACE_CONFIG_RULES_KEY)
1618
@GraphQLDataFetcher(SpaceConfigRuleFetcher.class)
1719
SpaceConfigRuleResultSet spaceConfigRules();
20+
21+
@GraphQLField
22+
@GraphQLNonNull
23+
@GraphQLName(SPACES_KEY)
24+
@GraphQLDataFetcher(SpacesFetcher.class)
25+
SpaceResultSet spaces();
1826
}

0 commit comments

Comments
 (0)