Flutter SQFlite convert Class toJson() - sql

I am building a SQFlite database for my app but I have a problem with the creation of my DB. Converting my class toJson() the code throws me the following errors:
Database file:
Future<Entries> create(Entries entries) async {
final db = await instance.database;
final id = await db.insert(tableFavs, entries.toJson());
}
Error (at entries.toJson()): A value of type 'Set' can't be returned from the method 'toJson' because it has a return type of 'Map<dynamic, dynamic>'.
Here is my class:
import 'package:flutter/material.dart';
const String tableFavs = 'favorites';
class EntryFields {
static late String id = '_id';
static late String name = '_name';
static late String navigation = '_navigation';
}
class Entries {
final int id;
final String name;
final Widget navigation;
Entries({
required this.id,
required this.name,
required this.navigation,
});
Map<Object> toJson() => {
EntryFields.id = id,
EntryFields.name = name,
EntryFields.navigation = navigation,
};
}
Does anyone knows how to fix this?

Related

Flutter - Class 'Future<dynamic>' has no instance method '[]'

I'm building a weather app for practice and I'm getting following error:
Class 'Future<dynamic>' has no instance method '[]'.
Receiver: Instance of 'Future<dynamic>'
Tried calling: []("weather")
And this is where I think it comes from:
void updateUI(dynamic weatherData) {
var condition = weatherData['weather'][0]['id'];
String cityName = weatherData['name'];
double temp = weatherData['main']['temp'];
temperature = temp.toInt();
}
Had to create a class for my Data i got from my api call:
class WeatherData {
final int conditionID;
final String cityName;
final double temperature;
const WeatherData({
required this.conditionID,
required this.cityName,
required this.temperature,
});
factory WeatherData.fromJson(Map<String, dynamic> json) {
return WeatherData(
conditionID: json['weather'][0]['id'],
cityName: json['name'],
temperature: json['main']['temp'],
);
}
}
And then use it in updateUI() like this:
void updateUI(WeatherData weatherData) {
var condition = weatherData.conditionID;
String cityName = weatherData.cityName;
double temp = weatherData.temperature;
temperature = temp.toInt();
}
As always the documentation helped me a lot:
https://docs.flutter.dev/cookbook/networking/fetch-data

How to map nested freezed union classes to drift/moor sql tables?

I need to save this Objects into a SQL/Drift DB, how can/should I design die Tables/Rows for an efficient mapping?
Here is are examples of a (deep)nested union class. It itself is a union class and also has a field which in itself is also a union class again.
What is the best way to deal with this?
#freezed
class TemplateDto with _$TemplateDto {
const factory TemplateDto({
required String templateID,
required String userID,
required String organisationID,
required bool shareWithOrg,
required bool shareGlobal,
required TemplateDataDto templateDataDto,
}) = _TemplateDto;
...
}
#freezed
class TemplateDataDto with _$TemplateDataDto {
const TemplateDataDto._();
const factory TemplateDataDto.templatePack({
required String templateName,
required List<String> templatesInPack,
}) = TemplatePackDto;
const factory TemplateDataDto.homeworkTemplate({
required String templateName,
required HomeworkDataDto homeworkDataDto,
}) = HomeworkTemplateDto;
const factory TemplateDataDto.XXXX({
...
}) = XXXTemplateDto;
...
}
#freezed
class HomeworkDataDto with _$HomeworkDataDto {
const HomeworkDataDto._();
const factory HomeworkDataDto.oneTimeHomework({
required String homeworkName,
required String homeworkDescription,
required bool isActive,
#JsonKey(
includeIfNull: true,
defaultValue: false,
)
required bool isPartOfMultiHomework,
required DateTime dueDate,
}) = _OneTimeHomeworkDto;
const factory HomeworkDataDto.multiOneTimeHomework({
...
}) = _MultiOneTimeHomeworkDto;
const factory HomeworkDataDto.recurringHomework({
...
}) = _RecurringHomeworkDto;
...
}

"LateInitializationError"

I'm having problems with the "non-nullable" and these errors when updated to last version.
I have this error message when run the app:
The following LateError was thrown building Builder:
LateInitializationError: Field '_rHelper#616106152' has not been initialized.
I'm trying to connect with sqlite, and this is Helper class:
class RHelper {
static late Database _database;
static late RHelper _rHelper;
RHelper._createInstance();
factory RHelper() {
if (_rHelper == null) {
_rHelper = RHelper._createInstance();
}
return _rHelper;
}
Future<Database> get database async {
if (_database == null) {
_database = await initializeDatabase();
}
return _database;
}
Future<Database> initializeDatabase() async {
var dir = await getDatabasesPath();
var path = dir + "Rminder.db";
var database =
await openDatabase(path, version: 1, onCreate: (db, version) {
db.execute('''
create table $tableReminder (
$colId integer primary key autoincrement,
$colName text not null,
$colDetails text,
$colSave int )
''');
});
return database;
}
and the initState Function:
I am just try to check if the database had initialized successfully or not!
void initState() async {
super.initState();
await helper
.initializeDatabase()
.then((value) => {print("------------donne?")}); }
Note: I also tried ".whenComplete()" but it doesn't worked!
You must declare
Database? _database;
RHelper? _rHelper;
instead of
static late Database _database;
static late RHelper _rHelper;
because these variables may contain null values (see your own code):
if (_rHelper == null) // <-------
Keyword late is used for non-nullable variables which will be initialized later (for example, in initState method).
UPDATE:
As _rHelper is nullable you must use ! (exclamation sign) to resolve nullable value into non-nullable value.
class RHelper {
factory RHelper() {
if (_rHelper == null) {
_rHelper = RHelper._createInstance();
}
return _rHelper!; // <--------------
}
RHelper._createInstance();
static RHelper? _rHelper;
}
P.S. Please read this article Understanding null safety.

Search where A or B with querydsl and spring data rest

http://localhost:8080/users?firstName=a&lastName=b ---> where firstName=a and lastName=b
How to make it to or ---> where firstName=a or lastName=b
But when I set QuerydslBinderCustomizer customize
#Override
default public void customize(QuerydslBindings bindings, QUser user) {
bindings.bind(String.class).all((StringPath path, Collection<? extends String> values) -> {
BooleanBuilder predicate = new BooleanBuilder();
values.forEach( value -> predicate.or(path.containsIgnoreCase(value) );
});
}
http://localhost:8080/users?firstName=a&firstName=b&lastName=b ---> where (firstName=a or firstName = b) and lastName=b
It seem different parameters with AND. Same parameters with what I set(predicate.or/predicate.and)
How to make it different parameters with AND like this ---> where firstName=a or firstName=b or lastName=b ??
thx.
Your current request param are grouped as List firstName and String lastName. I see that you want to keep your request parameters without a binding, but in this case it would make your life easier.
My suggestion is to make a new class with request param:
public class UserRequest {
private String lastName;
private List<String> firstName;
// getters and setters
}
For QueryDSL, you can create a builder object:
public class UserPredicateBuilder{
private List<BooleanExpression> expressions = new ArrayList<>();
public UserPredicateBuilder withFirstName(List<String> firstNameList){
QUser user = QUser.user;
expressions.add(user.firstName.in(firstNameList));
return this;
}
//.. same for other fields
public BooleanExpression build(){
if(expressions.isEmpty()){
return Expressions.asBoolean(true).isTrue();
}
BooleanExpression result = expressions.get(0);
for (int i = 1; i < expressions.size(); i++) {
result = result.and(expressions.get(i));
}
return result;
}
}
And after you can just use the builder as :
public List<User> getUsers(UserRequest userRequest){
BooleanExpression expression = new UserPredicateBuilder()
.withFirstName(userRequest.getFirstName())
// other fields
.build();
return userRepository.findAll(expression).getContent();
}
This is the recommended solution.
If you really want to keep the current params without a binding (they still need some kind of validation, otherwise it can throw an Exception in query dsl binding)
you can group them by path :
Map<StringPath,List<String>> values // example firstName => a,b
and after that to create your boolean expression based on the map:
//initial value
BooleanExpression result = Expressions.asBoolean(true).isTrue();
for (Map.Entry entry: values.entrySet()) {
result = result.and(entry.getKey().in(entry.getValues());
}
return userRepository.findAll(result);

NHibernate Dynamic Component Default Value Issue

All of my entities (that are mapped to a database table) inherit from an entity class with a dynamic component on it called Attributes e.g.:
public abstract class Entity<T> {
public virtual T Id { get; set; }
private IDictionary _attributes;
public virtual IDictionary Attributes {
get { return _attributes ?? (_attributes = new Hashtable()); }
set { _attributes = value; }
}
}
The Attributes collection allows me to add extra fields to each entity without directly changing the entity itself. This allows me to make my application more modular.
For example say I have the following entity:
public class User : Entity<int> {
public virtual string Name { get; set; }
}
Now say I have a Forum module which needs a NumPosts property against the User. I would add the field against the Users table in the database. This field is non nullable and has a default value of 0. I then map the field using the dynamic component against the User entity.
However when I try inserting the user by saying:
session.Save(new User() { Name = "Test" });
It throws an error as it's expecting me to set a value for NumPosts and the generated SQL would be something like:
INSERT INTO Users (Name, NumPosts) VALUES ('Test', NULL)
However NumPosts does not allow nulls and hence the error. Ideally I'd like it to say the following if the Attributes collection does not contain an entry for NumPosts:
INSERT INTO Users (Name) VALUES ('Test')
An alternative is to say the following which would work fine:
session.Save(new User() { Name = "Test", Attributes = new Hashtable() { { "NumPosts", 0 } } });
The problem I have is that I don't want the modules to have a dependency on each other and I can't really say this.
For reference here's a bare bones version of session factory method which maps the NumPosts field:
return Fluently.Configure()
...
.ExposeConfiguration(c => {
// Get the persistent class
var persistentClass = c.GetClassMapping("User");
// Create the attributes component
var component = new Component(persistentClass);
// Create a simple value
var simpleValue = new SimpleValue(persistentClass.Table);
// Set the type name
simpleValue.TypeName = "Int32";
// Create a new db column specification
var column = new Column("NumPosts");
column.Value = simpleValue;
column.Length = 10;
column.IsNullable = false;
column.DefaultValue = "0";
// Add the column to the value
simpleValue.AddColumn(column);
// Ad the value to the component
component.AddProperty(new Property() { Name = column.Name, Value = simpleValue });
// Add the component property
persistentClass.AddProperty(new Property() { Name = "Attributes", Value = component });
})
.BuildConfiguration();
I'd appreciate if someone could let me know if this is possible. Thanks
You know how to make it working as described above:
... An alternative is to say the following which would work fine:
session.Save(new User()
{
Name = "Test", Attributes = new Hashtable() { { "NumPosts", 0 } }
});
... The problem I have is that I don't want the modules to have a dependency on each other and I can't really say this...
In case, that the biggest issue is the explicit Attributes initialization ("...I don't want the modules to have a dependency...") we can use:
12.2. Event system
So, with Listener like this:
[Serializable]
public class MyPersistListener : NHibernate.Event.ISaveOrUpdateEventListener
{
public void OnSaveOrUpdate(SaveOrUpdateEvent #event)
{
var entity = #event.Entity as Entity<int>; // some interface IHaveAttributes
if (entity == null) // would be more appropriate
{
return;
}
var numPosts = entity.Attributes["NumPosts"] as int?;
if (numPosts.HasValue)
{
return;
}
entity.Attributes["NumPosts"] = 0;
}
}
Based on this doc snippet:
Configuration cfg = new Configuration();
ILoadEventListener[] stack = new ILoadEventListener[] { new MyLoadListener(), new DefaultLoadEventListener() };
cfg.EventListeners.LoadEventListeners = stack;
This should be the init in our case:
.ExposeConfiguration(c => {
var stack = new ISaveOrUpdateEventListener [] { new MyPersistListener() };
c.EventListeners.SaveEventListeners= stack;