Select count(col_name) in sqlite (Swift) not working - sql

I am using the sqlite wrapper here to access my sqlite database in Swift.
I wrote this code based on the wrapper to count the items on a table.
public func numberOfRows() -> Int {
let cmd = """
SELECT count(*) from \(self.tableName)
"""
do{
let db = DatabaseUtils.getInstance().getConnection()
let stmt = try db.prepare( cmd )
if try stmt.step() == .row {
return Int(from: stmt,index: 1) ?? -1
}
return -1
}catch {
Log.out("Error occurred while fetching count data in \(tableName)")
return -1
}
}
But it keeps returning -1 as the logic instructs when the count is not found.
Every other thing works so far; create tables, inserts, batched inserts.
Also a select count(col_name) from table_name where some_col = "?" also works.
QUESTION:
How do I remedy it to work for
SELECT count(*) from table_name?

The column numbers when returning values (e.g. the result of sqlite3_column_xxx) are zero-based. You’re attempting to retrieve column 1, when you meant column 0.
By the way, if you want to detect invalid index, you can remove that nil coalescing operator. E.g., so, instead of:
if try stmt.step() == .row {
return Int(from: stmt,index: 1) ?? -1
}
You could instead check to see if not only if step succeeded, but also that Int(from:index:) returned a non-nil value:
if try stmt.step() == .row {
if let count = Int(from: stmt, index: 1) {
return count
} else {
// do whatever you want when it fails, e.g.
fatalError("no value returned; invalid column index?")
}
}
Or perhaps more succinctly:
if try stmt.step() == .row, let count = Int(from: stmt, index: 1) {
return count
} else {
fatalError("no value returned; invalid column index?")
}
That would lead you to recognize that you need the 0-based index:
if try stmt.step() == .row, let count = Int(from: stmt, index: 0) {
return count
} else {
fatalError("no value returned; invalid column index?")
}

Related

Return Mono.empty() from Mono.fromCallable

I want to do something like below. In the Mono.fromCallable I run some block logic, then based on the value I either return Mono.empty() or the value so that it will either trigger the map or defaultIfEmpty.
Mono.fromCallable(() -> {
double number = Math.random();
if (number < 0.5) {
return Mono.empty();
}
return number;
})
.map(number -> 1)
.defaultIfEmpty(0)
This give an error since Mono.fromCallable expect a consistent return value. How do I adjust the code to make it work?
Although returning null is usually prohibited in Reactor APIs, it is a valid value that Callable may return, and Reactor handles it correctly by transforming into an empty Mono:
Mono.fromCallable(() -> {
double number = Math.random();
if (number < 0.5) {
return null;
}
return number;
})

use map function on condition in kotlin

I have a list of items and I want to edit its values before using it. I am using the map function to update each item in it. But the catch here is, I want to only update the items when the list size is 1. I want to return the list as it is if the size is larger than 1. How can I achieve this?
myList.map {
if(resources.getBoolean(R.bool.is_tablet) && it.itemList.size<6 && it.layerType == DOUBLE_LIST) {
it.layerType = SINGLE_LIST_AUTO
it.itemList.forEach {sectionItem->
sectionItem.layerType = SINGLE_LIST_AUTO
}
it
}else{
it
}
}
You can try using filter before map:
.filter { it.itemList.size == 1 }
I am assuming you want to modify the items in your list only if some conditions are met else return the same list unmodified.
You can consider using takeIf { } for this scenario if you desire to add some syntactic sugar
fun updateItemsInMyList(myList:List<SomeClass>): List<SomeClass> {
return myList
.takeIf {
// condition to modify items in your list
it.size > 1 && otherConditions
}
?.apply {
//update your items inside the list
}
?: myList // return the unmodified list if conditions are not met
}
If I understand your question correctly, you want to check if myList contains only one value else, you want update the values and return it. You could do something along the following lines,
myList.singleOrNull ?: myList.map {
if(resources.getBoolean(R.bool.is_tablet) && it.itemList.size<6 && it.layerType == DOUBLE_LIST) {
it.layerType = SINGLE_LIST_AUTO
it.itemList.forEach {sectionItem->
sectionItem.layerType = SINGLE_LIST_AUTO
}
it
}else{
it
}
}
return myList
Basically, check if there's only a single value in the list, if so, then return the value. In the case that there isn't (you get null), then you can map the value.

Is there a way to merge filter and map into single operation in Kotlin?

The below code will look for "=" and then split them. If there's no "=", filter them away first
myPairStr.asSequence()
.filter { it.contains("=") }
.map { it.split("=") }
However seeing that we have both
.filter { it.contains("=") }
.map { it.split("=") }
Wonder if there's a single operation that could combine the operation instead of doing it separately?
You can use mapNotNull instead of map.
myPairStr.asSequence().mapNotNull { it.split("=").takeIf { it.size >= 2 } }
The takeIf function will return null if the size of the list returned by split method is 1 i.e. if = is not present in the string. And mapNotNull will take only non null values and put them in the list(which is finally returned).
In your case, this solution will work. In other scenarios, the implementation(to merge filter & map) may be different.
I see your point and under the hood split is also doing an indexOf-check to get the appropriate parts.
I do not know of any such function supporting both operations in a single one, even though such a function would basically just be similar to what we have already for the private fun split-implementation.
So if you really want both in one step (and require that functionality more often), you may want to implement your own splitOrNull-function, basically copying the current (private) split-implementation and adapting mainly 3 parts of it (the return type List<String>?, a condition if indexOf delivers a -1, we just return null; and some default values to make it easily usable (ignoreCase=false, limit=0); marked the changes with // added or // changed):
fun CharSequence.splitOrNull(delimiter: String, ignoreCase: Boolean = false, limit: Int = 0): List<String>? { // changed
require(limit >= 0, { "Limit must be non-negative, but was $limit." })
var currentOffset = 0
var nextIndex = indexOf(delimiter, currentOffset, ignoreCase)
if (nextIndex == -1 || limit == 1) {
if (currentOffset == 0 && nextIndex == -1) // added
return null // added
return listOf(this.toString())
}
val isLimited = limit > 0
val result = ArrayList<String>(if (isLimited) limit.coerceAtMost(10) else 10)
do {
result.add(substring(currentOffset, nextIndex))
currentOffset = nextIndex + delimiter.length
// Do not search for next occurrence if we're reaching limit
if (isLimited && result.size == limit - 1) break
nextIndex = indexOf(delimiter, currentOffset, ignoreCase)
} while (nextIndex != -1)
result.add(substring(currentOffset, length))
return result
}
Having such a function in place you can then summarize both, the contains/indexOf and the split, into one call:
myPairStr.asSequence()
.mapNotNull {
it.splitOrNull("=") // or: it.splitOrNull("=", limit = 2)
}
Otherwise your current approach is already good enough. A variation of it would just be to check the size of the split after splitting it (basically removing the need to write contains('=') and just checking the expected size, e.g.:
myPairStr.asSequence()
.map { it.split('=') }
.filter { it.size > 1 }
If you want to split a $key=$value-formats, where value actually could contain additional =, you may want to use the following instead:
myPairStr.asSequence()
.map { it.split('=', limit = 2) }
.filter { it.size > 1 }
// .associate { (key, value) -> key to value }

how to loop over fields of a struct for query filtering

I have a database where each row corresponds to a struct with the following fields
type item struct {
ItemId *string `json:"item_id"`
OwnerId *string `json:"owner_id"`
Status *string `json:"status"`
... // many more
}
Inside the database, all fields are filled for all rows. Now I would like to have a function that takes an item object whose fields may not be filled as input and return a SQL query string. For example
func FindItems(filter item) string
The input item serves as a filter. The logic is as follows (in kind of python style)
query = `select * from item_table`
condition = ""
for field, value in filter:
if value != nil:
condition = " and " if condition else " where "
condition += " field=value"
query += condition
How can I do this in go? Or is there a better way to do filter in go?
You can use reflect package to enumerate your structure fields and values:
package main
import (
"fmt"
"reflect"
)
type item struct {
ItemID *string `json:"item_id"`
OwnerID *string `json:"owner_id"`
Status *string `json:"status"`
}
func FindItemsQuery(filter item) string {
query := `select * from item_table`
condition := ""
val := reflect.ValueOf(filter)
for i := 0; i < val.NumField(); i++ {
valField := val.Field(i)
if !valField.IsNil() {
if condition != "" {
condition += " and "
} else {
condition += " where "
}
condition += fmt.Sprintf("%s=%v", val.Type().Field(i).Tag.Get("json"), valField.Elem())
}
}
return query + condition
}
func main() {
itemID := "123"
item := item{ItemID: &itemID}
fmt.Println(FindItemsQuery(item)) // select * from item_table where item_id=123
}
Keep in mind that using additional json tags like json:"item_id,omitempty" will break your query. You should consider using custom structure tags to define the names of SQL fields.

How to query database and return single row only

I'm new to programming and I'm trying to do simple projects to learn more. I've done researching, but I can't seem to find a solution to my problem. Perhaps, my program is not properly structured, but here it goes:
THIS BLOCK WILL VALIDATE IF THE ENTERED EMPLOYEE ID ALREADY EXISTS IN DATABASE. THIS IS CALLED IN A SERVLET
public boolean login(String employeeID) throws SQLException {
String sql = "select count(*) as count from employees where emp_id=?";
statement = connection.prepareStatement(sql);
statement.setString(1, employeeID);
rs = statement.executeQuery();
if (rs.next()) {
count = rs.getInt("count");
}
rs.close();
if (count == 0) {
return false;
} else {
return true;
}
}
/* METHOD BELOW ITERATES THE FIELDS FROM MYSQL DATABASE, BUT IT DISPLAYS ALL OF IT.
I JUST WANT TO GET A SINGLE ROW MATCHING THE EMPLOYEE ID PARAMETER ENTERED.*/
public List<EmployeeNumber> _list() throws SQLException {
List<EmployeeNumber> result = new ArrayList<>();
String sql = "select * from employees";
statement = connection.prepareStatement(sql);
rs = statement.executeQuery();
if (rs.next()) {
EmployeeNumber emp = new EmployeeNumber();
emp.setEmployeeNumber(rs.getString(1));
emp.setFirstName(rs.getString(2));
emp.setLastName(rs.getString(3));
emp.setEmail(rs.getString(4));
emp.setDepartment(rs.getString(5));
emp.setFirstApprover(rs.getString(6));
emp.setSecondApprover(rs.getString(7));
result.add(emp);
}
if (rs != null) {
rs.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
return result;
}
}
I think it has something to do with my SQL Query statement but I can't figure out how to fix it.
So in a nutshell, when I submit the employee ID from JSP page, it will validate if that exists, and if it does, I want to display all the column fields within the same row where this employee ID is positioned. How do I do that? Results will be displayed on another JSP page.
Thank you.
You're first counting how many employees have the given ID. Then you're selecting all the rows from the employee table.
Skip the first query, and only use the second one, but by adding a where clause, just as you did with the first query:
select * from employees where emp_id=?
Then after you've bound the parameter (as you did for the first query), test if there is a row returned:
if (rs.next()) {
// get the data, and return an EmployeeNumber instance containing the data
}
else {
// no employee with the given ID exists: return null
}
Note that the method shouldn't return a List<EmployeeNumber>, but an EmployeeNumber, since you only want to get 1 employee from the table.
Maybe try something like this?
String sql = "select count(*) as count from employees where emp_id=?";
statement = connection.prepareStatement(sql);
statement.setString(1, employeeID);
int count = statement.ExecuteScalar();
if (count == 0) {
return false;
} else {
return true;
}
}
http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlcommand.executescalar(v=vs.110).aspx
You can also set a breakpoint and step through your code and see where the exception is being thrown. That would help us, knowing the exception message and where it's breaking.