Extracting sql data in ionic 5 without getting a ZoneAwarePromise - sqlite

Using the ionic 5 framework I am trying to extract data from my SQLite database using a function:
getGlobal(name, db) {
console.log('... getting global');
var result;
sqlQuery = 'SELECT `value` FROM globals WHERE `name` = "' + name + '"';
console.log('sql query: ' + sqlQuery);
result = db.executeSql(sqlQuery, []).then(value => {
return JSON.parse(value.rows.item(0).value);
});
console.log('return: ', result);
return result;
}
I have tried even further ".then(data => {})" chaining to extract the correct result but withoug success. Always produces a ZoneAwarePromise.
Not sure where I am going wrong

The problem is not with the function itslef. Even converting it to an async function with await will return a fullfilled promise.
At the receiving end, eg
getGlobal('variable', db)
extract the value by adding
.then(value => console.log(value));
This is me learning more about promises. Maybe this answer is helpful to others.

Related

how to write costomselect query which returns Future in Flutter/moor

I'm developing apps by flutter/moor.
but I don't get how to write custom query which returns Future<List> class object.
I could wrote query which returns Stream class object.
but it's not enough.
does anyone now how to change it to one which returns Future class.
query I wrote is bellow
db.dart
Stream<List<QuestionHeader>> selectQuestionHeaderByKey(int businessYear,int period, int questionNo) {
return
customSelect(
'SELECT *'
+'From question_Headers '
+'WHERE business_Year = ? '
+'AND period = ? '
+'AND question_No = ?;',
variables: [Variable.withInt(businessYear),Variable.withInt(period),Variable.withInt(questionNo)],
readsFrom: {questionHeaders},
).watch().map((rows) {
return rows
.map((row) => QuestionHeader(
businessYear:row.readInt('businessYear')
,period:row.readInt('period')
,questionNo:row.readInt('questionNo')
,subjectId:row.readInt('subjectId')
,compulsoryType:row.readInt('compulsoryType')
,answerType:row.readInt('answerType')
,questionText:row.readString('questionText')
,numberAnswer:row.readInt('numberAnswer')
,correctType1:row.readInt('correctType1')
,correctType2:row.readInt('correctType2')
,correctType3:row.readInt('correctType3')
,favorite:row.readBool('favorite')
)).toList();
});
}
this works but I need Future<List> class to return.

LINQ to Entities does not recognize the method call within it

I completely understand that this is because LINQ query requires the whole expression to be translated to a server , and therefore I cant call an outside method in it. but as I have looked at other answers there is not relative solution to this. the only approach that I thought about is to loop through all the items in the model and than passing them to the query one by one but even though this approach would not help so I am seeking help in here for anyone to help me to figure out how to call a method or a way of calling a method appendstr that initializes a.PostedDate before checking its actual equivalent value in the giving LINQ Query.
[HttpGet]
public ActionResult SearchResult(int? page, string searchTitle = null, string searchLocation = null, string last24 = "")
{
ViewBag.searchTitle = searchTitle;
ViewBag.searchLocation = searchLocation;
ViewBag.page = page;
ViewBag.last24 = last24;
setUpApi(searchTitle, searchLocation);
var result = new List<AllJobModel>().AsQueryable();
if (!string.IsNullOrEmpty(ViewBag.searchTitle) || !string.IsNullOrEmpty(ViewBag.searchTitle) || !string.IsNullOrEmpty(ViewBag.last24))
{
setUpApi(searchTitle, searchLocation);
DateTime now = DateTime.Now;
result = db.AllJobModel.Where(a => a.JobTitle.Contains(searchTitle) && a.locationName.Contains(searchLocation) &&
appendstr(a.PostedDate).Equals(now.AddHours(-24).ToString("MM-dd-yyyy")));
}
else
{
result = from app in db.AllJobModel select app;
}
return View(result.ToList().ToPagedList(page ?? 1, 5));
}
The second method that gets called in the LINQ Query
public string appendstr(string str)
{
var x = str.Split(' ');
return 01 + "-" + x[1] + "-" + x[2];
}
I think you already understand that the .NET code you write in the Where clause is actually an expression that is parsed and converted to SQL. So if you have a funky string manipulation method, you can't use it directly.
The brute force option, as you seem to already understand, it to materialize the query first and then run the C# code over the results. You can do this with ToList() or AsEnumerable().
result = db.AllJobModel
.Where
(
a => a.JobTitle.Contains(searchTitle)
&& a.LocationName.Contains(searchLocation)
)
.AsEnumerable()
.Where
(
a => appendstr(a.PostedDate).Equals(now.AddHours(-24).ToString("MM-dd-yyyy")))
);
However in your specific case you can try a trick. You are attempting a date comparison, which SQL is perfectly capable of doing... you just need to convert that funky PostedDate to a SQL DateTime so that you can compare it directly. The gimmick for that is to use SqlFunctions.DateAdd to add null interval (e.g. 0 days). This implicitly converts the string to DateTime, where you can now query on the SQL side:
var targetDate = DateTime.Now.AddHours(-24);
result = db.AllJobModel
.Where
(
a => a.JobTitle.Contains(searchTitle)
&& a.LocationName.Contains(searchLocation)
&& SqlFunctions.DateAdd("DAY", 0, a.PostedDate) == targetDate
);
Credit goes to this post for the workaround.

Can't get data when passing two parameters on SQLite in React Native

I tried to pass two parametes like below for select query but I am no getting the data
db.transaction(tx => {
tx.executeSql('SELECT * FROM data WHERE (month = ? AND items_id = ?);', ["Sep 2018",68], (_, { rows }) => {
console.log(JSON.stringify(rows));
});
});
OutPut :
{"_array":[],"length":0}
But is passed the value in query I got the out put like below
db.transaction(tx => {
tx.executeSql('SELECT * FROM data WHERE (month = "Sep 2018" AND items_id = 68);', [], (_, { rows }) => {
console.log(JSON.stringify(rows));
});
});
Output :
{"_array":[{"item_id":"68","item_name":"Apple","month":"Sep 2018"}],"length":1}
Note :
I am using Expo Sqlite ("expo": "^27.0.1",)
import Expo, { SQLite } from 'expo';
const db = SQLite.openDatabase('itemsDb.db');
Kindly help to achieve this. Thanks!
It may have the same bug as in react-native-sqlite-storage:
The parameters are converted from numbers into strings making the query expression to fail, as the items_id column contain integers
One solution is to cast the value back to integer in the SQL command:
SELECT * FROM data WHERE (month = ? AND items_id = cast(? as integer))
The original bug is reported here

Display result of a query that calculates the total of a field as the value of a label in a list

I have two Datasource tables Projects and tt_records with a hours number field. There is a one to many relation between the Project and tt_records. I would like to display the total number of hours per project in a table. I am able to compute the total hours in server side function, how do I bind the total with a label on the UI. I am attempting to use the following in the binding on the field. I see the function is called through info statements in the console logs, however the value does not display on the UI clientgetProjHours(#datasource.item._key); following is the Client Script
function clientgetProjHours(key){
return (google.script.run.withSuccessHandler(function (key) {
console.info("received result");
}).getProjHours(key));
}
Following is the server side script
function getProjHours(key){
console.log ("In the function getProjHours (" + key +")");
var pRecords = app.models.Projects.getRecord(key);
console.log("Contents of " + pRecords);
var tRecords =pRecords.tt_record;
console.log("Contents of t Records" + tRecords);
var total = 0;
tRecords.forEach (function (item){
total += item.actuals;
});
console.log ("The result is: " + total);
return total;
}
Could you please suggest the best way to achieve this fuction.
Thank you very much for your help
key parameter in function (key) { is the result of the Server Script.
So you just need to replace:
function (key) {
With:
function (result)
Also replace:
console.info("received result");
With:
app.pages.[PageName].descendants.[LabelName].text = result;
But as it mentioned already Calculated Model should fit such use case better.

NS_ERROR_FILE_IS_LOCKED when several requests using SQLite on Mozilla plateform

I'm trying to use Storage mechanism in Mozilla platform (in thundebird 3.0).
The following code is used after each test to erase the table present in the database:
function tearDown()
{
let database = new Database();
let req1 = "SELECT name FROM sqlite_master WHERE type='table'";
let statement = database.connection.createStatement(req1);
let tables = [];
while(statement.executeStep()) {
tables.push(statement.row.name);
}
statement.reset();
for(table in tables) {
let req2 = "DROP TABLE " + tables[table];
database.connection.executeSimpleSQL(req2);
}
}
But I've an error during executeSimpleSQL of req2 (NS_ERROR_FILE_IS_LOCKED), It seems that SQLite doesn't release the lock from the first statement. I've tried reset(), finalize(), but nothing works. How can I properly release the lock of the first statement?
Answering myself: I forgot to release a previous statement in previous code of my application.
Final story: when you use
statement.executeStep()
Check:
be sure that the last call of this statement return false
or never forgot to release it:
statement.reset();
var statement = dbConn.createStatement("SELECT COUNT(name) AS nameOcurrences FROM Table1 WHERE name = '" + aName + "';");
var occurrences;
while(statement.executeStep()) {
occurrences = statement.row.nameOcurrences;
}

Resources