How to compare user input and the record in sqflite - flutter

In sqflite database, I have a table called user. The user consists of username a, b, c.
When user enter the input var a, the system will compare with the username in table user. If user input equal to username in table user, system will print the error message, else the system will print success.
I try to use the future builder, but it didnĀ“t work. How can I do the validation in Test.dart?
Thank you.
This is my code:
SqliteHelper.dart
Future getDat(UserAccount userAccount) async {
var dbClient = await db;
name = userAccount.username;
List<Map> result = await dbClient.query("UserAccount",
where: "username =?", whereArgs: [userAccount.username]);
if (result.length == 1) {
return name;
}
}
Test.dart
_saveData() async {
var db = UserAccountHelper();
var mynote = UserAccount(cTitle.text);
await db.getDat(mynote);
FutureBuilder(
future: db.getDat(mynote),
builder: (context, snapshot) {
if (snapshot.hasError) print(snapshot.error);
var data = snapshot.data;
if (snapshot.hasData) print("test 3");
if(snapshot.data.toString() == cTitle.text.toString())
{print("success")}
else{print("error")};
});
}

Future<String> getDat(String username) async {
var dbClient = await db;
List<Map> result = await dbClient.query("UserAccount",
where: "username =?", whereArgs: [username]);
if (result.length == 1) {
return name;
}
return null;
}
_saveData() async {
var db = UserAccountHelper();
var username = cTitle.text;
if(await db.getDat(username) != null) {
print('Error');
return;
}
print('Success');
}
Things I modified:
You don't need an UserAccount as parameter, because you use only the username from it.
The getDat returns null if the username isn't found in database;
In _saveData, if the result from the getDat is not null error is printed, else, success is printed.

Related

Sqflite get locked on bulk insertion even after using transaction object and batch

I am new to flutter and I am doing bulk insertion in sqflite database. I have tried using both transaction and batch objects but my issue still remains there and database gets locked.
Here is what i am doing.
Future<List<ShopsModel>> fetchShops() async{
int count = 0;
List<ShopsModel> shopsList = [];
int id = 0;
String date = "";
List<SyncDataModel> syncList = await DatabaseHelper.instance.getSyncDataHistory();
syncList.forEach((element) {
id = element.SyncID!;
date = element.ShopSyncDate == null ? "" : element.ShopSyncDate!;
});
//Info.startProgress();
String response = await ApiServices.getMethodApi("${ApiUrls.IMPORT_SHOPS}?date=$date");
if(response.isEmpty || response == null){
return shopsList;
}
var shopsApiResponse = shopsApiResponseFromJson(response);
if(shopsApiResponse.data != null){
shopsApiResponse.data!.forEach((element) async{
await insertShops(element);
count++;
if(count == 1){
syncList.length == 0 ? await DatabaseHelper.instance.insertSyncDataHistory(
SyncDataModel(
ShopSyncDate: DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()),
LastSyncDate: DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now())
)) :
await DatabaseHelper.instance.updateShopSyncDate(
DateFormat('yyyy-MM-dd HH:mm:ss').format(DateTime.now()), id);
}
});
}
return shopsList;
}
Future insertShops(ShopsModel row) async{
var shopsRow = await DatabaseHelper.instance.getShopByShopId(row.shopID!);
if(shopsRow.IsModify == 0 || shopsRow.IsModify == null) {
var result = await DatabaseHelper.instance.deleteImportedShops(
row.shopID!, DateFormat('yyyy-MM-dd HH:mm:ss').format(
DateTime.parse(row.updatedOn!)));
if (result > 0) {
print('Shop has been deleted');
}
await DatabaseHelper.instance.insertShops(
ShopsModel(
shopID: row.shopID,
shopName: row.shopName,
shopCode: row.shopCode,
contactPerson: row.contactPerson,
contactNo: row.contactNo,
nTNNO: row.nTNNO,
regionID: row.regionID,
areaID: row.areaID,
salePersonID: row.salePersonID,
createdByID: row.createdByID,
updatedByID: row.updatedByID,
systemNotes: row.systemNotes,
remarks: row.remarks,
description: row.description,
entryDate: DateFormat('yyyy-MM-dd HH:mm:ss').format(
DateTime.parse(row.entryDate!)),
branchID: row.branchID,
longitiude: row.longitiude,
latitiude: row.latitiude,
googleAddress: row.googleAddress,
createdOn: DateFormat('yyyy-MM-dd HH:mm:ss').format(
DateTime.parse(row.createdOn!)),
updatedOn: DateFormat('yyyy-MM-dd HH:mm:ss').format(
DateTime.parse(row.updatedOn!)),
tradeChannelID: row.tradeChannelID,
route: row.route,
vPO: row.vPO,
sEO: row.sEO,
imageUrl: row.imageUrl,
IsModify: 0
)
);
}
}
// Below are my Database methods
Future<int> deleteImportedShops(int shopID, String updatedDate) async{
Database db = await instance.database;
return await db.delete("$shopsTable", where: 'ShopID = ? AND UpdatedOn <= ?', whereArgs: [shopID, updatedDate]);
}
Future<void> insertShops(ShopsModel shopsRow) async{
Database db = await instance.database;
await db.transaction((txn) async {
var batch = txn.batch();
batch.insert("$shopsTable", shopsRow.toJson(), conflictAlgorithm: ConflictAlgorithm.replace);
await batch.commit();
});
}
Future<void> insertSyncDataHistory(SyncDataModel row) async{
Database db = await instance.database;
await db.transaction((txn) async {
var batch = txn.batch();
batch.insert("$syncDataTable", row.toJson(), conflictAlgorithm: ConflictAlgorithm.replace);
await batch.commit();
});
}
Future<void> updateShopSyncDate(String? pDate, int id) async{
Database db = await instance.database;
await db.transaction((txn) async {
var batch = txn.batch();
batch.rawUpdate("UPDATE SyncDataHistory SET ShopSyncDate = ?, LastSyncDate = ? WHERE SyncID = ?", [pDate, pDate, id]);
await batch.commit();
});
}
Here are the details what I am getting as an output.
Warning database has been locked for 0:00:10.000000. Make sure you always use the transaction object for database operations during a transaction
Please help me out. Any help would be appreciated.

How to show displayName of contact as text?

I want to pick a random number from contact list and show it as Text. Below is what I came up with but when I insert showNext() somewhere on main.dart as text, I get Closure: () => Future from Function 'showNext': static.() instead of a number. How do I show a number?
Future<void> showNext() async {
var status = await Permission.contacts.status;
if (status.isGranted) {
var contacts = await ContactsService.getContacts;
var list = contacts;
list.shuffle();
randomNum= (list.first.phones?.first.value ?? '');
Text('$randomNum');
Future<Widget> showNext() async {
var status = await Permission.contacts.status;
if (status.isGranted) {
final Iterable<Contact> contacts = (await ContactsService.getContacts(withThumbnails: false));
var list = contacts.toList();
list=list.shuffle();
randomNum= (list.first.phones?.first.value ?? '');
return Text('$randomNum');
}
when you want use:
FutureBuilder<String>(
future: showNext(),
builder: (context, snapShot) {
if (!snapShot.hasData) {
return Container();
}
return snapShot.data;
},
)

How to get inside data in Future<Map<dynamic, dynamic>>?

Future<Map> returnUserMap() async {
final FirebaseUser currentUser = await _auth.currentUser();
Map userMap = {
"UserName": currentUser.displayName,
"UserEmail": currentUser.email,
"UserUrl": currentUser.photoUrl
};
print("1");
print(userMap);
return userMap;
}
return value type is Instance of 'Future>'.
I want to get a UserName, how can I do it?
Your function returnUserMap() returns a Future<Map>. I suspect that the error you describe is not in the code snippet you copied.
Whenever the task to be performed may take some time, you will receive a future. You can wait for futures in an async function with await.
It is therefore recommended to use a so-called FutureBuilder in your build() function:
FutureBuilder<FirebaseUser>(
future: _auth.currentUser(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
final FirebaseUser user = snapshot.data;
if (user.displayName == null || user.displayName.isEmpty())
return text(currentUser.email); // display email if name isn't set
return text(currentUser.displayName);
}
if (snapshot.hasError) {
return text(snapshot.error);
}
return text('loading...');
},
),
If you want to have the displayName outside your build() function, the following code should do the job when you are inside of an async function:
final FirebaseUser user = await _auth.currentUser();
final String displayName = user.displayName;
print('the displayName of the current user is: $displayName');
And this code when you are in a normal function:
_auth.currentUser().then((FirebaseUser user) {
String displayName = user.displayName;
print('displayName: $displayName');
}).catchError((error) {
print('error: ' + error.toString());
});
I think it's worth watching the following video for further understanding:
Async/Await - Flutter in Focus

How do I get data from an sqflite table and display it as a % inside text widget

import 'dart:io';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
class DatabaseHelper {
static final _databaseName = "MyDatabase.db";
static final _databaseVersion = 1;
static final table = 'my_table';
static final columnId = '_id';
static final columnName = 'name';
static final columnAge = 'age';
// make this a singleton class
DatabaseHelper._privateConstructor();
static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
// only have a single app-wide reference to the database
static Database _database;
Future<Database> get database async {
if (_database != null) return _database;
// lazily instantiate the db the first time it is accessed
_database = await _initDatabase();
return _database;
}
// this opens the database (and creates it if it doesn't exist)
_initDatabase() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, _databaseName);
return await openDatabase(path,
version: _databaseVersion,
onCreate: _onCreate);
}
// SQL code to create the database table
Future _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE $table (
$columnId INTEGER PRIMARY KEY,
$columnName TEXT NOT NULL,
$columnAge INTEGER NOT NULL
)
''');
}
// Helper methods
// Inserts a row in the database where each key in the Map is a column name
// and the value is the column value. The return value is the id of the
// inserted row.
Future<int> insert(Map<String, dynamic> row) async {
Database db = await instance.database;
return await db.insert(table, row);
}
// All of the rows are returned as a list of maps, where each map is
// a key-value list of columns.
Future<List<Map<String, dynamic>>> queryAllRows() async {
Database db = await instance.database;
return await db.query(table);
}
// All of the methods (insert, query, update, delete) can also be done using
// raw SQL commands. This method uses a raw query to give the row count.
Future<double> queryRowCount() async {
Database db = await instance.database;
List<Map<String, dynamic>> x = await db.rawQuery('SELECT COUNT(*) FROM $table');
int rowCount = Sqflite.firstIntValue(x);
return rowCount.toDouble();
}
// We are assuming here that the id column in the map is set. The other
// column values will be used to update the row.
Future<int> update(Map<String, dynamic> row) async {
Database db = await instance.database;
int id = row[columnId];
return await db.update(table, row, where: '$columnId = ?', whereArgs: [id]);
}
// Deletes the row specified by the id. The number of affected rows is
// returned. This should be 1 as long as the row exists.
Future<int> delete(int id) async {
Database db = await instance.database;
return await db.delete(table, where: '$columnId = ?', whereArgs: [id]);
}
Future<List<Map<String, dynamic>>> queryOmnivore() async {
Database db = await instance.database;
return await db.query(table, where: '$columnName = ?', whereArgs: ['omnivore']);
}
Future<List<Map<String, dynamic>>> queryPescatarian() async {
Database db = await instance.database;
return await db.query(table, where: '$columnName = ?', whereArgs: ['pescatarian']);
}
Future<List<Map<String, dynamic>>> queryVegetarian() async {
Database db = await instance.database;
return await db.query(table, where: '$columnName = ?', whereArgs: ['vegetarian']);
}
Future<int> queryVegetarianCount() async {
var vegList = await queryVegetarian();
int count = vegList.length;
return count;
}
Future<double> queryOmnivoreCount() async {
var omniList = await queryOmnivore();
int omniCount = omniList.length;
return omniCount.toDouble();
}
Future<double> calcOmnivorePercentage() async {
var x = await queryOmnivoreCount();
var y = await queryRowCount();
double omniPercentage = (x / y) * 100;
return omniPercentage;
}
}
Hey Folks!
I was hoping someone may be able to help me please?!
I'm trying to figure out how to take data out of a a sqflite table I've created, perform a calculation that expresses it as a percentage of the other values, and display it inside a text widget in the app.
I've actually managed to get the result to print in the console using this code:
void omnivorePercentageQ() async {
final omni = await dbHelper.calcOmnivorePercentage();
print('omnivore percentage: ${omni.toStringAsFixed(1)}');
}
But I have no idea how to get it to show up in a text widget in the app itself.
Any ideas would be greatly appreciated!
Thank you,
Jason
you are not far off the answer, and already catch the value of the calculation needed. As i can see you dont need to pass any parameters to the function so i would recomend using a futurebuilder:
return FutureBuilder(
future: dbHelper.calcOmnivorePercentage(),
builder: (context, AsyncSnapshot<double> snapshot) {
if (snapshot.hasData) {
return Center( child: Text('${snapshot.data.toStringAsFixed(1)}'),);
}else
return Center(
child: CupertinoActivityIndicator(),
);
});
The Future Builder class https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html
Serves to manage widgets that depend on futures, since your calculation and database querys are async you can check its state (As inside the widget in snapshot.hasData). That conditional checks if the future has finished and else shows an indicator. Hope it helps

Unable to display ListView from SqFLite

My data is able to upload to the database without any error, however i cant seem to display my listview with the data.
As you can see from the _submit() function, if theres an error, snackbar will be shown indicating theres an error and will not proceed to the mainpage, however, the result shows a snackbar with a success message,
So Im suspecting it has to do with my listview code, or my databasehelper as I may have missed out something in the code.
Any help is deeply appreciated!
Heres my listview code:
FutureBuilder<List<Note>>(
future: _databaseHelper.getNoteList(),
builder: (BuildContext context, AsyncSnapshot<List<Note>> snapshot){
if(snapshot.hasData){
return ListView.builder(
itemCount: _count,
itemBuilder: (BuildContext context, int position) {
Note note = snapshot.data[position];
return Card(
color: Colors.white,
elevation: 2.0,
child: new ListTile(
title: new Text(note.title),
subtitle: new Text(note.bodyText),
onTap: () =>
_navigateToEditAddPage(note, 'Edit a Note'),
onLongPress: () => _showDeleteDialog(note),
),
);
});
}else{
return Container(width: 0,height: 0,);
}
},),
Heres my insertData code:
void _submit() async {
if (_formKey.currentState.validate()) {
note.title = _titleController.text;
note.bodyText = _bodyTextController.text;
note.date = _dateController.text;
if (note.id == null) {
int result = await _databaseHelper.insertData(note);
if (result != 0) {
_moveToHomePage('Note successfully added');
} else {
_showSnackBar('Note unable to be inserted due to some error');
}
} else {
int result = await _databaseHelper.updateData(note);
if (result != 0) {
_moveToHomePage('Note successfully updated');
} else {
_showSnackBar('Note unable to be updated due to some error');
}
}
}
}
Heres my DatabaseHelper code:
class DatabaseHelper {
static Database _database;
String dataTable = 'NoteTable';
String colId = 'id';
String colTitle = 'title';
String colBody = 'bodyText';
String colDate = 'date';
DatabaseHelper._();
static final DatabaseHelper db = DatabaseHelper._();
Future<Database> get database async {
if (_database == null) {
_database = await initializeDatabase();
}
return _database;
}
Future<Database> initializeDatabase() async {
Directory directory = await getApplicationDocumentsDirectory();
String path = directory.path + 'notes.db';
var notesDatabase =
await openDatabase(path, version: 1, onCreate: _createDb);
return notesDatabase;
}
void _createDb(Database database, int newVersion) async {
await database.execute("CREATE TABLE $dataTable ("
"$colId INTEGER PRIMARY KEY AUTOINCREMENT,"
"$colTitle TEXT,"
"$colBody TEXT,"
"$colDate TEXT"
")");
}
Future<List<Map<String, dynamic>>> getNoteListMap() async {
Database db = await this.database;
var result = await db.query(dataTable);
return result;
}
Future<int> insertData(Note note) async {
Database db = await this.database;
var result = await db.insert(dataTable,note.toMap(),conflictAlgorithm:
ConflictAlgorithm.replace,);
return result;
}
Future<int> updateData(Note note) async {
Database db = await this.database;
var result = await db.update(dataTable,note.toMap(),
where: 'colId = ?', whereArgs: [note.id]);
return result;
}
Future<int> deleteData(Note note) async {
Database db = await this.database;
var result = await db
.delete(dataTable, where: 'colId = ?', whereArgs: [note.id]);
return result;
}
Future<int> getCount() async{
Database db = await this.database;
List<Map<String,dynamic>> x = await db.rawQuery('SELECT COUNT (*) from $dataTable');
int result = Sqflite.firstIntValue(x);
return result;
}
Future<List<Note>> getNoteList() async {
var noteMapList = await getNoteListMap();
int count = noteMapList.length;
//list of notes, each note consist of their own independent variables
List<Note> noteList;
for (int i = 0; i < count; i++) {
noteList.add(Note.fromMapObject(noteMapList[i]));
}
return noteList;
}
}
And lastly my Note model:
class Note {
int _id;
String _date;
String _title;
String _bodyText;
Note(this._date, this._title, this._bodyText);
Note.withId(this._id, this._date, this._title, this._bodyText);
set date(String date) {
this._date = date;
}
get date => _date;
set title(String title) {
this._title = title;
}
get title => _title;
set bodyText(String bodyText){
this._bodyText = bodyText;
}
get bodyText => _bodyText;
get id => _id;
Map<String, dynamic> toMap() {
var map = new Map<String, dynamic>();
if (_id != null) {
map['id'] = _id;
}
map['title'] = _title;
map['bodyText'] = _bodyText;
map['date'] = _date;
return map;
}
//Converting a map object to a note object
Note.fromMapObject(Map<String,dynamic> fromMap){
_id = fromMap['id'];
_title = fromMap['title'];
_bodyText = fromMap['bodyText'];
_date = fromMap['date'];
}
}
I found two errors in your code.
1: in getNoteList() of DatabaseHelper
List<Note> noteList;
to
List<Note> noteList = [];
2: in listview code
itemCount: _count,
to
itemCount: snapshot.data.length,
result: