From 66defb666980c14da4add9db4eeba18c5325e0f0 Mon Sep 17 00:00:00 2001 From: Sambo Chea Date: Sat, 7 Aug 2021 12:20:52 +0700 Subject: [PATCH] Task: A completed guide for graphql with query, mutation for user and acccount and with entity and relationships and configs and add schema.graphqls for user and account too in graphql demo --- build.gradle.kts | 1 + .../graphql/demo/config/GraphQLConfig.kt | 15 ++++++ .../graphql/demo/config/ManagementConfig.kt | 8 +++ .../graphql/demo/context/GMutation.kt | 12 +++++ .../graphql/demo/domain/AbstractEntity.kt | 3 ++ .../graphql/demo/domain/AbstractInput.kt | 5 ++ .../graphql/demo/domain/account/Account.kt | 38 ++++++++------ .../domain/account/AccountEntityListener.kt | 15 ++++++ .../demo/domain/account/AccountInput.kt | 7 +++ .../demo/domain/account/AccountMapper.kt | 10 ++++ .../cubetiqs/graphql/demo/domain/user/User.kt | 44 ++++++++++++---- .../demo/domain/user/UserEntityListener.kt | 11 ++++ .../graphql/demo/domain/user/UserInput.kt | 10 ++++ .../graphql/demo/domain/user/UserMapper.kt | 12 +++++ .../graphql/demo/mutation/AccountMutation.kt | 26 ++++++++++ .../graphql/demo/mutation/UserMutation.kt | 22 ++++++++ .../graphql/demo/query/AccountQuery.kt | 18 +++++++ .../cubetiqs/graphql/demo/query/UserQuery.kt | 18 +++++++ .../demo/repository/AccountRepository.kt | 8 +++ .../graphql/demo/repository/UserRepository.kt | 14 +++++ src/main/resources/application.yml | 8 ++- src/main/resources/schema.graphqls | 52 +++++++++++++++++++ 22 files changed, 331 insertions(+), 26 deletions(-) create mode 100644 src/main/kotlin/com/cubetiqs/graphql/demo/config/GraphQLConfig.kt create mode 100644 src/main/kotlin/com/cubetiqs/graphql/demo/config/ManagementConfig.kt create mode 100644 src/main/kotlin/com/cubetiqs/graphql/demo/context/GMutation.kt create mode 100644 src/main/kotlin/com/cubetiqs/graphql/demo/domain/AbstractInput.kt create mode 100644 src/main/kotlin/com/cubetiqs/graphql/demo/domain/account/AccountInput.kt create mode 100644 src/main/kotlin/com/cubetiqs/graphql/demo/domain/account/AccountMapper.kt create mode 100644 src/main/kotlin/com/cubetiqs/graphql/demo/domain/user/UserInput.kt create mode 100644 src/main/kotlin/com/cubetiqs/graphql/demo/domain/user/UserMapper.kt create mode 100644 src/main/kotlin/com/cubetiqs/graphql/demo/mutation/AccountMutation.kt create mode 100644 src/main/kotlin/com/cubetiqs/graphql/demo/mutation/UserMutation.kt create mode 100644 src/main/kotlin/com/cubetiqs/graphql/demo/query/AccountQuery.kt create mode 100644 src/main/kotlin/com/cubetiqs/graphql/demo/query/UserQuery.kt create mode 100644 src/main/kotlin/com/cubetiqs/graphql/demo/repository/AccountRepository.kt create mode 100644 src/main/kotlin/com/cubetiqs/graphql/demo/repository/UserRepository.kt diff --git a/build.gradle.kts b/build.gradle.kts index 1ddd3b4..2d2359f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -19,6 +19,7 @@ repositories { extra["graphqlVersion"] = "11.0.0" dependencies { + implementation("com.graphql-java:graphql-java-extended-scalars:16.0.0") implementation("com.graphql-java-kickstart:graphql-spring-boot-starter:${property("graphqlVersion")}") implementation("com.graphql-java-kickstart:playground-spring-boot-starter:${property("graphqlVersion")}") implementation("com.graphql-java-kickstart:voyager-spring-boot-starter:${property("graphqlVersion")}") diff --git a/src/main/kotlin/com/cubetiqs/graphql/demo/config/GraphQLConfig.kt b/src/main/kotlin/com/cubetiqs/graphql/demo/config/GraphQLConfig.kt new file mode 100644 index 0000000..de4c292 --- /dev/null +++ b/src/main/kotlin/com/cubetiqs/graphql/demo/config/GraphQLConfig.kt @@ -0,0 +1,15 @@ +package com.cubetiqs.graphql.demo.config + +import graphql.scalars.ExtendedScalars +import graphql.schema.idl.RuntimeWiring +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +@Configuration +class GraphQLConfig { + @Bean + fun extendsScalars(): RuntimeWiring.Builder { + return RuntimeWiring.newRuntimeWiring() + .scalar(ExtendedScalars.DateTime) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/graphql/demo/config/ManagementConfig.kt b/src/main/kotlin/com/cubetiqs/graphql/demo/config/ManagementConfig.kt new file mode 100644 index 0000000..02a3452 --- /dev/null +++ b/src/main/kotlin/com/cubetiqs/graphql/demo/config/ManagementConfig.kt @@ -0,0 +1,8 @@ +package com.cubetiqs.graphql.demo.config + +import org.springframework.context.annotation.Configuration +import org.springframework.transaction.annotation.EnableTransactionManagement + +@Configuration +@EnableTransactionManagement +class ManagementConfig \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/graphql/demo/context/GMutation.kt b/src/main/kotlin/com/cubetiqs/graphql/demo/context/GMutation.kt new file mode 100644 index 0000000..d81e9da --- /dev/null +++ b/src/main/kotlin/com/cubetiqs/graphql/demo/context/GMutation.kt @@ -0,0 +1,12 @@ +package com.cubetiqs.graphql.demo.context + +import org.springframework.core.annotation.AliasFor +import org.springframework.stereotype.Component + +@Retention(AnnotationRetention.RUNTIME) +@Target(AnnotationTarget.CLASS) +@Component +annotation class GMutation( + @get:AliasFor(annotation = Component::class) + val value: String = "", +) diff --git a/src/main/kotlin/com/cubetiqs/graphql/demo/domain/AbstractEntity.kt b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/AbstractEntity.kt index c4cdf05..2e437f5 100644 --- a/src/main/kotlin/com/cubetiqs/graphql/demo/domain/AbstractEntity.kt +++ b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/AbstractEntity.kt @@ -1,7 +1,10 @@ package com.cubetiqs.graphql.demo.domain +import org.springframework.data.jpa.domain.support.AuditingEntityListener import java.io.Serializable +import javax.persistence.EntityListeners import javax.persistence.MappedSuperclass @MappedSuperclass +@EntityListeners(AuditingEntityListener::class) abstract class AbstractEntity : Serializable \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/graphql/demo/domain/AbstractInput.kt b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/AbstractInput.kt new file mode 100644 index 0000000..4da096a --- /dev/null +++ b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/AbstractInput.kt @@ -0,0 +1,5 @@ +package com.cubetiqs.graphql.demo.domain + +import java.io.Serializable + +abstract class AbstractInput : Serializable \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/graphql/demo/domain/account/Account.kt b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/account/Account.kt index fbd798f..ad73039 100644 --- a/src/main/kotlin/com/cubetiqs/graphql/demo/domain/account/Account.kt +++ b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/account/Account.kt @@ -1,6 +1,8 @@ package com.cubetiqs.graphql.demo.domain.account import com.cubetiqs.graphql.demo.domain.AbstractEntity +import com.cubetiqs.graphql.demo.domain.user.User +import com.fasterxml.jackson.annotation.JsonBackReference import org.hibernate.Hibernate import org.springframework.data.annotation.CreatedDate import org.springframework.data.annotation.LastModifiedDate @@ -9,41 +11,47 @@ import java.util.* import javax.persistence.* @Entity -@Table( - name = "accounts", indexes = [ - Index(name = "idx_account_id", columnList = "id") - ] -) -@EntityListeners(AccountEntityListener::class) +@Table(name = "accounts", indexes = [ + Index(name = "idx_account_code", columnList = "code") +]) +@EntityListeners(value = [AccountEntityListener::class]) open class Account( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - var id: Long? = null, + open var id: Long? = null, + + @Column(length = 9) + open var code: String? = null, @Column - var balance: BigDecimal = BigDecimal.ZERO, + open var balance: BigDecimal = BigDecimal.ZERO, @Column - var currentBalance: BigDecimal = BigDecimal.ZERO, + open var currentBalance: BigDecimal = BigDecimal.ZERO, @Column(length = 10) @Enumerated(EnumType.STRING) - var accountType: AccountType = AccountType.BASIC, + open var type: AccountType = AccountType.BASIC, @Column(length = 3) @Enumerated(EnumType.STRING) - var currency: AccountCurrency = AccountCurrency.USD, + open var currency: AccountCurrency = AccountCurrency.USD, @Version - var version: Long? = null, + open var version: Long? = null, @CreatedDate @Temporal(TemporalType.TIMESTAMP) - var createdDate: Date? = null, + open var createdDate: Date? = null, @LastModifiedDate @Temporal(TemporalType.TIMESTAMP) - var updatedDate: Date? = null, + open var updatedDate: Date? = null, + + @JsonBackReference + @ManyToOne(fetch = FetchType.LAZY,cascade = [CascadeType.REFRESH, CascadeType.DETACH]) + @JoinColumn(name = "user_id") + open var user: User? = null, ) : AbstractEntity() { override fun equals(other: Any?): Boolean { if (this === other) return true @@ -57,6 +65,6 @@ open class Account( @Override override fun toString(): String { - return this::class.simpleName + "(id = $id , balance = $balance , currentBalance = $currentBalance , accountType = $accountType , currency = $currency , version = $version , createdDate = $createdDate , updatedDate = $updatedDate )" + return this::class.simpleName + "(id = $id , balance = $balance , currentBalance = $currentBalance , type = $type , currency = $currency , version = $version , createdDate = $createdDate , updatedDate = $updatedDate , user = ${user?.id} )" } } \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/graphql/demo/domain/account/AccountEntityListener.kt b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/account/AccountEntityListener.kt index 855442b..89b82af 100644 --- a/src/main/kotlin/com/cubetiqs/graphql/demo/domain/account/AccountEntityListener.kt +++ b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/account/AccountEntityListener.kt @@ -1,10 +1,25 @@ package com.cubetiqs.graphql.demo.domain.account +import java.util.* +import javax.persistence.PostPersist import javax.persistence.PrePersist +import javax.persistence.PreUpdate class AccountEntityListener { @PrePersist fun beforeSave(account: Account) { + if (account.createdDate == null) { + account.createdDate = Date() + } + } + @PreUpdate + fun beforeUpdate(account: Account) { + account.updatedDate = Date() + } + + @PostPersist + fun afterSaved(account: Account) { + account.code = account.id.toString().padStart(9, '0') } } \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/graphql/demo/domain/account/AccountInput.kt b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/account/AccountInput.kt new file mode 100644 index 0000000..d629007 --- /dev/null +++ b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/account/AccountInput.kt @@ -0,0 +1,7 @@ +package com.cubetiqs.graphql.demo.domain.account + +data class AccountInput( + var userId: Long? = null, + var type: AccountType? = null, + var currency: AccountCurrency? = null, +) \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/graphql/demo/domain/account/AccountMapper.kt b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/account/AccountMapper.kt new file mode 100644 index 0000000..951d9d0 --- /dev/null +++ b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/account/AccountMapper.kt @@ -0,0 +1,10 @@ +package com.cubetiqs.graphql.demo.domain.account + +object AccountMapper { + fun fromInputToAccount(input: AccountInput): Account { + return Account( + type = input.type ?: AccountType.BASIC, + currency = input.currency ?: AccountCurrency.USD, + ) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/graphql/demo/domain/user/User.kt b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/user/User.kt index 74ba91e..dd74a9c 100644 --- a/src/main/kotlin/com/cubetiqs/graphql/demo/domain/user/User.kt +++ b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/user/User.kt @@ -1,6 +1,9 @@ package com.cubetiqs.graphql.demo.domain.user import com.cubetiqs.graphql.demo.domain.AbstractEntity +import com.cubetiqs.graphql.demo.domain.account.Account +import com.fasterxml.jackson.annotation.JsonManagedReference +import org.hibernate.Hibernate import org.springframework.data.annotation.CreatedDate import org.springframework.data.annotation.LastModifiedDate import java.util.* @@ -9,43 +12,64 @@ import javax.persistence.* @Entity @Table( name = "users", indexes = [ - Index(name = "idx_user_id", columnList = "id"), Index(name = "idx_user_code", columnList = "code"), Index(name = "idx_user_username", columnList = "username"), ] ) -@EntityListeners(UserEntityListener::class) +@EntityListeners(value = [UserEntityListener::class]) open class User( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - var id: Long? = null, + open var id: Long? = null, @Column(unique = true, length = 65, nullable = false) - var code: String? = null, + open var code: String? = null, @Column(unique = true, length = 35, nullable = false) - var username: String? = null, + open var username: String? = null, @Column(length = 100) - var password: String? = null, + open var password: String? = null, @Column(length = 50) - var name: String? = null, + open var name: String? = null, @Version - var version: Long? = null, + open var version: Long? = null, @CreatedDate @Temporal(TemporalType.TIMESTAMP) - var createdDate: Date? = null, + open var createdDate: Date? = null, @LastModifiedDate @Temporal(TemporalType.TIMESTAMP) - var updatedDate: Date? = null, + open var updatedDate: Date? = null, + + @JsonManagedReference + @OneToMany(fetch = FetchType.LAZY,mappedBy = "user", cascade = [CascadeType.ALL], orphanRemoval = true) + open var accounts: MutableSet = mutableSetOf(), + + @Basic + open var enabled: Boolean = true, ) : AbstractEntity() { @Transient fun updatePassword(newPassword: String) { // hash it here this.password = newPassword } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (other == null || Hibernate.getClass(this) != Hibernate.getClass(other)) return false + other as User + + return id != null && id == other.id + } + + override fun hashCode(): Int = 562048007 + + @Override + override fun toString(): String { + return this::class.simpleName + "(id = $id , code = $code , username = $username , password = $password , name = $name , version = $version , createdDate = $createdDate , updatedDate = $updatedDate , enabled = $enabled )" + } } \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/graphql/demo/domain/user/UserEntityListener.kt b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/user/UserEntityListener.kt index b69a723..b68ebbe 100644 --- a/src/main/kotlin/com/cubetiqs/graphql/demo/domain/user/UserEntityListener.kt +++ b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/user/UserEntityListener.kt @@ -2,10 +2,21 @@ package com.cubetiqs.graphql.demo.domain.user import java.util.* import javax.persistence.PrePersist +import javax.persistence.PreUpdate class UserEntityListener { @PrePersist fun beforeSave(user: User) { + user.id = null user.code = UUID.randomUUID().toString() + + if (user.createdDate == null) { + user.createdDate = Date() + } + } + + @PreUpdate + fun beforeUpdate(user: User) { + user.updatedDate = Date() } } \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/graphql/demo/domain/user/UserInput.kt b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/user/UserInput.kt new file mode 100644 index 0000000..b57db35 --- /dev/null +++ b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/user/UserInput.kt @@ -0,0 +1,10 @@ +package com.cubetiqs.graphql.demo.domain.user + +import com.cubetiqs.graphql.demo.domain.AbstractInput + +data class UserInput( + val username: String? = null, + val password: String? = null, + val name: String? = null, + val enabled: Boolean? = null, +) : AbstractInput() \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/graphql/demo/domain/user/UserMapper.kt b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/user/UserMapper.kt new file mode 100644 index 0000000..5cfb016 --- /dev/null +++ b/src/main/kotlin/com/cubetiqs/graphql/demo/domain/user/UserMapper.kt @@ -0,0 +1,12 @@ +package com.cubetiqs.graphql.demo.domain.user + +object UserMapper { + fun fromInputToUser(input: UserInput): User { + return User( + username = input.username, + password = input.password, + name = input.name, + enabled = input.enabled ?: true, + ) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/graphql/demo/mutation/AccountMutation.kt b/src/main/kotlin/com/cubetiqs/graphql/demo/mutation/AccountMutation.kt new file mode 100644 index 0000000..a4497fc --- /dev/null +++ b/src/main/kotlin/com/cubetiqs/graphql/demo/mutation/AccountMutation.kt @@ -0,0 +1,26 @@ +package com.cubetiqs.graphql.demo.mutation + +import com.cubetiqs.graphql.demo.context.GMutation +import com.cubetiqs.graphql.demo.domain.account.Account +import com.cubetiqs.graphql.demo.domain.account.AccountInput +import com.cubetiqs.graphql.demo.domain.account.AccountMapper +import com.cubetiqs.graphql.demo.repository.AccountRepository +import com.cubetiqs.graphql.demo.repository.UserRepository +import graphql.kickstart.tools.GraphQLMutationResolver +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.transaction.annotation.Propagation +import org.springframework.transaction.annotation.Transactional + +@GMutation +class AccountMutation @Autowired constructor( + private val accountRepository: AccountRepository, + private val userRepository: UserRepository, +) : GraphQLMutationResolver { + @Transactional(propagation = Propagation.REQUIRES_NEW) + fun openAccount(input: AccountInput): Account { + val account = AccountMapper.fromInputToAccount(input) + val user = userRepository.findById(input.userId ?: 0).orElse(null) ?: throw Exception("User not found to open an account!") + account.user = user + return accountRepository.save(account) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/graphql/demo/mutation/UserMutation.kt b/src/main/kotlin/com/cubetiqs/graphql/demo/mutation/UserMutation.kt new file mode 100644 index 0000000..d340a7d --- /dev/null +++ b/src/main/kotlin/com/cubetiqs/graphql/demo/mutation/UserMutation.kt @@ -0,0 +1,22 @@ +package com.cubetiqs.graphql.demo.mutation + +import com.cubetiqs.graphql.demo.context.GMutation +import com.cubetiqs.graphql.demo.domain.user.User +import com.cubetiqs.graphql.demo.domain.user.UserInput +import com.cubetiqs.graphql.demo.domain.user.UserMapper +import com.cubetiqs.graphql.demo.repository.UserRepository +import graphql.kickstart.tools.GraphQLMutationResolver +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.transaction.annotation.Propagation +import org.springframework.transaction.annotation.Transactional + +@GMutation +class UserMutation @Autowired constructor( + private val userRepository: UserRepository, +) : GraphQLMutationResolver { + @Transactional(propagation = Propagation.REQUIRES_NEW) + fun createUser(input: UserInput): User { + val user = UserMapper.fromInputToUser(input) + return userRepository.save(user) + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/graphql/demo/query/AccountQuery.kt b/src/main/kotlin/com/cubetiqs/graphql/demo/query/AccountQuery.kt new file mode 100644 index 0000000..767c907 --- /dev/null +++ b/src/main/kotlin/com/cubetiqs/graphql/demo/query/AccountQuery.kt @@ -0,0 +1,18 @@ +package com.cubetiqs.graphql.demo.query + +import com.cubetiqs.graphql.demo.context.GQuery +import com.cubetiqs.graphql.demo.domain.account.Account +import com.cubetiqs.graphql.demo.repository.AccountRepository +import graphql.kickstart.tools.GraphQLQueryResolver +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Pageable + +@GQuery +class AccountQuery @Autowired constructor( + private val accountRepository: AccountRepository, +) : GraphQLQueryResolver { + fun fetchAccounts(): Collection { + val accounts = accountRepository.findAll(Pageable.unpaged()) + return accounts.content + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/graphql/demo/query/UserQuery.kt b/src/main/kotlin/com/cubetiqs/graphql/demo/query/UserQuery.kt new file mode 100644 index 0000000..9e1db81 --- /dev/null +++ b/src/main/kotlin/com/cubetiqs/graphql/demo/query/UserQuery.kt @@ -0,0 +1,18 @@ +package com.cubetiqs.graphql.demo.query + +import com.cubetiqs.graphql.demo.context.GQuery +import com.cubetiqs.graphql.demo.domain.user.User +import com.cubetiqs.graphql.demo.repository.UserRepository +import graphql.kickstart.tools.GraphQLQueryResolver +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.data.domain.Pageable + +@GQuery +class UserQuery @Autowired constructor( + private val userRepository: UserRepository, +) : GraphQLQueryResolver { + fun fetchUsers(): Collection { + val users = userRepository.queryAllByEnabledIsTrue(Pageable.unpaged()) + return users.content + } +} \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/graphql/demo/repository/AccountRepository.kt b/src/main/kotlin/com/cubetiqs/graphql/demo/repository/AccountRepository.kt new file mode 100644 index 0000000..7c6cbb8 --- /dev/null +++ b/src/main/kotlin/com/cubetiqs/graphql/demo/repository/AccountRepository.kt @@ -0,0 +1,8 @@ +package com.cubetiqs.graphql.demo.repository + +import com.cubetiqs.graphql.demo.domain.account.Account +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository + +@Repository +interface AccountRepository : JpaRepository \ No newline at end of file diff --git a/src/main/kotlin/com/cubetiqs/graphql/demo/repository/UserRepository.kt b/src/main/kotlin/com/cubetiqs/graphql/demo/repository/UserRepository.kt new file mode 100644 index 0000000..80678a8 --- /dev/null +++ b/src/main/kotlin/com/cubetiqs/graphql/demo/repository/UserRepository.kt @@ -0,0 +1,14 @@ +package com.cubetiqs.graphql.demo.repository + +import com.cubetiqs.graphql.demo.domain.user.User +import org.springframework.data.domain.Page +import org.springframework.data.domain.Pageable +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.stereotype.Repository + +@Repository +interface UserRepository : JpaRepository { + @Query("select u from User u where u.enabled = true") + fun queryAllByEnabledIsTrue(pageable: Pageable): Page +} \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index e3adbc4..f0f9dff 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -9,8 +9,14 @@ spring: password: ${DB_PASSWORD:your-password} driver-class-name: org.postgresql.Driver jpa: + database: postgresql + database-platform: org.hibernate.dialect.PostgreSQLDialect hibernate: - ddl-auto: update + ddl-auto: ${HIBERNATE_DDL:update} + show-sql: ${JPA_SHOW_SQL:true} + properties: + hibernate: + enable_lazy_load_no_trans: ${HIBERNATE_LAZY_NO_TRANS:true} # Spring Boot Actuator management: diff --git a/src/main/resources/schema.graphqls b/src/main/resources/schema.graphqls index 216c610..7f489f3 100644 --- a/src/main/resources/schema.graphqls +++ b/src/main/resources/schema.graphqls @@ -1,7 +1,59 @@ +enum AccountType { + BASIC + PREMIUM + BUSINESS +} + +enum AccountCurrency { + USD + KHR +} + +type User { + id: ID + code: String + username: String + name: String + enabled: Boolean +} + +type Account { + id: ID + code: String + balance: Float + currentBalance: Float + type: AccountType + currency: AccountCurrency + user: User! +} + +input UserInput { + username: String + password: String + name: String + enabled: Boolean +} + +input AccountInput { + userId: Int + type: AccountType + currency: AccountCurrency +} + type Query { hello: String + + fetchUsers: [User]! + + fetchAccounts: [Account]! } type Subscription { hello: Int +} + +type Mutation { + createUser(input: UserInput): User! + + openAccount(input: AccountInput): Account! } \ No newline at end of file