Skip to content

Commit 59b5de4

Browse files
author
aek
committed
Project structure
1 parent ba4fe78 commit 59b5de4

File tree

15 files changed

+543
-1
lines changed

15 files changed

+543
-1
lines changed

pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@
3131
<artifactId>spring-boot-starter-test</artifactId>
3232
<scope>test</scope>
3333
</dependency>
34+
<dependency>
35+
<groupId>org.projectlombok</groupId>
36+
<artifactId>lombok</artifactId>
37+
<optional>true</optional>
38+
</dependency>
3439
</dependencies>
3540

3641
<build>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package com.tutorial.springdatamongodbdynamicqueries.controller;
2+
3+
import com.tutorial.springdatamongodbdynamicqueries.domain.Employee;
4+
import com.tutorial.springdatamongodbdynamicqueries.service.EmployeeService;
5+
import org.springframework.web.bind.annotation.*;
6+
7+
import java.util.List;
8+
import java.util.Optional;
9+
10+
@RestController
11+
@RequestMapping("/employee")
12+
public class EmployeeController {
13+
14+
private final EmployeeService employeeService;
15+
16+
public EmployeeController(EmployeeService employeeService) {
17+
this.employeeService = employeeService;
18+
}
19+
20+
21+
@GetMapping()
22+
public List<Employee> get() {
23+
return employeeService.getAll();
24+
25+
}
26+
27+
@PostMapping()
28+
public Employee save(@RequestBody Employee employee) {
29+
return employeeService.save(employee);
30+
}
31+
32+
@PutMapping(value = "/{id}")
33+
public Employee update(@PathVariable("id") String id, @RequestBody Employee employee) {
34+
35+
Optional<Employee> emp = employeeService.getById(id);
36+
if (emp.isPresent()) {
37+
emp.get().setFirstName(employee.getFirstName());
38+
emp.get().setLastName(employee.getLastName());
39+
emp.get().setEmail(employee.getEmail());
40+
41+
return employeeService.save(emp.get());
42+
}
43+
throw new RuntimeException("not found");
44+
45+
}
46+
47+
@GetMapping("/{id}")
48+
public Employee getEmployeeById(@PathVariable(value = "id") String id) {
49+
return employeeService.getById(id).orElseThrow(() -> new RuntimeException("not found"));
50+
}
51+
@DeleteMapping("/{id}")
52+
public void deleteEmployee(@PathVariable(value = "id") String id) {
53+
employeeService.deleteById(id);
54+
}
55+
56+
57+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright (c) 2019. @aek - (anicetkeric@gmail.com)
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*
15+
*/
16+
17+
package com.tutorial.springdatamongodbdynamicqueries.controller.dto;
18+
19+
import com.tutorial.springdatamongodbdynamicqueries.enums.FilterOperationEnum;
20+
import lombok.AllArgsConstructor;
21+
import lombok.Getter;
22+
import lombok.RequiredArgsConstructor;
23+
import lombok.Setter;
24+
25+
/**
26+
* <h2>FilterCondition</h2>
27+
*
28+
* @author aek
29+
* <p>
30+
* Description: Filter Condition Class
31+
*/
32+
@Setter
33+
@Getter
34+
@AllArgsConstructor
35+
@RequiredArgsConstructor
36+
public class FilterCondition {
37+
38+
private String field;
39+
private FilterOperationEnum operator;
40+
private Object value;
41+
42+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.tutorial.springdatamongodbdynamicqueries.domain;
2+
3+
import lombok.AllArgsConstructor;
4+
import lombok.Data;
5+
import lombok.NoArgsConstructor;
6+
import lombok.NonNull;
7+
8+
@Data
9+
@AllArgsConstructor
10+
@NoArgsConstructor
11+
public class Department {
12+
13+
@NonNull
14+
private String code;
15+
16+
private String name;
17+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.tutorial.springdatamongodbdynamicqueries.domain;
2+
3+
import lombok.*;
4+
import lombok.experimental.Accessors;
5+
import org.springframework.data.annotation.Id;
6+
import org.springframework.data.mongodb.core.mapping.Document;
7+
8+
@Builder
9+
@Data
10+
@AllArgsConstructor
11+
@NoArgsConstructor
12+
@Accessors(chain = true)
13+
@Document(collection = "employee")
14+
public class Employee {
15+
16+
@Id
17+
private String id;
18+
19+
private String firstName;
20+
21+
private String lastName;
22+
23+
private String email;
24+
25+
@NonNull
26+
private Department department;
27+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright (c) 2019. @aek - (anicetkeric@gmail.com)
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*
15+
*/
16+
17+
package com.tutorial.springdatamongodbdynamicqueries.enums;
18+
19+
import com.fasterxml.jackson.annotation.JsonValue;
20+
21+
/**
22+
* <h2>FilterOperation</h2>
23+
*
24+
* @author aek
25+
* <p>
26+
* Description:
27+
*/
28+
public enum FilterOperationEnum {
29+
30+
EQUAL("eq"),
31+
NOT_EQUAL("neq"),
32+
GREATER_THAN("gt"),
33+
GREATER_THAN_OR_EQUAL_TO("gte"),
34+
LESS_THAN("lt"),
35+
LESSTHAN_OR_EQUAL_TO("lte"),
36+
IN("in"),
37+
NOT_IN("nin"),
38+
BETWEEN("btn"),
39+
CONTAINS("like"),
40+
NOT_CONTAINS("notLike"),
41+
IS_NULL("isnull"),
42+
IS_NOT_NULL("isnotnull"),
43+
START_WITH("startwith"),
44+
END_WITH("endwith"),
45+
IS_EMPTY("isempty"),
46+
IS_NOT_EMPTY("isnotempty"),
47+
JOIN("jn"),
48+
IS("is");
49+
50+
51+
private final String value;
52+
53+
FilterOperationEnum(String value) {
54+
this.value = value;
55+
}
56+
57+
@Override
58+
@JsonValue
59+
public String toString() {
60+
return String.valueOf(value);
61+
}
62+
63+
public static FilterOperationEnum fromValue(String value) {
64+
for (FilterOperationEnum op : FilterOperationEnum.values()) {
65+
66+
//Case insensitive operation name
67+
if (String.valueOf(op.value).equalsIgnoreCase(value)) {
68+
return op;
69+
}
70+
}
71+
return null;
72+
}
73+
74+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.tutorial.springdatamongodbdynamicqueries.repository;
2+
3+
import com.tutorial.springdatamongodbdynamicqueries.domain.Employee;
4+
import org.springframework.stereotype.Repository;
5+
6+
@Repository
7+
public interface EmployeeRepository extends ResourceRepository<Employee, String> {
8+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.tutorial.springdatamongodbdynamicqueries.repository;
2+
3+
import org.springframework.data.domain.Page;
4+
import org.springframework.data.domain.Pageable;
5+
import org.springframework.data.mongodb.core.query.Query;
6+
import org.springframework.data.mongodb.repository.MongoRepository;
7+
import org.springframework.data.repository.NoRepositoryBean;
8+
9+
import java.io.Serializable;
10+
11+
@NoRepositoryBean
12+
public interface ResourceRepository<T, I extends Serializable> extends MongoRepository<T, I> {
13+
14+
Page<T> findAll(Query query, Pageable pageable);
15+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
package com.tutorial.springdatamongodbdynamicqueries.repository.support;
2+
3+
import com.tutorial.springdatamongodbdynamicqueries.controller.dto.FilterCondition;
4+
import org.bson.types.ObjectId;
5+
import org.springframework.data.mongodb.core.query.Criteria;
6+
import org.springframework.data.mongodb.core.query.Query;
7+
8+
import java.util.ArrayList;
9+
import java.util.HashMap;
10+
import java.util.List;
11+
import java.util.Map;
12+
import java.util.function.Function;
13+
import java.util.stream.Collectors;
14+
15+
/**
16+
* This class is used to build all the queries passed as parameters.
17+
* filterAndConditions (filter list for the AND operator)
18+
* filterOrConditions (filter list for the OR operator)
19+
*/
20+
public class GenericFilterCriteriaBuilder {
21+
22+
private final List<FilterCondition> filterAndConditions;
23+
private final List<FilterCondition> filterOrConditions;
24+
25+
private static final Map<String, Function<FilterCondition, Criteria>>
26+
FILTER_CRITERIA = new HashMap<>();
27+
28+
public GenericFilterCriteriaBuilder() {
29+
filterOrConditions = new ArrayList<>();
30+
filterAndConditions = new ArrayList<>();
31+
}
32+
33+
public Query addCondition(List<FilterCondition> andConditions, List<FilterCondition> orConditions) {
34+
35+
if (andConditions != null && !andConditions.isEmpty()) {
36+
filterAndConditions.addAll(andConditions);
37+
}
38+
if (orConditions != null && !orConditions.isEmpty()) {
39+
filterOrConditions.addAll(orConditions);
40+
}
41+
42+
List<Criteria> criteriaAndClause = new ArrayList<>();
43+
List<Criteria> criteriaOrClause = new ArrayList<>();
44+
Criteria criteria = new Criteria();
45+
46+
// build criteria
47+
filterAndConditions.stream().map(condition -> criteriaAndClause.add(buildCriteria(condition))).collect(Collectors.toList());
48+
filterOrConditions.stream().map(condition -> criteriaOrClause.add(buildCriteria(condition))).collect(Collectors.toList());
49+
50+
51+
if (!criteriaAndClause.isEmpty() && !criteriaOrClause.isEmpty()) {
52+
53+
return new Query(criteria.andOperator(criteriaAndClause.toArray(new Criteria[0])).orOperator(criteriaOrClause.toArray(new Criteria[0])));
54+
55+
} else if (!criteriaAndClause.isEmpty()) {
56+
return new Query(criteria.andOperator(criteriaAndClause.toArray(new Criteria[0])));
57+
} else if (!criteriaOrClause.isEmpty()) {
58+
59+
return new Query(criteria.orOperator(criteriaOrClause.toArray(new Criteria[0])));
60+
61+
} else {
62+
return new Query();
63+
}
64+
65+
}
66+
67+
68+
// create map of filter
69+
static {
70+
FILTER_CRITERIA.put("EQUAL", condition -> Criteria.where(condition.getField()).is(condition.getValue()));
71+
FILTER_CRITERIA.put("NOT_EQUAL", condition -> Criteria.where(condition.getField()).ne(condition.getValue()));
72+
FILTER_CRITERIA.put("GREATER_THAN", condition -> Criteria.where(condition.getField()).gt(condition.getValue()));
73+
FILTER_CRITERIA.put("GREATER_THAN_OR_EQUAL_TO", condition -> Criteria.where(condition.getField()).gte(condition.getValue()));
74+
FILTER_CRITERIA.put("LESS_THAN", condition -> Criteria.where(condition.getField()).lt(condition.getValue()));
75+
FILTER_CRITERIA.put("LESSTHAN_OR_EQUAL_TO", condition -> Criteria.where(condition.getField()).lte(condition.getValue()));
76+
FILTER_CRITERIA.put("CONTAINS", condition -> Criteria.where(condition.getField()).regex((String) condition.getValue()));
77+
FILTER_CRITERIA.put("JOIN", condition -> Criteria.where(condition.getField()).is(new ObjectId((String) condition.getValue())));
78+
}
79+
80+
81+
/**
82+
* Build the predicate according to the request
83+
*
84+
* @param condition The condition of the filter requested by the query
85+
* @return {{@link Criteria}}
86+
*/
87+
private Criteria buildCriteria(FilterCondition condition) {
88+
Function<FilterCondition, Criteria>
89+
function = FILTER_CRITERIA.get(condition.getOperator().name());
90+
91+
if (function == null) {
92+
throw new IllegalArgumentException("Invalid function param type: ");
93+
}
94+
95+
return function.apply(condition);
96+
}
97+
98+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.tutorial.springdatamongodbdynamicqueries.repository.support;
2+
3+
import com.tutorial.springdatamongodbdynamicqueries.repository.ResourceRepository;
4+
import org.springframework.data.domain.Page;
5+
import org.springframework.data.domain.PageImpl;
6+
import org.springframework.data.domain.Pageable;
7+
import org.springframework.data.mongodb.core.MongoOperations;
8+
import org.springframework.data.mongodb.core.query.Query;
9+
import org.springframework.data.mongodb.repository.query.MongoEntityInformation;
10+
import org.springframework.data.mongodb.repository.support.SimpleMongoRepository;
11+
import org.springframework.util.Assert;
12+
13+
import java.io.Serializable;
14+
import java.util.List;
15+
16+
public class ResourceRepositoryImpl<T, I extends Serializable> extends SimpleMongoRepository<T, I> implements ResourceRepository<T, I> {
17+
18+
private MongoOperations mongoOperations;
19+
private MongoEntityInformation entityInformation;
20+
21+
public ResourceRepositoryImpl(final MongoEntityInformation entityInformation, final MongoOperations mongoOperations) {
22+
super(entityInformation, mongoOperations);
23+
24+
this.entityInformation = entityInformation;
25+
this.mongoOperations = mongoOperations;
26+
}
27+
28+
@Override
29+
public Page<T> findAll(final Query query, final Pageable pageable) {
30+
Assert.notNull(query, "Query must not be null!");
31+
32+
long total = mongoOperations.count(query, entityInformation.getJavaType(), entityInformation.getCollectionName());
33+
List<T> content = mongoOperations.find(query.with(pageable), entityInformation.getJavaType(), entityInformation.getCollectionName());
34+
35+
return new PageImpl<T>(content,pageable,total);
36+
}
37+
}

0 commit comments

Comments
 (0)