How to write test for construction of a class using Dio? - flutter

I have a class which will fetch the imgUrl on first creation in the constructor.
And I need to write a test to make sure that the get method of Dio instance is called.
However, I have trouble that the fetch result returns null instead of Future so that I cannot call then.
The class:
#JsonSerializable()
class DogBreed with ChangeNotifier {
#JsonKey(ignore: true)
final Dio dio;
final String id;
final String bred_for;
final String breed_group;
final String life_span;
final String name;
final String origin;
final String temperament;
final String description;
final Measurement height;
final Measurement weight;
var imgUrl = '';
DogBreed({
this.dio,
this.id,
this.bred_for,
this.breed_group,
this.life_span,
this.name,
this.origin,
this.temperament,
this.description,
this.height,
this.weight,
}) {
dio.get(
'xxxxx,
queryParameters: {
'breed_id': id,
'limit': 1,
},
).then((result) {
final List data = result.data;
if (result.statusCode == 200) {
if (data.isNotEmpty) {
imgUrl = result.data[0]['url'];
} else {
imgUrl = NO_IMAGE_AVAILABLE_URL;
}
notifyListeners();
}
});
}
factory DogBreed.fromJson(Map<String, dynamic> json) =>
_$DogBreedFromJson(json);
}
My test:
class MockDio extends Mock implements Dio {}
void main() {
MockDio mockDio;
setUp(() {
mockDio = MockDio();
});
test(
"fetch the imageUrl on constructor",
() async {
when(mockDio.get(any))
.thenAnswer((_) async => Response(data: 'url', statusCode: 200));
final newBreedProvider = DogBreed(
dio: mockDio,
id: '12',
);
verify(mockDio.get(
'xxxx',
queryParameters: {
'breed_id': 12,
'limit': 1,
},
));
},
);
}
Result when run test:
dart:core Object.noSuchMethod
package:practises/projects/dog_facts/providers/dog_breed.dart 46:7 new DogBreed
test/projects/dog_facts/providers/dog_breed_test.dart 24:32 main.<fn>
NoSuchMethodError: The method 'then' was called on null.
Receiver: null
Tried calling: then<Null>(Closure: (Response<dynamic>) => Null)
Could anyone help me to figure out how to write this test or suggest me a new way of implementing so that I can write a test on this one?

I figured out why, it's my mistake that I need to provide queryParameters for get method in the test. It should be:
when(
mockPdio.get(
any,
queryParameters: anyNamed('queryParameters'),
),
).thenAnswer((_) async => Response(data: 'url', statusCode: 200));
Cheers.

Related

How to write exception in build of AsyncNotifier from riverpod

When not connected to the internet, executing the following code will cause a _ClientSocketException.
How should I write the exception handling?
class AsyncTodosNotifier extends AsyncNotifier<List<Todo>> {
Future<List<Todo>> _fetchTodo() async {
final json = await http.get('api/todos'); //** _ClientSocketException Error occurred**
final todos = jsonDecode(json) as List<Map<String, dynamic>>;
return todos.map((todo) => Todo.fromJson(todo)).toList();
}
#override
Future<List<Todo>> build() async {
return _fetchTodo();
}
Using the AsyncNotifier's build() from riverpod, I would like to code exception handling with AsyncValue.guard, but it results in a syntax error.
How should I write it to make it work?
When trying to get json data, if I can't connect to the internet, I want to write exception handling so that it doesn't abort.
Reference:
https://docs-v2.riverpod.dev/docs/providers/notifier_provider
full code:
implementation.
#immutable
class Todo {
const Todo({
required this.id,
required this.description,
required this.completed,
});
factory Todo.fromJson(Map<String, dynamic> map) {
return Todo(
id: map['id'] as String,
description: map['description'] as String,
completed: map['completed'] as bool,
);
}
final String id;
final String description;
final bool completed;
Map<String, dynamic> toJson() => <String, dynamic>{
'id': id,
'description': description,
'completed': completed,
};
}
class AsyncTodosNotifier extends AsyncNotifier<List<Todo>> {
Future<List<Todo>> _fetchTodo() async {
final json = await http.get('api/todos'); //** _ClientSocketException Error occurred**
final todos = jsonDecode(json) as List<Map<String, dynamic>>;
return todos.map((todo) => Todo.fromJson(todo)).toList();
}
#override
Future<List<Todo>> build() async {
return _fetchTodo();
}
Future<void> addTodo(Todo todo) async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() async {
await http.post('api/todos', todo.toJson());
return _fetchTodo();
});
}
}
final asyncTodosProvider =
AsyncNotifierProvider<AsyncTodosNotifier, List<Todo>>(() {
return AsyncTodosNotifier();
});

Flutter: NoSuchMethodError: Class 'int' has no instance method

My debug statement is displaying the database correctly, by after something is going wrong and in getting the error: Unhandled Exception: NoSuchMethodError: Class 'int' has no instance method '[]'. I am getting null data when I'm trying to display is in my application, this is because the list i am using to store the values has length 0
following is my class
class UserDetails extends ChangeNotifier {
final String? userId;
final String? mobileno;
bool? userStatus;
final String? adhar;
final String? pan;
final String? adharno;
final String? panno;
UserDetails(
{this.userId,
this.mobileno,
this.userStatus = false,
this.adhar,
this.pan,
this.adharno,
this.panno});
}
following is my api where I am facing error
Future<void> getUsers(BuildContext context) async {
final url = '${PurohitApi().baseUrl}${PurohitApi().users}';
final List<UserDetails> loadedUsers = [];
try {
final client = RetryClient(
http.Client(),
retries: 4,
when: (response) {
return response.statusCode == 401 ? true : false;
},
onRetry: (req, res, retryCount) async {
//print('retry started $token');
if (retryCount == 0 && res?.statusCode == 401) {
var accessToken = await Provider.of<Auth>(context, listen: false)
.restoreAccessToken();
// Only this block can run (once) until done
req.headers['Authorization'] = accessToken;
}
},
);
var response = await client.get(
Uri.parse(url),
headers: {'Authorization': authToken!},
);
final extractedData = json.decode(response.body) as Map<String, dynamic>;
print(extractedData);
if (extractedData['data'] == null) {
return;
}
extractedData.forEach((userId, userData) {
print(userId);
loadedUsers.add(
UserDetails(
userId: userData['data']['id'],
mobileno: userData['data']['mobileno'],
userStatus: userData['data']['userstatus'],
adhar: userData['data']['adhar'],
pan: userData['data']['pan'],
adharno: userData['data']['adharno'],
panno: userData['data']['panno'],
),
);
});
_users = loadedUsers.reversed.toList();
//print(users);
notifyListeners();
} catch (e) {
print(e);
}
}
}
I am facing NoSuchMethodError: Class 'int' has no instance method '[]'Tried calling: from above api following is my response
I think userId should not be String, It should be an integer
class UserDetails extends ChangeNotifier {
final int? userId;
final String? mobileno;
bool? userStatus;
final String? adhar;
final String? pan;
final String? adharno;
final String? panno;
UserDetails(
{this.userId,
this.mobileno,
this.userStatus = false,
this.adhar,
this.pan,
this.adharno,
this.panno});
}
try to print your data in this error I think your data should be like userData['id'],
the above error is you try to use int as an object in the data returned
the returned userData is an int
change this code :
extractedData.forEach((userId, userData) {
print(userId);
loadedUsers.add(
UserDetails(
userId: userData['data']['id'],
mobileno: userData['data']['mobileno'],
userStatus: userData['data']['userstatus'],
adhar: userData['data']['adhar'],
pan: userData['data']['pan'],
adharno: userData['data']['adharno'],
panno: userData['data']['panno'],
),
);
});
to this :
loadedUsers.add(
UserDetails(
userId: extractedData['data']['id'],
mobileno: extractedData['data']['mobileno'],
userStatus: extractedData['data']['userstatus'],
adhar: extractedData['data']['adhar'],
pan: extractedData['data']['pan'],
adharno: extractedData['data']['adharno'],
panno: extractedData['data']['panno'],
),
);
the reason why :
extractedData is a map<String,dynamic>, when you call function forEach(key, value) :
the value is not a map, is an Object, or dynamic. the key is a String.
when you call this fuction :
value['data]
its will throw that error
if you extractedData is a List of Map, you can keep you original code, and change type of extractedData to List :
final extractedData = json.decode(response.body) as List<Map<String, dynamic>>;
Edit :
your data in the response is a list Of a map so the code will be this :
final extractedData = json.decode(response.body) as Map<String,dynamic>;
List<Map<String,dynamic>> data = extractedData['data'];
for (var map in data){
loadedUsers.add(
UserDetails(
userId: map['id'],
mobileno: map['mobileno'],
userStatus: map['userstatus'],
adhar: map['adhar'],
pan: map['pan'],
adharno: map['adharno'],
panno: map['panno'],
),
);
}

Error fetching API / A value of type 'List<Heroes>' can't be returned from the method 'getHeroes' because has a return type of 'Future<List<String>?>

im new in Dart/Flutter and im struggling with consuming API, here is my file thats inside my model folder:
List<Heroes> heroesFromJson(String str) =>
List<Heroes>.from(json.decode(str).map((x) => Heroes.fromJson(x)));
String heroesToJson(List<Heroes> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Heroes {
Heroes({
required this.id,
required this.name,
required this.localizedName,
required this.primaryAttr,
required this.attackType,
required this.roles,
});
int id;
String name;
String localizedName;
String primaryAttr;
String attackType;
List<String> roles;
factory Heroes.fromJson(Map<String, dynamic> json) => Heroes(
id: json["id"],
name: json["name"],
localizedName: json["localized_name"],
primaryAttr: json["primary_attr"],
attackType: json["attack_type"],
roles: List<String>.from(json["roles"].map((x) => x)),
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"localized_name": localizedName,
"primary_attr": primaryAttr,
"attack_type": attackType,
"roles": List<dynamic>.from(roles.map((x) => x)),
};
}
And here is where im getting the error, inside services folder:
class DotaServices {
Future<List<String>?> getHeroes() async {
var client = http.Client();
var url = Uri.parse('https://api.opendota.com/api/heroes');
var response = await client.get(url);
if (response.statusCode == 200) {
var json = response.body;
return heroesFromJson(json);
}
}
}
The error is occuring in that line:
return heroesFromJson(json);
And the message that appears is:
A value of type 'List<Heroes>' can't be returned from the method 'getHeroes' because it has a return type of 'Future<List<String>?>'.
how to solve it? Im struggling real hard on this :/
Your method returns a list of heroes... so... you need to return a list of heroes:
Future<List<String>?> getHeroes() async {
needs to be
Future<List<Heroes>?> getHeroes() async {
heroesFromJson returns a list of heroes so getHeroes has to return a list of heroes:
Future<List<Heroes>?> getHeroes()
Also, your method heroesFromJson returns a List<Heroes> not nullable, but your method getHeroes() return a List<Heroe>? which is nullable.
You either can make your return from heroesFromJson a nullable list List<T>? or your return from getHeroes() a non-nullable list List
Be careful making your List nullable or non-nullable List<Hero>?, not your Hero List<Hero?>
It seems to me that such code should work more reliably.
return Hero.fromJsonList(json as List);
This small example (including function main) was generated with a very small script.
import 'dart:convert';
import 'package:http/http.dart' as http;
void main(List<String> args) async {
final svc = DotaServices();
final heroes = await svc.getHeroes();
print('Heroes: ${heroes.length}');
}
class DotaServices {
Future<List<Hero>> getHeroes() async {
final client = http.Client();
final url = Uri.parse('https://api.opendota.com/api/heroes');
final response = await client.get(url);
if (response.statusCode == 200) {
final source = response.body;
final json = jsonDecode(source);
return Hero.fromJsonList(json as List);
}
throw StateError('Http error: ${response.statusCode}');
}
}
class Hero {
Hero(
{required this.id,
required this.name,
required this.localizedName,
required this.primaryAttr,
required this.attackType,
required this.roles});
factory Hero.fromJson(Map json) {
return Hero(
id: json['id'] as int,
name: json['name'] as String,
localizedName: json['localized_name'] as String,
primaryAttr: json['primary_attr'] as String,
attackType: json['attack_type'] as String,
roles: json['roles'] == null
? []
: (json['roles'] as List).map((e) => e as String).toList(),
);
}
final int id;
final String name;
final String localizedName;
final String primaryAttr;
final String attackType;
final List<String> roles;
static List<Hero> fromJsonList(List json) {
return json.map((e) => Hero.fromJson(e as Map)).toList();
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'localized_name': localizedName,
'primary_attr': primaryAttr,
'attack_type': attackType,
'roles': roles,
};
}
static List<Map<String, dynamic>> toJsonList(List<Hero> list) {
return list.map((e) => e.toJson()).toList();
}
}
Using this codegen script you can generate the models and serializers.
It also generates a working example.
import 'dart:io';
import 'package:object_serializer/json_serializer_generator.dart';
import 'package:yaml/yaml.dart';
void main() {
final classes = loadYaml(_classes) as Map;
final g = JsonSerializerGenerator();
final classesCode = g.generateClasses(classes);
final values = {
'classes': classesCode,
};
var source = g.render(_template, values);
source = g.format(source);
File('bin/stackoverflow.dart').writeAsStringSync(source);
}
const _classes = '''
Hero:
fields:
id: int
name: String
localizedName: {type: String, alias: localized_name}
primaryAttr: {type: String, alias: primary_attr}
attackType: {type: String, alias: attack_type}
roles: List<String>
''';
const _template = r'''
import 'dart:convert';
import 'package:http/http.dart' as http;
void main(List<String> args) async {
final svc = DotaServices();
final heroes = await svc.getHeroes();
print('Heroes: ${heroes.length}');
}
class DotaServices {
Future<List<Hero>> getHeroes() async {
final client = http.Client();
final url = Uri.parse('https://api.opendota.com/api/heroes');
final response = await client.get(url);
if (response.statusCode == 200) {
final source = response.body;
final json = jsonDecode(source);
return Hero.fromJsonList(json as List);
}
throw StateError('Http error: ${response.statusCode}');
}
}
{{classes}}
''';

Data gets lost when added to a Model

I am getting data from Firebase Database and Adding it to a List of my Model class. I tested the incoming data by printing to Console and it works fine, but once i add the data to my model class, it disappears.
Here's my Provider class where i'm loading the data.
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:local_stuffs_notification/apis/fcm.dart';
import 'package:local_stuffs_notification/models/request_model.dart';
import 'package:shared_preferences/shared_preferences.dart';
class IncomingRequest with ChangeNotifier {
List<RequestModel> _incomingRequests = [];
IncomingRequest(this._incomingRequests);
List<RequestModel> get incomingRequest {
return [..._incomingRequests];
}
Future<void> setIncomingRequest(RequestModel requestModel) async {
try {
DatabaseReference reference =
FirebaseDatabase.instance.ref("incomingRequests");
reference.child(requestModel.id).child(Fcm.getUid()).set(
{
"name": requestModel.name.toString(),
"phone": requestModel.phone.toString(),
"email": requestModel.email.toString(),
"fcmToken": requestModel.fcmToken.toString(),
},
);
notifyListeners();
} catch (error) {
rethrow;
}
}
Future<void> loadIncomingRequests() async {
try {
SharedPreferences preferences = await SharedPreferences.getInstance();
DatabaseReference reference = FirebaseDatabase.instance
.ref('incomingRequests/${preferences.getString('userId')!}');
Stream<DatabaseEvent> stream = reference.onValue;
stream.listen((DatabaseEvent event) {
print(event.snapshot.value);
final data = event.snapshot.value as Map;
print('data: $data');
final List<RequestModel> loadedRequest = [];
data.forEach(
(key, value) {
print('requestData: ${value['name']}');
loadedRequest.add(
RequestModel(
id: key.toString(),
name: value['name'].toString(),
fcmToken: value['fcmToken'].toString(),
phone: value['phone'].toString(),
email: value['email'].toString(),
),
);
print(loadedRequest);
},
);
_incomingRequests = loadedRequest;
print('LoadedRequests: $loadedRequest');
notifyListeners();
});
// reference.onValue.listen(
// (event) {
// if (event.snapshot.value == null) {
// return;
// }
// final data = event.snapshot.value as Map;
// final List<RequestModel> loadedRequests = [];
// data.forEach(
// (key, requestData) {
// loadedRequests.add(
// RequestModel(
// id: key,
// name: requestData['name'],
// fcmToken: requestData['fcmToken'],
// phone: requestData['phone'],
// email: requestData['email'],
// ),
// );
// },
// );
// _incomingRequests = loadedRequests;
// notifyListeners();
// },
//);
} catch (error) {
rethrow;
}
}
}
Here's my Model Class
class RequestModel {
final String id;
final String name;
final String fcmToken;
final String phone;
final String email;
RequestModel({
required this.id,
required this.name,
required this.fcmToken,
required this.phone,
required this.email,
});
}
I'm getting the data until i added it to loadedRequest List
Please help, i've spent hours on this and i don't know what i'm doing wrong. When i print the loadedRequest list, i get an empty list. Thanks.
Those logs aren't showing an empty list - It says [Instance of 'RequestModel']. That means there is a value there, but Dart simply doesn't know how to convert RequestModel to a String so that it can be printed out on the console.
An empty list would be printed simply as [], and if you had two values, for example, you would see [Instance of 'RequestModel', Instance of 'RequestModel'].
To print out your values with more detail, you can override the toString() method on your class.
For example:
class RequestModel {
final String id;
final String name;
final String fcmToken;
final String phone;
final String email;
RequestModel({
required this.id,
required this.name,
required this.fcmToken,
required this.phone,
required this.email,
});
#override
String toString() =>
"RequestModel(id: $id, name: $name, fcmToken: $fcmToken, phone: $phone, email: $email)";
}
take a look at the raw data once again, it contains all the users data so you need to get the access the uid before the name
final uid = FirebaseAuth.instance.currentUser!.uid;
and then for the RequestModel:
name: data[uid]['name']

Riverpod: Simple way to ingest REST API

I'm currently building an app that is ingesting the WordPress REST API to display blog posts. On initial app load, I want to have it pull initial data with a method to then pull more posts via user interaction. I currently have this working, however, my implementation seems complex and there may be a cleaner way to get this working. I based my implementation on this GitHub issue response. Here is what my code looks like:
In main.dart:
final blogRepository = FutureProvider((ref) async {
final posts = await getPosts();
return BlogService(posts);
},
);
final blogProvider = StateNotifierProvider<BlogService, List<BlogPost>>((ref) => throw UnimplementedError(
"Access to a [BlogService] should be provided through a [ProviderScope]."));
In blogservice.dart:
class BlogService extends StateNotifier<List<BlogPost>> {
final List<BlogPost> _posts;
BlogService(this._posts) : super(_posts);
List<BlogPost> get posts => _posts;
Future<void> morePosts(int length) async {
Response response;
var dio = Dio();
response = await dio.get('https://wordpress-site.com/wp-json/wp/v2/posts/?offset=' + length.toString());
var posts = (response.data as List);
state = [...state, ...posts.map((post) => BlogPost.fromJson(post)).toList()];
}
}
Future<List<BlogPost>> getPosts() async {
Response response;
var dio = Dio();
response = await dio.get('https://wordpress-site.com/wp-json/wp/v2/posts/');
var posts = (response.data as List);
return posts.map((post) => BlogPost.fromJson(post)).toList();
}
I think a better way of doing this would be to use AsyncValue, however, I wasn't able to find any good reference implementations consuming an API using this.
This is an example using AsyncValue - It eliminates the repository
Have your service.dart file like this:
final blogServiceProvider = Provider<BlogService>((ref) => BlogService());
class BlogService {
Future<AsyncValue<List<BlogPost>>> getBlogPost() async {
try {
var dio = Dio();
Response response = await dio.get('https://wordpress-site.com/wp-json/wp/v2/posts/');
var posts = (response.data as List);
List<BlogPost> list = posts.map<BlogPost>((post) => BlogPost.fromJson(post)).toList();
return AsyncData(list);
} catch (e) {
return AsyncError("Something went wrong");
}
}
}
And your provider like so:
final blogNotifierProvider = StateNotifierProvider<BlogNotifier, AsyncValue<List<BlogPost>>>((ref){
BlogService _service = ref.read(blogServiceProvider);
return BlogNotifier(_service);
});
class BlogNotifier extends StateNotifier<AsyncValue<List<BlogPost>>> {
BlogNotifier(this._service) : super(AsyncLoading()) {
getPosts();
}
final BlogService _service;
void getPosts() async {
state = await _service.getBlogPost();
}
}
Edit: To merge existing posts with new ones, try this:
class BlogService {
List<BlogPost> _posts = [];
Future<AsyncValue<List<BlogPost>>> getBlogPost() async {
try {
var dio = Dio();
Response response = await dio.get('https://wordpress-site.com/wp-json/wp/v2/posts/');
var posts = (response.data as List);
List<BlogPost> list = posts.map<BlogPost>((post) => BlogPost.fromJson(post)).toList();
_posts = list;
return AsyncData(list);
} catch (e) {
return AsyncError("Something went wrong");
}
}
Future<AsyncValue<List<BlogPost>>> morePosts() async {
try {
var dio = Dio();
Response response = await dio.get('https://wordpress-site.com/wp-json/wp/v2/posts/?offset=' + length.toString());
var posts = (response.data as List);
List<BlogPost> list = posts.map<BlogPost>((post) => BlogPost.fromJson(post)).toList();
_posts.addAll(list);
return AsyncData(_posts);
} catch (e) {
return AsyncError("Something went wrong");
}
}
}
And the notifier class would be:
class BlogNotifier extends StateNotifier<AsyncValue<List<BlogPost>>> {
BlogNotifier(this._service) : super(AsyncLoading()) {
getPosts();
}
final BlogService _service;
void getPosts() async {
state = await _service.getBlogPost();
}
void morePosts() async {
state = await _service.morePosts();
}
}
Please best wa create another class to provide data from Api and use drift Package
see my screens how i provide data from database (drift is sqlite DB)
This is my database class based on sqlite(drift)
import 'dart:io';
import 'package:drift/native.dart';
import 'package:mobile_nsk/models/policy/driver.dart';
import 'package:mobile_nsk/models/policy/driver_converter.dart';
import 'package:mobile_nsk/models/policy/holders.dart';
import 'package:mobile_nsk/models/policy/holders_converter.dart';
import 'package:mobile_nsk/models/policy/vehicle.dart';
import 'package:mobile_nsk/models/policy/vehicle_converter.dart';
import 'package:path/path.dart' as p;
import 'package:drift/drift.dart';
import 'package:path_provider/path_provider.dart';
part 'database.g.dart';
LazyDatabase _openConnection()=> LazyDatabase(()async{
final dbFolder = await getApplicationDocumentsDirectory();
final file = File(p.join(dbFolder.path, 'db.sqlite'));
return NativeDatabase(file,logStatements: true);
});
#DriftDatabase(tables: [Holders, Drivers, Vehicles])
class MyDatabase extends _$MyDatabase {
MyDatabase() : super(_openConnection());
// Для страхователя
Future<List<Holder>> getAllHolders() => select(holders).get();
Stream<List<Holder>> watchAllHolder() => select(holders).watch();
Future insertNewHolder(Holder holder) => into(holders).insert(holder, mode: InsertMode.insertOrReplace);
Future deleteHolder(Holder holder) => delete(holders).delete(holder);
Future<Holder> getHolderById(Holder holder)=> select(holders).getSingle();
Future insetData(Holder holder) => into(holders).insert(holder, mode: InsertMode.insertOrReplace);
Future updateHolder(Holder holder, int id, String phone) async
{
await update(holders)..where((tbl) => tbl.id.equals(id))..write(HoldersCompanion(phone: Value(phone)));
await into(holders).insert(holder, mode: InsertMode.insertOrReplace);
}
// Для Водителя
Future<List<Driver>> getAllDriver() => select(drivers).get();
Stream<List<Driver>> watchAllDriver() => select(drivers).watch();
Future insertNewDriver(Driver driver) => into(drivers).insert(driver, mode: InsertMode.insertOrReplace);
Future deleteDriver(Driver driver) => delete(drivers).delete(driver);
// Для транспорта
Future<List<Vehicle>> getAllVehicles() => select(vehicles).get();
Stream<List<Vehicle>> watchAllVehicle() => select(vehicles).watch();
Future insertNewVehicle(Vehicle vehicle) => into(vehicles).insert(vehicle, mode: InsertMode.insertOrReplace);
Future deleteVehicle(Vehicle vehicle) => delete(vehicles).delete(vehicle);
// всегда инкрементить версию схему если что то добавил/убрал/изменил/нахуевертил
#override
int get schemaVersion => 1;
}
this iss my holder model (ang generate by build_runner)
import 'package:drift/drift.dart';
import 'package:json_annotation/json_annotation.dart' as j;
import 'package:mobile_nsk/database/database.dart';
import 'package:mobile_nsk/models/policy/holders_converter.dart';
#UseRowClass(Holder)
class Holders extends Table{
IntColumn get id => integer()();
TextColumn get firstName =>text()();
TextColumn get middleName => text()();
TextColumn get lastName => text()();
TextColumn get legalName => text()();
IntColumn get isIndividual => integer()();
TextColumn get iin => text()();
IntColumn get isResident => integer()();
TextColumn get phone => text()();
TextColumn get email => text()();
TextColumn get address => text()();
IntColumn get documentTypeId => integer()();
TextColumn get documentNumber => text()();
TextColumn get documentIssueDate => text()();
TextColumn get classType => text().named("class")();
TextColumn get birthDate => text()();
BoolColumn get isExperienced => boolean()();
BoolColumn get isPrivileged => boolean()();
TextColumn get holders =>
text().map(const HolderConverter()).nullable()();
#override
Set<Column> get primaryKey=> {id};
}
#j.JsonSerializable()
class Holder implements Insertable<Holder>{
final int id;
final String firstName;
final String middleName;
final String lastName;
final String legalName;
final int isIndividual;
final String iin;
final int isResident;
final String phone;
final String email;
final String address;
final int documentTypeId;
final String documentNumber;
final String documentIssueDate;
#j.JsonKey(name: "class")
final String classType;
final String birthDate;
final bool isExperienced;
final bool isPrivileged;
const Holder(this.id, this.firstName, this.middleName, this.lastName, this.legalName, this.isIndividual, this.iin, this.isResident, this.phone, this.email, this.address, this.documentTypeId, this.documentNumber, this.documentIssueDate, this.classType, this.birthDate, this.isExperienced, this.isPrivileged);
factory Holder.fromJson(Map<String, dynamic>json)=> Holder(
json['id'] as int,
json['firstName'] as String? ?? "",
json['middleName'] as String? ?? "",
json['lastName'] as String? ?? "",
json['legalName'] as String? ?? "",
json['isIndividual'] as int,
json['iin'] as String? ?? "",
json['isResident'] as int? ?? 0,
json['phone'] as String? ?? "",
json['email'] as String? ?? "",
json['address'] as String? ?? "",
json['documentTypeId'] as int? ?? 0,
json['documentNumber'] as String? ?? "",
json['documentIssueDate'] as String? ?? "",
json['class'] as String? ?? "",
json['birthDate'] as String? ?? "",
json['isExperienced'] as bool? ?? false,
json['isPrivileged'] as bool? ?? false,
);
Map<String, dynamic>toJson()=>{
'id': id,
'firstName':firstName,
'middleName': middleName,
'lastName': lastName,
'legalName': legalName,
'isIndividual': isIndividual,
'iin': iin,
'isResident': isResident,
'phone': phone,
'email': email,
'address': address,
'documentTypeId': documentTypeId,
'documentNumber': documentNumber,
'documentIssueDate': documentIssueDate,
'class': classType,
'birthDate': birthDate,
'isExperienced': isExperienced,
'isPrivileged': isPrivileged,
};
#override
Map<String, Expression> toColumns(bool nullToAbsent) {
return HoldersCompanion(
id: Value(id),
firstName: Value(firstName),
middleName: Value(middleName),
lastName: Value(lastName),
legalName: Value(legalName),
isIndividual: Value(isIndividual),
iin: Value(iin),
isResident: Value(isResident),
phone: Value(phone),
email: Value(email),
address: Value(address),
documentTypeId: Value(documentTypeId),
documentNumber: Value(documentNumber),
documentIssueDate: Value(documentIssueDate),
classType: Value(classType),
birthDate: Value(birthDate),
isExperienced: Value(isExperienced),
isPrivileged: Value(isPrivileged)
).toColumns(nullToAbsent);
}
}
this is my code inser from api to database
import 'dart:convert';
import 'dart:developer';
import 'package:http/http.dart' as http;
import 'package:mobile_nsk/database/database.dart';
import 'package:mobile_nsk/models/policy/holders.dart';
class HolderProvider {
String baseUrl = 'http://172.16.3.49:9096/api/v1';
Future<void> getHolder(
String iin,MyDatabase database
) async {
final response = await http.get(
Uri.parse(baseUrl + '/Customer/get_full_client?iin=$iin'),
headers: {'Content-Type': 'application/json'});
if (jsonDecode(response.body)['isExperienced'] != false) {
database.insertNewHolder(Holder.fromJson(jsonDecode(response.body)));
} else {
throw Exception();
}
}
}