Skip to content

Query by example #89

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 14, 2024
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 @@ -11,6 +11,7 @@
import software.xdev.spring.data.eclipse.store.repository.config.EclipseStoreClientConfiguration;


@SuppressWarnings("checkstyle:MagicNumber")
public class FindByIdCustomerWithAutoIdBenchmark
{
public abstract static class ExistingCustomerSpringState extends SpringState
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright © 2024 XDEV Software (https://xdev.software)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package software.xdev.spring.data.eclipse.store.repository.interfaces;

import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.data.repository.query.QueryByExampleExecutor;


@NoRepositoryBean
public interface EclipseStoreQueryByExampleExecutor<T> extends QueryByExampleExecutor<T>
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
public interface EclipseStoreRepository<T, ID>
extends
EclipseStoreListCrudRepository<T, ID>,
EclipseStoreListPagingAndSortingRepositoryRepository<T, ID>
EclipseStoreListPagingAndSortingRepositoryRepository<T, ID>,
EclipseStoreQueryByExampleExecutor<T>
{
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
import java.util.Iterator;
import java.util.Objects;

import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;

import org.springframework.data.domain.Sort;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
Expand All @@ -28,10 +31,6 @@
import org.springframework.data.util.TypeInformation;
import org.springframework.util.ObjectUtils;

import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import software.xdev.spring.data.eclipse.store.exceptions.FieldAccessReflectionException;
import software.xdev.spring.data.eclipse.store.repository.access.AccessHelper;
import software.xdev.spring.data.eclipse.store.repository.query.criteria.AbstractCriteriaNode;
import software.xdev.spring.data.eclipse.store.repository.query.criteria.Criteria;
import software.xdev.spring.data.eclipse.store.repository.query.criteria.CriteriaSingleNode;
Expand Down Expand Up @@ -249,16 +248,6 @@ private boolean isSimpleComparisonPossible(final Part part)
private ReflectedField<T, ?> getDeclaredField(final Part part)
{
final String fieldName = part.getProperty().getSegment();
try
{
return new ReflectedField<>(AccessHelper.getInheritedPrivateField(this.domainClass, fieldName));
}
catch(final NoSuchFieldException e)
{
throw new FieldAccessReflectionException(String.format(
"Field %s in class %s was not found!",
fieldName,
this.domainClass.getSimpleName()), e);
}
return ReflectedField.createReflectedField(this.domainClass, fieldName);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import java.util.Objects;

import jakarta.annotation.Nonnull;

import software.xdev.spring.data.eclipse.store.exceptions.FieldAccessReflectionException;
import software.xdev.spring.data.eclipse.store.repository.access.AccessHelper;


Expand All @@ -38,6 +40,21 @@ public ReflectedField(final Field field)
this.field = Objects.requireNonNull(field);
}

public static <T, E> ReflectedField<T, E> createReflectedField(final Class<T> domainClass, final String fieldName)
{
try
{
return new ReflectedField<>(AccessHelper.getInheritedPrivateField(domainClass, fieldName));
}
catch(final NoSuchFieldException e)
{
throw new FieldAccessReflectionException(String.format(
"Field %s in class %s was not found!",
fieldName,
domainClass.getSimpleName()), e);
}
}

/**
* Reads the field of the given object. If the fields is not accessible, it is made accessible with the
* {@link AccessHelper#readFieldVariable(Field, Object)}.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*
* Copyright © 2024 XDEV Software (https://xdev.software)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package software.xdev.spring.data.eclipse.store.repository.query.by.example;

import java.util.Collection;
import java.util.List;
import java.util.stream.Stream;

import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.repository.query.FluentQuery;

import software.xdev.spring.data.eclipse.store.repository.EclipseStoreStorage;
import software.xdev.spring.data.eclipse.store.repository.query.criteria.CriteriaByExample;
import software.xdev.spring.data.eclipse.store.repository.query.executors.CountQueryExecutor;
import software.xdev.spring.data.eclipse.store.repository.query.executors.ExistsQueryExecutor;
import software.xdev.spring.data.eclipse.store.repository.query.executors.ListQueryExecutor;
import software.xdev.spring.data.eclipse.store.repository.query.executors.PageableQueryExecutor;
import software.xdev.spring.data.eclipse.store.repository.query.executors.SingleQueryExecutor;
import software.xdev.spring.data.eclipse.store.repository.support.copier.working.WorkingCopier;


/**
* Needed to support {@link QueryByExampleExecutor}.
*/
public class EclipseStoreFetchableFluentQuery<T, S extends T> implements FluentQuery.FetchableFluentQuery<S>
{
private final WorkingCopier<T> copier;
private final Example<S> example;
private final Class<T> domainClass;
private final EclipseStoreStorage storage;
private final Sort sort;

public EclipseStoreFetchableFluentQuery(
final WorkingCopier<T> copier,
final Example<S> example,
final Class<T> domainClass,
final EclipseStoreStorage storage,
final Sort sort
)
{
this.copier = copier;
this.example = example;
this.domainClass = domainClass;
this.storage = storage;
this.sort = sort;
}

@Override
public FetchableFluentQuery<S> sortBy(final Sort sort)
{
return new EclipseStoreFetchableFluentQuery(
this.copier,
this.example,
this.domainClass,
this.storage,
sort
);
}

@Override
public <R> FetchableFluentQuery<R> as(final Class<R> resultType)
{
throw new UnsupportedOperationException("The method as() is not yet supported");
}

@Override
public FetchableFluentQuery<S> project(final Collection<String> properties)
{
throw new UnsupportedOperationException("The method project() is not yet supported");
}

@Override
public S oneValue()
{
return this.firstValue();
}

@Override
public S firstValue()
{
final SingleQueryExecutor<T> query =
new SingleQueryExecutor<>(this.copier, new CriteriaByExample<>((Example<T>)this.example), this.sort);
return this.storage.getReadWriteLock().read(
() ->
(S)query.execute(
this.domainClass,
this.storage.getEntityList(this.domainClass),
new Object[]{this.sort})
);
}

@Override
public List<S> all()
{
final ListQueryExecutor<T> query =
new ListQueryExecutor<>(this.copier, new CriteriaByExample<>(this.example));
return this.storage.getReadWriteLock().read(
() -> (List<S>)query.execute(this.domainClass, this.storage.getEntityList(this.domainClass), new Object[]{
this.sort})
);
}

@Override
public Page<S> page(final Pageable pageable)
{
final PageableQueryExecutor<T> pageableQuery =
new PageableQueryExecutor<>(this.copier, new CriteriaByExample<>(this.example), this.sort);
return this.storage.getReadWriteLock().read(
() ->
(Page<S>)pageableQuery.execute(
this.domainClass,
this.storage.getEntityList(this.domainClass),
new Object[]{pageable, this.sort})
);
}

@Override
public Stream<S> stream()
{
return this.all().stream();
}

@Override
public long count()
{
final CountQueryExecutor<T> query = new CountQueryExecutor<>(new CriteriaByExample<>(this.example));
return this.storage.getReadWriteLock().read(
() -> query.execute(this.domainClass, this.storage.getEntityList(this.domainClass), null)
);
}

@Override
public boolean exists()
{
final ExistsQueryExecutor<T> query = new ExistsQueryExecutor<>(new CriteriaByExample<>(this.example));
return this.storage.getReadWriteLock().read(
() -> query.execute(this.domainClass, this.storage.getEntityList(this.domainClass), null)
);
}
}
Loading