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.