Hi I'm working on a flutter project
Here's my DB file
notes_service.dart
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:my_notebook/extensions/list/filter.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' show join;
import 'package:my_notebook/services/crud/crud_exceptions.dart';
class NotesService {
Database? _db;
List<DatabaseNotes> _notes = [];
DatabaseUser? _user;
static final NotesService _shared = NotesService._sharedInstance();
NotesService._sharedInstance() {
_notesStreamController = StreamController<List<DatabaseNotes>>.broadcast(
onListen: () {
_notesStreamController.sink.add(_notes);
},
);
}
factory NotesService() => _shared;
late final StreamController<List<DatabaseNotes>> _notesStreamController;
Stream<List<DatabaseNotes>> get allNotes =>
_notesStreamController.stream.filter((note) {
final currentUser = _user;
if (currentUser != null) {
return note.userId == currentUser.id;
} else {
throw UserShouldBeSetBeforeReadingAllNotesException();
}
});
Future<DatabaseUser> getOrCreateUser({
required String email,
bool setAsCurrentUser = true,
}) async {
try {
final user = await getUser(email: email);
if (setAsCurrentUser) {
_user = user;
}
return user;
} on CouldNotFindUserException {
final createdUser = await createUser(email: email);
if (setAsCurrentUser) {
_user = createdUser;
}
return createdUser;
} catch (e) {
rethrow;
}
}
Future<void> _cacheNotes() async {
final allNotes = await getAllNotes();
_notes = allNotes.toList();
_notesStreamController.add(_notes);
}
Future<DatabaseNotes> updateNote({
required DatabaseNotes note,
required String text,
}) async {
await _ensureDbIsOpen();
final db = _getDatabaseOrThrow();
// make sure note exists
await getNotes(id: note.id);
// update db
final updateCount = await db.update(
notesTable,
{
textColumn: text,
isSyncedWithCloudColumn: 0,
},
where: 'id = ?',
whereArgs: [note.id],
);
if (updateCount == 0) {
throw CouldNotUpdateNoteException();
} else {
final updatedNote = await getNotes(id: note.id);
_notes.removeWhere((note) => note.id == updatedNote.id);
_notes.add(updatedNote);
_notesStreamController.add(_notes);
return updatedNote;
}
}
Future<Iterable<DatabaseNotes>> getAllNotes() async {
await _ensureDbIsOpen();
final db = _getDatabaseOrThrow();
final notes = await db.query(notesTable);
return notes.map((noteRow) => DatabaseNotes.fromRow(noteRow));
}
Future<DatabaseNotes> getNotes({required int id}) async {
await _ensureDbIsOpen();
final db = _getDatabaseOrThrow();
final notes = await db.query(
notesTable,
limit: 1,
where: 'id = ?',
whereArgs: [id],
);
if (notes.isEmpty) {
throw CouldNotFindNoteException();
} else {
final note = DatabaseNotes.fromRow(notes.first);
_notes.removeWhere((note) => note.id == id);
_notes.add(note);
_notesStreamController.add(_notes);
return note;
}
}
Future<int> deleteAllNotes() async {
await _ensureDbIsOpen();
final db = _getDatabaseOrThrow();
final numOfDeletions = await db.delete(notesTable);
_notes = [];
_notesStreamController.add(_notes);
return numOfDeletions;
}
Future<void> deleteNote({required int id}) async {
await _ensureDbIsOpen();
final db = _getDatabaseOrThrow();
final deletedCount = await db.delete(
notesTable,
where: 'id = ?',
whereArgs: [id],
);
if (deletedCount == 0) {
throw CouldNotDeleteNoteException();
} else {
_notes.removeWhere((note) => note.id == id);
_notesStreamController.add(_notes);
}
}
Future<DatabaseNotes> createNote({required DatabaseUser owner}) async {
await _ensureDbIsOpen();
final db = _getDatabaseOrThrow();
final dbUser = await getUser(email: owner.email);
// making sure owner exists in db with correct id
if (dbUser != owner) {
throw CouldNotFindUserException();
}
const text = '';
// create note
final noteId = await db.insert(
notesTable,
{
userIdColumn: owner.id,
textColumn: text,
isSyncedWithCloudColumn: 1,
},
);
final note = DatabaseNotes(
id: noteId,
userId: owner.id,
text: text,
isSyncedWithCloud: true,
);
_notes.add(note);
_notesStreamController.add(_notes);
return note;
}
Future<DatabaseUser> getUser({required String email}) async {
await _ensureDbIsOpen();
final db = _getDatabaseOrThrow();
final results = await db.query(
userTable,
limit: 1,
where: 'email = ?',
whereArgs: [email.toLowerCase()],
);
if (results.isEmpty) {
throw CouldNotFindUserException();
} else {
return DatabaseUser.fromRow(results.first);
}
}
Future<DatabaseUser> createUser({required String email}) async {
await _ensureDbIsOpen();
final db = _getDatabaseOrThrow();
final results = await db.query(
userTable,
limit: 1,
where: 'email = ?',
whereArgs: [email.toLowerCase()],
);
if (results.isNotEmpty) {
throw UserAlreadyExistsException();
}
final userId = await db.insert(
userTable,
{
emailColumn: email.toLowerCase(),
},
);
return DatabaseUser(
id: userId,
email: email,
);
}
Future<void> deleteUser({required String email}) async {
await _ensureDbIsOpen();
final db = _getDatabaseOrThrow();
final deletedCount = await db.delete(
userTable,
where: 'email = ?',
whereArgs: [email.toLowerCase()],
);
if (deletedCount != 1) {
throw CouldNotDeleteUserException();
}
}
Database _getDatabaseOrThrow() {
final db = _db;
if (db == null) {
throw DatabaseAlreadyOpenedException();
} else {
return db;
}
}
Future<void> close() async {
final db = _db;
if (db == null) {
throw DatabaseNotOpenedException();
} else {
await db.close();
_db = null;
}
}
Future<void> _ensureDbIsOpen() async {
try {
await open();
} on DatabaseAlreadyOpenedException {}
}
Future<void> open() async {
if (_db != null) {
throw DatabaseAlreadyOpenedException();
}
try {
final docsPath = await getApplicationDocumentsDirectory();
final dbPath = join(docsPath.path, dbName);
final db = await openDatabase(dbPath);
_db = db;
// create user table
await db.execute(createUserTable);
// create note table
await db.execute(createNotesTable);
await _cacheNotes();
} on MissingPlatformDirectoryException {
throw UnableToGetDocumentDirectoryException();
}
}
}
#immutable
class DatabaseUser {
final int id;
final String email;
const DatabaseUser({
required this.id,
required this.email,
});
DatabaseUser.fromRow(Map<String, Object?> map)
: id = map[idColumn] as int,
email = map[emailColumn] as String;
#override
String toString() => 'Person, ID = $id, email = $email';
#override
bool operator ==(covariant DatabaseUser other) => id == other.id;
#override
int get hashCode => id.hashCode;
}
class DatabaseNotes {
final int id;
final int userId;
final String text;
final bool isSyncedWithCloud;
DatabaseNotes({
required this.id,
required this.userId,
required this.text,
required this.isSyncedWithCloud,
});
DatabaseNotes.fromRow(Map<String, Object?> map)
: id = map[idColumn] as int,
userId = map[userIdColumn] as int,
text = map[textColumn] as String,
isSyncedWithCloud =
(map[isSyncedWithCloudColumn] as int) == 1 ? true : false;
#override
String toString() =>
'Note, ID = $id, userId = $userId, text = $text, isSyncedWithCloud = $isSyncedWithCloud';
#override
bool operator ==(covariant DatabaseNotes other) => id == other.id;
#override
int get hashCode => id.hashCode;
}
const dbName = 'notes.db';
const userTable = 'user';
const notesTable = 'notes';
const idColumn = 'id';
const emailColumn = 'email';
const userIdColumn = 'user_id';
const textColumn = 'text';
const isSyncedWithCloudColumn = 'is_synced_with_cloud';
const createUserTable = '''CREATE TABLE IF NOT EXISTS "user" (
"id" INTEGER NOT NULL,
"email" INTEGER NOT NULL UNIQUE,
PRIMARY KEY("id" AUTOINCREMENT)
);''';
const createNotesTable = ''' CREATE TABLE IF NOT EXISTS "notes" (
"id" INTEGER NOT NULL,
"user_id" INTEGER NOT NULL,
"text" TEXT,
"is_synced_with_cloud" INTEGER NOT NULL DEFAULT 0,
FOREIGN KEY("user_id") REFERENCES "user"("id"),
PRIMARY KEY("id" AUTOINCREMENT)
);''';
And now I want to get the email address when user is filling the form (TextFieldController) for registering.So how can I get the email address and show it on another screen?And if I added some extra fields on register form (eg: Name, Address etc) do I need to update on above sql?I'm actually new to databases. I'm willing to have your help.
Related
I am getting this error:
E/SQLiteLog( 5621): (1) table note has no column named is_synced_with_cloud in "INSERT INTO note (user_id, text, is_synced_with_cloud) VALUES (?, ?, ?)"
This is my code:
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:myprogram/services/crud/crud_exceptions.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' show join;
class NotesService {
Database? _db;
List<DatabaseNote> _notes = [];
static final NotesService _shared = NotesService._sharedInstance();
NotesService._sharedInstance() {
_notesStreamController = StreamController<List<DatabaseNote>>.broadcast(
onListen: () {
_notesStreamController.sink.add(_notes);
},
);
}
factory NotesService() => _shared;
late final StreamController<List<DatabaseNote>> _notesStreamController;
Stream<List<DatabaseNote>> get allNotes => _notesStreamController.stream;
Future<DatabaseUser> getOrCreateUser({required String email}) async {
try {
final user = await getUser(email: email);
return user;
} on CouldNotFindUser {
final createdUser = await createUser(email: email);
return createdUser;
} catch (e) {
rethrow;
}
}
Future<void> _cacheNotes() async {
final allNotes = await getAllNotes();
_notes = allNotes.toList();
_notesStreamController.add(_notes);
}
Future<DatabaseNote> updateNote({
required DatabaseNote note,
required String text,
}) async {
await _ensureDbIsOpen();
final db = _getDatabaseOrThrow();
// make sure note exists
await getNote(id: note.id);
// update DB
final updatesCount = await db.update(noteTable, {
textColumn: text,
isSyncedWithCloudColumn: 0,
});
if (updatesCount == 0) {
throw CouldNotUpdateNote();
} else {
final updatedNote = await getNote(id: note.id);
_notes.removeWhere((note) => note.id == updatedNote.id);
_notes.add(updatedNote);
_notesStreamController.add(_notes);
return updatedNote;
}
}
Future<Iterable<DatabaseNote>> getAllNotes() async {
await _ensureDbIsOpen();
final db = _getDatabaseOrThrow();
final notes = await db.query(noteTable);
return notes.map((noteRow) => DatabaseNote.fromRow(noteRow));
}
Future<DatabaseNote> getNote({required int id}) async {
await _ensureDbIsOpen();
final db = _getDatabaseOrThrow();
final notes = await db.query(
noteTable,
limit: 1,
where: 'id = ?',
whereArgs: [id],
);
if (notes.isEmpty) {
throw CouldNotFindNote();
} else {
final note = DatabaseNote.fromRow(notes.first);
_notes.removeWhere((note) => note.id == id);
_notes.add(note);
_notesStreamController.add(_notes);
return note;
}
}
Future<int> deleteAllNotes() async {
await _ensureDbIsOpen();
final db = _getDatabaseOrThrow();
final numberOfDeletions = await db.delete(noteTable);
_notes = [];
_notesStreamController.add(_notes);
return numberOfDeletions;
}
Future<void> deleteNote({required int id}) async {
await _ensureDbIsOpen();
final db = _getDatabaseOrThrow();
final deletedCount = await db.delete(
noteTable,
where: 'id = ?',
whereArgs: [id],
);
if (deletedCount == 0) {
throw CouldNotDeleteNote();
} else {
_notes.removeWhere((note) => note.id == id);
_notesStreamController.add(_notes);
}
}
Future<DatabaseNote> createNote({required DatabaseUser owner}) async {
await _ensureDbIsOpen();
final db = _getDatabaseOrThrow();
// make sure owner exists in the database with the correct id
final dbUser = await getUser(email: owner.email);
if (dbUser != owner) {
throw CouldNotFindUser();
}
const text = '';
// create the note
final noteId = await db.insert(noteTable, {
userIdColumn: owner.id,
textColumn: text,
isSyncedWithCloudColumn: 1,
});
final note = DatabaseNote(
id: noteId,
userId: owner.id,
text: text,
isSyncedWithCloud: true,
);
_notes.add(note);
_notesStreamController.add(_notes);
return note;
}
Future<DatabaseUser> getUser({required String email}) async {
await _ensureDbIsOpen();
final db = _getDatabaseOrThrow();
final results = await db.query(
userTable,
limit: 1,
where: 'email = ?',
whereArgs: [email.toLowerCase()],
);
if (results.isEmpty) {
throw CouldNotFindUser();
} else {
return DatabaseUser.fromRow(results.first);
}
}
Future<DatabaseUser> createUser({required String email}) async {
await _ensureDbIsOpen();
final db = _getDatabaseOrThrow();
final results = await db.query(
userTable,
limit: 1,
where: 'email = ?',
whereArgs: [email.toLowerCase()],
);
if (results.isNotEmpty) {
throw UserAlreadyExists();
}
final userId = await db.insert(userTable, {
emailColumn: email.toLowerCase(),
});
return DatabaseUser(
id: userId,
email: email,
);
}
Future<void> deleteUser({required String email}) async {
await _ensureDbIsOpen();
final db = _getDatabaseOrThrow();
final deletedCount = await db.delete(
userTable,
where: 'email = ?',
whereArgs: [email.toLowerCase()],
);
if (deletedCount != 1) {
throw CouldNotDeleteUser();
}
}
Database _getDatabaseOrThrow() {
final db = _db;
if (db == null) {
throw DatabaseIsNotOpen();
} else {
return db;
}
}
Future<void> close() async {
final db = _db;
if (db == null) {
throw DatabaseIsNotOpen();
} else {
await db.close();
_db = null;
}
}
Future<void> _ensureDbIsOpen() async {
try {
await open();
} on DatabaseAlreadyOpenException {
// empty
}
}
Future<void> open() async {
if (_db != null) {
throw DatabaseAlreadyOpenException();
}
try {
final docsPath = await getApplicationDocumentsDirectory();
final dbPath = join(docsPath.path, dbName);
final db = await openDatabase(dbPath);
_db = db;
// create the user table
await db.execute(createUserTable);
// create note table
await db.execute(createNoteTable);
await _cacheNotes();
} on MissingPlatformDirectoryException {
throw UnableToGetDocumentsDirectory();
}
}
}
#immutable
class DatabaseUser {
final int id;
final String email;
const DatabaseUser({
required this.id,
required this.email,
});
DatabaseUser.fromRow(Map<String, Object?> map)
: id = map[idColumn] as int,
email = map[emailColumn] as String;
#override
String toString() => 'Person, ID = $id, email = $email';
#override
bool operator ==(covariant DatabaseUser other) => id == other.id;
#override
int get hashCode => id.hashCode;
}
class DatabaseNote {
final int id;
final int userId;
final String text;
final bool isSyncedWithCloud;
DatabaseNote({
required this.id,
required this.userId,
required this.text,
required this.isSyncedWithCloud,
});
DatabaseNote.fromRow(Map<String, Object?> map)
: id = map[idColumn] as int,
userId = map[userIdColumn] as int,
text = map[textColumn] as String,
isSyncedWithCloud =
(map[isSyncedWithCloudColumn] as int) == 1 ? true : false;
#override
String toString() =>
'Note, ID = $id, userId = $userId, isSyncedWithCloud = $isSyncedWithCloud, text = $text';
#override
bool operator ==(covariant DatabaseNote other) => id == other.id;
#override
int get hashCode => id.hashCode;
}
const dbName = 'notes.db';
const noteTable = 'note';
const userTable = 'user';
const idColumn = 'id';
const emailColumn = 'email';
const userIdColumn = 'user_id';
const textColumn = 'text';
const isSyncedWithCloudColumn = 'is_synced_with_cloud';
const createUserTable = '''CREATE TABLE IF NOT EXISTS "user" (
"id" INTEGER NOT NULL,
"email" TEXT NOT NULL UNIQUE,
PRIMARY KEY("id" AUTOINCREMENT)
);''';
const createNoteTable = '''CREATE TABLE IF NOT EXISTS "note" (
"id" INTEGER NOT NULL,
"user_id" INTEGER NOT NULL,
"text" TEXT,
"is_synced_with_cloud" INTEGER NOT NULL DEFAULT 0,
FOREIGN KEY("user_id") REFERENCES "user"("id"),
PRIMARY KEY("id" AUTOINCREMENT)
);''';
This is a notes app. When you press the plus button it takes you to the new notes view and when any text is typed into the text text space and you go back to the notes view its supposed to automatically save and appear on the notes view but noting appears
So I have been following this tutorial to build a Crowd-Funding Dapp using blockchain, solidity, react. And I keep getting the following mentioned error whenever I start React App. I think it might be related to contract address. The above image is what I get after I click on inspect. As I am still a beginner in Blockchain and programming in general it would be really helpful if anyone can suggest any solutions.
The error
Blockchain loaded
blockchain.jsx:219 call revert exception [ See: https://links.ethers.org/v5-errors-CALL_EXCEPTION ] (method="getProjects()", data="0x", errorArgs=null, errorName=null, errorSignature=null, reason=null, code=CALL_EXCEPTION, version=abi/5.7.0)
blockchain.jsx:220 Uncaught (in promise) Error: No ethereum object.
at reportError (blockchain.jsx:220:1)
at loadProjects (blockchain.jsx:116:1)
at async Home.jsx:13:1
Here is the contract file which is Genesis.sol and the blockchain.jsx in which the error occurs.
Genesis.sol
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
contract Genesis {
address public owner;
uint public projectTax;
uint public projectCount;
uint public balance;
statsStruct public stats;
projectStruct[] projects;
mapping(address => projectStruct[]) projectsOf;
mapping(uint => backerStruct[]) backersOf;
mapping(uint => bool) public projectExist;
enum statusEnum {
OPEN,
APPROVED,
REVERTED,
DELETED,
PAIDOUT
}
struct statsStruct {
uint totalProjects;
uint totalBacking;
uint totalDonations;
}
struct backerStruct {
address owner;
uint contribution;
uint timestamp;
bool refunded;
}
struct projectStruct {
uint id;
address owner;
string title;
string description;
string imageURL;
uint cost;
uint raised;
uint timestamp;
uint expiresAt;
uint backers;
statusEnum status;
}
modifier ownerOnly(){
require(msg.sender == owner, "Owner reserved only");
_;
}
event Action (
uint256 id,
string actionType,
address indexed executor,
uint256 timestamp
);
constructor(uint _projectTax) {
owner = msg.sender;
projectTax = _projectTax;
}
function createProject(
string memory title,
string memory description,
string memory imageURL,
uint cost,
uint expiresAt
) public returns (bool) {
require(bytes(title).length > 0, "Title cannot be empty");
require(bytes(description).length > 0, "Description cannot be empty");
require(bytes(imageURL).length > 0, "ImageURL cannot be empty");
require(cost > 0 ether, "Cost cannot be zero");
projectStruct memory project;
project.id = projectCount;
project.owner = msg.sender;
project.title = title;
project.description = description;
project.imageURL = imageURL;
project.cost = cost;
project.timestamp = block.timestamp;
project.expiresAt = expiresAt;
projects.push(project);
projectExist[projectCount] = true;
projectsOf[msg.sender].push(project);
stats.totalProjects += 1;
emit Action (
projectCount++,
"PROJECT CREATED",
msg.sender,
block.timestamp
);
return true;
}
function updateProject(
uint id,
string memory title,
string memory description,
string memory imageURL,
uint expiresAt
) public returns (bool) {
require(msg.sender == projects[id].owner, "Unauthorized Entity");
require(bytes(title).length > 0, "Title cannot be empty");
require(bytes(description).length > 0, "Description cannot be empty");
require(bytes(imageURL).length > 0, "ImageURL cannot be empty");
projects[id].title = title;
projects[id].description = description;
projects[id].imageURL = imageURL;
projects[id].expiresAt = expiresAt;
emit Action (
id,
"PROJECT UPDATED",
msg.sender,
block.timestamp
);
return true;
}
function deleteProject(uint id) public returns (bool) {
require(projects[id].status == statusEnum.OPEN, "Project no longer opened");
require(msg.sender == projects[id].owner, "Unauthorized Entity");
projects[id].status = statusEnum.DELETED;
performRefund(id);
emit Action (
id,
"PROJECT DELETED",
msg.sender,
block.timestamp
);
return true;
}
function performRefund(uint id) internal {
for(uint i = 0; i < backersOf[id].length; i++) {
address _owner = backersOf[id][i].owner;
uint _contribution = backersOf[id][i].contribution;
backersOf[id][i].refunded = true;
backersOf[id][i].timestamp = block.timestamp;
payTo(_owner, _contribution);
stats.totalBacking -= 1;
stats.totalDonations -= _contribution;
}
}
function backProject(uint id) public payable returns (bool) {
require(msg.value > 0 ether, "Ether must be greater than zero");
require(projectExist[id], "Project not found");
require(projects[id].status == statusEnum.OPEN, "Project no longer opened");
stats.totalBacking += 1;
stats.totalDonations += msg.value;
projects[id].raised += msg.value;
projects[id].backers += 1;
backersOf[id].push(
backerStruct(
msg.sender,
msg.value,
block.timestamp,
false
)
);
emit Action (
id,
"PROJECT BACKED",
msg.sender,
block.timestamp
);
if(projects[id].raised >= projects[id].cost) {
projects[id].status = statusEnum.APPROVED;
balance += projects[id].raised;
performPayout(id);
return true;
}
if(block.timestamp >= projects[id].expiresAt) {
projects[id].status = statusEnum.REVERTED;
performRefund(id);
return true;
}
return true;
}
function performPayout(uint id) internal {
uint raised = projects[id].raised;
uint tax = (raised * projectTax) / 100;
projects[id].status = statusEnum.PAIDOUT;
payTo(projects[id].owner, (raised - tax));
payTo(owner, tax);
balance -= projects[id].raised;
emit Action (
id,
"PROJECT PAID OUT",
msg.sender,
block.timestamp
);
}
function requestRefund(uint id) public returns (bool) {
require(
projects[id].status != statusEnum.REVERTED ||
projects[id].status != statusEnum.DELETED,
"Project not marked as revert or delete"
);
projects[id].status = statusEnum.REVERTED;
performRefund(id);
return true;
}
function payOutProject(uint id) public returns (bool) {
require(projects[id].status == statusEnum.APPROVED, "Project not APPROVED");
require(
msg.sender == projects[id].owner ||
msg.sender == owner,
"Unauthorized Entity"
);
performPayout(id);
return true;
}
function changeTax(uint _taxPct) public ownerOnly {
projectTax = _taxPct;
}
function getProject(uint id) public view returns (projectStruct memory) {
require(projectExist[id], "Project not found");
return projects[id];
}
function getProjects() public view returns (projectStruct[] memory) {
return projects;
}
function getBackers(uint id) public view returns (backerStruct[] memory) {
return backersOf[id];
}
function payTo(address to, uint256 amount) internal {
(bool success, ) = payable(to).call{value: amount}("");
require(success);
}
}
blockchain.jsx
import abi from '../abis/src/contracts/Genesis.sol/Genesis.json'
import address from '../abis/contractAddress.json'
import { getGlobalState, setGlobalState } from '../store'
import { ethers } from 'ethers'
const { ethereum } = window
const contractAddress = address.address
const contractAbi = abi.abi
const connectWallet = async () => {
try {
if (!ethereum) return alert('Please install Metamask')
const accounts = await ethereum.request({ method: 'eth_requestAccounts' })
setGlobalState('connectedAccount', accounts[0]?.toLowerCase())
} catch (error) {
reportError(error)
}
}
const isWallectConnected = async () => {
try {
if (!ethereum) return alert('Please install Metamask')
const accounts = await ethereum.request({ method: 'eth_accounts' })
setGlobalState('connectedAccount', accounts[0]?.toLowerCase())
window.ethereum.on('chainChanged', (chainId) => {
window.location.reload()
})
window.ethereum.on('accountsChanged', async () => {
setGlobalState('connectedAccount', accounts[0]?.toLowerCase())
await isWallectConnected()
})
if (accounts.length) {
setGlobalState('connectedAccount', accounts[0]?.toLowerCase())
} else {
alert('Please connect wallet.')
console.log('No accounts found.')
}
} catch (error) {
reportError(error)
}
}
const getEtheriumContract = async () => {
const connectedAccount = getGlobalState('connectedAccount')
if (connectedAccount) {
const provider = new ethers.providers.Web3Provider(ethereum)
const signer = provider.getSigner()
const contract = new ethers.Contract(contractAddress, contractAbi, signer)
return contract
} else {
return getGlobalState('contract')
}
}
const createProject = async ({
title,
description,
imageURL,
cost,
expiresAt,
}) => {
try {
if (!ethereum) return alert('Please install Metamask')
const contract = await getEtheriumContract()
cost = ethers.utils.parseEther(cost)
await contract.createProject(title, description, imageURL, cost, expiresAt)
} catch (error) {
reportError(error)
}
}
const updateProject = async ({
id,
title,
description,
imageURL,
expiresAt,
}) => {
try {
if (!ethereum) return alert('Please install Metamask')
const contract = await getEtheriumContract()
await contract.updateProject(id, title, description, imageURL, expiresAt)
} catch (error) {
reportError(error)
}
}
const deleteProject = async (id) => {
try {
if (!ethereum) return alert('Please install Metamask')
const contract = await getEtheriumContract()
await contract.deleteProject(id)
} catch (error) {
reportError(error)
}
}
const loadProjects = async () => {
try {
if (!ethereum) return alert('Please install Metamask')
const contract = await getEtheriumContract()
const projects = await contract.getProjects()
const stats = await contract.stats()
setGlobalState('stats', structureStats(stats))
setGlobalState('projects', structuredProjects(projects))
} catch (error) {
reportError(error)
}
}
const loadProject = async (id) => {
try {
if (!ethereum) return alert('Please install Metamask')
const contract = await getEtheriumContract()
const project = await contract.getProject(id)
setGlobalState('project', structuredProjects([project])[0])
} catch (error) {
alert(JSON.stringify(error.message))
reportError(error)
}
}
const backProject = async (id, amount) => {
try {
if (!ethereum) return alert('Please install Metamask')
const connectedAccount = getGlobalState('connectedAccount')
const contract = await getEtheriumContract()
amount = ethers.utils.parseEther(amount)
await contract.backProject(id, {
from: connectedAccount,
value: amount._hex,
})
} catch (error) {
reportError(error)
}
}
const getBackers = async (id) => {
try {
if (!ethereum) return alert('Please install Metamask')
const contract = await getEtheriumContract()
let backers = await contract.getBackers(id)
setGlobalState('backers', structuredBackers(backers))
} catch (error) {
reportError(error)
}
}
const payoutProject = async (id) => {
try {
if (!ethereum) return alert('Please install Metamask')
const connectedAccount = getGlobalState('connectedAccount')
const contract = await getEtheriumContract()
await contract.payOutProject(id, {
from: connectedAccount,
})
} catch (error) {
reportError(error)
}
}
const structuredBackers = (backers) =>
backers
.map((backer) => ({
owner: backer.owner.toLowerCase(),
refunded: backer.refunded,
timestamp: new Date(backer.timestamp.toNumber() * 1000).toJSON(),
contribution: parseInt(backer.contribution._hex) / 10 ** 18,
}))
.reverse()
const structuredProjects = (projects) =>
projects
.map((project) => ({
id: project.id.toNumber(),
owner: project.owner.toLowerCase(),
title: project.title,
description: project.description,
timestamp: new Date(project.timestamp.toNumber()).getTime(),
expiresAt: new Date(project.expiresAt.toNumber()).getTime(),
date: toDate(project.expiresAt.toNumber() * 1000),
imageURL: project.imageURL,
raised: parseInt(project.raised._hex) / 10 ** 18,
cost: parseInt(project.cost._hex) / 10 ** 18,
backers: project.backers.toNumber(),
status: project.status,
}))
.reverse()
const toDate = (timestamp) => {
const date = new Date(timestamp)
const dd = date.getDate() > 9 ? date.getDate() : `0${date.getDate()}`
const mm =
date.getMonth() + 1 > 9 ? date.getMonth() + 1 : `0${date.getMonth() + 1}`
const yyyy = date.getFullYear()
return `${yyyy}-${mm}-${dd}`
}
const structureStats = (stats) => ({
totalProjects: stats.totalProjects.toNumber(),
totalBacking: stats.totalBacking.toNumber(),
totalDonations: parseInt(stats.totalDonations._hex) / 10 ** 18,
})
const reportError = (error) => {
console.log(error.message)
throw new Error('No ethereum object.')
}
export {
connectWallet,
isWallectConnected,
createProject,
updateProject,
deleteProject,
loadProjects,
loadProject,
backProject,
getBackers,
payoutProject,
}
I tried running these commands in separate terminals
npx hardhat node
npx hardhat run scripts/deploy.js --network localhost
The contract gets deployed but the error continues and I should be able to create new projects for Crowdfunding Dapp but because of this error the projects do not get loaded.
I have one data table named "visits" and its working fine. Now I am trying to create another data table name "bookings". But I can not do it. Is there any one who can help me to create the new data table? This my my DBHelper Class code:
DB Helper Class:
======================
import 'package:mrhandyman_admin/models/visit_list_model.dart';
import 'package:sqflite/sqflite.dart';
class DBHelper {
static Database? _db;
static final int _version = 1;
static final String _tableName="visits";
static Future<void> initDb() async {
if (_db != null) {
return;
}
try {
String _path = await getDatabasesPath() + 'visits.db';
_db = await openDatabase(
_path,
version: _version,
onCreate: (db, version) async {
print("Creating a new entry");
return await db.execute(
"CREATE TABLE $_tableName("
"id INTEGER PRIMARY KEY AUTOINCREMENT,"
"customerName STRING, customerPhone STRING,"
"moveFromAddress STRING, moveToAddress STRING,"
"visitDate STRING, visitTime STRING, remind INTEGER,"
"isCompleted INTEGER)",
);
},
);
} catch (e) {
print(e);
}
}
static Future<int> insert(VisitListModel? visitListModel) async {
print("insert function called");
return await _db?.insert(_tableName, visitListModel!.toJson())??1;
}
static Future<List<Map<String, dynamic>>> query() async {
print("query function called");
return await _db!.query(_tableName);
}
static delete(VisitListModel visitListModel) async {
return await _db!.delete(_tableName, where: 'id=?', whereArgs: [visitListModel.id]);
}
static update(int id) async{
return await _db!.rawUpdate('''
UPDATE visits
SET isCompleted = ?
WHERE id =?
''', [1, id]
);
}
}
Visit Controller
import 'package:get/get.dart';
import 'package:mrhandyman_admin/database/db_helper.dart';
import 'package:mrhandyman_admin/models/visit_list_model.dart';
class VisitListController extends GetxController{
#override
void onReady() {
super.onReady();
}
var visitList = <VisitListModel>[].obs;
Future<int> addVisit({VisitListModel? visitListModel}) async {
return await DBHelper.insert(visitListModel);
}
//get all data from table
void getVisits() async {
List<Map<String, dynamic>> visits = await DBHelper.query();
visitList.assignAll(visits.map((data) => new VisitListModel.fromJson(data)).toList());
}
void delete(VisitListModel visitListModel) async {
await DBHelper.delete(visitListModel);
getVisits();
}
void markTaskCompleted(int id) async {
await DBHelper.update(id);
getVisits();
}
}
Hello, I have one data table named "visits" and its working fine. Now I am trying to create another data table name "bookings". But I can not do it. Is there any one who can help me to create the new data table? This my my DBHelper Class code:
I am a completely a beginner to sqlite and flutter. I was trying to create a local database to my flutter to do app. So I watched some youtube videos and started to implementing a database using flutter sqflite plugin. Everything worked fine because all I did was copy typing the you tubers code, until I had to add an extra parameter to the code which is a boolean, in order to track the status of the task (like done the task or not). I used an int value to save the bool, while sqlite does not supports boolean values. I used two functions, one to update the text and the other to update the switch value.
And secondly when I tap on a switch it triggers all the switches in the list. I want to solve that issue as well.
Model class for the Task
class Tasksdb {
final int? id;
final String taskName;
bool isDone;
Tasksdb({
this.id,
required this.taskName,
required this.isDone,
});
factory Tasksdb.fromMap(Map<String, dynamic> json) => Tasksdb(
id: json['id'],
taskName: json['taskName'],
isDone: (json['isDone'] as int) == 0 ? false : true);
Map<String, dynamic> toMap() {
return {
'id': id,
'taskName': taskName,
'isDone': isDone,
};
}
}
DatabaseHelper class
class DatabaseHelper {
DatabaseHelper._privateConstructor();
static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
static Database? _database;
Future<Database> get database async => _database ??= await _initDatabase();
Future<Database> _initDatabase() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, 'tasks.db');
return await openDatabase(
path,
version: 1,
onCreate: _onCreate,
);
}
Future _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE IF NOT EXISTS "taskstable" (
"id" INTEGER,
"taskName" TEXT,
"isDone" INTEGER NOT NULL DEFAULT 0,
PRIMARY KEY("id" AUTOINCREMENT)
);
''');
}
Future<List<Tasksdb>> getTasks() async {
Database db = await instance.database;
var tasksQuery = await db.query(
'taskstable',
);
List<Tasksdb> taskList = tasksQuery.isNotEmpty
? tasksQuery.map((c) => Tasksdb.fromMap(c)).toList()
: [];
return taskList;
}
Future<int> add(Tasksdb task) async {
Database db = await instance.database;
return await db.insert('taskstable', {
'id': task.id,
'taskName': task.taskName,
'isDone': 0,
});
}
Future<int> update(Tasksdb task) async {
Database db = await instance.database;
return await db.update(
'taskstable',
task.toMap(),
where: "id = ?",
whereArgs: [task.id],
);
}
Future<int> updateIsDone(bool isDoneTodb) async {
Database db = await instance.database;
return await db.update(
'taskstable',
{
'isDone': isDoneTodb == true ? 1 : 0,
},
);
}
}
HomeScreen widget
class SqliteApp extends StatefulWidget {
const SqliteApp({Key? key}) : super(key: key);
#override
_SqliteAppState createState() => _SqliteAppState();
}
class _SqliteAppState extends State<SqliteApp> {
int? selectedId;
final textController = TextEditingController();
bool isDone = false;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: TextField(
controller: textController,
),
),
body: Center(
child: FutureBuilder<List<Tasksdb>>(
future: DatabaseHelper.instance.getTasks(),
builder: (BuildContext context,
AsyncSnapshot<List<Tasksdb>> snapshot) {
if (!snapshot.hasData) {
return const Center(child: Text('Loading...'));
}
return snapshot.data!.isEmpty
? const Center(child: Text('No tasks in List.'))
: ListView(
children: snapshot.data!.map((task) {
return Center(
child: Card(
color: selectedId == task.id
? Colors.green
: Colors.yellow,
child: ListTile(
trailing: Switch( //the problem is here, doesn't save to db
value: isDone,
onChanged: (val) async {
setState(() {
isDone = val;
});
await DatabaseHelper.instance
.updateIsDone(
isDone,
);
}),
title: Text(task.taskName),
onTap: () {
setState(() {
if (selectedId == null) {
textController.text = task.taskName;
selectedId = task.id;
} else {
textController.text = 'add something';
selectedId = null;
}
});
},
),
),
);
}).toList(),
);
}),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
await DatabaseHelper.instance.add(
Tasksdb(
taskName: textController.text,
isDone: false,
),
);
setState(() {
textController.clear();
selectedId = null;
});
},
),
),
);
}
}
I found the answer: (in case of if someone had the same question)
I removed the bool isDone from the material app widget, and instead of assigning the switch val to that bool I assigned it to database's task.isDone value. To avoid switch's auto trigger, I parsed the Taskdb to the updateIsDone function
Future<int> updateIsDone(Tasksdb task, bool isDoneTodb) async {
Database db = await instance.database;
return await db.update(
'taskstable',
{
'isDone': isDoneTodb == true ? 1 : 0,
},
where: "id = ?",
whereArgs: [task.id]);
}
...
Switch(
value: task.isDone,
onChanged: (val) async {
setState(() {
task.isDone = val;
});
await DatabaseHelper.instance
.updateIsDone(task, task.isDone);
});
I'm having trouble querying a SQFlite db table in Flutter. I get the following warning several times:
I/chatty (32047): uid=10160(com.example.SQFLite_test) 1.ui identical 18498 lines 2
I/flutter (32047): Warning database has been locked for 0:00:10.000000. Make sure you always use the transaction
object for database operations during a transaction
I get the warning when calling the getClients() method to get all clients from the Client table. The main issue though is that it seems to freeze the code as well. Even when I only try to select the top 100, it still gives me the warning and it freezes and doesn't progress.
My db class helping me to init and manage the database:
class LogServiceTwo {
LogServiceTwo._();
static final LogServiceTwo logRepo = LogServiceTwo._();
static Database _database;
Future<Database> get database async {
if (_database != null) {
return _database;
}
var db = await openDb();
// if (db == null) {
// _database = await initDB();
// return _database;
// }
var hasClientTableB = await hasClientTable(db);
if (hasClientTableB) {
_database = db;
return _database;
}
// var backup = await restoreBackup(db);
// if (backup != null) {
// _database = backup;
// return _database;
// }
await createClientTable(db);
_database = db;
return _database;
}
Future createClientTable(Database db) async {
await db.execute("CREATE TABLE Client ("
"id INTEGER PRIMARY KEY,"
"first_name TEXT,"
"last_name TEXT,"
"blocked BIT"
")");
}
Future<bool> hasClientTable(Database db) async {
try {
var table = await db.query("Client");
return table != null;
} catch (e) {
return false;
}
}
Future<Database> openDb() async {
try {
var path = await getPersistentDbPath();
var db = await openDatabase(path, version: 1);
return db;
} catch (e) {
return null;
}
}
Future initDB() async {
var path = await getPersistentDbPath();
return await openDatabase(path, version: 1, onOpen: (db) {}, onCreate: (Database db, int version) async {
await db.execute("CREATE TABLE Client ("
"id INTEGER PRIMARY KEY,"
"first_name TEXT,"
"last_name TEXT,"
"blocked BIT"
")");
});
}
Future newClient(Client newClient) async {
final db = await database;
var res = await db.insert("Client", newClient.toMap());
return res;
}
Future newClients(List<Client> clients) async {
var clientMaps = clients.map((client) => client.toMap()).toList();
final db = await database;
clientMaps.forEach((clientMap) async {
await db.insert("Client", clientMap);
});
}
Future<Client> getClient(int id) async {
final db = await database;
var res = await db.query("Client", where: "id = ?", whereArgs: [id]);
return res.isNotEmpty ? Client.fromMap(res.first) : Null;
}
Future<List<Client>> getAllClients() async {
final db = await database;
var res = await db.query("Client");
List<Client> list = res.isNotEmpty ? res.map((c) => Client.fromMap(c)).toList() : [];
return list;
}
Future<List<Client>> getBlockedClients() async {
final db = await logRepo.database;
var res = await db.rawQuery("SELECT * FROM Client WHERE blocked=1");
List<Client> list = res.isNotEmpty ? res.toList().map((c) => Client.fromMap(c)) : null;
return list;
}
Future<List<String>> getTables() async {
var db = await logRepo.database;
var tableNames = (await db.query('sqlite_master', where: 'type = ?', whereArgs: ['table'])).map((row) => row['name'] as String).toList(growable: false);
return tableNames;
}
Future<String> getPersistentDbPath() async {
return await createPersistentDbDirecotry();
}
Future createPersistentDbDirecotry() async {
var externalDirectoryPath = await ExtStorage.getExternalStorageDirectory();
var persistentDirectory = "$externalDirectoryPath/db_persistent";
await createDirectory(persistentDirectory);
return "$persistentDirectory/persistent.db";
}
Future createDirectory(String path) async {
await (new Directory(path).create());
}
Future<bool> askForWritePermission() async {
var status = await Permission.storage.status;
if (!status.isGranted) {
status = await Permission.storage.request();
return status.isGranted;
}
return status.isGranted;
}
Future mockData() async {
var clients = ClientMocker.createClients();
await newClients(clients);
}
Future deleteAll() async {
var db = await database;
await db.rawDelete("DELETE FROM Client");
}
// Get all clients, throws warnings and stops proceeding in the code.
Future getClients() async {
try {
var db = await database;
return await db.rawQuery("SELECT * FROM Client");
} catch (e) {
print(e);
}
}
}
My main class calling the database service for testing purposes:
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
// This makes the visual density adapt to the platform that you run
// the app on. For desktop platforms, the controls will be smaller and
// closer together (more dense) than on mobile platforms.
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
void initState() {
// firstTest();
// secondTest();
thirdTest();
testText = "";
super.initState();
}
String testText;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
// Center is a layout widget. It takes a single child and positions it
// in the middle of the parent.
child: Column(
children: [
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height,
child: Text(testText),
)
],
),
),
);
}
Future firstTest() async {
testText = "";
// var client = new Client(blocked: false, firstName: "Tobias", lastName: "Eliasson", id: null);
// await LogRepository.logRepo.newClient(client);
// await LogRepository.logRepo.newClient(client);
// await LogRepository.logRepo.newClient(client);
var clients = await LogRepository.logRepo.getAllClients();
clients.forEach((c) {
setState(() {
testText += "\n${c.toMap()}";
});
print(c.toMap());
});
setState(() {
testText += "Length of found clients: ${clients.length.toString()}";
});
var success = await LogRepository.logRepo.saveBackup();
print(success);
}
Future secondTest() async {
try {
await LogRepository.logRepo.deleteAll();
await LogRepository.logRepo.mockData();
var a = DateTime.now();
print("Saving backup $a");
var backupSuccess = await LogRepository.logRepo.saveBackup();
print("Backup success: $backupSuccess");
var b = DateTime.now();
print("Saved backup:${a.difference(b)}");
} catch (e) {
print("Error!!!");
print(e);
}
}
Future thirdTest() async {
await LogServiceTwo.logRepo.database;
await LogServiceTwo.logRepo.mockData();
var clients = await LogServiceTwo.logRepo.getClients();
print(clients.length);
}
}
As far as I can see, I await all db operations and only use on db object to access it so there shouldn't be any weird parallell access going on. Maybe you find an error somewhere I'm missing though. In case you wonder why I create the database in external memory, is that the database needs to be persistent and saved when uninstalling the app or updating it.
Thanks!
I found the problem and learnt a lesson. In short, follow conventions and best practices when accessing a database. The problem was that I inserted one client at the time inside the method:
Future newClients(List<Client> clients) async {
var clientMaps = clients.map((client) => client.toMap()).toList();
final db = await database;
clientMaps.forEach((clientMap) async {
await db.insert("Client", clientMap);
});
}
When inserting or doing many db operations at the same moment, use batch and commit instead like this:
Future newClients(List<Client> clients) async {
var clientMaps = clients.map((client) => client.toMap()).toList();
final db = await database;
var batch = db.batch();
clientMaps.forEach((clientMap) async {
batch.insert("Client", clientMap);
});
await batch.commit(noResult: true);
}
With the batch and commit solution I could insert 90 000 clients on first try with no errors and could query them all after.