Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.babyfish.jimmer.sql.ast.impl.EntitiesImpl Maven / Gradle / Ivy
package org.babyfish.jimmer.sql.ast.impl;
import org.babyfish.jimmer.Input;
import org.babyfish.jimmer.View;
import org.babyfish.jimmer.meta.ImmutableProp;
import org.babyfish.jimmer.meta.ImmutableType;
import org.babyfish.jimmer.meta.PropId;
import org.babyfish.jimmer.meta.TypedProp;
import org.babyfish.jimmer.runtime.DraftSpi;
import org.babyfish.jimmer.runtime.ImmutableSpi;
import org.babyfish.jimmer.runtime.Internal;
import org.babyfish.jimmer.sql.Entities;
import org.babyfish.jimmer.sql.ast.Expression;
import org.babyfish.jimmer.sql.ast.PropExpression;
import org.babyfish.jimmer.sql.ast.impl.mutation.BatchEntitySaveCommandImpl;
import org.babyfish.jimmer.sql.ast.impl.mutation.DeleteCommandImpl;
import org.babyfish.jimmer.sql.ast.impl.mutation.SimpleEntitySaveCommandImpl;
import org.babyfish.jimmer.sql.ast.impl.query.FilterLevel;
import org.babyfish.jimmer.sql.ast.impl.query.MutableRootQueryImpl;
import org.babyfish.jimmer.sql.ast.impl.query.Queries;
import org.babyfish.jimmer.sql.ast.impl.table.FetcherSelectionImpl;
import org.babyfish.jimmer.sql.ast.mutation.BatchEntitySaveCommand;
import org.babyfish.jimmer.sql.ast.mutation.DeleteCommand;
import org.babyfish.jimmer.sql.ast.mutation.SimpleEntitySaveCommand;
import org.babyfish.jimmer.sql.ast.query.ConfigurableRootQuery;
import org.babyfish.jimmer.sql.ast.query.Example;
import org.babyfish.jimmer.sql.ast.query.Order;
import org.babyfish.jimmer.sql.ast.table.Table;
import org.babyfish.jimmer.sql.cache.Cache;
import org.babyfish.jimmer.sql.cache.CacheEnvironment;
import org.babyfish.jimmer.sql.cache.CacheLoader;
import org.babyfish.jimmer.sql.fetcher.DtoMetadata;
import org.babyfish.jimmer.sql.fetcher.Fetcher;
import org.babyfish.jimmer.sql.fetcher.impl.FetchPath;
import org.babyfish.jimmer.sql.fetcher.impl.FetcherSelection;
import org.babyfish.jimmer.sql.fetcher.impl.FetcherUtil;
import org.babyfish.jimmer.sql.runtime.Converters;
import org.babyfish.jimmer.sql.runtime.ExecutionPurpose;
import org.babyfish.jimmer.sql.runtime.JSqlClientImplementor;
import org.jetbrains.annotations.Nullable;
import java.sql.Connection;
import java.util.*;
import java.util.function.Function;
public class EntitiesImpl implements Entities {
private final JSqlClientImplementor sqlClient;
private final boolean forUpdate;
private final Connection con;
private final ExecutionPurpose purpose;
public EntitiesImpl(JSqlClientImplementor sqlClient) {
this(sqlClient, false, null, ExecutionPurpose.QUERY);
}
public EntitiesImpl(JSqlClientImplementor sqlClient, boolean forUpdate, Connection con, ExecutionPurpose purpose) {
this.sqlClient = sqlClient;
this.forUpdate = forUpdate;
this.con = con;
this.purpose = purpose;
}
@SuppressWarnings({"unchecked", "rawtypes"})
private static ImmutableType immutableTypeOf(Class> type) {
if (View.class.isAssignableFrom(type)) {
return DtoMetadata.of((Class extends View>) type).getFetcher().getImmutableType();
}
return ImmutableType.get(type);
}
public JSqlClientImplementor getSqlClient() {
return sqlClient;
}
public Connection getCon() {
return con;
}
public EntitiesImpl forSqlClient(JSqlClientImplementor sqlClient) {
if (this.sqlClient == sqlClient) {
return this;
}
return new EntitiesImpl(sqlClient, forUpdate, con, purpose);
}
@Override
public Entities forUpdate() {
if (forUpdate) {
return this;
}
return new EntitiesImpl(sqlClient, true, con, purpose);
}
@Override
public Entities forConnection(Connection con) {
if (this.con == con) {
return this;
}
return new EntitiesImpl(sqlClient, forUpdate, con, purpose);
}
public Entities forLoader() {
if (purpose == ExecutionPurpose.LOAD) {
return this;
}
return new EntitiesImpl(sqlClient, forUpdate, con, ExecutionPurpose.LOAD);
}
public Entities forExporter() {
if (purpose == ExecutionPurpose.EXPORT) {
return this;
}
return new EntitiesImpl(sqlClient, forUpdate, con, ExecutionPurpose.EXPORT);
}
@Override
public E findById(Class type, Object id) {
return sqlClient.getConnectionManager().execute(con, con -> findById(type, id, con));
}
@Override
public List findByIds(Class type, Collection> ids) {
return sqlClient.getConnectionManager().execute(con, con -> findByIds(type, ids, con));
}
@Override
public Map findMapByIds(Class type, Collection ids) {
return sqlClient.getConnectionManager().execute(con, con -> findMapByIds(type, ids, con));
}
@Override
public E findById(Fetcher fetcher, Object id) {
return sqlClient.getConnectionManager().execute(con, con -> findById(fetcher, id, con));
}
@Override
public List findByIds(Fetcher fetcher, Collection> ids) {
return sqlClient.getConnectionManager().execute(con, con -> findByIds(fetcher, ids, con));
}
@Override
public Map findMapByIds(Fetcher fetcher, Collection ids) {
return sqlClient.getConnectionManager().execute(con, con -> findMapByIds(fetcher, ids, con));
}
private E findById(Class type, Object id, Connection con) {
if (id instanceof Collection>) {
throw new IllegalArgumentException(
"id cannot be collection, do you want to call 'findByIds'?"
);
}
List rows = findByIds(type, null, Collections.singleton(id), con);
return rows.isEmpty() ? null : rows.get(0);
}
private List findByIds(Class type, Collection> ids, Connection con) {
return findByIds(type, null, ids, con);
}
@SuppressWarnings("unchecked")
private Map findMapByIds(Class type, Collection ids, Connection con) {
PropId idPropId = immutableTypeOf(type).getIdProp().getId();
List entities = findByIds(type, null, ids, con);
Map map = new LinkedHashMap<>((entities.size() * 4 + 2) / 3);
for (E entity : entities) {
if (View.class.isAssignableFrom(type)) {
map.put((ID) ((ImmutableSpi) (((View>) entity).toEntity())).__get(idPropId), entity);
} else {
map.put((ID) ((ImmutableSpi) entity).__get(idPropId), entity);
}
}
return map;
}
private E findById(Fetcher fetcher, Object id, Connection con) {
if (id instanceof Collection>) {
throw new IllegalArgumentException(
"id cannot be collection, do you want to call 'findByIds'?"
);
}
List rows = findByIds(fetcher.getJavaClass(), fetcher, Collections.singleton(id), con);
return rows.isEmpty() ? null : rows.get(0);
}
private List findByIds(Fetcher fetcher, Collection> ids, Connection con) {
return findByIds(fetcher.getJavaClass(), fetcher, ids, con);
}
@SuppressWarnings("unchecked")
private Map findMapByIds(Fetcher fetcher, Collection ids, Connection con) {
ImmutableType type = fetcher.getImmutableType();
PropId idPropId = type.getIdProp().getId();
List entities = findByIds((Class) type.getJavaClass(), fetcher, ids, con);
Map map = new LinkedHashMap<>((entities.size() * 4 + 2) / 3);
for (E entity : entities) {
map.put((ID) ((ImmutableSpi) entity).__get(idPropId), entity);
}
return map;
}
@SuppressWarnings("unchecked")
private List findByIds(
Class type,
Fetcher fetcher,
Collection> ids,
Connection con
) {
if (ids == null || ids.isEmpty()) {
return Collections.emptyList();
}
if (View.class.isAssignableFrom(type)) {
return findByIds(DtoMetadata.of((Class extends View>) type), ids, con);
}
Set distinctIds;
if (ids instanceof Set>) {
distinctIds = (Set) ids;
} else {
distinctIds = new LinkedHashSet<>(ids);
}
ImmutableType immutableType = ImmutableType.get(type);
Class> idClass = immutableType.getIdProp().getElementClass();
for (Object id : distinctIds) {
if (Converters.tryConvert(id, idClass) == null) {
throw new IllegalArgumentException(
"The type of \"" +
immutableType.getIdProp() +
"\" must be \"" +
idClass.getName() +
"\""
);
}
}
Cache cache = sqlClient.getCaches().getObjectCache(immutableType);
if (cache != null) {
Collection cachedEntities = cache.getAll(
distinctIds,
new CacheEnvironment<>(
sqlClient,
con,
CacheLoader.objectLoader(
sqlClient,
con,
(Class) immutableType.getJavaClass()
),
true
)
).values();
List entities = new ArrayList<>(cachedEntities.size());
for (E entity : cachedEntities) {
if (entity != null) {
entities.add(entity);
}
}
if (fetcher != null && !entities.isEmpty()) {
boolean needUnload = false;
for (ImmutableSpi spi : (List) entities) {
for (ImmutableProp prop : immutableType.getProps().values()) {
if (spi.__isLoaded(prop.getId()) && !fetcher.getFieldMap().containsKey(prop.getName())) {
needUnload = true;
break;
}
}
}
if (needUnload) {
ListIterator itr = (ListIterator) entities.listIterator();
while (itr.hasNext()) {
ImmutableSpi spi = itr.next();
itr.set(
(ImmutableSpi) Internal.produce(immutableType, spi, draft -> {
for (ImmutableProp prop : immutableType.getProps().values()) {
if (!prop.isView() &&
spi.__isLoaded(prop.getId()) &&
!fetcher.getFieldMap().containsKey(prop.getName())) {
((DraftSpi) draft).__unload(prop.getId());
}
}
})
);
}
}
FetcherUtil.fetch(
sqlClient,
con,
Collections.singletonList(
new FetcherSelection() {
@Override
public FetchPath getPath() {
return null;
}
@Override
public Fetcher> getFetcher() {
return fetcher;
}
@Override
public PropExpression.Embedded> getEmbeddedPropExpression() {
return null;
}
@Override
public @Nullable Function, E> getConverter() {
return null;
}
}
),
entities
);
}
return entities;
}
ConfigurableRootQuery, E> query = Queries.createQuery(
sqlClient, immutableType, purpose, FilterLevel.DEFAULT, (q, table) -> {
Expression idProp = table.get(immutableType.getIdProp().getName());
if (distinctIds.size() == 1) {
q.where(idProp.eq(distinctIds.iterator().next()));
} else {
q.where(idProp.in(distinctIds));
}
return q.select(((Table) table).fetch(fetcher));
}
);
if (forUpdate) {
query = query.forUpdate(true);
}
return query.execute(con);
}
@SuppressWarnings("unchecked")
private List findByIds(
DtoMetadata, ?> metadata,
Collection> ids,
Connection con
) {
Set distinctIds;
if (ids instanceof Set>) {
distinctIds = (Set) ids;
} else {
distinctIds = new LinkedHashSet<>(ids);
}
Fetcher> fetcher = metadata.getFetcher();
Function, E> converter = (Function, E>) metadata.getConverter();
ImmutableType immutableType = metadata.getFetcher().getImmutableType();
Class> idClass = immutableType.getIdProp().getElementClass();
for (Object id : distinctIds) {
if (Converters.tryConvert(id, idClass) == null) {
throw new IllegalArgumentException(
"The type of \"" +
immutableType.getIdProp() +
"\" must be \"" +
idClass.getName() +
"\""
);
}
}
Cache cache = sqlClient.getCaches().getObjectCache(immutableType);
if (cache != null) {
Collection cachedEntities = cache.getAll(
distinctIds,
new CacheEnvironment<>(
sqlClient,
con,
CacheLoader.objectLoader(
sqlClient,
con,
(Class) immutableType.getJavaClass()
),
true
)
).values();
List entities = new ArrayList<>(cachedEntities.size());
for (E entity : cachedEntities) {
if (entity != null) {
entities.add(entity);
}
}
if (!entities.isEmpty()) {
boolean needUnload = false;
for (ImmutableSpi spi : (List) entities) {
for (ImmutableProp prop : immutableType.getProps().values()) {
if (spi.__isLoaded(prop.getId()) && !fetcher.getFieldMap().containsKey(prop.getName())) {
needUnload = true;
break;
}
}
}
if (needUnload) {
ListIterator itr = (ListIterator) entities.listIterator();
while (itr.hasNext()) {
ImmutableSpi spi = itr.next();
itr.set(
(ImmutableSpi) Internal.produce(immutableType, spi, draft -> {
for (ImmutableProp prop : immutableType.getProps().values()) {
if (!prop.isView() &&
spi.__isLoaded(prop.getId()) &&
!fetcher.getFieldMap().containsKey(prop.getName())) {
((DraftSpi) draft).__unload(prop.getId());
}
}
})
);
}
}
FetcherUtil.fetch(
sqlClient,
con,
Collections.singletonList(
new FetcherSelection() {
@Override
public FetchPath getPath() {
return null;
}
@Override
public Fetcher> getFetcher() {
return fetcher;
}
@Override
public PropExpression.Embedded> getEmbeddedPropExpression() {
return null;
}
@Override
public @Nullable Function, E> getConverter() {
return converter;
}
}
),
entities
);
}
return entities;
}
ConfigurableRootQuery, E> query = Queries.createQuery(
sqlClient, immutableType, purpose, FilterLevel.DEFAULT, (q, table) -> {
Expression idProp = table.get(immutableType.getIdProp().getName());
if (distinctIds.size() == 1) {
q.where(idProp.eq(distinctIds.iterator().next()));
} else {
q.where(idProp.in(distinctIds));
}
return q.select(new FetcherSelectionImpl<>(table, fetcher, converter));
}
);
if (forUpdate) {
query = query.forUpdate(true);
}
return query.execute(con);
}
@SuppressWarnings("unchecked")
@Override
public List findAll(Class type) {
if (View.class.isAssignableFrom(type)) {
return find(DtoMetadata.of((Class>) type), null);
}
return find(ImmutableType.get(type), null, null);
}
@SuppressWarnings("unchecked")
@Override
public List findAll(Class type, TypedProp.Scalar, ?>... sortedProps) {
if (View.class.isAssignableFrom(type)) {
DtoMetadata, ?> metadata = DtoMetadata.of((Class>) type);
return find(metadata, null, sortedProps);
}
return find(ImmutableType.get(type), null, null, sortedProps);
}
@Override
public List findAll(Fetcher fetcher, TypedProp.Scalar, ?>... sortedProps) {
return find(fetcher.getImmutableType(), fetcher, null, sortedProps);
}
@Override
public List findByExample(Example example, TypedProp.Scalar, ?>... sortedProps) {
ExampleImpl exampleImpl = (ExampleImpl) example;
return find(exampleImpl.type(), null, exampleImpl, sortedProps);
}
@Override
public List findByExample(Example example, Fetcher fetcher, TypedProp.Scalar, ?>... sortedProps) {
ExampleImpl exampleImpl = (ExampleImpl) example;
return find(exampleImpl.type(), fetcher, exampleImpl, sortedProps);
}
@Override
public > List findExample(Class viewType, Example example, TypedProp.Scalar, ?>... sortedProps) {
return find(DtoMetadata.of(viewType), (ExampleImpl) example, sortedProps);
}
private List find(
ImmutableType type,
Fetcher fetcher,
ExampleImpl example,
TypedProp.Scalar, ?>... sortedProps
) {
if (fetcher != null && fetcher.getImmutableType() != type) {
throw new IllegalArgumentException(
"The type of fetcher is \"" +
fetcher.getImmutableType() +
"\", it does not match the query root type \"" +
type +
"\""
);
}
if (example != null && example.type() != type) {
throw new IllegalArgumentException(
"The type of example is \"" +
example.type() +
"\", it does not match the query root type \"" +
type +
"\""
);
}
MutableRootQueryImpl> query =
new MutableRootQueryImpl<>(sqlClient, type, ExecutionPurpose.QUERY, FilterLevel.DEFAULT);
Table table = query.getTable();
if (example != null) {
example.applyTo(query);
}
for (TypedProp.Scalar, ?> sortedProp : sortedProps) {
if (!sortedProp.unwrap().getDeclaringType().isAssignableFrom(type)) {
throw new IllegalArgumentException(
"The sorted field \"" +
sortedProp +
"\" does not belong to the type \"" +
type +
"\" or its super types"
);
}
Expression> expr = table.get(sortedProp.unwrap().getName());
Order astOrder;
if (sortedProp.isDesc()) {
astOrder = expr.desc();
} else {
astOrder = expr.asc();
}
if (sortedProp.isNullsFirst()) {
astOrder = astOrder.nullsFirst();
}
if (sortedProp.isNullsLast()) {
astOrder = astOrder.nullsLast();
}
query.orderBy(astOrder);
}
return query.select(
fetcher != null ? table.fetch(fetcher) : table
).execute(con);
}
@SuppressWarnings("unchecked")
private List find(
DtoMetadata, ?> metadata,
ExampleImpl> example,
TypedProp.Scalar, ?>... sortedProps
) {
Fetcher> fetcher = metadata.getFetcher();
Function, V> converter = (Function, V>) metadata.getConverter();
ImmutableType type = fetcher.getImmutableType();
MutableRootQueryImpl> query =
new MutableRootQueryImpl<>(sqlClient, type, ExecutionPurpose.QUERY, FilterLevel.DEFAULT);
if (example != null) {
example.applyTo(query);
}
Table> table = query.getTable();
for (TypedProp.Scalar, ?> sortedProp : sortedProps) {
if (!sortedProp.unwrap().getDeclaringType().isAssignableFrom(type)) {
throw new IllegalArgumentException(
"The sorted field \"" +
sortedProp +
"\" does not belong to the type \"" +
type +
"\" or its super types"
);
}
Expression> expr = table.get(sortedProp.unwrap().getName());
Order astOrder;
if (sortedProp.isDesc()) {
astOrder = expr.desc();
} else {
astOrder = expr.asc();
}
if (sortedProp.isNullsFirst()) {
astOrder = astOrder.nullsFirst();
}
if (sortedProp.isNullsLast()) {
astOrder = astOrder.nullsLast();
}
query.orderBy(astOrder);
}
return query.select(
new FetcherSelectionImpl<>(table, fetcher, converter)
).execute(con);
}
@Override
public SimpleEntitySaveCommand saveCommand(E entity) {
if (entity instanceof Collection>) {
throw new IllegalArgumentException("entity cannot be collection, do you want to call `saveAll/saveAllCommand`?");
}
if (entity instanceof Input>) {
throw new IllegalArgumentException(
"entity cannot be input, " +
"please call another overloaded function whose parameter is input"
);
}
return new SimpleEntitySaveCommandImpl<>(sqlClient, con, entity);
}
@Override
public BatchEntitySaveCommand saveEntitiesCommand(Collection entities) {
for (E e : entities) {
if (e instanceof Input>) {
throw new IllegalArgumentException(
"the collection cannot contains input, " +
"please call another overloaded function `saveInputsCommand`"
);
}
}
return new BatchEntitySaveCommandImpl<>(sqlClient, con, entities);
}
@Override
public DeleteCommand deleteCommand(
Class> type,
Object id
) {
if (id instanceof Collection>) {
throw new IllegalArgumentException("`id` cannot be collection, do you want to call `deleteAll/deleteAllCommand`?");
}
if ((id instanceof ImmutableSpi && ((ImmutableSpi) id).__type().isEntity()) || id instanceof Input>) {
throw new IllegalArgumentException("`id` must be simple type");
}
return batchDeleteCommand(type, Collections.singleton(id));
}
@SuppressWarnings("unchecked")
@Override
public DeleteCommand deleteAllCommand(
Class> type,
Collection> ids
) {
for (Object id : ids) {
if ((id instanceof ImmutableSpi && ((ImmutableSpi) id).__type().isEntity()) || id instanceof Input>) {
throw new IllegalArgumentException("All the elements of `ids` must be simple type");
}
}
ImmutableType immutableType = immutableTypeOf(type);
return new DeleteCommandImpl(sqlClient, con, immutableType, ids);
}
}