SQLite Insert is not working properly in swift - swift

I am trying to insert data from array into my table. If the insert is done I think, its suppose to print it in the console, but it is not. So I tried db.trace(println) and it shows me
SELECT * FROM "formatedData1"
My createDatabase function:
func createDatabase(){
var data = db["formatedData1"]
db.create(table: data, ifNotExists: true){ d in
d.column(type, primaryKey: true)
d.column(ada)
d.column(code)
d.column(name)
d.column(proof)
d.column(size)
d.column(case_size)
d.column(price)
}
for var i = 0; i < self.dataArrayMut.count; ++i{
data.insert(type <- (self.dataArrayMut[i].valueForKey("Type") as! String), ada <- (self.dataArrayMut[i].valueForKey("ADA") as! String), code <- (self.dataArrayMut[i].valueForKey("Code") as! String), name <- (self.dataArrayMut[i].valueForKey("Name") as! String), proof <- (self.dataArrayMut[i].valueForKey("Proof") as! String), size <- (self.dataArrayMut[i].valueForKey("Size") as! String), case_size <- (self.dataArrayMut[i].valueForKey("CaseSize") as! String), price <- (self.dataArrayMut[i].valueForKey("Price") as! String))
}
db.trace(println)
}
Then I tried to run queries on the table to see if the data exists.
1st query:
//Select * From data
let all = Array(data)
println(all.description)
And when I print it I get
[SQLite.Row, SQLite.Row, SQLite.Row, SQLite.Row, SQLite.Row, SQLite.Row, SQLite.Row, SQLite.Row]
2nd Query
//Select name From data where type = rum
let query = data.select(name)
.filter(type == "Rum")
println(query)
And when I print it I get
"formatedData1"
3rd Query
I wanted to print all rows only from two columns.
for datas in data.select(type, name){
println("type: \(data[type]), name: \(data[name])")
}
And It prints
SELECT "Type", "Name" FROM "formatedData1"
type: SQLite.Expression<Swift.String>, name: SQLite.Expression<Swift.String>
type: SQLite.Expression<Swift.String>, name: SQLite.Expression<Swift.String>
type: SQLite.Expression<Swift.String>, name: SQLite.Expression<Swift.String>
type: SQLite.Expression<Swift.String>, name: SQLite.Expression<Swift.String>
type: SQLite.Expression<Swift.String>, name: SQLite.Expression<Swift.String>
type: SQLite.Expression<Swift.String>, name: SQLite.Expression<Swift.String>
type: SQLite.Expression<Swift.String>, name: SQLite.Expression<Swift.String>
type: SQLite.Expression<Swift.String>, name: SQLite.Expression<Swift.String>
Sorry for long question but any help would be highly appreciated.

SQLite.swift doesn't print the insert results to the console by itself, you have to do something like this:
let (id, statement) = data.insert(type <- (self.dataArrayMut[i].valueForKey("Type") as! String))
Then you can check id and statement and print the results to the console:
if let dbRowID = id {
println("New entry: \(dbRowID)")
} else if statement.failed {
println("Row insertion failed because \(statement.reason!)")
}
To access the row contents you need to use the types defined in the db, not literals:
let all = Array(data)
for row in all {
let name = row[self.name]
println(name)
}
Here self.name is one of the types created by the class containing createDatabase(), and corresponds to one of your columns.
EDIT:
You can access the content of a Row either by subscripting it (data[name], where name is of type Expression) or by its get method (data.get(name)).
To answer your comment: if you do data[42], it means to get the 42nd Row, not column. With this Row, you can then get your column content by using an Expression like I just explained.
Note that in Xcode, with ALT+CLICK you can see the type of any variable, it can help you while following your data flow.

Related

GRDB in Swift - .fetchAll Only Ever Returns One Column

My Original Code
func getUserByEmpNum(_ id: Int) -> String {
let nameQuery: String = "SELECT fld_str_firstname, fld_str_lastName FROM userView WHERE fld_int_id = \(id);"
var returnStr = ""
do {
let dbQueue = try DatabaseQueue(path: MYCDatabase.pathToDatabase)
try dbQueue.inTransaction(.none) { (db) -> Database.TransactionCompletion in
let returnStrs = try String.fetchAll(db, sql: nameQuery)
// Placing a breakpoint here, returnStrs only has one element?
return .commit
}
} catch {
print (error)
}
return returnStr
}
My Question
In this code if I do a query like select fld_str_firstname from myOwnUserView where fld_int_id = 2; I get one element in my returnStrs array, which is as expected. Then selecting the two fields, as in nameQuery, I still only ever get one string in the returnStrs array.
Why is this, and how do I fit it to get all the selected columns in the response?
String.fetchAll returns an array of Strings extracted from the leftmost selected column, as documented. One string for each fetched row. Not one string for each selected column.
If you want to grab strings from several columns, use Row.fetchAll, which returns an array of database rows. From those rows, you can extract each column you are interested into:
let rows = try Row.fetchAll(db, sql: "SELECT fld_str_firstname, fld_str_lastName FROM ...")
for row in rows {
let firstName: String = row["fld_str_firstname"]
let lastName: String = row["fld_str_lastName"]
}
See this chapter of the documentation for more information about extracting values from database rows.
Since you are reading the name from a single row identified with its id, you may prefer the fetchOne method, which consumes a single database row (see Fetching Methods):
if let row = try Row.fetchOne(db, sql: "SELECT ... WHERE fld_int_id = ?", arguments: [id]) {
let firstName: String = row["fld_str_firstname"]
let lastName: String = row["fld_str_lastName"]
// Use first and last name
} else {
// ID does not exist in the database: do what is appropriate.
}

Firebase + Swift: Grab only the latest change for a child node

I have a locations-orders table that looks like this:
I want to only grab the latest order that is added to the record (not all the other orders that are already inside it). This is what I have, which doesn't work (fyi I hardcoded the location-orders key):
static func observeOrders(lId: String, f: #escaping (AppState.Order) -> () ) {
FIRDatabase.database().reference(withPath: "locations-orders/5P9TF215PZ3ZV")
.child("orders")
.queryEnding(atValue: nil)
.queryLimited(toLast: 1)
.observe(.childAdded, with: { firebaseSnapshot in
let orderObject = firebaseSnapshot.value as! [String: AnyObject]
print("orderObject")
print(orderObject) // <-------------------- only prints once, never prints again
let order = AppState.Order(
title: orderObject["name"] as! String,
subtitle: orderObject["item_variation_name"] as! String,
createdAt: Date(timeIntervalSince1970: TimeInterval(orderObject["created_at"] as! Int / 1000)),
name: "name",
status: AppState.Order.Status.Pending
)
f(order)
})
}
What's wrong with my query??
Let's simplify. If you want to get the last item added and then any new items added, how about this:
let ref = "your orders path"
ref.queryLimited(toLast: 1)
.observe(.childAdded, with: { snapshot in
print(snapshot?.value)
})

Getting results from arbitrary SQL statements with correct binding in SQLite.swift

The SQLite.swift documentation says about executing arbitrary SQL:
let stmt = try db.prepare("SELECT id, email FROM users")
for row in stmt {
for (index, name) in stmt.columnNames.enumerate() {
print ("\(name)=\(row[index]!)")
// id: Optional(1), email: Optional("alice#mac.com")
}
}
I wanted to get the values directly like this
let stmt = try db.prepare("SELECT id, email FROM users")
for row in stmt {
let myInt: Int64 = row[0] // error: Cannot convert value of type 'Binding?' to specified type 'Int64'
let myString: String = row[1] // error: Cannot convert value of type 'Binding?' to specified type 'String'
}
but the row index is of type Binding? and I can't figure out how to convert that to the type I need. I see there is a Statement.bind method in the source code but I am still not discovering how to apply it.
You can retrieve correctly typed selected columns from a table like this:
// The database.
let db = try Connection(...)
// The table.
let users = Table("users")
// Typed column expressions.
let id = Expression<Int64>("id")
let email = Expression<String>("email")
// The query: "SELECT id, email FROM users"
for user in try db.prepare(users.select(id, email)) {
let id = user[id] // Int64
let mail = user[email] // String
print(id, mail)
}
An alternative is to (optionally) cast the Binding values
to the correct type:
let stmt = try db.prepare("SELECT id, email FROM users")
for row in stmt {
if let id = row[0] as? Int64,
let mail = row[1] as? String {
print(id, mail)
}
}

Query data by value of deep child [duplicate]

This question already has answers here:
Firebase v3 Query by Grandchild
(2 answers)
Closed 6 years ago.
I have a data structure like this:
groups
-KOrPKM2QUzuMnMlHfJu
name: "Testgroup 1"
members
0: 123456789
1: 987654321
-KOrPKM2QUzuMnMFGfXa
name: "Testgroup 2"
members
0: 123456789
The number of members is not defined.
How can I get every group where one of the members is 123456789?
This question is different from this because in the other one the key of the value to check is actually known.
The unique ID is generated when push is used, to retrieve the values under that node, you can use child_added.
firebase.database().ref('groups').on('child_added', snap => {
firebase.database().ref('groups/'+snap.key+'/members').on('child_added', childSnapshot => {
if(childSnapshot.val() == '123456789') {
console.log('123456789 found in ' + snap.val().name);
}
});
});
The above code adds a child_added listener to groups so the moment it finds an existing child under groups or when a new child is added, it will trigger child_added, now snap.key contains what you want, the unique generated ID, to compare the value stored in members, another child_added listener is set on members which returns all the value stored under 0, 1...
Now childSnapshot.val() contains the value you want to compare, a simple IF statement is enough and if a match is found, you just print the group name with snap.val().name;
I created NSObject class and called it FBNSArrayDB, inside it I created the firebase ID's in your case it will be:
var name: NSString?
var members: NSString?
var 0: NSString?
var 1: NSString?
then do this in your UIViewController
var fbarray = [FBNSArrayDB]()//at the top
inside func
let ref = FIRDatabase.database().reference().child(uid!)// I assume you are saving this under uid nod!
ref.child("groups").observeEventType(.ChildAdded, withBlock: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject]{
let xy = FBNSArrayDB()
xy.setValuesForKeysWithDictionary(dictionary)
guard let SomeV = xy.0
else {
print ("NA")
return
}
if SomeV == "123456789"
{
self.fbarray.append(xy) //this way you can use the array values outside the Func
print (xy.name)
print (xy.0)
print (xy.1)
print (snapshot.key) // if you want to get the AutoID
}
}
}, withCancelBlock: nil)

Use a predicate to search a NSMutableArray of Objects

I have a collection of contacts I would like to filter: var arraycontacts: NSMutableArray = []
arraycontacts contains a large list of FriendModel Objects:
var friend = FriendModel(
name: self.contactName(contact),
phone: self.contactPhones(contact),
email: self.contactEmails(contact),
phoneString: self.contactPhonesString(contact)
)
self.arraycontacts.addObject(friend)
I'd like to be able to use filterContentSearchText, to limit this array to users that match or are LIKE a name string. Basically, I'd like to search by name.
This is my attempt:
func filterContentForSearchText(searchText: String, scope: String = "All") {
let namePredicate = NSPredicate(format: "name like %#", searchText)
let term = self.arraycontacts.filteredArrayUsingPredicate(namePredicate!)
println(term)
}
My above code produces the following error: this class is not key value coding-compliant for the key name.
Obviously, the predicate can't see the name property on my FriendModel object. How can I fix my query?
Thanks!
First, drop the NSMutableArray and just use var arrayContacts: [FriendModel] = [].
Then use the filter method on the array.
var friend = FriendModel(
name: self.contactName(contact),
phone: self.contactPhones(contact),
email: self.contactEmails(contact),
phoneString: self.contactPhonesString(contact)
)
self.arraycontacts.append(friend)
let filteredArray = self.arrayContacts.filter() {
$0.name.hasPrefix(searchString)
}
Or something like that anyway.
Here you go...