Dart T type- fromJson implementation - firebase

I have a normal class like this
class University implements BaseResponseContract {
final String? name;
final int? id;
University({required this.id, required this.name});
factory University.fromJson(Map<String, dynamic> json) => _$UniversityFromJson(json);
Map<String, dynamic> toJson() => _$UniversityToJson(this);
}
and this is BaseResponseContract
abstract class BaseResponseContract<T> {
factory T.fromJson(Map<String, dynamic> json);
}
This gives an error now, I want to correct and
I want to build a general Firebase class to read datas so that I dont have to write from scratch everytime,
abstract class IFirebaseEntity<T> {
final String collectionName;
late final instance;
IFirebaseEntity(this.collectionName) {
instance = FirebaseFirestore.instance.collection(collectionName)
.withConverter(fromFirestore: (snapshot,_)=>**T.fromJson(snapshot)**, toFirestore: toFirestore);
}
However it doesn't work. It doesn't recognize T.fromJson() method,
I want to build a Firebase Entity class to build such a functionality that, I will extend with a T and will be able to use that firebase class generated by the abstract class.
This is an example that extends this FirebaseEntity
class ReadUnivercities extends IFirebaseEntity<University> {
ReadUnivercities(String collectionName) : super(collectionName);
}

Related

Error in CreateInstance() while dynamically creating object of concrete type in Factory Pattern

I am actually new to design patterns and trying to implement factory pattern with .NET Core.
I tried to see couple of posts related to factory pattern and trying to implement it, I have added the concrete types in the config and reading it as dictionary in my code -
My Factory Interface -
public interface IEmpFactory
{
public BaseEmployee CreateEmployeeType<EmpType>()
where EmpType : BaseEmployee, new();
}
Implementation -
public class EmpFactoryImpl : IEmpFactory
{
public BaseEmployee CreateEmployeeType<EmpType>()
where EmpType: BaseEmployee, new()
{
return new EmpType();
}
}
Below are my services which are using the Factory as dependency -
public interface IEmpService
{
public string GetEmployeeBonus();
}
public class ContractEmpService : IEmpService
{
IEmpFactory _empFactory;
public ContractEmpService(IEmpFactory empFactory) =>
_empFactory = empFactory;
private BaseEmployee CreateMyEmployee() =>
_empFactory.CreateEmployeeType<ContractEmp>();
public string GetEmployeeBonus() =>
return CreateMyEmployee().GetBonus();
}
public class PermEmpService : IEmpService
{
private readonly IEmpFactory _empFactory;
public PermEmpService(IEmpFactory empFactory) =>
_empFactory = empFactory;
private BaseEmployee CreateMyEmployee() =>
_empFactory.CreateEmployeeType<PermEmp>();
public string GetEmployeeBonus() =>
CreateMyEmployee().GetBonus();
}
Added these concrete types in the config -
"ConfigurationProps": {
"EmpServices": {
"PermEmp": "SimpleFactoryWithoutSwitchCase.Service.PermEmpService",
"ContractEmp": "SimpleFactoryWithoutSwitchCase.Service.ContractEmpService"
}
}
Created the class to create a instance of the concrete type based on the type i.e, PermEmp or ContractEmp dynamically -
public class EmployeeTypeRouter : IEmployeeTypeRouter
{
private readonly ConfigurationProps _props;
public EmployeeTypeRouter(ConfigurationProps props)
{
_props = props;
}
public IEmpService GetInstance(string key)
{
string className = _props.EmpServices
.Where(k => k.Key.Equals(key)).FirstOrDefault().Value;
Type t = Type.GetType(className);
return (IEmpService)Activator.CreateInstance(t);
}
}
This is my calling method -
[HttpGet(Name = "GetEmployeeBonus")]
public string Get()
{
string type = "PermEmp";
IEmpService empService = _empRouter.GetInstance(type);
return empService.GetEmployeeBonus();
}
based on the type passed here i want to fetch the concrete type and call the method.
I am getting the error like this on CreateInstance method -
System.MissingMethodException: `Cannot dynamically create an instance of type 'SimpleFactoryWithoutSwitchCase.Service.PermEmpService'. Reason: No parameterless constructor defined.'
Which is very clear, but I don't want to create a parameterless constructor.
Since I am registering the dependencies in .NET Core, do I need to pass it again here? (which does not make sense for me)
Any help is really appreciated or if you feel I am doing something wrong please let me know.
Your EmployeeTypeRouter class tries to replicate the creation process that your DI Container can do more eloquently. So instead of calling Activator.CreateInstance, forward the resolution to the DI Container.
This means the following things:
Register all known IEmpService at startup.
Resolve the expected type from the IServiceProvider from inside the EmployeeTypeRouter.
In other words, change the startup code to the following:
var dictionary = props.EmpServices
.ToDictionary(p => p.Key, p => Type.GetType(p.Value));
foreach (string pair in dictionary)
{
services.AddTransient(pair.Value);
}
services.AddTransient<IEmployeeTypeRouter, EmployeeTypeRouter>();
services.AddTransient<Func<string, IEmpService>>(sp =>
key => (IEmpService)sp.GetRequiredService(dictionary[key]));
And change EmployeeTypeRouter to the following:
public class EmployeeTypeRouter : IEmployeeTypeRouter
{
private readonly Func<string, IEmpService> _factory;
public EmployeeTypeRouter(Func<string, IEmpService> factory)
{
_factory = factory;
}
public IEmpService GetInstance(string key) =>
_factory.Invoke(key);
}
In the previous code snippet, EmployeeTypeRouter makes use of the Func<string, IEmpService> delegate, which functions as factory. Under the covers the delegate calls back into the IServiceProvider.
There are of course several ways to skin a cat. You could also move some of the startup logic into EmployeeTypeRouter, or even remove the IEmployeeTypeRouter altogether and let application code depend directly on Func<string, IEmpService> delegate.

Flutter - Mockito Firestore...get() - The method 'document' was called on null

for learning purposes I am trying to mock a Firestore controller class with Mockito.
firestore_controller.dart
import 'package:cloud_firestore/cloud_firestore.dart';
class FirestoreController implements FirestoreControllerInterface {
final Firestore firestoreApi;
FirestoreController({this.firestoreApi});
#override
Future<DocumentSnapshot> read() async {
final DocumentSnapshot document = await this.firestoreApi.collection('user').document('user_fooBar').get();
return document;
}
}
firestore_controller_test.dart
import 'package:flutter_test/flutter_test.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:mockito/mockito.dart';
import 'package:fooApp/Core/repositories/firebase/firestore_controller.dart';
class MockFirestoreBackend extends Mock implements Firestore {}
class MockDocumentSnapshot extends Mock implements DocumentSnapshot {}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group("Firebase Controller", () {
final Firestore firestoreMock = MockFirestoreBackend();
final MockDocumentSnapshot mockDocumentSnapshot = MockDocumentSnapshot();
FirestoreController sut;
test("try to read a document", () async {
// Arrange
final Map<String, dynamic> _fakeResponse = {
'foo': 123,
'bar': 'foobar was here',
};
sut = FirestoreController(firestoreApi: firestoreMock); // INJECT MOCK
// Arrange: Mock
when(firestoreMock.collection('user').document('user_fooBar').get()).thenAnswer((_) => Future<MockDocumentSnapshot>.value(mockDocumentSnapshot));
when(mockDocumentSnapshot.data).thenReturn(_fakeResponse);
// Act
final fakeDocument = await sut.read();
});
});
}
🚨 Console Output 🚨
NoSuchMethodError: The method 'document' was called on null.
Receiver: null
Tried calling: document("user_fooBar")
sorry if the mistake is obvious, this is the first time I've used Mockito
Where's my error? What do I miss? Thanks a lot!
try this:
https://pub.dev/packages/cloud_firestore_mocks
A test I've done using it:
class MockFirestore extends Mock implements Firestore {}
class MockDocument extends Mock implements DocumentSnapshot {}
void main() {
final _tAppointmentModel = AppointmentModel(
appointmentID: kAppointmentID,
date: DateTime.parse("2020-12-05 20:18:04Z"),
description: "test description",
doctorID: kDoctorID,
hospitalID: kHospitalID,
infantID: kInfantID,
);
group('AppointmentModel tests: ', () {
final tAppointmentID = kAppointmentID;
final tInfantID = kInfantID;
final tDoctorID = kDoctorID;
final tHospitalID = kHospitalID;
test('should be a subclass of Appointment', () async {
expect(_tAppointmentModel, isA<Appointment>());
});
test('store and retrieve document from Firestore', () async {
final instance = MockFirestoreInstance();
await instance.collection('appointments').add({
'appointmentID': tAppointmentID,
'date': DateTime.parse("2020-12-05 20:18:04Z"),
'description': "test description",
'doctorID': tDoctorID,
'hospitalID': tHospitalID,
'infantID': tInfantID,
});
final snapshot = await instance.collection('appointments').getDocuments();
final String expected = _tAppointmentModel.props[0];
final String result = snapshot.documents[0].data['appointmentID'];
expect(expected, result);
});
});
}
So I think I've found why this is - it appears to be a bug(ette) in Mockito, in that it doesn't handle the "dot walk" from collection(any) to document() or getDocuments(). I fixed it like this:
declare five classes:
class MockFirebaseClient extends Mock implements Firestore {} //for your mock injection
class MockCollectionReference extends Mock implements CollectionReference {} //for when declaration
class MockQuerySnapshot extends Mock implements QuerySnapshot {} //for the thenAnswer return on collection of docs
class MockDocumentReference extends Mock implements DocumentReference {} //for single doc query
class MockDocumentSnapshot extends Mock implements DocumentSnapshot {} // for the thenAnswer return on single doc query
Do your setup etc - then the when clauses are just:
when(mockCollectionReference.getDocuments())
.thenAnswer((_) => Future.value(mockQuerySnapshot)); //for collection of docs query
when(mockDocumentReference.get())
.thenAnswer((_) => Future.value(mockDocumentSnapshot)); //for single doc query

Get Class Properties

I'm need a way to get the properties of a class, as I know this is with reflection, but I don't know how to apply it to Flutter.
This is my class:
class Login {
final String name;
final String email;
final String token;
final String refreshToken;
final String createdAt;
final String expiresAt;
final bool isValid;
Login({this.name, this.email, this.token, this.refreshToken, this.createdAt, this.expiresAt, this.isValid});
}
And I have to do something like getOwnProperties like is done in JS.
I need to get an array of the properties that the class has.
There is no reflection available in Flutter. You can use code generation for example with the reflectable package or custom generation using https://pub.dartlang.org/packages/build

Entity Framework Core: issue with Contains method

There is my simplified model of db:
public class Chat
{
public ICollection<ApplicationUser> Users {get; set;} //nav property - represents participants of a chat
}
public class ApplicationUser : IdentityUser // it represents a net-identity user; it does not have any references to chats
{...}
So, in controller's class I try to get chats such as contain current user as a participant:
var user = GetUser();
_context.Chats.Where(chat => chat.Users.Contains(user)).ToList();
This code throws exception:
You can not use the type of expression ...ApplicationUser for
parameter's type
"Microsoft.EntityFrameworkCore.Storage.ValueBuffer" of method "Boolean
Contains[ValueBuffer](System.Collections.Generic.IEnumerable`1[Microsoft.EntityFrameworkCore.Storage.ValueBuffer],
Microsoft.EntityFrameworkCore.Storage.ValueBuffer)"
What is the problem here?
You need use Any(), like this
var chatsList =_context.Chats.Where(chat => chat.Users.Any(u => u.id== user.id)).ToList();

Null reference on Dagger 2 #Inject

I've created a gist highlighting the issue I'm running into. I'm using an Application Module to provide a Firebase dependency for me to inject elsewhere.
When I try to #Inject Firebase mFirebase in the data layer that dependency is never satisfied.
I'm trying to keep the Context out of my other layers, but the Firebase service depends on it. I'm interested in learning any other patterns to help keep Android classes out of my business logic.
FirebaseService.java
public class FirebaseService {
#Inject Firebase mFirebaseRef; //NEVER GET'S INJECTED!
#Override
public LoginResult signinWithEmail(final String email, final String password) {
mFirebaseRef.dostuff(); //THIS REFERENCE DOESN'T GET INJECTED!
}
}
ApplicationModule
#Provides
#Singleton
Firebase provideFirebase(#ApplicationContext Context context) {
Firebase.setAndroidContext(context);
return new Firebase(Util.FIREBASE_URL);
}
ApplicationComponent
#Singleton
#Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
#ApplicationContext Context context();
Application application();
Firebase firebase();
}
MyActivity
public class MyActivity extends AppCompatActivity {
private ActivityComponent mActivityComponent;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public ActivityComponent getActivityComponent() {
if (mActivityComponent == null) {
mActivityComponent = DaggerActivityComponent.builder()
.activityModule(new ActivityModule(this))
.applicationComponent(MyApplication.get(this).getComponent())
.build();
}
return mActivityComponent;
}
The full code example is on github
Annotating a field with #Inject is not enough for the field injection to work. There's no magic involved, you just have to tell Dagger to do the injection.
First, add this method to your ApplicationComponent:
void inject(FirebaseService firebaseService);
Then, call this method from your FirebaseService (I guess it's an Android service, so add this to the onCreate method):
applicationComponent.inject(this);
This should do the trick. There's a great answer to a similar problem here.
EDIT
I've looked at your repository and I think you don't even need field injection in this case. You can just provide the Firebase dependency through a constructor. Here's your #Provides method:
#Provides
#Singleton
LoginService provideLoginService() {
return new FirebaseLoginService();
}
Add Firebase as a parameter to it and pass it to the FirebaseLoginService constructor:
#Provides
#Singleton
LoginService provideLoginService(Firebase firebase) {
return new FirebaseLoginService(firebase);
}
The constructor:
public FirebaseLoginService(Firebase firebase) {
this.mFirebaseRef = firebase;
}
Remove the #Inject annotation from your mFirebaseRef field since it's not needed anymore.
Here's the corresponding pull request.

Resources