All Downloads are FREE. Search and download functionalities are using the official Maven repository.

tech.ydb.yoj.repository.db.Table Maven / Gradle / Ivy

Go to download

Core YOJ (YDB ORM for Java) abstractions and APIs for domain entities, repositories, transactions etc.

There is a newer version: 2.6.1
Show newest version
package tech.ydb.yoj.repository.db;

import com.google.common.collect.Sets;
import lombok.NonNull;
import tech.ydb.yoj.databind.expression.FilterExpression;
import tech.ydb.yoj.databind.expression.OrderExpression;
import tech.ydb.yoj.repository.db.bulk.BulkParams;
import tech.ydb.yoj.repository.db.cache.FirstLevelCache;
import tech.ydb.yoj.repository.db.list.ListRequest;
import tech.ydb.yoj.repository.db.list.ListResult;
import tech.ydb.yoj.repository.db.list.ViewListResult;
import tech.ydb.yoj.repository.db.readtable.ReadTableParams;
import tech.ydb.yoj.repository.db.statement.Changeset;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toSet;
import static java.util.stream.Stream.concat;

public interface Table> {
    > Stream readTable(ReadTableParams params);

    > Stream readTableIds(ReadTableParams params);

    , ID extends Entity.Id> Stream readTable(Class viewClass, ReadTableParams params);

    Class getType();

    @CheckForNull
    T find(Entity.Id id);

     V find(Class viewType, Entity.Id id);

    > List find(Range range);

    > List findIds(Range range);

    > List findIds(Set partialIds);

    > List find(Class viewType, Range range);

    > List find(Class viewType, Set ids);

    List findAll();

     List findAll(Class viewType);

    List find(
            @Nullable String indexName,
            @Nullable FilterExpression filter,
            @Nullable OrderExpression orderBy,
            @Nullable Integer limit,
            @Nullable Long offset
    );

    > List findIds(
            @Nullable String indexName,
            @Nullable FilterExpression filter,
            @Nullable OrderExpression orderBy,
            @Nullable Integer limit,
            @Nullable Long offset
    );

     List find(
            Class viewType,
            @Nullable String indexName,
            @Nullable FilterExpression filter,
            @Nullable OrderExpression orderBy,
            @Nullable Integer limit,
            @Nullable Long offset,
            boolean distinct
    );

    > List find(
            Set ids,
            @Nullable FilterExpression filter,
            @Nullable OrderExpression orderBy,
            @Nullable Integer limit
    );

    > List findUncached(
            Set ids,
            @Nullable FilterExpression filter,
            @Nullable OrderExpression orderBy,
            @Nullable Integer limit
    );

    > List find(
            Class viewType,
            Set ids,
            @Nullable FilterExpression filter,
            @Nullable OrderExpression orderBy,
            @Nullable Integer limit
    );

     List find(
            String indexName,
            Set keys,
            @Nullable FilterExpression filter,
            @Nullable OrderExpression orderBy,
            @Nullable Integer limit
    );

     List find(
            Class viewType,
            String indexName,
            Set keys,
            @Nullable FilterExpression filter,
            @Nullable OrderExpression orderBy,
            @Nullable Integer limit
    );

    Stream streamAll(int batchSize);

    > Stream streamAll(Class viewType, int batchSize);

    > Stream streamPartial(ID partial, int batchSize);

    , V extends ViewId> Stream streamPartial(Class viewType, ID partial, int batchSize);

    > Stream streamAllIds(int batchSize);

    > Stream streamPartialIds(ID partial, int batchSize);

    long count(String indexName, FilterExpression filter);

    long countAll();

    // Unsafe
    T insert(T t);

    // Unsafe
    T save(T t);

    // Unsafe: may delete only entity, but not its projections, if entity was not loaded
    void delete(Entity.Id id);

    // Unsafe
    void deleteAll();

    default Stream readTable() {
        return readTable(ReadTableParams.getDefault());
    }

    default > Stream readTableIds() {
        return readTableIds(ReadTableParams.getDefault());
    }

    default FirstLevelCache getFirstLevelCache() {
        return null;
    }

    @NonNull
    default  T find(Entity.Id id, Supplier throwIfAbsent) throws X {
        T found = find(id);
        if (found != null) {
            return found;
        } else {
            throw throwIfAbsent.get();
        }
    }

    default T findOrDefault(Entity.Id id, Supplier defaultSupplier) {
        T found = find(id);
        return found != null ? found : defaultSupplier.get();
    }

    default  V find(Class viewType, Entity.Id id, Supplier throwIfAbsent) throws X {
        V found = find(viewType, id);
        if (found != null) {
            return found;
        } else {
            throw throwIfAbsent.get();
        }
    }

    default T modifyIfPresent(Entity.Id id, Function modify) {
        return Optional.ofNullable(find(id))
                .map(modify)
                .map(this::save)
                .orElse(null);
    }

    default T generateAndSaveNew(@NonNull Supplier generator) {
        for (int i = 0; i < 7; i++) {
            T t = generator.get();
            if (find(t.getId()) == null) {
                return save(t);
            }
        }
        throw new IllegalStateException("Cannot generate unique entity id");
    }

    default  T saveNewOrThrow(@NonNull T t, @NonNull Supplier alreadyExists) throws X {
        if (find(t.getId()) != null) {
            throw alreadyExists.get();
        }
        return save(t);
    }

    default  T updateExistingOrThrow(@NonNull T t, @NonNull Supplier notFound) throws X {
        if (find(t.getId()) == null) {
            throw notFound.get();
        }
        return save(t);
    }

    default T saveOrUpdate(@NonNull T t) {
        find(t.getId());
        return save(t);
    }

    default T deleteIfExists(@NonNull Entity.Id id) {
        T t = find(id);
        if (t != null) {
            delete(id);
        }
        return t;
    }

    default > void deleteAll(Set ids) {
        find(ids);
        ids.forEach(this::delete);
    }

    default > void deleteAll(Range range) {
        find(range).forEach(e -> delete(e.getId()));
    }

    // Unsafe
    @SuppressWarnings("unchecked")
    default void insert(T first, T... rest) {
        insertAll(concat(Stream.of(first), Stream.of(rest)).collect(toList()));
    }

    // Unsafe
    default void insertAll(Collection entities) {
        entities.forEach(this::insert);
    }

    // Unsafe
    default > void delete(Set ids) {
        ids.forEach(this::delete);
    }

    // Unsafe
    default > void delete(Range range) {
        findIds(range).forEach(this::delete);
    }

    default ListResult list(ListRequest request) {
        List nextPage = toQueryBuilder(request).find();
        return ListResult.forPage(request, postLoad(nextPage));
    }

    default  ViewListResult list(Class viewType, ListRequest request) {
        List nextPage = toQueryBuilder(request).find(viewType);
        return ViewListResult.forPage(request, viewType, nextPage);
    }

    default > List find(Set ids) {
        if (ids.isEmpty()) {
            return List.of();
        }

        var orderBy = EntityExpressions.defaultOrder(getType());
        var cache = getFirstLevelCache();
        var isPartialIdMode = ids.iterator().next().isPartial();

        var foundInCache = ids.stream()
                .filter(cache::containsKey)
                .map(cache::peek)
                .flatMap(Optional::stream)
                .collect(Collectors.toMap(Entity::getId, Function.identity()));
        var remainingIds = Sets.difference(ids, foundInCache.keySet());
        var foundInDb = findUncached(remainingIds, null, orderBy, null);

        var merged = new HashMap, T>();

        // some entries found in db with partial id query may already be in cache (after update/delete),
        // so we must return actual entries from cache
        for (var entry : foundInDb) {
            var id = entry.getId();
            if (cache.containsKey(id)) {
                var cached = cache.peek(id);
                cached.ifPresent(t -> merged.put(id, t));
                // not present means marked as deleted in cache
            } else {
                merged.put(id, this.postLoad(entry));
            }
        }

        // add entries found in cache and not fetched from db
        for (var pair : foundInCache.entrySet()) {
            var id = pair.getKey();
            var entry = pair.getValue();
            merged.put(id, entry);
        }

        if (!isPartialIdMode) {
            Set> foundInDbIds = foundInDb.stream().map(Entity::getId).collect(toSet());
            Set> foundInCacheIds = new HashSet<>(foundInCache.keySet());
            Sets.difference(Sets.difference(ids, foundInDbIds), foundInCacheIds).forEach(cache::putEmpty);
        }

        return merged.values().stream().sorted(EntityIdSchema.SORT_ENTITY_BY_ID).collect(Collectors.toList());
    }

    default void bulkUpsert(List input, BulkParams params) {
        throw new UnsupportedOperationException();
    }

    default TableQueryBuilder toQueryBuilder(ListRequest request) {
        return query()
                .index(request.getIndex())
                .filter(request.getFilter())
                .orderBy(request.getOrderBy())
                .offset(request.getOffset())
                .limit(request.getPageSize() + 1);
    }

    default List postLoad(List list) {
        return list.stream().map(this::postLoad).collect(Collectors.toList());
    }

    default T postLoad(T e) {
        return e.postLoad();
    }

    default long count(FilterExpression filter) {
        return count(null, filter);
    }

    default TableQueryBuilder query() {
        return new TableQueryBuilder<>(this);
    }

    @Deprecated
    void update(Entity.Id id, Changeset changeset);

    /**
     * Base interface for views, that is, arbitrary subsets of {@link Entity} fields.
     *
     * @see ViewId
     */
    interface View {
    }

    /**
     * Base interface for ID-aware views, that is, subsets of {@link Entity} fields
     * that contain the Entity's ID.
     *
     * @param  entity type
     * @see RecordViewId
     */
    interface ViewId> extends View {
        Entity.Id getId();
    }

    /**
     * Base interface for ID-aware views that are implemented as {@link java.lang.Record Java Records}.
     * 

Forwards {@link ViewId#getId() ViewId's getId() method} to the record's {@code id()} accessor, * so you don't need to override the {@code getId()} method yourself. * * @param entity type * @see ViewId */ interface RecordViewId> extends ViewId { Entity.Id id(); @Override default Entity.Id getId() { return id(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy