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

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.

Related

Variables won't change after executing once().then function in firebase ( Flutter )

I'm trying to get data from firebase and it worked with once().then function, but the problem is when I save the data a variable, its value will change only inside the function ( when the execution of the function is finished then the variable will not have the returned value from firebase )
code example :
static var temp = [];
void tempp() {
var db = FirebaseDatabase.instance.reference();
db.once().then((DataSnapshot snapshot) {
temp.add(1);
print(temp[0]);
});
print(temp[0]);
}
So, the first print statement will print the new value in temp list which is at index zero
but for the second print ( outside the once().then function ) will cause value range error
Invalid value: Valid value range is empty: 0
that means the value that was saved in the function it is not there anymore
How can I save the value after function is executed ?
I tried to use global variables it didn't work,
your help is much appreciated.
thank you.

Extracting sql data in ionic 5 without getting a ZoneAwarePromise

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.

Cannot get Realm result for objects filtered by the latest (nsdate) value of a property of a collection property swift (the example is clearer)

I Have the following model
class Process: Object {
#objc dynamic var processID:Int = 1
let steps = List<Step>()
}
class Step: Object {
#objc private dynamic var stepCode: Int = 0
#objc dynamic var stepDateUTC: Date? = nil
var stepType: ProcessStepType {
get {
return ProcessStepType(rawValue: stepCode) ?? .created
}
set {
stepCode = newValue.rawValue
}
}
}
enum ProcessStepType: Int { // to review - real value
case created = 0
case scheduled = 1
case processing = 2
case paused = 3
case finished = 4
}
A process can start, processing , paused , resume (to be in step processing again), pause , resume again,etc. the current step is the one with the latest stepDateUTC
I am trying to get all Processes, having for last step ,a step of stepType processing "processing ", ie. where for the last stepDate, stepCode is 2 .
I came with the following predicate... which doesn't work. Any idea of the right perform to perform such query ?
my best trial is the one. Is it possible to get to this result via one realm query .
let processes = realm.objects(Process.self).filter(NSPredicate(format: "ANY steps.stepCode = 2 AND NOT (ANY steps.stepCode = 4)")
let ongoingprocesses = processes.filter(){$0.steps.sorted(byKeyPath: "stepDateUTC", ascending: false).first!.stepType == .processing}
what I hoped would work
NSPredicate(format: "steps[LAST].stepCode = \(TicketStepType.processing.rawValue)")
I understand [LAST] is not supported by realm (as per the cheatsheet). but is there anyway around I could achieve my goal through a realm query?
There are a few ways to approach this and it doesn't appear the date property is relevant because lists are stored in sequential order (as long as they are not altered), so the last element in the List was added last.
This first piece of code will filter for processes where the last element is 'processing'. I coded this long-handed so the flow is more understandable.
let results = realm.objects(Process.self).filter { p in
let lastIndex = p.steps.count - 1
let step = p.steps[lastIndex]
let type = step.stepType
if type == .processing {
return true
}
return false
}
Note that Realm objects are lazily loaded - which means thousands of objects have a low memory impact. By filtering using Swift, the objects are filtered in memory so the impact is more significant.
The second piece of code is what I would suggest as it makes filtering much simpler, but would require a slight change to the Process model.
class Process: Object {
#objc dynamic var processID:Int = 1
let stepHistory = List<Step>() //RENAMED: the history of the steps
#objc dynamic var name = ""
//ADDED: new property tracks current step
#objc dynamic var current_step = ProcessStepType.created.index
}
My thought here is that the Process model keeps a 'history' of steps that have occurred so far, and then what the current_step is.
I also modified the ProcessStepType enum to make it more filterable friendly.
enum ProcessStepType: Int { // to review - real value
case created = 0
case scheduled = 1
case processing = 2
case paused = 3
case finished = 4
//this is used when filtering
var index: Int {
switch self {
case .created:
return 0
case .scheduled:
return 1
case .processing:
return 2
case .paused:
return 3
case .finished:
return 4
}
}
}
Then to return all processes where the last step in the list is 'processing' here's the filter
let results2 = realm.objects(Process.self).filter("current_step == %#", ProcessStepType.processing.index)
The final thought is to add some code to the Process model so when a step is added to the list, the current_step var is also updated. Coding that is left to the OP.

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.

Add "blocking" to Swift for-loop

I am using Swift in a project, and using SQLite.swift for database handling. I am trying to retrieve the most recent entry from my database like below:
func returnLatestEmailAddressFromEmailsTable() -> String{
let dbPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true).first as String
let db = Database("\(dbPath)/db.sqlite3")
let emails = db["emails"]
let email = Expression<String>("email")
let time = Expression<Int>("time")
var returnEmail:String = ""
for res in emails.limit(1).order(time.desc) {
returnEmail = res[email]
println("from inside: \(returnEmail)")
}
return returnEmail
}
I am trying to test the returned string from the above function like this:
println("from outside: \(returnLatestEmailAddressFromEmailsTable())")
Note how I print the value from both inside and outside of the function. Inside, it works every single time. I am struggling with the "from outside:" part.
Sometimes the function returns the correct email, but sometimes it returns "" (presumably, the value was not set in the for loop).
How can I add "blocking" functionality so calling returnLatestEmailAddressFromEmailsTable() will always first evaluate the for loop, and only after this return the value?

Resources