2015-10-06 2 views
0

Я хотел бы создать простую функцию расстояния для заказа объектов, извлеченных из базы данных SQLite в Swift2. Я использую потрясающую структуру SQLite.swift.Как создать пользовательскую функцию типа безопасного в 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, значения центраLon представляют центр, откуда я вычисления расстояния объектов):

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

Пропущенный это без 'sqlite.swift' тега! В вашем определении и исходном SQL у вас есть 4 аргумента, но в вашей версии с типом безопасности у вас есть 2. Не могли бы вы обновить его, чтобы быть более представительным, что вы ищете? – stephencelis

+0

@stephencelis Извините, но счастлив, что вы его нашли. Я обновил свой вопрос! – Csaba

ответ

0

Там нет хорошего способа сделать это еще (многие из выражения потенциала помощников сейчас находятся внутри 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 
    ) 
} 
+1

Это решение работает, но расстояние не называется. Я напечатал запрос с помощью 'stmt.expression.asSQL()' и обнаружил, что он добавляет кавычки вокруг вызова функции расстояния, который мешает ему оценивать: ** SELECT "id" FROM "objects" WHERE ("lat" МЕЖДУ 47.1955518216418 И 47.7955518216418 И 47.7955518216418 И «lng» МЕЖДУ 18.7366857050623 И 19.3366857050623) ЗАКАЗАТЬ «Расстояние» («« lat »,« lng », 47.4955518216418, 19.0366857050623)« ASC LIMIT 20 ** Сняв запятые, raw SQL, он вернул правильные значения. Можно ли как-то «выключить» цитату? – Csaba

+0

@ Csaba Вы знаете, как его решить? У меня та же проблема – adboco

+1

@adboco, к сожалению, я не мог ее устранить элегантным способом, поэтому я переписал фреймворк и удалил добавление цитаты ... btw Я обнаружил, что цитата вообще не нужна нигде в моих случаях использования. – Csaba

0

Текущая документация дает надежду на этот вопрос. Тем не менее, я не могу получить код примера для компиляции с несколькими аргументами (Тип контекстного закрытия '([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