Skip to content
Draft
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 @@ -82,11 +82,12 @@ public void commit() {
throw new IllegalStateException("Transaction was invalidated. Commit isn't possible");
}
endTransaction("commit()", this::commitImpl);
options.getRepositoryTransactionListeners().forEach(l -> l.onCommit(this));
}

private void commitImpl() {
try {
transactionLocal.projectionCache().applyProjectionChanges(this);
options.getRepositoryTransactionListeners().forEach(l -> l.onBeforeFlushWrites(this));

for (Runnable pendingWrite : pendingWrites) {
pendingWrite.run();
Expand All @@ -102,6 +103,7 @@ private void commitImpl() {
@Override
public void rollback() {
endTransaction("rollback()", this::rollbackImpl);
options.getRepositoryTransactionListeners().forEach(l -> l.onRollback(this));
}

private void rollbackImpl() {
Expand Down Expand Up @@ -149,7 +151,7 @@ final <T extends Entity<T>> void doInWriteTransaction(
});
if (options.isImmediateWrites()) {
query.run();
transactionLocal.projectionCache().applyProjectionChanges(this);
options.getRepositoryTransactionListeners().forEach(l -> l.onImmediateWrite(this));
} else {
pendingWrites.add(query);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,8 @@ public void update(Entity.Id<T> id, Changeset changeset) {

transaction.getWatcher().markRowRead(tableDescriptor, id);
transaction.doInWriteTransaction("update(" + id + ", " + changeset + ")", tableDescriptor, shard -> shard.update(id, patch));
transaction.getTransactionLocal().firstLevelCache(tableDescriptor).remove(id);
getFirstLevelCache().remove(id);
transaction.getOptions().getEntityEventListeners().forEach(l -> l.onUpdate(tableDescriptor, id, changeset));
}

@Override
Expand Down Expand Up @@ -178,7 +179,7 @@ public T find(Entity.Id<T> id) {
if (id.isPartial()) {
throw new IllegalArgumentException("Cannot use partial id in find method");
}
return transaction.getTransactionLocal().firstLevelCache(tableDescriptor).get(id, __ -> {
return getFirstLevelCache().get(id, __ -> {
markKeyRead(id);
T entity = transaction.doInTransaction("find(" + id + ")", tableDescriptor, shard -> shard.find(id));
return postLoad(entity);
Expand All @@ -196,7 +197,7 @@ public <V extends View> V find(Class<V> viewType, Entity.Id<T> id) {
throw new IllegalArgumentException("Cannot use partial id in find method");
}

FirstLevelCache<T> cache = transaction.getTransactionLocal().firstLevelCache(tableDescriptor);
FirstLevelCache<T> cache = getFirstLevelCache();
if (cache.containsKey(id)) {
return cache.peek(id)
.map(entity -> toView(viewType, schema, entity))
Expand Down Expand Up @@ -428,25 +429,25 @@ public T insert(T tt) {
T t = tt.preSave();
transaction.getWatcher().markRowRead(tableDescriptor, t.getId());
transaction.doInWriteTransaction("insert(" + t + ")", tableDescriptor, shard -> shard.insert(t));
transaction.getTransactionLocal().firstLevelCache(tableDescriptor).put(t);
transaction.getTransactionLocal().projectionCache().save(t);
getFirstLevelCache().put(t);
transaction.getOptions().getEntityEventListeners().forEach(l -> l.onSave(tableDescriptor, t));
return t;
}

@Override
public T save(T tt) {
T t = tt.preSave();
transaction.doInWriteTransaction("save(" + t + ")", tableDescriptor, shard -> shard.save(t));
transaction.getTransactionLocal().firstLevelCache(tableDescriptor).put(t);
transaction.getTransactionLocal().projectionCache().save(t);
getFirstLevelCache().put(t);
transaction.getOptions().getEntityEventListeners().forEach(l -> l.onSave(tableDescriptor, t));
return t;
}

@Override
public void delete(Entity.Id<T> id) {
transaction.doInWriteTransaction("delete(" + id + ")", tableDescriptor, shard -> shard.delete(id));
transaction.getTransactionLocal().firstLevelCache(tableDescriptor).putEmpty(id);
transaction.getTransactionLocal().projectionCache().delete(id);
getFirstLevelCache().putEmpty(id);
transaction.getOptions().getEntityEventListeners().forEach(l -> l.onDelete(tableDescriptor, id));
}

@Override
Expand Down Expand Up @@ -575,8 +576,9 @@ public T postLoad(T entity) {
return null;
}
T t = entity.postLoad();
transaction.getTransactionLocal().firstLevelCache(tableDescriptor).put(t);
transaction.getTransactionLocal().projectionCache().load(t);
getFirstLevelCache().put(t);
transaction.getOptions().getEntityEventListeners().forEach(l -> l.onLoad(tableDescriptor, t));

return t;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
import tech.ydb.yoj.repository.test.sample.model.BadlyWrappedEntity;
import tech.ydb.yoj.repository.test.sample.model.BadlyWrappedEntity.BadStringValueWrapper;
import tech.ydb.yoj.repository.test.sample.model.Book;
import tech.ydb.yoj.repository.test.sample.model.BookProjectionsOldStyle;
import tech.ydb.yoj.repository.test.sample.model.Bubble;
import tech.ydb.yoj.repository.test.sample.model.BytePkEntity;
import tech.ydb.yoj.repository.test.sample.model.Complex;
Expand Down Expand Up @@ -686,7 +687,7 @@ public void viewStreamAll() {
}
db.tx(() -> db.table(Book.class)
.streamAll(Book.TitleViewId.class, 100)
.forEach(titleView -> assertThat(titleView.getTitle()).isNotBlank()));
.forEach(titleView -> assertThat(titleView.title()).isNotBlank()));

assertThat(db.tx(() -> db.table(Book.class).streamAll(Book.TitleViewId.class, 2)
.limit(1).collect(toList())))
Expand Down Expand Up @@ -2188,6 +2189,57 @@ public void projections() {
.isEqualTo(0L);
}

@Test
public void projectionsOldStyle() {
db.tx(() -> {
db.table(BookProjectionsOldStyle.class).save(new BookProjectionsOldStyle(new BookProjectionsOldStyle.Id("1"), 1, "title1", List.of("author1")));
db.table(BookProjectionsOldStyle.class).save(new BookProjectionsOldStyle(new BookProjectionsOldStyle.Id("2"), 1, "title2", List.of("author2")));
db.table(BookProjectionsOldStyle.class).save(new BookProjectionsOldStyle(new BookProjectionsOldStyle.Id("3"), 1, null, List.of("author1", "author2")));
db.table(BookProjectionsOldStyle.class).save(new BookProjectionsOldStyle(new BookProjectionsOldStyle.Id("4"), 1, "title1", List.of()));
});

assertThat(db.tx(() -> db.table(BookProjectionsOldStyle.ByTitle.class).countAll()))
.isEqualTo(3L);
assertThat(db.tx(() -> db.table(BookProjectionsOldStyle.ByTitle.class).find(Range.create(new BookProjectionsOldStyle.ByTitle.Id("title1", null)))))
.hasSize(2);
assertThat(db.tx(() -> db.table(BookProjectionsOldStyle.ByTitle.class).find(Range.create(new BookProjectionsOldStyle.ByTitle.Id("title2", null)))))
.hasSize(1);

assertThat(db.tx(() -> db.table(BookProjectionsOldStyle.ByAuthor.class).countAll()))
.isEqualTo(4L);
assertThat(db.tx(() -> db.table(BookProjectionsOldStyle.ByAuthor.class).find(Range.create(new BookProjectionsOldStyle.ByAuthor.Id("author1", null)))))
.hasSize(2);
assertThat(db.tx(() -> db.table(BookProjectionsOldStyle.ByAuthor.class).find(Range.create(new BookProjectionsOldStyle.ByAuthor.Id("author2", null)))))
.hasSize(2);

db.tx(() -> {
db.table(BookProjectionsOldStyle.class).modifyIfPresent(new BookProjectionsOldStyle.Id("1"), b -> b.updateTitle("title2"));
db.table(BookProjectionsOldStyle.class).modifyIfPresent(new BookProjectionsOldStyle.Id("2"), b -> b.updateTitle(null));
db.table(BookProjectionsOldStyle.class).modifyIfPresent(new BookProjectionsOldStyle.Id("3"), b -> b.withAuthors(List.of("author2")));
db.table(BookProjectionsOldStyle.class).modifyIfPresent(new BookProjectionsOldStyle.Id("4"), b -> b.withAuthors(List.of("author1", "author2")));
});

assertThat(db.tx(() -> db.table(BookProjectionsOldStyle.ByTitle.class).countAll()))
.isEqualTo(2L);
assertThat(db.tx(() -> db.table(BookProjectionsOldStyle.ByTitle.class).find(Range.create(new BookProjectionsOldStyle.ByTitle.Id("title1", null)))))
.hasSize(1);
assertThat(db.tx(() -> db.table(BookProjectionsOldStyle.ByTitle.class).find(Range.create(new BookProjectionsOldStyle.ByTitle.Id("title2", null)))))
.hasSize(1);

assertThat(db.tx(() -> db.table(BookProjectionsOldStyle.ByAuthor.class).countAll()))
.isEqualTo(5L);
assertThat(db.tx(() -> db.table(BookProjectionsOldStyle.ByAuthor.class).find(Range.create(new BookProjectionsOldStyle.ByAuthor.Id("author1", null)))))
.hasSize(2);
assertThat(db.tx(() -> db.table(BookProjectionsOldStyle.ByAuthor.class).find(Range.create(new BookProjectionsOldStyle.ByAuthor.Id("author2", null)))))
.hasSize(3);

db.tx(() -> db.table(BookProjectionsOldStyle.class).findAll().forEach(b -> db.table(BookProjectionsOldStyle.class).delete(b.getId())));
assertThat(db.tx(() -> db.table(BookProjectionsOldStyle.ByTitle.class).countAll()))
.isEqualTo(0L);
assertThat(db.tx(() -> db.table(BookProjectionsOldStyle.ByAuthor.class).countAll()))
.isEqualTo(0L);
}

/**
* {@link #parallelTx(boolean, boolean, Consumer)} make two tx.
* In first - read from table (see consumers - findAll, findId, findRange)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import tech.ydb.yoj.repository.db.TableDescriptor;
import tech.ydb.yoj.repository.test.sample.model.BadlyWrappedEntity;
import tech.ydb.yoj.repository.test.sample.model.Book;
import tech.ydb.yoj.repository.test.sample.model.BookProjectionsOldStyle;
import tech.ydb.yoj.repository.test.sample.model.Bubble;
import tech.ydb.yoj.repository.test.sample.model.BytePkEntity;
import tech.ydb.yoj.repository.test.sample.model.Complex;
Expand Down Expand Up @@ -47,6 +48,7 @@ private TestEntities() {
public static final List<Class<? extends Entity>> ALL = List.of(
Project.class, UniqueProject.class, TypeFreak.class, Complex.class, Referring.class, Primitive.class,
Book.class, Book.ByAuthor.class, Book.ByTitle.class,
BookProjectionsOldStyle.class, BookProjectionsOldStyle.ByAuthor.class, BookProjectionsOldStyle.ByTitle.class,
LogEntry.class, Team.class,
BytePkEntity.class,
EntityWithValidation.class,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,65 +1,58 @@
package tech.ydb.yoj.repository.test.sample.model;

import lombok.Value;
import lombok.NonNull;
import lombok.With;
import tech.ydb.yoj.repository.db.Entity;
import tech.ydb.yoj.repository.db.RecordEntity;
import tech.ydb.yoj.repository.db.Table;
import tech.ydb.yoj.repository.db.projection.EntityWithProjections;
import tech.ydb.yoj.repository.db.projection.ProjectionCollection;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Value
@With
public class Book implements Entity<Book> {
Id id;
int version;
String title;
List<String> authors;

public record Book(
Id id,
int version,
String title,
List<String> authors
) implements RecordEntity<Book>, EntityWithProjections<Book> {
public Book updateTitle(String title) {
return withTitle(title).withVersion(version + 1);
}

@Override
public List<Entity<?>> createProjections() {
return Stream.concat(
Optional.ofNullable(title).map(t -> new ByTitle(new ByTitle.Id(t, id))).stream(),
authors.stream().map(a -> new ByAuthor(new ByAuthor.Id(a, id)))
).collect(Collectors.toList());
public ProjectionCollection collectProjections() {
return ProjectionCollection.builder()
.addEntityIfNotNull(title, t -> new ByTitle(new ByTitle.Id(t, id)))
.addAllEntities(authors.stream().map(a -> new ByAuthor(new ByAuthor.Id(a, id))))
.build();
}

@Value
public static class Id implements Entity.Id<Book> {
String id;
public record Id(String id) implements Entity.Id<Book> {
}

@Value
public static class ByTitle implements Entity<ByTitle> {
Id id;
public record ByTitle(Id id) implements RecordEntity<ByTitle> {
public record Id(
@NonNull
String title,

@Value
public static class Id implements Entity.Id<ByTitle> {
String title;
Book.Id id;
Book.Id id
) implements Entity.Id<ByTitle> {
}
}

@Value
public static class ByAuthor implements Entity<ByAuthor> {
Id id;

@Value
public static class Id implements Entity.Id<ByAuthor> {
String author;
Book.Id id;
public record ByAuthor(Id id) implements RecordEntity<ByAuthor> {
public record Id(
String author,
Book.Id id
) implements Entity.Id<ByAuthor> {
}
}

@Value
public static class TitleViewId implements Table.ViewId<Book> {
Id id;
String title;
public record TitleViewId(
Id id,
String title
) implements Table.RecordViewId<Book> {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package tech.ydb.yoj.repository.test.sample.model;

import lombok.NonNull;
import lombok.Value;
import lombok.With;
import tech.ydb.yoj.repository.db.Entity;
import tech.ydb.yoj.repository.db.Table;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Value
@With
public class BookProjectionsOldStyle implements Entity<BookProjectionsOldStyle> {
Id id;
int version;
String title;
List<String> authors;

public BookProjectionsOldStyle updateTitle(String title) {
return withTitle(title).withVersion(version + 1);
}

@Override
public List<Entity<?>> createProjections() {
return Stream.concat(
Optional.ofNullable(title).map(t -> new ByTitle(new ByTitle.Id(t, id))).stream(),
authors.stream().map(a -> new ByAuthor(new ByAuthor.Id(a, id)))
).collect(Collectors.toList());
}

@Value
public static class Id implements Entity.Id<BookProjectionsOldStyle> {
String id;
}

@Value
public static class ByTitle implements Entity<ByTitle> {
Id id;

@Value
public static class Id implements Entity.Id<ByTitle> {
@NonNull
String title;

BookProjectionsOldStyle.Id id;
}
}

@Value
public static class ByAuthor implements Entity<ByAuthor> {
Id id;

@Value
public static class Id implements Entity.Id<ByAuthor> {
String author;
BookProjectionsOldStyle.Id id;
}
}

@Value
public static class TitleViewId implements Table.ViewId<BookProjectionsOldStyle> {
Id id;
String title;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ public void commit() {
throw t;
}
endTransaction("commit", this::doCommit);
options.getRepositoryTransactionListeners().forEach(l -> l.onCommit(this));
}

@Override
Expand All @@ -169,6 +170,7 @@ public void rollback() {
log.info("Failed to rollback the transaction", t);
}
});
options.getRepositoryTransactionListeners().forEach(l -> l.onRollback(this));
}

private void doCommit() {
Expand Down Expand Up @@ -282,7 +284,7 @@ private static <PARAMS> Params getSdkParams(Statement<PARAMS, ?> statement, PARA
}

private void flushPendingWrites() {
transactionLocal.projectionCache().applyProjectionChanges(this);
options.getRepositoryTransactionListeners().forEach(l -> l.onBeforeFlushWrites(this));
QueriesMerger.create(cache)
.merge(pendingWrites)
.forEach(this::execute);
Expand Down Expand Up @@ -480,7 +482,7 @@ public <PARAMS> void pendingExecute(Statement<PARAMS, ?> statement, PARAMS value
YdbRepository.Query<PARAMS> query = new YdbRepository.Query<>(statement, value);
if (options.isImmediateWrites()) {
execute(query);
transactionLocal.projectionCache().applyProjectionChanges(this);
options.getRepositoryTransactionListeners().forEach(l -> l.onImmediateWrite(this));
} else {
pendingWrites.add(query);
}
Expand Down
Loading