Bad state: failed to create cursor: 10001 Can not modify object of sync-enabled type "Income" because sync has not been activated for this store - flutter-objectbox

I am new to objectbox in flutter and already getting an error while trying to put object in the store. I have the following code:
objectbox class
import 'package:finsec/features/income/data/models/Income.dart';
import '../../../../objectbox.g.dart';
import 'dart:async';
class ObjectBox {
/// The Store of this app.
late final Store store;
late final Box<Income> incomeBox;
/// A stream of all notes ordered by date.
late final Stream<Query<Income>> incomeQueryStream;
ObjectBox._create(this.store) {
// Add any additional setup code, e.g. build queries.
incomeBox = Box<Income>(store);
final qBuilder = incomeBox.query(Income_.monthNumber.equals(1) & Income_.calendarYear.equals(2022));
incomeQueryStream = qBuilder.watch(triggerImmediately: true);
// Stream<Query<Income>> watchedQuery = incomeBox.query().watch();
}
/// Create an instance of ObjectBox to use throughout the app.
static Future<ObjectBox> create() async {
// Future<Store> openStore() {...} is defined in the generated objectbox.g.dart
final store = await openStore();
return ObjectBox._create(store);
}
}
then on my main.dart file i have the following
/// Provides access to the ObjectBox Store throughout the app.
late ObjectBox objectBox;
late SyncClient _syncClient;
bool hasBeenInitialized = false;
Future<void> main() async {
// This is required so ObjectBox can get the application directory
// to store the database in.
WidgetsFlutterBinding.ensureInitialized();
objectBox = await ObjectBox.create();
runApp(new MyHomePage( initialDate: DateTime.now()));
}
class MyHomePage extends StatefulWidget {
final DateTime initialDate;
const MyHomePage({required this.initialDate}) ;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
//some code here
}
in another class called incomeModel.dart, i am trying to call the putMany function. here is partial code from the other class
void saveIncome(String status) {
final isoCalendar = IsoCalendar.fromDateTime(this.form.value[datePaidLabel]);
int groupID = Utilities.getUniqueCode();
List<Income> incomeList = <Income>[];
Income income = new Income(
groupID: groupID,
expectedAmount: double.parse(this.form.value[incomeAmountLabel]),
actualAmount: double.parse(this.form.value[incomeAmountLabel]),
frequency: this.form.value[frequencyLabel],
dateReceived: this.form.value[datePaidLabel].toString(),
category: this.form.value[categoryLabel],
depositAcct: this.form.value[depositToLabel],
description: this.form.value[descriptionLabel],
status: status,
weekNumber: isoCalendar.weekNumber,
monthNumber: Utilities.epochConverter("MONTH", this.form.value[datePaidLabel]),
calendarYear: isoCalendar.year,
isActive: isActiveY,
groupName: currentTransactions,
);
incomeList.add(income);
DateTime dateDerivedValue = this.form.value[datePaidLabel];
for (int i = 1; i <= Utilities.getFrequency(this.form.value[frequencyLabel]); i++) {
dateDerivedValue = Utilities.getDate(
this.form.value[frequencyLabel], dateDerivedValue, incomeTransaction, i
);
incomeList.add(new Income(
groupID: groupID,
expectedAmount: double.parse(this.form.value[incomeAmountLabel]),
actualAmount: double.parse(this.form.value[incomeAmountLabel]),
frequency: this.form.value[frequencyLabel],
dateReceived: dateDerivedValue.toString(),
category: this.form.value[categoryLabel],
depositAcct: this.form.value[depositToLabel],
description: this.form.value[descriptionLabel],
status: status,
weekNumber: isoCalendar.weekNumber,
monthNumber:
Utilities.epochConverter(
"MONTH", this.form.value[datePaidLabel]),
calendarYear: isoCalendar.year,
isActive: isActiveY,
groupName: currentTransactions,
)
);
}
objectBox.incomeBox.putMany(incomeList);
}
as you can see , i am calling objectBox.incomeBox.putMany(incomeList) from incomeModel.dart class. the objectBox object is in the main class so i am importing it in incomeModel so that i can access it. however, i am getting the following error
Bad state: failed to create cursor: 10001 Can not modify object of sync-enabled type "Income" because sync has not been activated for this store.
i am not sure what this means or what to do. I will have many classes that will inserting data and i need to access the store from any class so that i can insert,update,delete data.
can someone helpme fix this? how can i make this work? thanks in advance

I solved this problem by use objectbox_sync_flutter_libs instead of objectbox_flutter_libs in pubspec.yml

Related

error: The argument type 'Stream<List<List<NewsModel>>>' can't be assigned to the parameter type 'Stream<List<NewsModel>>'

I'm extracting two lists from a single stream function to save money by minimizing reads. How can I bind the stream to individual List fields? I'm using Firebase Firestore and Getx State management
The error I'm getting is
error: The argument type 'Stream<List<List<NewsModel>>>' can't be assigned to the parameter type 'Stream<List<NewsModel>>'.
Code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:dummy_app/models/NewsModel.dart';
import 'package:get/get.dart';
class FirebaseController extends GetxController {
#override
void onInit() {
newsModelList.bindStream(stream()); //Getting ERROR HERE
newsModelListYesterday.bindStream(stream()); //Getting ERROR HERE
super.onInit();
}
// Observable list bind to stream
RxList<NewsModel> newsModelList = <NewsModel>[].obs;
//
RxList<NewsModel> newsModelListYesterday = <NewsModel>[].obs;
// Stream
Stream<List<List<NewsModel>>> stream() {
return FirebaseFirestore.instance
.collection('news')
.doc("Business")
.snapshots()
.map((ds) {
var mapData = ds.data(); // Extracts map
/// Extracting today and yesterday field
final stringToday = mapData!['today'];
final stringYesterday = mapData!['yesterday'];
/// Storing Lists in a Var
List mapListToday = mapData![stringToday];
List mapListYesterday = mapData![stringYesterday];
/// Empty model lists to assign val
List<NewsModel> modelListToday = [];
List<NewsModel> modelListYesterday = [];
/// Assigning values to both lists
mapListToday.forEach((element) {
modelListToday.add(NewsModel.fromMap(element));
});
mapListYesterday.forEach((element) {
modelListYesterday.add(NewsModel.fromMap(element));
});
return [modelListToday, modelListYesterday];
});
}
}

Flutter Firebase error in read data: type 'List<dynamic>' is not a subtype of type 'Map<String, dynamic>' in type cast

Error: Exception has occurred.
_CastError (type 'List' is not a subtype of type 'Map<String, dynamic>' in type cast)
How can i solve this problem??
Edit:
'extractedData' is Map, how can i convert it to List to add it in 'final List loadedProducts = [];'?
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/foundation.dart';
class ProductMain with ChangeNotifier{
final String idFood;
final String nameFood;
// ignore: non_constant_identifier_names
final String ImgUrl;
ProductMain({
#required this.idFood,
this.nameFood,
// ignore: non_constant_identifier_names
this.ImgUrl,
});
}
for the post required: "It looks like your post is mostly code; please add some more details."
"It looks like your post is mostly code; please add some more details."
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:app/product_main_data.dart';
import 'package:http/http.dart' as http;
class ProductsMainPV with ChangeNotifier {
List<ProductMain> _items = [];
List<ProductMain> get items {
return [..._items];
}
ProductMain findById(String idFood) {
return _items.firstWhere((prod) => prod.idFood == idFood);
}
Future<void> fetchAndSetProducts() async {
const url =
'https://app.firebaseio.com/productList.json';
try {
final response = await http.get(url);
final extractedData = json.decode(response.body);
final List<ProductMain> loadedProducts = [];
extractedData.forEach((product) {
print(product);
loadedProducts.add(ProductMain(
idFood: product,
nameFood: product['nameFood'],
ImgUrl: product['ImgUrl'],
));
});
_items = loadedProducts;
notifyListeners();
} catch (error) {
throw (error);
}
}
void updateProduct(String id, ProductMain newProduct) {
final prodIndex = _items.indexWhere((prod) => prod.idFood == id);
if (prodIndex >= 0) {
_items[prodIndex] = newProduct;
notifyListeners();
} else {
print('...');
}
}
}
Output:
product is null
I am not sure about this, since your question doesn't contain the structure of response recieved. But give this a try.
final extractedData = json.decode(response.body) as Map<String, dynamic>;
Since you are listing all products, it maybe list of items. So casting it to Map doesn't work!
final extractedData = json.decode(response.body);
......
extractedData.forEach((product) {
print(product);
// Do Something!
}
Looks like your response.body is a List not a Map. What are you expecting the url call to return? You can test it before processing by using eg. If (response.body is Map)...else if (response.body is List)... if it is a Map, process it as a Map otherwise process it as a List.
Update based on comments
It's a list of maps. So you need to iterate over the list and process each map, probably iterating over each map. So a couple of for-in or for-each loops are needed. As per the other answer, print out each iteration to see what you have.

How to work with nested Models in Sqlflite Flutter

I am going to be working with sqlflite package in Flutter, and I have been reading a lot about it. However, everywhere I find the example being shown for the single model, that is
SingleModel{
String data1, data2;
....
}
I have followed
Store list of objects in sqlite
Sqlflite operation in Flutter
these as well, but that did not quite resolve it. My main requirements is to work with the data like this:
user: {
'id': unique_key,
'name': 'abc',
'courses': [
{ 'coursename': 'some_coursename'},
{ 'coursename': 'some_other_coursename'}
]
}
I have designed my model correctly,
UserModel Class
class UserModel{
int id;
String name;
List<Course> _courses;
UserModel.set(Map data){
this.id = data['id'];
this.name = data['name'];
if(data['courses'] != null)
this.courses = [data['courses']];
}
// append more courses
void setMorCourses(Map course){
// checking for duplicate errors
if(!this.courses.contains(course['course']))
this.courses.add(course['course'])
}
}
Now, I am confused on how to use the Nested Model with sqlflite. I believe I need to work in the DatabaseHelper class.
Course Class
class CourseModel{
String coursename;
CourseModel.set(Map data){
this.coursename = data['coursename'];
}
}

Firebase Dynamic Querying using results of barcode scanner (Ionic 3 & Angularfire2)

I have a case where I need to dynamically retrieve the results of a specific book. I would like to retrieve that specific book by using its ISBN number (highlighted in bold below). This is how my database looks like:
{
"results" :
{
"key1" : {
"Character_Depth" : 4,
"Dialogue" : 4,
"Plot" : 5,
"Theme" : 3,
"Writing_Style" : 3,
"bookName" : "Ionic",
"isbnNumber" : "0123456789012"
},
"key2" : {
"Character_Depth" : 4,
"Dialogue" : 4,
"Plot" : 4,
"Theme" : 2,
"Writing_Style" : 4,
"bookName" : "Justin",
"isbnNumber" : "036000291452"
}
}
}
Before I dive into the code, here is some important information I think you need to know. What I am trying to specifically do is use a barcode scanner to scan the ISBN number of a book. Then I would like to use that scanned ISBN number to dynamically retrieve results from that database. With that being said, I need to design my code in such a way that the barcode scanner variable is updated every single time (with each scan) to the new barcode number (already completed). Then that barcode number is fed into the query (which I still can't get to work, and is what I need help with) which retrieves a child node based on that number.
My code:
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams, AlertController } from 'ionic-angular';
import { BarcodeScanner, BarcodeScannerOptions } from '#ionic-native/barcode-scanner';
import { AngularFireAuth } from 'angularfire2/auth';
import { AngularFireDatabase, AngularFireList } from 'angularfire2/database';
import { HomePage } from '../home/home';
import { Observable } from 'rxjs/Observable';
#IonicPage()
#Component({
selector: 'page-login',
templateUrl: 'login.html',
})
export class LoginPage {
bookResults: Observable<any[]>;
options: BarcodeScannerOptions;
results: {};
constructor(public navCtrl: NavController,
public navParams: NavParams,
private fire: AngularFireAuth,
private database: AngularFireDatabase,
private barcodeScanner: BarcodeScanner,
private alertCtrl: AlertController) {
/* ########## part of the code where I specifically need help ########## */
this.bookResults = this.database.list('results').valueChanges();
}
/* ########### Barcode scanner function */
async Scan(){
this.results = await this.barcodeScanner.scan();
console.log(this.results);
}
}
Right now, what happens is that the "this.bookResults = this.database.list('results').valueChanges();" retrieves the above database. However, I need some guidance as to how to change my query such that I can retrieve specific child nodes based on the "isbnNumber" instance of each child.
I've tried several things. More recently I've tried:
this.bookResults = this.database.list('/results', {
query: {
orderByChild: isbnNumber,
equalTo: this.results,
}
});
but that didn't work. I've tried other things such as:
this.bookResults =
this.database.list('/results/${this.results}').valueChanges();
but it hasn't worked either.
I've read various stackoverflow threads, so I wouldn't be surprised if this was marked as duplicate. I have tried following the instructions of various threads, yet I felt that the way retrieving information from the database didn't specifically apply to my current situation, as the values used to retrieve specific child nodes where hardcoded into the query. I need a dynamically changing query that adjusts itself based on the barcode scanner's results).
Please let me know if there is anything that was unclear from this post, and I'd be more than happy to help. Also, if you are interested in seeing the source code, here is a link to my github repo containing it:
https://github.com/islamaymansais/honey_scanner
(go to src -> pages -> login -> login.ts)
Thanks for taking the time to read this long post. I am a beginner , I've gone through plenty of posts but unfortunately I was not able to apply the appropriate changes due to my lack of experience with ionic.
As per the readme notes for the Angular firebase library the following should work:
constructor(public navCtrl: NavController,
public navParams: NavParams,
private fire: AngularFireAuth,
private database: AngularFireDatabase,
private barcodeScanner: BarcodeScanner,
private alertCtrl: AlertController) {
this.getData();
}
async function Scan(){
this.results = await this.barcodeScanner.scan();
console.log(this.results);
this.getData();
}
this.getData = () => {
var scanned_Barcode_Text = "";
if (Object.keys(this.results).length > 0){
if(typeof this.results['text'] != 'undefined' && this.results['text'] != ""){
scanned_Barcode_Text = this.results['text'];
}
}
this.bookResults = this.database.list('/results',
ref => (scanned_Barcode_Text != "") ? ref.orderByChild('isbnNumber').equalTo(scanned_Barcode_Text) : ref
).snapshotChanges();
}
call the getData() function in the constructor and also in the success function of the barcode scan.
The orderBy and equal to queries can only be called on the reference objects which is the second parameter(optional) of the AngularFireDatabase object. The usage is similar to the reduce function of the Array.prototype.
Hope this helps.
Try this.
let booksRef = this.firebase.database().ref("results/");
booksRef.orderByChild("isbnNumber").equalTo(scannedBarCode).on("child_added", function(data) {
console.log(data.val());
this.bookResults = data.val();
});
I am considering that you have got the barcode value already and have it in the variable scannerBarCode.
Sidenote: In my opinion, since you are querying the database on ISBN, you should use that instead of key. It will make it simple. Also try the new Cloud Firestore that has better querying features.

TypeScript - passing a class as an argument, and reflection

I am writing a generic unmarshaller. It converts graph DB data to generated TypeScript (1.8.7) model classes. The input is JSON. The output should be an instance of a model class.
My ultimate goal is to create something like Hibernate OGM, only for Tinkerpop Frames and TypeScript, with REST endpoint in the middle.
What's the right way to pass a class as a parameter and reach it's static members? I want to have something like this:
SomeModel some = <SomeModel> unmarshaller.fromJSON({/*Object from JSON*/}, SomeModel);
I've tried to write a method.
Not sure if I am heading in the right direction, feel free to suggest different approaches.
public fromJSON(input: Object, clazz: typeof FrameModel): FrameModel
{
// This only demonstrates access to Framemodel's metadata
// about original Java model classes.
clazz.graphPropertyMapping;
clazz.graphRelationMapping;
let result = {};
...
return result;
}
...
But when I tried to execute this on Plunker, I got execution errors with unuseful stacktrace.
The model superclass looks like this:
/**
* Things common to all Frames models on the Typescript side.
*/
export class FrameModel
{
// Model metadata
static discriminator: string;
static graphPropertyMapping: { [key:string]:string; };
static graphRelationMapping: { [key:string]:string; };
// Each instance needs a vertex ID
private vertexId: number;
public getVertexId(): number {
return this.vertexId;
}
}
Sample model class:
import {TestPlanetModel} from './TestPlanetModel';
import {TestShipModel} from './TestShipModel';
export class TestGeneratorModel extends FrameModel
{
static discriminator: string = 'TestGenerator';
static graphPropertyMapping: { [key:string]:string; } = {
bar: 'boo',
name: 'name',
rank: 'rank',
};
static graphRelationMapping: { [key:string]:string; } = {
colonizes: 'colonizedPlanet',
commands: 'ship',
};
boo: string;
name: string;
rank: string;
public colonizedPlanet: TestPlanetModel[]; // edge label 'colonizedPlanet'
public ship: TestShipModel; // edge label 'ship'
}
I haven't found much material on reflection and class handling in TypeScript.
I know how I would do this in Java.
I know how I would do this in JavaScript.
I understand that I might achieve similar results with decorators, but having fields or static fields seemed a bit simpler, for generated models.
You've maybe already noticed that class members cannot have const keyword. But you could go with static instead. Also member should be public if you want it to be accessible from outside world.
public static graphPropertyMapping: { [key:string]:string; } = {
bar: 'boo',
name: 'name',
rank: 'rank',
};
As for creating result instance:
let result = new clazz();
//copy properties
return result;
If I understand you correctly then here's something to help you get started:
interface Model {}
interface ModelData {}
interface MyModelConstructor<M extends Model, D extends ModelData> {
new(data: D): M;
// static members
graphPropertyMapping: any;
graphRelationMapping: any;
}
class Unmarshaller {
public fromJSON<T>(input: string | ModelData, ctor: MyModelConstructor<T, ModelData>): T {
let data: ModelData = (typeof input === "string") ? JSON.parse(input) : input;
let propertyMapping = ctor.graphPropertyMapping;
let relationMapping = ctor.graphRelationMapping;
// do whatever with the mappings
return new ctor(input);
}
}
(code in playground)
I don't know how your models look like, so I hope this is close enough.
I recently released an enhanced version of the TypeScript compiler that allows exactly what you are expecting: read all (static or not) fields metadata from a class. For example you can write:
interface MyInterface {
active:boolean;
description: string;
}
class MyClass {
id: number;
name: string;
myComplexField: MyInterface;
}
function printMembers(clazz: Class) {
let fields = clazz.members.filter(m => m.type.kind !== 'function'); //exclude methods.
for(let field of fields) {
let typeName = field.type.kind;
if(typeName === 'class' || typeName === 'interface') {
typeName = (<Class | Interface>field.type).name;
}
console.log(`Field ${field.name} of ${clazz.name} has type: ${typeName}`);
}
}
printMembers(MyClass.getClass());
this is the output:
$ node main.js
Field id of MyClass has type: number
Field name of MyClass has type: string
Field myComplexField of MyClass has type: MyInterface
Of course, if you change the members property access of clazz to statics you will retrieve all static members. These information can be accessed at coding time too, so you can use autocompletion.
You can do the same with Interfaces metadata. Simply write MyInterface for example, and access its members.
You can find the project here.

Resources