Skip to content

Commit

Permalink
Added crud for notes
Browse files Browse the repository at this point in the history
  • Loading branch information
SMSourov committed Oct 7, 2023
1 parent d8ef1b0 commit 69096eb
Show file tree
Hide file tree
Showing 5 changed files with 388 additions and 2 deletions.
17 changes: 17 additions & 0 deletions lib/services/crud/crud_exceptions.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class DatabaseAlreadyOpenException implements Exception {}

class UnableToGetDocumentsDirectory implements Exception {}

class DatabaseIsNotOpen implements Exception {}

class CouldNotDeleteUser implements Exception {}

class UserAlreadyExists implements Exception {}

class CouldNotFindUser implements Exception {}

class CouldNotDeleteNote implements Exception {}

class CouldNotFindNotes implements Exception {}

class CouldNotUpdateNote implements Exception {}
258 changes: 258 additions & 0 deletions lib/services/crud/notes_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
import 'package:cleanifi/services/crud/crud_exceptions.dart';
import 'package:flutter/material.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' show join;

class NotesService {
Database? _db;

Future<DatabaseNote> updateNote({
required DatabaseNote note,
required String text,
}) async {
final db = _getDatabaseOrThrow();

await getNote(id: note.id);

final updatesCount = await db.update(noteTable, {
textColumn: text,
isSyncedWithCloudColumn: 0,
});

if (updatesCount == 0) {
throw CouldNotUpdateNote;
} else {
return await getNote(id: note.id);
}
}

Future<Iterable<DatabaseNote>> getAllNotes() async {
final db = _getDatabaseOrThrow();
final notes = await db.query(noteTable);

return notes.map((noteRow) => DatabaseNote.fromRow(noteRow));
}

Future<DatabaseNote> getNote({required int id}) async {
final db = _getDatabaseOrThrow();
final notes = await db.query(
noteTable,
limit: 1,
where: "id = ?",
whereArgs: [id],
);

if (notes.isEmpty) {
throw CouldNotFindNotes();
} else {
return DatabaseNote.fromRow(notes.first);
}
}

Future<int> deleteAllNotes() async {
final db = _getDatabaseOrThrow();
return await db.delete(noteTable);
}

Future<void> deleteNote({required int id}) async {
final db = _getDatabaseOrThrow();
final deletedCount = await db.delete(
noteTable,
where: 'id = ?',
whereArgs: [id],
);
if (deletedCount == 0) {
throw CouldNotDeleteNote();
}
}

Future<DatabaseNote> createNote({required DatabaseUser owner}) async {
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);
return note;
}

Future<DatabaseUser> getUser({required String email}) async {
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 {
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 {
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> 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 user table
await db.execute(createUserTable);
// create note table
await db.execute(createNoteTable);
} 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" INTEGER,
"is_synced_with_cloud" INTEGER NOT NULL DEFAULT 0,
FOREIGN KEY("user_id") REFERENCES "user"("id"),
PRIMARY KEY("id" AUTOINCREMENT)
);
''';
4 changes: 4 additions & 0 deletions macos/Flutter/GeneratedPluginRegistrant.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ import cloud_firestore
import firebase_analytics
import firebase_auth
import firebase_core
import path_provider_foundation
import sqflite

func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
FLTFirebaseFirestorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseFirestorePlugin"))
FLTFirebaseAnalyticsPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAnalyticsPlugin"))
FLTFirebaseAuthPlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseAuthPlugin"))
FLTFirebaseCorePlugin.register(with: registry.registrar(forPlugin: "FLTFirebaseCorePlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))
}
Loading

0 comments on commit 69096eb

Please sign in to comment.