Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ISSUE-776] add selectFrom spec #777

Open
wants to merge 3 commits into
base: develop
Choose a base branch
from
Open
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
71 changes: 71 additions & 0 deletions docs/en/jpql-with-kotlin-jdsl/statements.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,77 @@ from(
)
```

### Select From clause

Use `selectFrom()` and pass [Entity](entities.md) and [Join](statements.md#Join-For-SelectFrom) to specify the entities for selection.
In the `selectFrom()` function you can create the select and from clause at once.
'SelectFrom()' has the same effect as calling the existing 'select()' and 'from()', respectively.

```kotlin
// selectFrom stmt
selectFrom(entity(Author::class))

// select and from stms
select(
entity(Author::class)
).from(
entity(Employee::class)
)
```

#### Join For SelectFrom

It is the same as [Join](statements.md#Join) above.

```kotlin
@Entity
// ...
class Book(
// ...

@OneToMany(mappedBy = "book", cascade = [CascadeType.ALL], orphanRemoval = true)
val authors: MutableSet<BookAuthor>,
)

@Entity
// ...
class BookAuthor(
@Id
@Column(name = "author_id")
val authorId: Long,
) {
@Id
@ManyToOne
@JoinColumn(name = "isbn")
lateinit var book: Book
}

@Entity
// ...
class Author(
@Id
@Column(name = "author_id")
val authorId: Long,

// ...
)

selectFrom(
entity(Book::class),
join(Book::authors), // Association Join
join(Author::class).on(path(BookAuthor::authorId).eq(path(Author::authorId))), // Join
)
```

Calling 'as()' after 'join()' can also achieve the same result as [Join](statements.md#Join)

```kotlin
selectFrom(
entity(Book::class),
join(Book::authors).`as`(entity(BookAuthor::class, "author")),
)
```

### Where clause

Use `where()` and pass [Predicate](predicates.md) to restrict the data when building a where clause in the select statement.
Expand Down
71 changes: 71 additions & 0 deletions docs/ko/jpql-with-kotlin-jdsl/statements.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,77 @@ from(
)
```

### Select From clause

select statement의 select clause와 from clause를 한 번에 만들기 위해, `selectFrom()`을 이용할 수 있습니다.
`selectFrom()`은 [Entity](entities.md)와 [Join](statements.md#Join-For-SelectFrom)을 파라미터로 받아 어떤 entity를 통해 조회가 되는지 표현합니다.
`selectFrom()`은 기존의 `select()`, `from()`을 각각 호출하는 것과 동일한 효과를 가져옵니다.

```kotlin
// selectFrom stmt
selectFrom(entity(Author::class))

// select and from stms
select(
entity(Author::class)
).from(
entity(Employee::class)
)
```

#### Join For SelectFrom

위의 [Join](statements.md#Join)과 동일한 역할을 합니다.

```kotlin
@Entity
// ...
class Book(
// ...

@OneToMany(mappedBy = "book", cascade = [CascadeType.ALL], orphanRemoval = true)
val authors: MutableSet<BookAuthor>,
)

@Entity
// ...
class BookAuthor(
@Id
@Column(name = "author_id")
val authorId: Long,
) {
@Id
@ManyToOne
@JoinColumn(name = "isbn")
lateinit var book: Book
}

@Entity
// ...
class Author(
@Id
@Column(name = "author_id")
val authorId: Long,

// ...
)

selectFrom(
entity(Book::class),
join(Book::authors), // Association Join
join(Author::class).on(path(BookAuthor::authorId).eq(path(Author::authorId))), // Join
)
```

`join()` 이후에 `as()`를 호출하 것 또한 [Join](statements.md#Join)와 동일한 결과를 얻을 수 있습니다.

```kotlin
selectFrom(
entity(Book::class),
join(Book::authors).`as`(entity(BookAuthor::class, "author")),
)
```

### Where clause

select statement의 where clause를 만들기 위해, `where()`를 사용할 수 있습니다.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import com.linecorp.kotlinjdsl.dsl.jpql.join.impl.AssociationJoinDsl
import com.linecorp.kotlinjdsl.dsl.jpql.join.impl.FetchJoinDsl
import com.linecorp.kotlinjdsl.dsl.jpql.join.impl.JoinDsl
import com.linecorp.kotlinjdsl.dsl.jpql.select.SelectQueryFromStep
import com.linecorp.kotlinjdsl.dsl.jpql.select.SelectQueryWhereStep
import com.linecorp.kotlinjdsl.dsl.jpql.select.impl.SelectQueryFromStepDsl
import com.linecorp.kotlinjdsl.dsl.jpql.sort.SortNullsStep
import com.linecorp.kotlinjdsl.dsl.jpql.sort.impl.SortDsl
Expand All @@ -33,6 +34,7 @@ import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expression
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressionable
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Expressions
import com.linecorp.kotlinjdsl.querymodel.jpql.expression.Subquery
import com.linecorp.kotlinjdsl.querymodel.jpql.from.Fromable
import com.linecorp.kotlinjdsl.querymodel.jpql.join.JoinType
import com.linecorp.kotlinjdsl.querymodel.jpql.path.Path
import com.linecorp.kotlinjdsl.querymodel.jpql.path.Pathable
Expand Down Expand Up @@ -3119,6 +3121,18 @@ open class Jpql : JpqlDsl {
)
}

/**
* Creates a select clause in a select from query.
*/
@SinceJdsl("3.5.3")
inline fun <reified T : Any> selectFrom(
expr: Entityable<T>,
vararg froms: Fromable?,
): SelectQueryWhereStep<T> {
return select(expr)
.from(expr, *froms)
}

/**
* Creates a select clause in a select query.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,4 +88,59 @@ class FromDslTest : WithAssertions {

assertThat(actual).isEqualTo(expected)
}

@Test
fun `selectFrom() with entity`() {
// when
val selectFrom = queryPart {
selectFrom(
entity1,
)
}.toQuery()
val actual: SelectQuery<Book> = selectFrom

// then
val expected = SelectQueries.selectQuery(
returnType = Book::class,
distinct = false,
select = listOf(entity1),
from = listOf(
entity1,
),
)

assertThat(actual).isEqualTo(expected)
}

@Test
fun `selectFrom() with froms`() {
// when
val selectFrom = queryPart {
selectFrom(
entity1,
null,
entity2,
null,
join1,
null,
join2,
)
}.toQuery()
val actual: SelectQuery<Book> = selectFrom

// then
val expected = SelectQueries.selectQuery(
returnType = Book::class,
distinct = false,
select = listOf(entity1),
from = listOf(
entity1,
entity2,
join1,
join2,
),
)

assertThat(actual).isEqualTo(expected)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,26 @@ class SelectExample : WithAssertions {
assertThat(actual).isEqualTo(listOf(4L))
}

@Test
fun `authors who haven't written a book with selectFrom`() {
// when
val query = jpql {
selectFrom(
entity(Author::class),
leftJoin(BookAuthor::class).on(path(Author::authorId).equal(path(BookAuthor::authorId))),
).where(
path(BookAuthor::authorId).isNull(),
).orderBy(
path(Author::authorId).asc(),
)
}

val actual = entityManager.createQuery(query, context).resultList

// then
assertThat(actual.map { it.authorId }).isEqualTo(listOf(4L))
}

@Test
fun `the book with the most authors`() {
// when
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,26 @@ class SelectExample : WithAssertions {
assertThat(actual).isEqualTo(listOf(4L))
}

@Test
fun `authors who haven't written a book with selectFrom`() {
// when
val query = jpql {
selectFrom(
entity(Author::class),
leftJoin(BookAuthor::class).on(path(Author::authorId).equal(path(BookAuthor::authorId))),
).where(
path(BookAuthor::authorId).isNull(),
).orderBy(
path(Author::authorId).asc(),
)
}

val actual = entityManager.createQuery(query, context).resultList

// then
assertThat(actual.map { it.authorId }).isEqualTo(listOf(4L))
}

@Test
fun `the book with the most authors`() {
// when
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,26 @@ class SelectExample : WithAssertions {
assertThat(actual).isEqualTo(listOf(4L))
}

@Test
fun `authors who haven't written a book with selectFrom`() {
// when
val query = jpql {
selectFrom(
entity(Author::class),
leftJoin(BookAuthor::class).on(path(Author::authorId).equal(path(BookAuthor::authorId))),
).where(
path(BookAuthor::authorId).isNull(),
).orderBy(
path(Author::authorId).asc(),
)
}

val actual = entityManager.createQuery(query, context).resultList

// then
assertThat(actual.map { it.authorId }).isEqualTo(listOf(4L))
}

@Test
fun books() {
// when
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,28 @@ class SelectMutinySessionExample : WithAssertions {
assertThat(actual).isEqualTo(listOf(4L))
}

@Test
fun `authors who haven't written a book with selectFrom`() {
// when
val query = jpql {
selectFrom(
entity(Author::class),
leftJoin(BookAuthor::class).on(path(Author::authorId).equal(path(BookAuthor::authorId))),
).where(
path(BookAuthor::authorId).isNull(),
).orderBy(
path(Author::authorId).asc(),
)
}

val actual = sessionFactory.withSession {
it.createQuery(query, context).resultList
}.await().indefinitely()

// then
assertThat(actual.map { it.authorId }).isEqualTo(listOf(4L))
}

@Test
fun `the book with the most authors`() {
// when
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,28 @@ class SelectMutinyStatelessSessionExample : WithAssertions {
assertThat(actual).isEqualTo(listOf(4L))
}

@Test
fun `authors who haven't written a book with selectFrom`() {
// when
val query = jpql {
selectFrom(
entity(Author::class),
leftJoin(BookAuthor::class).on(path(Author::authorId).equal(path(BookAuthor::authorId))),
).where(
path(BookAuthor::authorId).isNull(),
).orderBy(
path(Author::authorId).asc(),
)
}

val actual = sessionFactory.withStatelessSession {
it.createQuery(query, context).resultList
}.await().indefinitely()

// then
assertThat(actual.map { it.authorId }).isEqualTo(listOf(4L))
}

@Test
fun `the book with the most authors`() {
// when
Expand Down
Loading
Loading