Skip to content

Commit 2516d06

Browse files
committed
improve
1 parent c64203d commit 2516d06

File tree

11 files changed

+142
-28
lines changed

11 files changed

+142
-28
lines changed

src/main/java/com/surrealdb/FileRef.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
/**
44
* Reference to a file stored in a SurrealDB bucket. Obtained from
55
* {@link Value#getFile()} when {@link Value#isFile()} is true.
6+
*
7+
* Valid only for the lifetime of the {@link Value} it was obtained from; do
8+
* not retain a reference after that Value is no longer in use.
69
*/
710
public class FileRef extends Native {
811

src/main/java/com/surrealdb/LiveNotification.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ public String getAction() {
2525
return action;
2626
}
2727

28-
/** The record value (content) for this notification. */
28+
/**
29+
* The record value (content) for this notification. May be null when the
30+
* notification does not include record content (e.g. some server events).
31+
*
32+
* @return the record value, or null
33+
*/
2934
public Value getValue() {
3035
return value;
3136
}

src/main/java/com/surrealdb/LiveStream.java

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

55
/**
66
* Blocking iterator over live query notifications. Call {@link #next()} in a
7-
* loop and {@link #close()} when done (or use try-with-resources if we add
8-
* AutoCloseable).
7+
* loop and {@link #close()} when done. Implements {@link AutoCloseable} for
8+
* use in try-with-resources.
99
*/
10-
public class LiveStream {
10+
public class LiveStream implements AutoCloseable {
1111

1212
static {
1313
Loader.loadNative();
@@ -35,6 +35,7 @@ public Optional<LiveNotification> next() {
3535
/**
3636
* Releases the live query and stops receiving notifications. Idempotent.
3737
*/
38+
@Override
3839
public void close() {
3940
if (handle != 0) {
4041
releaseNative(handle);

src/main/java/com/surrealdb/Native.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
package com.surrealdb;
22

3+
/**
4+
* Base for types backed by a native pointer. Instances are only valid for the
5+
* lifetime of the native resource (e.g. the parent {@link Value} or connection
6+
* they were obtained from). Using an instance after the underlying resource
7+
* has been released may cause undefined behavior or native errors.
8+
*/
39
public abstract class Native {
410

511
// Unique internal ptr used by the native library to locate the SurrealDB

src/main/java/com/surrealdb/Transaction.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ public class Transaction extends Native {
2323

2424
/**
2525
* Commits the transaction. After this call, the transaction is completed and
26-
* must not be used.
26+
* must not be used. On failure the native layer throws; the return value is
27+
* only true on success.
2728
*/
2829
public void commit() {
2930
commit(getPtr());
@@ -32,7 +33,8 @@ public void commit() {
3233

3334
/**
3435
* Cancels (rolls back) the transaction. After this call, the transaction is
35-
* completed and must not be used.
36+
* completed and must not be used. On failure the native layer throws; the
37+
* return value is only true on success.
3638
*/
3739
public void cancel() {
3840
cancel(getPtr());

src/main/java/com/surrealdb/signin/BearerCredential.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.surrealdb.signin;
22

3+
import java.util.Objects;
4+
35
/**
46
* Credential that authenticates the session with an existing access token (e.g.
57
* JWT). Use with {@link com.surrealdb.Surreal#signin(Credential)} to set the
@@ -13,10 +15,11 @@ public class BearerCredential implements Credential {
1315
* Creates a bearer credential with the given access token.
1416
*
1517
* @param token
16-
* the access token (JWT) to use for authentication
18+
* the access token (JWT) to use for authentication; must not be
19+
* null
1720
*/
1821
public BearerCredential(String token) {
19-
this.token = token;
22+
this.token = Objects.requireNonNull(token, "token");
2023
}
2124

2225
/**

src/main/java/com/surrealdb/signin/RecordCredential.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.surrealdb.signin;
22

3+
import java.util.Objects;
4+
35
/**
46
* Credentials for signing up or signing in as a record user (record access
57
* method). Used with {@link com.surrealdb.Surreal#signup(RecordCredential)} and
@@ -14,7 +16,8 @@
1416
* <p>
1517
* The params object is serialized and sent as the signup/signin variables (e.g.
1618
* email, password). It must be a type that can be converted to a SurrealDB
17-
* value (e.g. Map, POJO, or primitive).
19+
* value (e.g. Map, POJO, or primitive). May be null; null is sent as SurrealDB
20+
* null.
1821
*/
1922
public class RecordCredential implements Credential {
2023

@@ -39,7 +42,7 @@ public class RecordCredential implements Credential {
3942
public RecordCredential(String namespace, String database, String access, Object params) {
4043
this.namespace = namespace;
4144
this.database = database;
42-
this.access = access;
45+
this.access = Objects.requireNonNull(access, "access");
4346
this.params = params;
4447
}
4548

@@ -58,7 +61,7 @@ public RecordCredential(String namespace, String database, String access, Object
5861
public RecordCredential(String access, Object params) {
5962
this.namespace = null;
6063
this.database = null;
61-
this.access = access;
64+
this.access = Objects.requireNonNull(access, "access");
6265
this.params = params;
6366
}
6467

src/test/java/com/surrealdb/CredentialTests.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,16 @@ void signup_withRecordShortConstructor_hasNullNsDb() {
213213
assertEquals(Collections.singletonMap("a", 1), r.getParams());
214214
}
215215

216+
@Test
217+
void recordCredential_nullAccess_throws() {
218+
Throwable e1 = assertThrows(NullPointerException.class,
219+
() -> new RecordCredential("ns", "db", null, params("email", "a@b.com", "pass", "p")));
220+
assertNotNull(e1.getMessage());
221+
Throwable e2 = assertThrows(NullPointerException.class,
222+
() -> new RecordCredential(null, params("email", "a@b.com", "pass", "p")));
223+
assertNotNull(e2.getMessage());
224+
}
225+
216226
@Test
217227
void token_hasAccessAndOptionalRefresh() {
218228
Token t = new Token("access_jwt", null);
@@ -230,6 +240,12 @@ void bearer_holdsToken() {
230240
assertEquals("my_jwt", b.getToken());
231241
}
232242

243+
@Test
244+
void bearerCredential_nullToken_throws() {
245+
Throwable e = assertThrows(NullPointerException.class, () -> new BearerCredential(null));
246+
assertNotNull(e.getMessage());
247+
}
248+
233249
@Test
234250
void authenticate_returnsThis() {
235251
try (Surreal surreal = new Surreal()) {

src/test/java/com/surrealdb/ExportImportTests.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
import java.nio.file.Files;
44
import java.nio.file.Path;
5+
import java.nio.file.Paths;
56

67
import static org.junit.jupiter.api.Assertions.assertEquals;
8+
import static org.junit.jupiter.api.Assertions.assertFalse;
79
import static org.junit.jupiter.api.Assertions.assertTrue;
810
import org.junit.jupiter.api.Test;
911

@@ -37,4 +39,19 @@ void exportAndImportRoundTrip() throws Exception {
3739
Files.deleteIfExists(dir);
3840
}
3941
}
42+
43+
@Test
44+
void import_missingFile_returnsFalseOrThrows() {
45+
try (Surreal surreal = new Surreal()) {
46+
surreal.connect("memory").useNs("test").useDb("test");
47+
Path missing = Paths.get("nonexistent_" + System.nanoTime() + ".surql");
48+
try {
49+
boolean imported = surreal.import_(missing.toString());
50+
assertFalse(imported, "import of missing file should return false or throw");
51+
} catch (SurrealException e) {
52+
// expected when server throws instead of returning false
53+
assertTrue(e.getMessage() != null && !e.getMessage().isEmpty());
54+
}
55+
}
56+
}
4057
}

src/test/java/com/surrealdb/LiveQueryTests.java

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import static org.junit.jupiter.api.Assertions.assertNotNull;
77
import static org.junit.jupiter.api.Assertions.assertTrue;
8+
import org.junit.jupiter.api.Disabled;
89
import org.junit.jupiter.api.Test;
910

1011
import com.surrealdb.pojos.Person;
@@ -19,27 +20,28 @@ public class LiveQueryTests {
1920
void selectLiveReturnsLiveStream() {
2021
try (Surreal surreal = new Surreal()) {
2122
surreal.connect("memory").useNs("test").useDb("test");
22-
LiveStream stream = surreal.selectLive("person");
23-
assertNotNull(stream);
24-
stream.close();
23+
try (LiveStream stream = surreal.selectLive("person")) {
24+
assertNotNull(stream);
25+
}
2526
}
2627
}
2728

2829
@Test
2930
void liveStreamNextCanBlockAndClose() throws Exception {
31+
AtomicReference<Optional<LiveNotification>> result = new AtomicReference<>();
3032
try (Surreal surreal = new Surreal()) {
3133
surreal.connect("memory").useNs("test").useDb("test");
3234
surreal.create(Person.class, "person", Helpers.tobie);
33-
LiveStream stream = surreal.selectLive("person");
34-
assertNotNull(stream);
35-
// next() blocks until a notification or close; run in background and close
36-
// after short timeout
37-
AtomicReference<Optional<LiveNotification>> result = new AtomicReference<>();
38-
Thread consumer = new Thread(() -> result.set(stream.next()));
39-
consumer.setDaemon(true);
40-
consumer.start();
41-
Thread.sleep(500);
42-
stream.close();
35+
Thread consumer;
36+
try (LiveStream stream = surreal.selectLive("person")) {
37+
assertNotNull(stream);
38+
// next() blocks until a notification or close; run in background and close
39+
// after short timeout
40+
consumer = new Thread(() -> result.set(stream.next()));
41+
consumer.setDaemon(true);
42+
consumer.start();
43+
Thread.sleep(500);
44+
}
4345
consumer.join(2000);
4446
assertNotNull(result.get());
4547
}
@@ -49,11 +51,35 @@ void liveStreamNextCanBlockAndClose() throws Exception {
4951
void liveStreamCloseReleases() {
5052
try (Surreal surreal = new Surreal()) {
5153
surreal.connect("memory").useNs("test").useDb("test");
52-
LiveStream stream = surreal.selectLive("person");
53-
stream.close();
54-
// No exception; closing again or using after close is undefined but we don't
55-
// crash
54+
try (LiveStream stream = surreal.selectLive("person")) {
55+
// No exception; closing again or using after close is undefined but we don't
56+
// crash
57+
}
5658
assertTrue(true);
5759
}
5860
}
61+
62+
@Test
63+
void liveStreamTryWithResources() {
64+
try (Surreal surreal = new Surreal()) {
65+
surreal.connect("memory").useNs("test").useDb("test");
66+
try (LiveStream stream = surreal.selectLive("person")) {
67+
assertNotNull(stream);
68+
}
69+
// stream closed automatically; no leak
70+
}
71+
}
72+
73+
/**
74+
* Placeholder for future Surreal.kill(liveQueryId) support. The query ID is
75+
* available from {@link LiveNotification#getQueryId()}, but the Java client
76+
* does not yet expose kill(). Use {@link LiveStream#close()} to stop a live
77+
* query.
78+
*/
79+
@Test
80+
@Disabled("Surreal.kill(liveQueryId) not yet in Java API")
81+
void killLiveQuery_byQueryId() {
82+
// When kill(uuid) is added: start live query, get queryId from first
83+
// notification or API, call surreal.kill(queryId), assert stream ends.
84+
}
5985
}

0 commit comments

Comments
 (0)