I want to add conditional filter on joined table:
let query = first_table::table.into_boxed();
if Some(filter_string) = filter {
// ERROR: inner_join() generates value of new type,
// cannot assign it to boxed query
query = query
.inner_join(joined_table::table.on(...))
.filter(jointed_table::dsl::string_field.eq(filter_string))
}
// joined_table actually is not required here
let result = query.select(first_table::all_columns).load(...)?;
Is there a way to downcast type of modified query into original one's, or may be there's another way to do that without copy-pasting final chain .select().load() into condition?
Related
I have a working connection to a database in an iOS10 app, using SQLite.swift.
I want to select details for a specific university where I have an IHE_ID passed in from another view controller.
I would like to just select the row for that specific university, but I can't get a query to work. I can however loop through all the data with a prepare and then choose the one I need from that, which of course is more resource intensive than I need since I already have the specific IHE_ID passed in as anIHE Int from the sending view controller.
connection is working so omitting that code...
do {
let db = try Connection(destinationDBPath, readonly: true)
let IHEs = Table("IHE")
let IHE_ID = Expression<Int>("IHE_ID")
let IHE_Name = Expression<String>("IHE_Name")
let IHE_COE_Url = Expression<String>("IHE_COE_URL")
let IHE_Sector = Expression<Int>("IHE_Sector")
let IHE_COE_Name = Expression<String>("IHE_COE_Name")
for ihe in try db.prepare(IHEs){
if (ihe[IHE_ID] == anIHE){
// build this string, otherwise ignore rest of dataset (doing this because query isn't working)
buildIHE = "Name: \(ihe[IHE_Name])\n"
buildIHE.append("URL: \(ihe[IHE_COE_Url])\n")
// buildIHE.append("Sector: \(ihe[IHE_Sector])\n")
if (ihe[IHE_Sector] == 0) {
buildIHE.append("Sector: Public\n")
} else {
buildIHE.append("Sector: Private\n")
}
buildIHE.append("College of Education Name: \(ihe[IHE_COE_Name])\n")
}
}
print ("Got through building IHE portion of view")
What I'd like to do is use this instead of the for loop.
if let query = IHEs.select(IHE_ID,IHE_Name,IHE_COE_Url,IHE_Sector,IHE_COE_Name).filter(IHE_ID == anIHE){
print("Query successful for \(anIHE) with name \(query[IHE_Name])")
// more actions to build the string I need would then occur
} else {
print("Query has failed or returned nil")
}
Finally, I'll use the selected elements if I can get the query to work.
I think I probably just have something wrong with my syntax on the query, but any help is appreciated.
The line with the "if let query" has this error in Xcode:
Initializer for conditional binding must have Optional type, not 'Table'.
This leads me to think it's something with my use of the .select statement and just new to using SQLite.swift and swift in general.
Last thing is that anIHE comes into this function as an Int, and IHE_ID is Expression as shown in this code. I'm thinking this may be part of the problem.
The Initializer for conditional binding must have Optional type error means that the expression on the right of the if let v = expr statement is not an Optional: there is no point using if let, and the Swift compiler says that you should just write let v = expr.
And indeed, IHEs.select(...).filter(...) returns a non-optional value of type Table.
It is not the database row you expect, because the query has been defined, but not executed yet. After all, you weren't using db: where would the rows be loaded from?
The solution is to bring back the database connection, and load a single row. This is done with the pluck method.
if let ihe = try db.pluck(IHEs.select(...).filter(...)) {
print("Name \(ihe[IHE_Name])")
}
just wondering, how do I convert List to Result?
Cause I'm doing filtering of region and areas, and when user selected region then area should show only those area in the region. And when I'm asigning my areas to a variable defined as var areas: Results<Area>!, I got the compile error
Cannot assign value of type 'List' to type 'Results!'
my code is as below
if let regionString = self.selectedRegionString {
let region = self.realm.objects(Region).filter("name = '\(regionString)'").first
self.areas = region!.areas //this line is the problem
} else {
self.areas = self.realm.objects(Area)
}
I think you should define your self.areas like
var areas: List<Area>
It should have the same model class
Results is used for Realm's queries returned value.
I'm using Realm to persist data entries of Animals. Each animal entry has a type, weight, and color. I'm trying to say if an animal's type is equal to monkey, then return the monkey's weight.
class Animal: Object {
dynamic var type = ""
dynamic var weight = 0.0
dynamic var color = ""
}
let animalResults = Realm(path: Realm.defaultPath).objects(Animal)
I believe I need to filter & map the results, but I'm unsure how to do this with a Realm Object.
You can use filter method chaining to the results. If you would like to retrieve only monkey type animals, like following:
let monkeys = Realm().objects(Animal).filter("type == %#", "monkey")
If you want to collect the weight of monkeys, you can use map function to the results.
let weightOfMonkeys = map(monkeys) { $0.weight }
My code is as follows
var List_mall_rowid = [Int]()
let mall_rowid = SQL_list?.intForColumn("MH_rowid")
var duplicate: Bool = false
for rowid in List_mall_rowid{
if rowid == mall_rowid{
duplicate = true
}
}
but the if statement fails with compiler error
binary operator == cannot be applied....
I must have tried dozens of different syntax options, getting dozens of errors. What is the correct way to make this comparison?
In your if statement your rowid is Int type and your mall_rowid is another type (I am not sure which type) so you can not compare it and if you want to compare both then both must have same type.
My code is:
func getTimeStamps( tablename : String) -> String {
let time_stamps = db["time_stamps"]
let t_tabelle = Expression<String?>["tabelle"]
let t_time_stamp = Expression<String?>["TIME_StAMP"]
let query = time_stamps.filter(like(tablename, t_tabelle))
return query[t_time_stamp]
}
But I get an error on conversion:
Expression<String?> is not convertible to String
How can I return a String?
Thanks
Hauke
The error refers to the fact that your function signature for getTimeStamps, String -> String, has return type String, but the value you're returning, query[t_time_stamp], is an Expression<String?>.
Query structures can be subscripted with Expressions to return a namespaced version of the expression:
let id = Expression<Int64>("id") // literally: "id"
let users = db["users"]
let users_id = users[id] // literally: "users"."id"
In your case, subscripting query with t_time_stamp is merely returning a new, namespaced version of the t_time_stamp expression (in your version, "time_stamps"."TIME_StAMP"). This is helpful for disambiguation, but unlikely your intent.
It's tough to tell from the code provided exactly what you want to return from the function, but it looks like you want to execute the query in order to extract a value. Row structures, once fetched, can be subscripted with expressions to retrieve the underlying value.
If you're looking to retrieve a single row, try the following:
if let row = time_stamps.filter(like(tablename, t_tabelle)).first {
return row[t_time_stamp]
}
Your function, however, still returns String, not String?. If it's ever possible for your query to return zero rows or for any of the rows it does return to have a NULL timestamp column, you need to handle your optionals accordingly.
If, however, a NULL timestamp would indicate a programming error/bug, you should update String? to String accordingly:
let t_time_stamp = Expression<String>["TIME_StAMP"]
// ...
return query.first![t_time_stamp]
Please note that the above will crash if you're mishandling the potential for optional values.