Skip to content
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
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,21 @@ db.query("items", Item.class)
.update();
```

The `now()` function can also be applied using the `@CurrentTimestamp` annotation:

```java

@CurrentTimestamp(unit = TimeUnit.SECONDS, strategy = PreceptApplyStrategy.WHEN_NULL)
@Reindex(name = "created_at")
LocalDateTime createdAt;

@CurrentTimestamp(unit = TimeUnit.SECONDS, strategy = PreceptApplyStrategy.ALWAYS)
@Reindex(name = "updated_at")
LocalDateTime updatedAt;
```

See Javadoc for `@CurrentTimestamp` for more information.

##### serial()
The `serial()` function returns a unique identifier from the sequence of integer for each document in the namespace.
This function can be used in both `INSERT` and `UPDATE` queries.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2020-present Restream
*
* 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 ru.rt.restream.reindexer.annotations;

import ru.rt.restream.reindexer.PreceptApplyStrategy;
import ru.rt.restream.reindexer.TimeUnit;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Specifies that the value for the annotated field should be set to the current timestamp using {@code now()} function.
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CurrentTimestamp {

/**
* A time unit to use in {@code now()} function. Default is {@link TimeUnit#SECONDS}.
*
* @return the time unit to use in {@code now()} function, defaults to {@link TimeUnit#SECONDS}
*/
TimeUnit unit() default TimeUnit.SECONDS;

/**
* A precept apply strategy. Default is {@link PreceptApplyStrategy#ALWAYS}.
*
* @return the precept apply strategy to use, defaults to {@link PreceptApplyStrategy#ALWAYS}
*/
PreceptApplyStrategy strategy() default PreceptApplyStrategy.ALWAYS;

}
Original file line number Diff line number Diff line change
Expand Up @@ -148,19 +148,7 @@ && getFieldTypeByClass(fieldInfo.componentType) == COMPOSITE) {
String collate = reindex.collate();
CollateMode collateMode = getCollateMode(collate);
String sortOrder = getSortOrder(collateMode, collate);
ReindexerPrecept precept = null;
Serial serial = field.getAnnotation(Serial.class);
if (serial != null) {
if (!fieldInfo.isInt()) {
throw new IllegalStateException("@Serial is allowed only for int types (i.e INT, INT64)");
}
precept = ReindexerPrecept.builder()
.fieldPath(fieldPath)
.jsonPath(jsonPath)
.expression(Expression.serial())
.strategy(serial.strategy())
.build();
}
ReindexerPrecept precept = getReindexerPrecept(field, fieldInfo, fieldPath, jsonPath);
FullTextConfig fullTextConfig = getFullTextConfig(field, reindex.type());
validateUuidIndexHasTypeUuidOrString(reindex, fieldInfo);
boolean isUuid = reindex.isUuid() || fieldInfo.fieldType == UUID;
Expand Down Expand Up @@ -221,6 +209,37 @@ && getFieldTypeByClass(fieldInfo.componentType) == COMPOSITE) {
return indexes;
}

private ReindexerPrecept getReindexerPrecept(Field field, FieldInfo fieldInfo, String fieldPath, String jsonPath) {
Serial serial = field.getAnnotation(Serial.class);
CurrentTimestamp currentTimestamp = field.getAnnotation(CurrentTimestamp.class);
if (serial != null && currentTimestamp != null) {
throw new IllegalStateException("@Serial and @CurrentTimestamp are mutually exclusive");
}
if (serial != null) {
if (!fieldInfo.isInt() && !fieldInfo.isText()) {
throw new IllegalStateException("@Serial is allowed only for int types (i.e., INT, INT64) or string types");
}
return ReindexerPrecept.builder()
.fieldPath(fieldPath)
.jsonPath(jsonPath)
.expression(Expression.serial())
.strategy(serial.strategy())
.build();
}
if (currentTimestamp != null) {
if (!fieldInfo.isInt() && !fieldInfo.isText()) {
throw new IllegalStateException("@CurrentTimestamp is allowed only for int types (i.e., INT, INT64)");
}
return ReindexerPrecept.builder()
.fieldPath(fieldPath)
.jsonPath(jsonPath)
.expression(Expression.now(currentTimestamp.unit()))
.strategy(currentTimestamp.strategy())
.build();
}
return null;
}

private IndexType specifyDefaultIndexType(Reindex reindex, Field field, FieldInfo fieldInfo) {
if (reindex.type() != IndexType.DEFAULT) {
return reindex.type();
Expand Down Expand Up @@ -405,6 +424,10 @@ private static class FieldInfo {
private boolean isInt() {
return fieldType == INT || fieldType == INT64;
}

private boolean isText() {
return fieldType == STRING;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import ru.rt.restream.reindexer.TimeUnit;
import ru.rt.restream.reindexer.Transaction;
import ru.rt.restream.reindexer.annotations.Convert;
import ru.rt.restream.reindexer.annotations.CurrentTimestamp;
import ru.rt.restream.reindexer.annotations.Enumerated;
import ru.rt.restream.reindexer.annotations.Reindex;
import ru.rt.restream.reindexer.annotations.Serial;
Expand Down Expand Up @@ -1982,6 +1983,32 @@ public void testWithNowPreceptReturnsGeneratedTimestamp() {
assertThat(updated.updatedAt, greaterThan(updatedAt));
}

@SneakyThrows
@Test
public void testWithCurrentTimestampReturnsGeneratedTimestamp() {
FieldConverterRegistryFactory.INSTANCE.registerFieldConverter(CurrentTimestampTestItem.class, "createdAt", new LocalDateTimeUnitFieldConverter(TimeUnit.MILLIS));
FieldConverterRegistryFactory.INSTANCE.registerFieldConverter(CurrentTimestampTestItem.class, "updatedAt", new LocalDateTimeUnitFieldConverter(TimeUnit.MILLIS));
String namespaceName = "items";
db.openNamespace(namespaceName, NamespaceOptions.defaultOptions(), CurrentTimestampTestItem.class);

CurrentTimestampTestItem item = new CurrentTimestampTestItem(1, null, null);
CurrentTimestampTestItem inserted = db.insert(namespaceName, item);
assertThat(inserted, sameInstance(item));
assertThat(inserted.id, is(1));
LocalDateTime createdAt = inserted.createdAt;
LocalDateTime updatedAt = inserted.updatedAt;
assertThat(createdAt, notNullValue());
assertThat(updatedAt, notNullValue());

// Small delay to shift the updatedAt precept.
Thread.sleep(1000);
CurrentTimestampTestItem updated = db.update(namespaceName, inserted);
assertThat(updated, sameInstance(inserted));
assertThat(updated.id, is(1));
assertThat(updated.createdAt, is(createdAt));
assertThat(updated.updatedAt, greaterThan(updatedAt));
}

@Test
public void testTransactionUpsertWithSerialId() {
String namespaceName = "items";
Expand Down Expand Up @@ -3288,6 +3315,21 @@ public static class SerialIdTestItem {
private Integer version;
}

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class CurrentTimestampTestItem {
@Reindex(name = "id", isPrimaryKey = true)
private Integer id;
@CurrentTimestamp(unit = TimeUnit.MILLIS, strategy = PreceptApplyStrategy.WHEN_NULL)
Comment thread
MadSchemas marked this conversation as resolved.
Resolved
@Reindex(name = "createdAt")
private LocalDateTime createdAt;
@CurrentTimestamp(unit = TimeUnit.MILLIS)
@Reindex(name = "updatedAt")
private LocalDateTime updatedAt;
}

@Getter
@Setter
@Reindex(name = "composite", subIndexes = {"id", "name"})
Expand Down
Loading