Skip to content

Commit 92a94c3

Browse files
Initial outline for reusable repository extensions.
1 parent a4c5214 commit 92a94c3

File tree

15 files changed

+358
-0
lines changed

15 files changed

+358
-0
lines changed

mongodb/fragment-spi/README.md

Whitespace-only changes.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<parent>
6+
<groupId>org.springframework.data.examples</groupId>
7+
<artifactId>spring-data-mongodb-examples</artifactId>
8+
<version>2.0.0.BUILD-SNAPSHOT</version>
9+
</parent>
10+
11+
<artifactId>spring-data-mongodb-fragment-spi-atlas</artifactId>
12+
<name>Spring Data MongoDB - Fragment SPI</name>
13+
14+
</project>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.example.spi.mongodb.atlas;
2+
3+
import java.util.List;
4+
5+
import org.springframework.beans.BeansException;
6+
import org.springframework.beans.factory.config.BeanPostProcessor;
7+
import org.springframework.context.annotation.Bean;
8+
import org.springframework.data.domain.Limit;
9+
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
10+
import org.springframework.stereotype.Component;
11+
12+
/**
13+
* @author Christoph Strobl
14+
*/
15+
public interface AtlasRepository<T> {
16+
17+
List<T> vectorSearch(String index, String path, List<Double> vector, Limit limit);
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.example.spi.mongodb.atlas;
17+
18+
import org.springframework.beans.factory.config.BeanPostProcessor;
19+
import org.springframework.boot.autoconfigure.AutoConfiguration;
20+
import org.springframework.context.annotation.Bean;
21+
22+
/**
23+
* @author Christoph Strobl
24+
*/
25+
@AutoConfiguration
26+
public class AtlasRepositoryAutoConfiguration {
27+
28+
@Bean
29+
static BeanPostProcessor atlasRepositoryPostProcessor() {
30+
System.out.println("XXXX");
31+
return new AtlasRepositoryPostProcessor();
32+
}
33+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.example.spi.mongodb.atlas;
17+
18+
import java.util.List;
19+
import java.util.Objects;
20+
21+
import org.bson.Document;
22+
import org.springframework.beans.factory.annotation.Autowired;
23+
import org.springframework.data.domain.Limit;
24+
import org.springframework.data.mongodb.core.MongoOperations;
25+
import org.springframework.data.mongodb.core.aggregation.Aggregation;
26+
import org.springframework.data.mongodb.core.query.CriteriaDefinition;
27+
import org.springframework.data.repository.core.support.RepositoryMethodContext;
28+
import org.springframework.lang.Nullable;
29+
30+
class AtlasRepositoryFragment<T> implements AtlasRepository<T> {
31+
32+
private MongoOperations mongoOperations;
33+
34+
public AtlasRepositoryFragment(@Autowired MongoOperations mongoOperations) {
35+
this.mongoOperations = mongoOperations;
36+
}
37+
38+
@Override
39+
@SuppressWarnings("unchecked")
40+
public List<T> vectorSearch(String index, String path, List<Double> vector, Limit limit) {
41+
42+
RepositoryMethodContext metadata = RepositoryMethodContext.currentMethod();
43+
Objects.requireNonNull(metadata);
44+
45+
Class<?> domainType = metadata.getRepository().getDomainType();
46+
System.out.println("domainType: " + domainType);
47+
48+
Document $vectorSearch = createDocument(index, path, vector, limit, null, null, null);
49+
Aggregation aggregation = Aggregation.newAggregation(ctx -> $vectorSearch);
50+
51+
return (List<T>) mongoOperations.aggregate(aggregation, mongoOperations.getCollectionName(domainType), domainType);
52+
}
53+
54+
private static Document createDocument(String indexName, String path, List<Double> vector, Limit limit, @Nullable Boolean exact, @Nullable CriteriaDefinition filter, @Nullable Integer numCandidates) {
55+
56+
Document $vectorSearch = new Document();
57+
58+
$vectorSearch.append("index", indexName);
59+
$vectorSearch.append("path", path);
60+
$vectorSearch.append("queryVector", vector);
61+
$vectorSearch.append("limit", limit.max());
62+
63+
if (exact != null) {
64+
$vectorSearch.append("exact", exact);
65+
}
66+
67+
if (filter != null) {
68+
$vectorSearch.append("filter", filter.getCriteriaObject());
69+
}
70+
71+
if (numCandidates != null) {
72+
$vectorSearch.append("numCandidates", numCandidates);
73+
}
74+
75+
return new Document("$vectorSearch", $vectorSearch);
76+
}
77+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.example.spi.mongodb.atlas;
17+
18+
import java.lang.reflect.Field;
19+
import java.util.Arrays;
20+
21+
import org.springframework.beans.BeansException;
22+
import org.springframework.beans.factory.config.BeanPostProcessor;
23+
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
24+
import org.springframework.stereotype.Component;
25+
import org.springframework.util.ReflectionUtils;
26+
27+
/**
28+
* @author Christoph Strobl
29+
*/
30+
class AtlasRepositoryPostProcessor implements BeanPostProcessor {
31+
32+
@Override
33+
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
34+
35+
if (bean instanceof RepositoryFactoryBeanSupport rfbs) {
36+
37+
Field field = ReflectionUtils.findField(RepositoryFactoryBeanSupport.class, "repositoryInterface");
38+
ReflectionUtils.makeAccessible(field);
39+
if (Arrays.stream(((Class<?>) ReflectionUtils.getField(field, rfbs)).getInterfaces())
40+
.anyMatch(iface -> {
41+
return iface.equals(AtlasRepository.class);
42+
})) {
43+
rfbs.setExposeMetadata(true);
44+
}
45+
}
46+
return bean;
47+
}
48+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.example.spi.mongodb.atlas.AtlasRepositoryAutoConfiguration
2+
com.example.spi.mongodb.atlas.AtlasRepository=com.example.spi.mongodb.atlas.AtlasRepositoryFragment
3+

mongodb/fragment-spi/pom.xml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<parent>
6+
<groupId>org.springframework.data.examples</groupId>
7+
<artifactId>spring-data-mongodb-examples</artifactId>
8+
<version>2.0.0.BUILD-SNAPSHOT</version>
9+
</parent>
10+
11+
<artifactId>spring-data-mongodb-fragment-spi</artifactId>
12+
<packaging>pom</packaging>
13+
14+
<modules>
15+
<module>atlas-api</module>
16+
<module>sample</module>
17+
</modules>
18+
</project>

mongodb/fragment-spi/sample/pom.xml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
5+
<parent>
6+
<groupId>org.springframework.data.examples</groupId>
7+
<artifactId>spring-data-mongodb-examples</artifactId>
8+
<version>2.0.0.BUILD-SNAPSHOT</version>
9+
</parent>
10+
11+
<artifactId>spring-data-mongodb-fragment-spi-usage</artifactId>
12+
<name>Spring Data MongoDB - Fragment Usage</name>
13+
14+
<dependencies>
15+
<dependency>
16+
<groupId>org.springframework.data.examples</groupId>
17+
<artifactId>spring-data-mongodb-fragment-spi-atlas</artifactId>
18+
<version>${project.version}</version>
19+
</dependency>
20+
<dependency>
21+
<groupId>org.springframework.data.examples</groupId>
22+
<artifactId>spring-data-mongodb-example-utils</artifactId>
23+
<scope>test</scope>
24+
</dependency>
25+
</dependencies>
26+
</project>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.example.data.mongodb;
17+
18+
import org.springframework.boot.autoconfigure.SpringBootApplication;
19+
20+
/**
21+
* @author Christoph Strobl
22+
*/
23+
@SpringBootApplication
24+
public class ApplicationConfiguration {
25+
26+
// @Bean
27+
// BeanFactoryPostProcessor postProcessor() {
28+
// return new BeanFactoryPostProcessor() {
29+
// @Override
30+
// public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
31+
//
32+
// BeanDefinition movieRepository = beanFactory.getBeanDefinition("movieRepository");
33+
// movieRepository.getPropertyValues().add("exposeMetadata", true);
34+
// }
35+
// };
36+
// }
37+
38+
// @Bean
39+
// BeanPostProcessor postProcessor() {
40+
// return new AtlasRepositoryPostProcessor();
41+
// }
42+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.example.data.mongodb;
17+
18+
import org.springframework.data.mongodb.core.mapping.Document;
19+
20+
/**
21+
* @author Christoph Strobl
22+
* @since 2024/08
23+
*/
24+
@Document
25+
public class Movie {
26+
27+
String id;
28+
String title;
29+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.example.data.mongodb;
2+
3+
import com.example.spi.mongodb.atlas.AtlasRepository;
4+
import org.springframework.data.repository.CrudRepository;
5+
6+
/**
7+
* @author Christoph Strobl
8+
*/
9+
public interface MovieRepository extends CrudRepository<Movie, String>, AtlasRepository<Movie> {
10+
11+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.example.data.mongodb;
17+
18+
import java.util.List;
19+
20+
import org.junit.jupiter.api.Test;
21+
import org.springframework.beans.factory.annotation.Autowired;
22+
import org.springframework.boot.test.context.SpringBootTest;
23+
import org.springframework.data.domain.Limit;
24+
25+
/**
26+
* @author Christoph Strobl
27+
*/
28+
@SpringBootTest
29+
public class MovieRepositoryTests {
30+
31+
@Autowired MovieRepository repository;
32+
33+
@Test
34+
void xxx() {
35+
repository.vectorSearch("idx", "embeddings", List.of(100D), Limit.of(10));
36+
}
37+
}

mongodb/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
<module>querydsl</module>
3636
<module>linking</module>
3737
<module>util</module>
38+
<module>fragment-spi</module>
3839
</modules>
3940

4041
<dependencyManagement>

0 commit comments

Comments
 (0)