I'm creating todo app in flutter. And I need to show Todos date wise. Like all Todos created today should shown under Today, all the tomorrow's Todos should shown under Tomorrow.
I have created my table like this:
database.execute("""
CREATE TABLE Todotable(
id INTEGER PRIMARY KEY AUTOINCREMENT,
taskName TEXT NOT NULL,
taskTag TEXT NOT NULL,
date TEXT NOT NULL,
isReminder INTEGER NOT NULL,
isCompleted INTEGER NOT NULL
)
""");
I don't know how to query SQFlite data date wise and format it like Today and Tomorrow. And show in section like today and tomorrow as shown in design.
Thanks for answers:)
for getting todos for tomorrow
//for tomorrow
String tomorrowDate= DateTime.now().add(Duration(days: 1)).toIso8601String();
var todosForTomrrow= await database
.rawQuery('SELECT * FROM Todotable WHERE date = ?', [tomorrowDate]);
//for today
String todayDate= DateTime.now().toIso8601String();
var todosForToday= await database
.rawQuery('SELECT * FROM Todotable WHERE date = ?', [todayDate]);
Date is converted and saved here in string format and date should converted to same format before inserting into the table like this
You can create DATETIME columns in sqflite.
Here is an example for a Weather table created in a sqflite database:
batch.execute('''
CREATE TABLE $tableWeather (
$weatherLocalization TEXT NOT NULL,
$weatherDate DATETIME NOT NULL,
$weatherHumidityPercentage REAL,
$weatherWindDegree REAL,
$weatherWindSpeed REAL,
$weatherPressureHPascal INTEGER,
$weatherTemperatureCelsius REAL,
$weatherDescription TEXT,
$weatherIconId TEXT,
PRIMARY KEY($weatherLocalization, $weatherDate));
''',);
You can create a Weather object as follows:
class Weather{
String localization;
DateTime date;
double humidityPercentage;
double windDegree;
double windSpeedMS;
int pressureHPascal;
double temperatureCelsius;
String description;
String iconId;
Weather({
#required this.localization,
#required this.date,
this.humidityPercentage,
this.windDegree,
this.windSpeedMS,
this.pressureHPascal,
this.temperatureCelsius,
this.description,
this.iconId
});
//to be used when inserting a row in the table
Map<String, dynamic> toMap() {
final map = new Map<String, dynamic>();
map["$weatherLocalization"] = localization;
map["$weatherDate"] = date.toString();
map["$weatherHumidityPercentage"] = humidityPercentage;
map["$weatherWindDegree"] = windDegree;
map["$weatherWindSpeed"] = windSpeedMS;
map["$weatherPressureHPascal"] = pressureHPascal;
map["$weatherTemperatureCelsius"] = temperatureCelsius;
map["$weatherDescription"] = description;
map["$weatherIconId"] = iconId;
return map;
}
//to be used when converting the row into object
factory WeatherOnDate.fromMap(Map<String, dynamic> data) => new WeatherOnDate(
localization: data["$weatherLocalization"],
date: DateTime.parse(data["$weatherDate"]),
humidityPercentage: data["$weatherHumidityPercentage"],
windDegree: data["$weatherWindDegree"],
windSpeedMS: data["$weatherWindSpeed"],
pressureHPascal: data["$weatherPressureHPascal"],
temperatureCelsius: data["$weatherTemperatureCelsius"],
description: data["$weatherDescription"],
iconId: data["$weatherIconId"]
);
}
Be careful to transform your DateTime attribute to a String or int as I did in the toMap() function.
Then, when you want to fetch a date you can do this:
Future<Weather> fetchWeatherOnDate(DateTime dateTime) async {
DatabaseHelper _databaseHelper = Injection.injector.get();
List<Map<String, dynamic>> weatherMaps = await _databaseHelper.db.rawQuery(
'SELECT * FROM $tableWeather WHERE DATE($weatherDate) = DATE(?)',
[dateTime.toString()]);
List<Weather> weathers= [];
for (final weatherMap in weatherMaps) {
weathers.add(Weather.fromMap(weatherMap));
}
if (weathers.isNotEmpty){
return weathers[0];
}
return null;
}
DateTime today = DateTime.now()
Weather weatherToday = fetchWeatherOnDate(today);
I think that it gives you a good idea of how to solve your problem :)
DateTime is not supported in Flutter SQLite package.
Check the information about supported SQLite types:
https://pub.dev/packages/sqflite#supported-sqlite-types
DateTime is not a supported SQLite type. Personally I store them as int (millisSinceEpoch) or string (iso8601)
We can use String or int as suggested from the package developer.
To work with a conditional selection of items of day in DB, perhaps a String is more convenient.
Personally, I prefer user formatter to get the search keyword, as shown below:
DateFormat formater = DateFormat('yyyyMMdd');
var today = formater.format(DateTime.now());
var tomorrow = formater.format(DateTime.now().add(const Duration(days: 1)));
To search in DB, I'd use a method like below:
Future<TodoList?> getTodoListByDay(String day) async {
final db = await database;
String sql =
"SELECT * FROM Todotable WHERE date = \'${day}\' ";
var res = await db.rawQuery(sql);
List<TodoList> objs = res.isNotEmpty
? res.map((c) => TodoList.fromMap(c)).toList()
: [];
return objs.isNotEmpty ? objs : null;
}
TodoList class could be generate from json, as I do with 'jsonToDartModel' package.
import 'dart:convert';
class TodoList {
int? id;
String? taskName;
String? taskTag;
String? date;
int? isReminder;
int? isCompleted;
TodoList({
this.id,
this.taskName,
this.taskTag,
this.date,
this.isReminder,
this.isCompleted,
});
factory TodoList.fromMap(Map<String, dynamic> data) => TodoList(
id: data['id'] as int?,
taskName: data['taskName'] as String?,
taskTag: data['taskTag'] as String?,
date: data['date'] as String?,
isReminder: data['isReminder'] as int?,
isCompleted: data['isCompleted'] as int?,
);
Map<String, dynamic> toMap() => {
'id': id,
'taskName': taskName,
'taskTag': taskTag,
'date': date,
'isReminder': isReminder,
'isCompleted': isCompleted,
};
/// `dart:convert`
///
/// Parses the string and returns the resulting Json object as [TodoList].
factory TodoList.fromJson(String data) {
return TodoList.fromMap(json.decode(data) as Map<String, dynamic>);
}
/// `dart:convert`
///
/// Converts [TodoList] to a JSON string.
String toJson() => json.encode(toMap());
}
Related
For explaining what I am facing problem while creating a jsonstring from object list,I have created this basic demo,
actually I am trying to create a backup file for saving records but I am getting an error while jsonEncode.
getting following error
Converting object to an encodable object failed: Instance of 'TransactionModel'
class TransactionModel {
String id;
bool isexpense;
DateTime date;
double amount;
TransactionModel({
this.amount = 0.00,
required this.id,
this.isexpense = true,
required this.date,
});
Map<String, dynamic> toJson() {
return {
'id': id,
'isexpense': isexpense,
'date': date,
'amount': amount,
};
}
}
void main() {
List<TransactionModel> trans = [
TransactionModel(
date: DateTime.now(),
id: '1',),
];
String result = jsonEncode(trans);//error bcz of jsonEncode
print(result);
}
You can't encode an object with custom property like DateTime, you need first convert it to map, then encode it, try this:
void main() {
List<TransactionModel> trans = [
TransactionModel(
date: DateTime.now(),
id: '1',),
];
var listOfMap = trans.map((e) => e.toJson()).toList();
String result = jsonEncode(listOfMap);
print(result);
}
I'm using back4app.com services (Prase SDK) on my flutter project to handle my backend.
in this method I try to query on specific object :
Future<List> getList(String date) async {
final QueryBuilder<ParseObject> parseQuery =
QueryBuilder<ParseObject>(ParseObject('UsersEaten'));
parseQuery
..whereContains('eatenBy', getUsrName!)
..whereEqualTo('eatenDate', date);
final ParseResponse apiResponse = await parseQuery.query();
if (apiResponse.success && apiResponse.results != null) {
List<dynamic>? apiRes = apiResponse.results;
and I've got whole data about this object as a List of Map :
[{"className":"UsersEaten","objectId":"OmrLz358Cb","createdAt":"2021-09-12T11:27:41.824Z","updatedAt":"2021-09-12T11:27:41.824Z","eatenTitle":"egg roll","eatenCal":180,"eatenFat":40,"eatenProtein":30,"eatenCarb":10,"eatenBy":"usr45","eatenDate":"2021-09-12"}, {"className":"UsersEaten","objectId":"lWIeMw54mH","createdAt":"2021-09-12T12:37:21.389Z","updatedAt":"2021-09-12T12:37:21.389Z","eatenTitle":"meat butter","eatenCal":235,"eatenFat":34,"eatenProtein":34,"eatenCarb":9,"eatenBy":"usr45","eatenDate":"2021-09-12"}]
but I dont need whole data I just want a specific Key , Values from this map for example I just need UsersEaten key values, how should I apply this kind of filter in my query???
In case I understand your question right, you want to reduce the amount of keys returned by the server.
This can be achieved using keysToReturn(List<String> keys).
/// Define which keys in an object to return.
///
/// [String] keys will only return the columns of a result you want the data for,
/// this is useful for large objects
void keysToReturn(List<String> keys) {
limiters['keys'] = concatenateArray(keys);
}
So your query might look something like this:
parseQuery
..whereContains('eatenBy', getUsrName!)
..whereEqualTo('eatenDate', date)
keysToReturn(['YOUR_KEY_THAT_SHOULD_BE_RETURNED']);
There is also the exact opposite of this method available, called excludeKeys(List<String> keys).
Create data class I chose the name Example for it
class Example {
String? className;
String? objectId;
String? createdAt;
String? updatedAt;
String? eatenTitle;
int? eatenCal;
int? eatenFat;
int? eatenProtein;
int? eatenCarb;
String? eatenBy;
String? eatenDate;
Example({
this.className,
this.objectId,
this.createdAt,
this.updatedAt,
this.eatenTitle,
this.eatenCal,
this.eatenFat,
this.eatenProtein,
this.eatenCarb,
this.eatenBy,
this.eatenDate,
});
Map<String, dynamic> toMap() {
return {
'className': className,
'objectId': objectId,
'createdAt': createdAt,
'updatedAt': updatedAt,
'eatenTitle': eatenTitle,
'eatenCal': eatenCal,
'eatenFat': eatenFat,
'eatenProtein': eatenProtein,
'eatenCarb': eatenCarb,
'eatenBy': eatenBy,
'eatenDate': eatenDate,
};
}
factory Example.fromMap(Map<String, dynamic> map) {
return Example(
className: map['className'],
objectId: map['objectId'],
createdAt: map['createdAt'],
updatedAt: map['updatedAt'],
eatenTitle: map['eatenTitle'],
eatenCal: map['eatenCal'],
eatenFat: map['eatenFat'],
eatenProtein: map['eatenProtein'],
eatenCarb: map['eatenCarb'],
eatenBy: map['eatenBy'],
eatenDate: map['eatenDate'],
);
}
String toJson() => json.encode(toMap());
factory Example.fromJson(String source) => Example.fromMap(json.decode(source));
}
Unfortunately, I don't know how to use this service back4app.com, but it should look like this
if (apiResponse.success && apiResponse.results != null) {
final maps = jsonDecode(apiResponse.results).cast<Map<String, dynamic>>();
var exampleList = List.generate(maps.length, (i) {
return Example.fromMap(maps[i]);
});
//sum of calories
num sum = 0;
exampleList.forEach((element){sum += element.eatenCal;});
print(sum);
}
Overview:
App architecture details:
state management -> provider (not sure this is relevant, but in case you are interested)
data storage -> SQFlite
Specific issue details:
I have a calendarDay data model, with a property of
DateTime date;
I know that DateTime is not supported in SQLite (not in SQFlite either) and the recommendation is to use a String or Integer . I am struggling with how to actually do that.
Error I am getting:
flutter: *** WARNING ***
Invalid argument 2021-07-01 15:09:11.129598 with type DateTime.
Only num, String and Uint8List are supported. See https://github.com/tekartik/sqflite/blob/master/sqflite/doc/supported_types.md for details
This will throw an exception in the future. For now it is displayed once per type.
This is my setup:
calendar_day.dart
class CalendarDay {
int? id;
DateTime date;
CalendarDay(
{this.id,
required this.date});
// encode to SQLite database
Map<String, dynamic> toMap() {
final map = Map<String, dynamic>();
map['id'] = id;
map['date'] = date.toIso8601String(); //toString(); this toString did not work //jsonEncode(date) -> SERIALIZE THE ARRAYS INTO JSON strings, this did not work
return map;
}
// decode from SQLite database
static fromMap(Map map) {
return CalendarDay(
id: map['id'],
date: DateTime.parse(map['date']), // jsonDecode(map['date']));
}
}
database_client.dart
class DatabaseClient {
Future<Database> initializedDatabase() async {
WidgetsFlutterBinding.ensureInitialized();
String path = await getDatabasesPath();
return openDatabase(
join(path, 'three_things_database.db'),
onCreate: (database, version) async {
await database.execute(
"CREATE TABLE ${Strings.calendarDayDataBase} (id INTEGER PRIMARY KEY, date TEXT)",
); },
version: 1, ); }
// Create / insert calendarDay
Future<void> insertCalendarDay(CalendarDay day) async {
final Database database = await initializedDatabase();
await database.insert(
Strings.calendarDayDataBase,
day.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
}
I am thinking the problem lies with the toMap() method, since the error notes the DateTime object. But I am a bit stuck and don't really know how to get around this. Any help is greatly appreciated.
Additional things I have tried in toMap() :
I did include the code commented out, but for clarity, I'll post here:
I tried mapping the DateTime object to a JSONString. This would hopefully be enough for storing the map in SQLite database, but this approach threw the same error.
Tried mapping to a regular String using date.toString(). This did not work either. Since the recommendation (link above) from the SQFlite folks is to use ISO8601 string, I thought this approach would work.
Related question(s), yet did not solve my question:
Create DateTime column in SQFlite
Here's a clear example :
var dt = DateTime.now();
// String
var dtStr = dt.toIso8601String();
dt = DateTime.tryParse(dtStr);
// Int
var dtInt = dt.millisecondsSinceEpoch;
dt = DateTime.fromMillisecondsSinceEpoch(dtInt);
I'm trying to convert a timestamp I get from a network call and display it as regular time and date in my app. But I cant access the "int timestamp" from its class.
import 'package:intl/intl.dart';
int timeInMillis = **timestamp**; // I'm trying to get the timestamp here !!
var date = DateTime.fromMillisecondsSinceEpoch(timeInMillis);
var formattedDate = DateFormat('HH:mm - dd.MM.yyyy').format(date);
class Posts {
final String result;
final int timestamp;
final String time;
Posts({this.timestamp, this.result, this.time});
factory Posts.fromJson(Map<String, dynamic> json) {
return Posts(
result: json['result'],
timestamp: json['timestamp'],
time: formattedDate,
);
}
}
You need to convert the value from json using int.parse('1610515846')
import 'package:intl/intl.dart';
int timeInMillis = **timestamp**; // I'm trying to get the timestamp here !!
var date = DateTime.fromMillisecondsSinceEpoch(timeInMillis);
var formattedDate = DateFormat('HH:mm - dd.MM.yyyy').format(date);
class Posts {
final String result;
final int timestamp;
final String time;
Posts({this.timestamp, this.result, this.time});
factory Posts.fromJson(Map<String, dynamic> json) {
return Posts(
result: json['result'],
timestamp: int.parse(json['timestamp']),
time: formattedDate,
);
}
}
I have a complex model and could not able to save them on locally wiht Sqflite (Flutter).
I am able to save the base model on db. But I could not save others.
I try to do it like this.(Video has multiple data)
int res = await dbClient.insert("$tableName", game.toMap());
for (var i = 0; i < object.videos.length; i++) {
Video expectedList = Video.map(object.videos[i]);
int res2 = await dbClient.insert("video", expectedList.toMap());
}
This is the base model;
int versionParent;
double popularity;
String key;
String versionTitle;
dynamic keywords = List<Keyword>();
dynamic videos = List<Video>();
dynamic genres = List<Genres>();
This is the map function on model;
var map = Map<String, dynamic>();
map['genres'] = genres;
map['id'] = id;
map['keywords'] = keywords;
map['key'] = key;
map['versionTitle'] = versionTitle;
map['popularity'] = popularity;
map['videos'] = videos;
return map;
}
this is one of the dynamic list file model;
int _id;
int _game;
String _name;
String _videoId;
Map<String, dynamic> toMap() {
var map = Map<dynamic, dynamic>();
map['id'] = id;
map['game'] = game;
map['name'] = name;
map['video_id'] = videoId;
return map;
}
this is the tables I created (I create table for all of the dynamic lists)
await db.execute('CREATE TABLE $tableName(id INTEGER PRIMARY KEY,hypes INTEGER, updatedAt INTEGER, pulseCount INTEGER, coverCoverId INTEGER, versionParent INTEGER, popularity INTEGER, firstReleaseDate INTEGER, key TEXT , url TEXT, name TEXT, slug TEXT, summary TEXT, imageCoverId TEXT, versionTitle TEXT)');
await db.execute(
'CREATE TABLE video(id INTEGER PRIMARY KEY, game INTEGER, name TEXT, videoId TEXT)');