Skip to content

Commit 24352bf

Browse files
committed
Update
1 parent af7e663 commit 24352bf

12 files changed

Lines changed: 179 additions & 39 deletions

File tree

asql-core/src/main/java/me/zort/sqllib/internal/query/DeleteQuery.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import me.zort.sqllib.api.Executive;
55
import me.zort.sqllib.SQLDatabaseConnection;
66
import me.zort.sqllib.internal.query.part.LimitStatement;
7+
import me.zort.sqllib.internal.query.part.OffsetStatement;
78
import org.jetbrains.annotations.Nullable;
89

910
import java.util.ArrayList;
@@ -35,6 +36,12 @@ public DeleteQuery from(String table) {
3536
return this;
3637
}
3738

39+
@Override
40+
public DeleteQuery offset(int offset) {
41+
then(new OffsetStatement<>(this, new ArrayList<>(), offset));
42+
return this;
43+
}
44+
3845
public DeleteQuery limit(int limit) {
3946
then(new LimitStatement<>(this, new ArrayList<>(), limit));
4047
return this;

asql-core/src/main/java/me/zort/sqllib/internal/query/Limitable.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
public interface Limitable<P extends QueryNode<?> & Limitable<P>> { // P = self
44

5+
P offset(int offset);
56
P limit(int limit);
67

78
}

asql-core/src/main/java/me/zort/sqllib/internal/query/SelectQuery.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@
44
import me.zort.sqllib.api.Executive;
55
import me.zort.sqllib.SQLDatabaseConnection;
66
import me.zort.sqllib.internal.query.part.LimitStatement;
7+
import me.zort.sqllib.internal.query.part.OffsetStatement;
78
import org.jetbrains.annotations.Nullable;
89

910
import java.util.ArrayList;
1011
import java.util.Arrays;
1112
import java.util.List;
1213
import java.util.Objects;
1314

14-
public class SelectQuery extends QueryNode<QueryNode<?>> implements Executive, Conditional<SelectQuery>, Limitable<SelectQuery>, ResultSetAware {
15+
public class SelectQuery extends QueryNode<QueryNode<?>> implements
16+
Executive, Conditional<SelectQuery>, Limitable<SelectQuery>, ResultSetAware {
1517

1618
private final List<String> cols;
1719
private String table;
@@ -39,6 +41,12 @@ public SelectQuery from(String table) {
3941
return this;
4042
}
4143

44+
@Override
45+
public SelectQuery offset(int offset) {
46+
then(new OffsetStatement<>(this, new ArrayList<>(), offset));
47+
return this;
48+
}
49+
4250
public SelectQuery limit(int limit) {
4351
then(new LimitStatement<>(this, new ArrayList<>(), limit));
4452
return this;
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package me.zort.sqllib.internal.query.part;
2+
3+
import me.zort.sqllib.internal.query.QueryDetails;
4+
import me.zort.sqllib.internal.query.QueryNode;
5+
import me.zort.sqllib.internal.query.ResultSetAware;
6+
import org.jetbrains.annotations.Nullable;
7+
8+
import java.util.HashMap;
9+
import java.util.List;
10+
11+
public class OffsetStatement<P extends QueryNode<?>> extends QueryNode<P> implements ResultSetAware {
12+
13+
private final int offset;
14+
15+
public OffsetStatement(@Nullable P parent, List<QueryNode<?>> initial, int offset) {
16+
super(parent, initial, Integer.MAX_VALUE);
17+
this.offset = offset;
18+
}
19+
20+
@Override
21+
public QueryDetails buildQueryDetails() {
22+
return new QueryDetails(" OFFSET " + Math.max(offset, 0), new HashMap<>());
23+
}
24+
25+
@SuppressWarnings("unchecked")
26+
@Override
27+
public OffsetStatement<P> then(String part) {
28+
return (OffsetStatement<P>) super.then(part);
29+
}
30+
}

asql-debezium/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ build/
44
!**/src/main/**/build/
55
!**/src/test/**/build/
66

7+
main/java/me/zort/sqllib/debezium/Test.java
8+
79
### IntelliJ IDEA ###
810
.idea/modules.xml
911
.idea/jarRepositories.xml

asql-debezium/build.gradle

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,14 @@ dependencies {
1717
implementation 'io.debezium:debezium-connector-mysql:1.9.6.Final'
1818
implementation 'com.google.guava:guava:31.0-jre'
1919
implementation project(':api')
20+
implementation project(':shared')
2021
implementation project(':core')
2122
annotationProcessor 'org.projectlombok:lombok:1.18.24'
23+
}
24+
25+
task runWithJavaExec(type: JavaExec) {
26+
group = "Execution"
27+
description = "Run the main class with JavaExecTask"
28+
classpath = sourceSets.main.runtimeClasspath
29+
main = "me.zort.sqllib.debezium.Test"
2230
}

asql-debezium/settings.gradle

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
rootProject.name = 'asql-debezium'
22
include ":api"
33
include ":core"
4+
include ":shared"
45
project(":api").projectDir = file("../asql-api")
5-
project(":core").projectDir = file("../asql-core")
6+
project(":core").projectDir = file("../asql-core")
7+
project(":shared").projectDir = file("../asql-shared")

asql-debezium/src/main/java/me/zort/sqllib/debezium/ASQLDebeziumService.java renamed to asql-debezium/src/main/java/me/zort/sqllib/debezium/ASQLDebeziumWatcher.java

Lines changed: 68 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,17 @@
1111
import me.zort.sqllib.debezium.builder.EntityFilterBuilder;
1212
import org.jetbrains.annotations.NotNull;
1313

14+
import java.io.IOException;
1415
import java.lang.reflect.AnnotatedElement;
1516
import java.net.URI;
16-
import java.sql.Connection;
17+
import java.net.URISyntaxException;
18+
import java.sql.DatabaseMetaData;
1719
import java.util.HashMap;
1820
import java.util.List;
1921
import java.util.Map;
2022
import java.util.concurrent.CompletableFuture;
23+
import java.util.concurrent.ConcurrentHashMap;
2124
import java.util.concurrent.ExecutorService;
22-
import java.util.concurrent.Executors;
2325
import java.util.function.Consumer;
2426
import java.util.function.Function;
2527

@@ -40,31 +42,46 @@
4042
* @author ZorTik
4143
*/
4244
@Beta
43-
public final class ASQLDebeziumService implements
44-
DebeziumEngine.ChangeConsumer<ChangeEvent<String, String>>, Runnable {
45+
public final class ASQLDebeziumWatcher
46+
implements DebeziumEngine.ChangeConsumer<ChangeEvent<String, String>> {
4547

4648
@SneakyThrows
47-
public static @NotNull Builder configure(@NotNull SQLDatabaseConnection connection) {
49+
public static @NotNull Builder configure(
50+
@NotNull SQLDatabaseConnection connection, String password
51+
) {
4852
if (!(connection instanceof SQLDatabaseConnectionImpl)) {
4953
throw new IllegalArgumentException("Connection does not contain options!");
5054
} else if (!connection.isConnected()) {
5155
throw new IllegalArgumentException("Connection is not connected!");
5256
}
53-
Connection rawConnection = connection.getConnection();
54-
URI uri = new URI(rawConnection.getMetaData().getURL());
57+
DatabaseMetaData rawConnectionMeta = connection.getConnection().getMetaData();
58+
URI uri = new URI(rawConnectionMeta.getURL());
59+
return configure(
60+
uri.getHost(), uri.getPort(), rawConnectionMeta.getUserName(), password
61+
);
62+
}
63+
64+
public static @NotNull Builder configure(
65+
@NotNull String hostname,
66+
int port,
67+
@NotNull String username,
68+
@NotNull String password
69+
) throws URISyntaxException {
5570
Configuration.Builder configBuilder = Configuration.create()
56-
.with("database.hostname", uri.getHost())
57-
.with("database.port", uri.getPort());
58-
// TODO: Build configuration builder from raw connection details
71+
.with("database.hostname", hostname)
72+
.with("database.port", String.valueOf(port))
73+
.with("database.user", username)
74+
.with("database.password", password);
5975
return new Builder(configBuilder);
6076
}
6177

6278
private final DebeziumEngine<ChangeEvent<String, String>> engine;
6379
private final Map<RecordFilter, Consumer<ChangeEvent<String, String>>> handlers;
80+
private boolean running = false;
6481

65-
private ASQLDebeziumService(DebeziumEngine.Builder<ChangeEvent<String, String>> builder) {
82+
private ASQLDebeziumWatcher(DebeziumEngine.Builder<ChangeEvent<String, String>> builder) {
6683
this.engine = builder.notifying(this).build();
67-
this.handlers = null;
84+
this.handlers = new ConcurrentHashMap<>();
6885
}
6986

7087
@Override
@@ -85,9 +102,26 @@ public void handleBatch(
85102
committer.markBatchFinished();
86103
}
87104

88-
@Override
89-
public void run() {
90-
engine.run();
105+
public void start(ExecutorService executor) {
106+
if (running) {
107+
throw new IllegalStateException("Service is already running!");
108+
}
109+
executor.submit(engine);
110+
running = true;
111+
}
112+
113+
public void stop() {
114+
try {
115+
engine.close();
116+
} catch (IOException e) {
117+
throw new RuntimeException(e);
118+
} finally {
119+
running = false;
120+
}
121+
}
122+
123+
public @NotNull CompletableFuture<ChangeEvent<String, String>> awaitChange() {
124+
return awaitChange(RecordFilter.any());
91125
}
92126

93127
/**
@@ -116,7 +150,13 @@ public static class Builder {
116150
private Builder(Configuration.Builder initialConfig) {
117151
this.config = initialConfig;
118152
edit(builder -> builder
119-
.with("name", "Asql-Debezium-" + (++serviceCount)));
153+
.with("name", "Asql-Debezium-" + (++serviceCount))
154+
.with("offset.storage", "org.apache.kafka.connect.storage.FileOffsetBackingStore")
155+
.with("offset.storage.file.filename", System.getProperty("user.dir") + "/offsets.dat")
156+
.with("server.id", serviceCount)
157+
.with("database.history", "io.debezium.relational.history.FileDatabaseHistory")
158+
.with("io.debezium.relational.history.FileDatabaseHistory", System.getProperty("user.dir") + "/dbhistory.dat")
159+
.with("offset.flush.interval.ms", 1000));
120160
}
121161

122162
public @NotNull Builder edit(
@@ -130,10 +170,19 @@ private Builder(Configuration.Builder initialConfig) {
130170
return edit(builder -> builder.with("connector.class", type.getClassName()));
131171
}
132172

133-
public @NotNull ASQLDebeziumService build() {
173+
public @NotNull ASQLDebeziumWatcher build() {
174+
Configuration configuration = config.build();
175+
assertProperty(configuration, "connector.class");
176+
assertProperty(configuration, "database.hostname");
134177
DebeziumEngine.Builder<ChangeEvent<String, String>> builder = DebeziumEngine.create(Json.class)
135-
.using(config.build().asProperties());
136-
return new ASQLDebeziumService(builder);
178+
.using(configuration.asProperties());
179+
return new ASQLDebeziumWatcher(builder);
180+
}
181+
182+
private static void assertProperty(Configuration config, String name) {
183+
if (!config.hasKey(name)) {
184+
throw new IllegalArgumentException("Configuration requires property " + name);
185+
}
137186
}
138187
}
139188

asql-debezium/src/main/java/me/zort/sqllib/debezium/RecordFilter.java

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package me.zort.sqllib.debezium;
22

3+
import io.debezium.data.Envelope;
34
import io.debezium.engine.ChangeEvent;
5+
import me.zort.sqllib.debezium.filter.EnvelopeOpRecordFilter;
46
import me.zort.sqllib.mapping.annotation.Table;
57
import me.zort.sqllib.util.ParameterPair;
68
import org.jetbrains.annotations.NotNull;
@@ -10,11 +12,11 @@
1012

1113
/**
1214
* Tests a record if the provided record should be notified
13-
* to the registered consumer in {@link ASQLDebeziumService}.
15+
* to the registered consumer in {@link ASQLDebeziumWatcher}.
1416
*
1517
* @author ZorTik
1618
*/
17-
public final class RecordFilter {
19+
public class RecordFilter {
1820

1921
private static final long DEFAULT_EXPIRATION = 10000L;
2022

@@ -31,39 +33,46 @@ public boolean test(ChangeEvent<String, String> record) {
3133
return testFunction.test(record);
3234
}
3335

34-
public void setExpireAfter(long expireAfter) {
36+
public final void setExpireAfter(long expireAfter) {
3537
if (isRegistered()) {
3638
throw new IllegalStateException("Filter expiration cannot be changed after it has been registered!");
3739
}
3840
this.expireAfter = expireAfter;
3941
}
4042

41-
public boolean isRegistered() {
43+
public final boolean isRegistered() {
4244
return expireAt != -1;
4345
}
4446

45-
public boolean expired() {
47+
public final boolean expired() {
4648
return System.currentTimeMillis() >= expireAt;
4749
}
4850

49-
void markRegistered() {
51+
final void markRegistered() {
5052
if (isRegistered()) {
5153
throw new IllegalStateException("Filter has already been registered!");
5254
}
5355
expireAt = System.currentTimeMillis() + expireAfter;
5456
}
5557

58+
public static @NotNull RecordFilter any() {
59+
return new RecordFilter(record -> true);
60+
}
61+
5662
public static @NotNull RecordFilter table(AnnotatedElement element, ParameterPair... parameters) {
5763
final String table = Table.Util.getFromContext(element, parameters);
5864
return new RecordFilter(record -> record.destination().equals(table));
5965
}
6066

61-
public static @NotNull RecordFilter column(String column) {
62-
return new RecordFilter(record -> record.key().equals(column));
67+
public static @NotNull RecordFilter columnChanged(String column) {
68+
return new EnvelopeOpRecordFilter(record -> record.key().equals(column), Envelope.Operation.UPDATE);
6369
}
6470

65-
public static @NotNull RecordFilter column(String column, String value) {
66-
return new RecordFilter(record -> record.key().equals(column) && record.value().equals(value));
71+
public static @NotNull RecordFilter columnChanged(String column, String value) {
72+
return new EnvelopeOpRecordFilter(
73+
record -> record.key().equals(column) && record.value().equals(value),
74+
Envelope.Operation.UPDATE
75+
);
6776
}
6877

6978
public static @NotNull RecordFilter join(RecordFilter... filters) {

asql-debezium/src/main/java/me/zort/sqllib/debezium/RecordFilterBuilder.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@
1010

1111
/**
1212
* Provides easy to use API for building and executing filters
13-
* in {@link ASQLDebeziumService}.
13+
* in {@link ASQLDebeziumWatcher}.
1414
*
1515
* @see RecordFilter
16-
* @see ASQLDebeziumService
16+
* @see ASQLDebeziumWatcher
1717
* @author ZorTik
1818
*/
1919
public class RecordFilterBuilder {
2020

21-
private final ASQLDebeziumService service;
21+
private final ASQLDebeziumWatcher service;
2222
private RecordFilter filter;
2323

24-
public RecordFilterBuilder(ASQLDebeziumService service) {
24+
public RecordFilterBuilder(ASQLDebeziumWatcher service) {
2525
this.service = service;
2626
this.filter = null;
2727
}

0 commit comments

Comments
 (0)