Kotlin Exposed - выбор на основе количества подзапросов

В моей модели данных у меня очень простая связь «один ко многим» между задачами и ее элементами белого списка.

Я пытаюсь выбрать задачу, отфильтрованную по белому списку. В основном критерии выбора задачи - это когда задача либо не имеет записей в белом списке сама по себе, либо белый список совпадает по имени.

Этого можно добиться с помощью довольно простого SQL-запроса:

select c.* from challenge c, challenge_whitelist w where (c.id = w."challengeId" and w."userName" = 'testuser') or ((select count(*) where c.id = w."challengeId") = 0);

Я не могу перевести это на Exposed:

  // will not compile
  fun listAll(userName: String) {
    ExposedChallenge.wrapRows(
      ChallengeTable.innerJoin(ChallengeWhitelistTable)
        .slice(ChallengeTable.columns)
        .select((ChallengeWhitelistTable.userName eq userName) or (ChallengeTable.innerJoin(ChallengeWhitelistTable).selectAll().count() eq 0))
    ).toList()
  }

Проверка userName работает правильно, но ChallengeTable.innerJoin(ChallengeWhitelistTable).selectAll().count() eq 0) не квалифицируется как допустимое выражение (не будет компилироваться).

Обратите внимание, что сопоставления очень просты:

object ChallengeTable : IntIdTable() {
  val createdAt = datetime("createdAt")
}

class ExposedChallenge(id: EntityID<Int>) : IntEntity(id) {
  companion object : IntEntityClass<ExposedChallenge>(ChallengeTable)
  var createdAt by ChallengeTable.createdAt
  val whitelist by ExposedChallengeWhitelist referrersOn ChallengeWhitelistTable.challenge
}

object ChallengeWhitelistTable : IntIdTable(name = "challenge_whitelist") {
  var userName = varchar("userName", 50)
  var challengeId = integer("challengeId")
  val challenge = reference("challengeId", ChallengeTable).uniqueIndex()
}

class ExposedChallengeWhitelist(id: EntityID<Int>) : IntEntity(id) {
  companion object : IntEntityClass<ExposedChallengeWhitelist>(ChallengeWhitelistTable)

  val challengeId by ChallengeWhitelistTable.challengeId
  val challenge by ExposedChallenge referencedOn ChallengeWhitelistTable.challenge
}

Любая помощь будет оценена.


person alexs333    schedule 23.09.2019    source источник


Ответы (1)


Ваш SQL-запрос недействителен, поскольку вы используете select count(*) без части from. Но его можно переписать с помощью Exposed DSL, например:

ChallengeTable.leftJoin(ChallengeWhitelistTable).
    slice(ChallengeTable.columns).
    selectAll().
    groupBy(ChallengeTable.id, ChallengeWhitelistTable.userName).having {
    (ChallengeWhitelistTable.userName eq "testUser") or
    (ChallengeWhitelistTable.id.count() eq 0)
}

Другой способ - использовать только левое соединение:

ChallengeTable.leftJoin(ChallengeWhitelistTable).
    slice(ChallengeTable.columns).
    select {
        (ChallengeWhitelistTable.userName eq "testUser") or
        (ChallengeWhitelistTable.id.isNull())
    }
person Tapac    schedule 24.09.2019
comment
Разве вы не имели в виду leftJoin во втором фрагменте? Я использовал второй фрагмент с leftJoin и groupBy, и это помогло. Спасибо! - person alexs333; 01.10.2019