Skip to content

Commit a9502fe

Browse files
committed
Merge branch 'dev-temp' of github.com:lowcoder-org/lowcoder into fix/new-arch
2 parents 4d53662 + 2bfbf52 commit a9502fe

4 files changed

Lines changed: 85 additions & 3 deletions

File tree

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/query/view/LibraryQueryMetaView.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,15 @@ public record LibraryQueryMetaView(String id,
1212
String creatorName) {
1313

1414
public static LibraryQueryMetaView from(LibraryQuery libraryQuery, User user) {
15+
// Null-safe creator: a library query whose createdBy no longer resolves to a User (deleted user, or
16+
// deployed cross-environment) must not NPE the whole list. Mirrors DatasourceApiServiceImpl /
17+
// FolderApiServiceImpl (creator == null ? null : creator.getName()).
1518
return new LibraryQueryMetaView(libraryQuery.getId(),
1619
libraryQuery.getGid(),
1720
libraryQuery.getQuery().getCompType(),
1821
libraryQuery.getOrganizationId(),
1922
libraryQuery.getName(),
2023
libraryQuery.getCreatedAt().toEpochMilli(),
21-
user.getName());
24+
user == null ? null : user.getName());
2225
}
2326
}

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/query/view/LibraryQueryRecordMetaView.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ public static LibraryQueryRecordMetaView from(LibraryQueryRecord libraryQueryRec
2828
libraryQueryRecord.getTag(),
2929
libraryQueryRecord.getCommitMessage(),
3030
libraryQueryRecord.getCreatedAt().toEpochMilli(),
31-
libraryQueryRecordCreator.getName());
31+
// Null-safe creator (see LibraryQueryMetaView): tolerate an unresolved createdBy.
32+
libraryQueryRecordCreator == null ? null : libraryQueryRecordCreator.getName());
3233
}
3334
}

server/api-service/lowcoder-server/src/main/java/org/lowcoder/api/query/view/LibraryQueryView.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ public static LibraryQueryView from(LibraryQuery libraryQuery, User user) {
2020
libraryQuery.getName(),
2121
libraryQuery.getLibraryQueryDSL(),
2222
libraryQuery.getCreatedAt().toEpochMilli(),
23-
user.getName());
23+
// Null-safe creator (see LibraryQueryMetaView): tolerate an unresolved createdBy.
24+
user == null ? null : user.getName());
2425
}
2526
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package org.lowcoder.api.query.view;
2+
3+
import static org.assertj.core.api.Assertions.assertThat;
4+
import static org.assertj.core.api.Assertions.assertThatCode;
5+
6+
import java.time.Instant;
7+
import java.util.List;
8+
import java.util.Map;
9+
10+
import org.junit.jupiter.api.Test;
11+
import org.lowcoder.domain.query.model.LibraryQuery;
12+
import org.lowcoder.domain.query.model.LibraryQueryRecord;
13+
import org.lowcoder.domain.user.model.User;
14+
15+
/**
16+
* Unit tests that the Query Library view factories tolerate an unresolved creator (a {@code null} User)
17+
* instead of NPEing. This is the crash that 500'd {@code GET /api/library-queries/dropDownList} for a
18+
* cross-environment-deployed library query whose {@code createdBy} has no matching {@code User} on the
19+
* target -- one such row would take down the whole list. The integration test
20+
* {@link org.lowcoder.api.query.LibraryQueryApiServiceIntegrationTest} is {@code @Disabled}, so these guard
21+
* the leaf factories directly.
22+
*/
23+
class LibraryQueryMetaViewTest {
24+
25+
private static LibraryQuery libraryQuery() {
26+
return LibraryQuery.builder()
27+
.id("lq1")
28+
.gid("gid1")
29+
.organizationId("org1")
30+
.name("qryX")
31+
.libraryQueryDSL(Map.of("query", Map.of("compType", "js")))
32+
.createdAt(Instant.EPOCH)
33+
.build();
34+
}
35+
36+
@Test
37+
void metaViewFromNullUserYieldsNullCreatorName() {
38+
LibraryQueryMetaView view = LibraryQueryMetaView.from(libraryQuery(), null);
39+
assertThat(view.creatorName()).isNull();
40+
assertThat(view.name()).isEqualTo("qryX");
41+
}
42+
43+
@Test
44+
void libraryQueryViewFromNullUserYieldsNullCreatorName() {
45+
LibraryQueryView view = LibraryQueryView.from(libraryQuery(), null);
46+
assertThat(view.creatorName()).isNull();
47+
assertThat(view.name()).isEqualTo("qryX");
48+
}
49+
50+
@Test
51+
void recordMetaViewFromNullCreatorYieldsNullCreatorName() {
52+
LibraryQueryRecord record = LibraryQueryRecord.builder()
53+
.id("rec1")
54+
.libraryQueryId("lq1")
55+
.tag("v1.0.0")
56+
.commitMessage("msg")
57+
.libraryQueryDSL(Map.of("query", Map.of("compType", "js")))
58+
.createdAt(Instant.EPOCH)
59+
.build();
60+
LibraryQueryRecordMetaView view = LibraryQueryRecordMetaView.from(record, (User) null);
61+
assertThat(view.creatorName()).isNull();
62+
assertThat(view.tag()).isEqualTo("v1.0.0");
63+
}
64+
65+
@Test
66+
void aggregateViewFromNullCreatorDoesNotThrow() {
67+
// dropDownList builds LibraryQueryAggregateView with a possibly-null creator via both overloads.
68+
assertThatCode(() -> {
69+
LibraryQueryAggregateView noRecords = LibraryQueryAggregateView.from(libraryQuery(), null);
70+
assertThat(noRecords.libraryQueryMetaView().creatorName()).isNull();
71+
72+
LibraryQueryAggregateView withRecords =
73+
LibraryQueryAggregateView.from(libraryQuery(), null, List.<LibraryQueryRecord>of());
74+
assertThat(withRecords.libraryQueryMetaView().creatorName()).isNull();
75+
}).doesNotThrowAnyException();
76+
}
77+
}

0 commit comments

Comments
 (0)