Универсальный сервис для CRUD-запросов в KtorAndroid

Форум для тех, кто программирует под Android
Ответить
Anonymous
 Универсальный сервис для CRUD-запросов в Ktor

Сообщение Anonymous »

Я создал новый проект Ktor, в котором можно найти файл UsersSchema.kt.

Код: Выделить всё

@Serializable
data class ExposedUser(val name: String, val age: Int)

class UserService(database: Database) {
object Users : Table() {
val id = integer("id").autoIncrement()
val name = varchar("name", length = 50)
val age = integer("age")

override val primaryKey = PrimaryKey(id)
}

init {
transaction(database) {
SchemaUtils.create(Users)
}
}

suspend fun create(user: ExposedUser): Int = dbQuery {
Users.insert {
it[name] = user.name
it[age] = user.age
}[Users.id]
}

suspend fun read(id: Int): ExposedUser? {
return dbQuery {
Users.selectAll()
.where { Users.id eq id }
.map { ExposedUser(it[Users.name], it[Users.age]) }
.singleOrNull()
}
}

suspend fun update(id: Int, user: ExposedUser) {
dbQuery {
Users.update({ Users.id eq id }) {
it[name] = user.name
it[age] = user.age
}
}
}

suspend fun delete(id: Int) {
dbQuery {
Users.deleteWhere { Users.id.eq(id) }
}
}

private suspend fun  dbQuery(block: suspend () -> T): T =
newSuspendedTransaction(Dispatchers.IO) { block() }
}
На основе этого примера я создал файл CategorySchema.kt.

Код: Выделить всё

@Serializable
data class Category(
val id: String,
val name: String,
val image: String?,
val slug: String,
)

class CategoryService(database: Database) {
object CategoryTable: Table("\"Category\"") {
val id = varchar("id", 36).uniqueIndex()
val name = varchar("name", 50).uniqueIndex()
val image = text("image").nullable()
val slug = varchar("slug", 50).uniqueIndex()
val createdAt = datetime("createdAt")
val updatedAt = datetime("updatedAt")

override val primaryKey = PrimaryKey(id)
}

init {
transaction(database) {
SchemaUtils.create(CategoryTable)
addLogger(StdOutSqlLogger)
}
}

suspend fun getAll(): List {
try {
return dbQuery {
CategoryTable.selectAll().map {
Category(
it[CategoryTable.id],
it[CategoryTable.name],
it[CategoryTable.image],
it[CategoryTable.slug]
)
}
}
} catch (e: Exception) {
exposedLogger.error("Aucune catégorie existante")
return emptyList()
}
}

suspend fun getOne(id: String): Category? {
try {
return dbQuery {
CategoryTable
.selectAll()
.where { CategoryTable.id eq id }
.map {
Category(
it[CategoryTable.id],
it[CategoryTable.name],
it[CategoryTable.image],
it[CategoryTable.slug]
)
}
.singleOrNull()
}
} catch (e: Exception) {
exposedLogger.error("La catégorie recherchée n'existe pas")
return null
}
}

private suspend fun  dbQuery(block: suspend () -> T): T =
newSuspendedTransaction(Dispatchers.IO) { block() }
}
Затем я понял, что многие из моих таблиц имеют схожие методы, и, поскольку не хотелось повторяться, я решил создать класс BaseService.

Код: Выделить всё

abstract class BaseService(
private val table: ExposedTable,
private val mapper: (ResultRow) -> Entity
) {
suspend fun getAll(): List  {
try {
return dbQuery {
table.selectAll().map(mapper)
}
} catch (e: Exception) {
exposedLogger.error("Erreur lors de la récupération des éléments issus de ${table.tableName}")
return emptyList()
}
}

private suspend fun  dbQuery(block: suspend () -> T): T =
newSuspendedTransaction(Dispatchers.IO) { block() }
}
Однако я не знаю, как мне написать метод getOne().
Что я сделал пробовал:

Код: Выделить всё

suspend fun getOne(id: String): Entity? {
try {
return dbQuery {
table
.selectAll()
.where { table.primaryKey eq id }
.map(mapper)
.singleOrNull()
}
} catch (e: Exception) {
exposedLogger.error("Erreur lors de la récupération de l'élément issu de ${table.tableName}")
return null
}
}
Ошибка:

Несоответствие типов. Требуется: Операция найдена: Единица

Код: Выделить всё

suspend fun getOne(id: String): Entity? {
val key = table.primaryKey?.columns?.singleOrNull() ?: throw IllegalStateException("Error")
try {
return dbQuery {
table
.select { key eq id }
.map(mapper)
.singleOrNull()
}
Ошибка:

Несоответствие типов.
Обязательно:
Список
Найдено:
() → Единица

Что я хочу сделать:
Я хотел бы создать API только с методами GET и POST. Я должен иметь возможность получать данные из всех моих таблиц и обновлять некоторые из них. Поскольку методы GET всегда работают одинаково, я хотел создать универсальный сервис с двумя методами getAll() и getOne(). Благодаря этому я мог передавать им параметры и использовать их во всех своих сервисах.
Дополнительная информация:

Код: Выделить всё

UsersSchema.kt
был создан Ktor: я использовал его в качестве примера, а затем удалил из своего проекта. Я сгенерировал свои таблицы базы данных с помощью Prisma, и все они имеют свойство id, которое является строкой (точнее, UUID, но я разберусь с этим позже). Итак, если у таблицы нет свойства id типа String, это означает, что при создании таблицы произошла ошибка (которая не является частью этого проекта). Фактически все OtherTable будут похожи на CategoryTable, т. е. объект со строковым идентификатором и другими значениями, которые не обязательно являются общими для всех таблиц.

Подробнее здесь: https://stackoverflow.com/questions/792 ... ts-in-ktor
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Android»