Как создать пользовательскую функцию Type-Safe в SQLite.swift?

Я хотел бы создать простую функцию расстояния для упорядочения объектов при их извлечении из базы данных SQLite в Swift2. Я использую замечательный фреймворк SQLite.swift.

С помощью следующего я мог получить ближайшие объекты:

db.createFunction("distance") { (args) -> Binding? in
    assert(args.count == 4)
    if let lat1 = args[0] as? Double, let lon1 = args[1] as? Double, let lat2 = args[2] as? Double, let lon2 = args[3] as? Double {

        let deltaLat = lat1 - lat2
        let deltaLon = lon1 - lon2
        return deltaLat * deltaLat + deltaLon * deltaLon * 0.46512281898705
    }
    return nil
}

let queryString = "SELECT * FROM objects where lat != \"\" and lng != \"\" ORDER BY distance(lat, lng, \(lat), \(lng)) ASC LIMIT \(fetchLimit)"

let stmt = db.prepare(queryString)
for row in stmt {
    print(row)
}

Но я хотел бы использовать безопасное выражение SQL без использования строки запроса. Как я могу добавить функцию, чтобы заставить ее работать так (здесь значения lat и lon являются значениями Expression, которые представляют расположение строк в таблице, а значения centerLat, centerLon представляют собой центральную точку, из которой я вычисляю расстояние до объектов):

for row in db.order(distance(lat, lon, centerLat, centerLon).limit(fetchLimit) {
    print(row)
}

person Csaba    schedule 06.10.2015    source источник
comment
Пропустил это без тега sqlite.swift! В вашем определении и исходном SQL у вас есть 4 аргумента, но в вашей версии с безопасным типом у вас есть 2. Не могли бы вы обновить его, чтобы он был более репрезентативным для того, что вы ищете?   -  person stephencelis    schedule 09.10.2015
comment
@stephencelis Извините, но рад, что вы его нашли. Я обновил свой вопрос!   -  person Csaba    schedule 09.10.2015


Ответы (2)


Пока нет хорошего способа сделать это (многие помощники по построению выражений прямо сейчас являются внутренними для SQLite.swift). Я рекомендую вам открыть вопрос как запрос функции.

А пока, поскольку эти значения не нужно заключать в кавычки, вы можете сделать следующее:

func distance(
    lat1: Expression<Double>, lng1: Expression<Double>,
    lat2: Double, lng2: Double
) -> Expression<Double> {
    return Expression(
        literal: "distance(\(lat1.asSQL()), \(lng1.asSQL()), ?, ?)",
        lat2, lng2
    )
}
person stephencelis    schedule 14.10.2015
comment
Это решение работает, но расстояние не называется. Я напечатал запрос с stmt.expression.asSQL() и обнаружил, что он добавляет кавычки вокруг вызова функции расстояния, что препятствует его вычислению: SELECT id FROM «objects» WHERE (широта МЕЖДУ 47.1955518216418 И 47.7955518216418 И LNG МЕЖДУ 18.7366857050623 И 19.33668233050)ORDER BY Distance(широта, долгота, 47.4955518216418, 19.0366857050623) ASC LIMIT 20 Удалив запятые, а затем используя его как необработанный оператор SQL, он вернул правильные значения. Можно ли как-то «отключить» котировку? - person Csaba; 18.10.2015
comment
@Csaba, ты знаешь, как это решить? у меня такая же проблема - person adboco; 31.10.2017
comment
@adboco, к сожалению, я не смог решить это элегантным способом, поэтому я перезаписал структуру и удалил добавление цитаты ... кстати, я обнаружил, что цитата, как правило, не нужна нигде в моих случаях использования. - person Csaba; 06.11.2017

Текущая документация дает надежду на эту проблему. Однако я не могу заставить код примера компилироваться с более чем одним аргументом (Тип контекстного замыкания '([Binding?]) -> Binding?' ожидает 1 аргумент, но в теле замыкания использовались 2 ), должно быть возможно:

import MobileCoreServices

let typeConformsTo: (Expression<String>, String) -> Expression<Bool> = (
    try db.createFunction("typeConformsTo", deterministic: true) { UTI, conformsToUTI in
        return UTTypeConformsTo(UTI, conformsToUTI)
    }
)

https://github.com/stephencelis/SQLite.swift/blob/master/Documentation/Index.md#custom-sql-functions

person Pomo-J    schedule 09.01.2017