Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions devtools_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions:
6 changes: 3 additions & 3 deletions lib/local_shared.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ library local_shared;

import 'dart:async';
import 'dart:convert';
import 'package:flutter/foundation.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:shared_preferences/shared_preferences.dart';

Expand Down Expand Up @@ -39,6 +38,7 @@ class LocalShared {
///
/// The [id] is used as a namespace prefix for all saved keys.
const LocalShared(this.id);

/// The unique identifier for this [LocalShared] database instance
/// which will be used as prefix for [SharedPreferences].
final String id;
Expand Down Expand Up @@ -130,7 +130,7 @@ class LocalShared {
/// Shared.col(collectionID)...
/// ```
static SharedCollection col(String id) {
return SharedCollection(id, controller: _controller);
return LocalShared.collection(id);
}

/// Another shortcut that not so short compare to [col]
Expand All @@ -144,7 +144,7 @@ class LocalShared {
/// Shared.collection(collectionID)...
/// ```
static SharedCollection collection(String id) {
return LocalShared.col(id);
return SharedCollection(id, controller: _controller);
}

/// A stream that listens for any changes when you're interacting with collections or documents
Expand Down
13 changes: 6 additions & 7 deletions lib/src/shared_collection.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ class SharedCollection {

return result;
} catch (e) {
debugPrint("Failed to get ids, reason: $e");
return result;
}
}
Expand Down Expand Up @@ -145,7 +144,8 @@ class SharedCollection {
}

// [3] Updating the collection 🎉.
final bool result = await Shared._create(id, (collection ?? {}).merge(document));
final bool result =
await Shared._create(id, (collection ?? {}).merge(document));

// [4] Notify the stream about the change in the collection 📣.
_controller.add({
Expand Down Expand Up @@ -242,8 +242,8 @@ class SharedCollection {
success: delete,
message: delete
? 'Successfully migrated the collection from ID `${this.id}` to ID `$id`.'
: 'Failed to clear the old collection after migrating to the new ID. '
'Please try deleting the collection with ID `${this.id}` manually.',
: '''Failed to clear the old collection after migrating to the new ID.
Please try deleting the collection with ID `${this.id}` manually.''',
data: [
for (var item
in ((await Shared._read(delete ? id : this.id)) ?? {}).entries)
Expand All @@ -260,7 +260,6 @@ class SharedCollection {
}
}


/// Deletes the collection.
///
/// Returns a [SharedResponse] of [SharedNone] indicating the success or failure of the deletion.
Expand Down Expand Up @@ -329,7 +328,7 @@ class SharedCollection {
/// await Shared.collection(id).docs(id)...
/// ```
SharedManyDocument docs(Iterable<String> ids) {
return SharedManyDocument(ids, collection: this);
return documents(ids);
}

/// Another shortcut to interact with [SharedManyDocument] that not so short compared to [docs].
Expand All @@ -339,7 +338,7 @@ class SharedCollection {
/// await Shared.collection(id).documents(id)...
/// ```
SharedManyDocument documents(Iterable<String> ids) {
return docs(ids);
return SharedManyDocument(ids, collection: this);
}

@override
Expand Down
34 changes: 17 additions & 17 deletions lib/src/shared_document.dart
Original file line number Diff line number Diff line change
Expand Up @@ -144,25 +144,25 @@ class SharedDocument {

// [2] Check if collection exists or not 👻.
if (collection == null && !force) {
throw 'Unable to update the document. '
'The specified collection with ID `${this.collection.id}` does not exist. '
'To forcibly continue, '
'set the `force` parameter to true. '
'This action will create a new collection and a new document.';
throw '''Unable to update the document.
The specified collection with ID `${this.collection.id}` does not exist.
To forcibly continue,
set the `force` parameter to true.
This action will create a new collection and a new document.''';
}

// [3] Check if document exist or not 🕊.
if (collection?[id] == null && !force) {
throw 'Unable to update the document. '
'The specified document with ID `$id` does not exist. '
'To forcibly continue, '
'set the `force` parameter to true. '
'This action will create a new document.';
throw '''Unable to update the document.
The specified document with ID `$id` does not exist.
To forcibly continue,
set the `force` parameter to true.
This action will create a new document.''';
}

// [4] Updating the document 💼.
bool result = await Shared._create(this.collection.id, <String, dynamic>{
...collection ?? {},
...(collection ?? {}),
id: (collection?[id] as JSON? ?? {}).merge(document),
});

Expand Down Expand Up @@ -211,8 +211,8 @@ class SharedDocument {

// [2] Check collection existence 🔍.
if (collection == null && !force) {
throw 'Unable to migrate the document. '
'The specified collection with ID `${this.collection.id}` does not exist.';
throw '''Unable to migrate the document.
The specified collection with ID `${this.collection.id}` does not exist.''';
}

// [3] Source and destination cannot be identical.
Expand All @@ -223,8 +223,8 @@ class SharedDocument {

// [4] Source document existence.
if (collection?[this.id] == null && !force) {
throw 'Unable to migrate the document. '
'The source document with ID `${this.id}` does not exist.';
throw '''Unable to migrate the document.
The source document with ID `${this.id}` does not exist.''';
}

// [5] Target existence check.
Expand Down Expand Up @@ -288,8 +288,8 @@ class SharedDocument {

// [2] Check if collection exists or not 👻.
if (collection == null) {
throw 'Unable to delete the document. '
'The specified collection with ID `${this.collection.id}` does not exist.';
throw '''Unable to delete the document.
The specified collection with ID `${this.collection.id}` does not exist.''';
}

// [3] Check if document exists or not 🕊.
Expand Down
50 changes: 25 additions & 25 deletions lib/src/shared_many_document.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,13 @@ class SharedManyDocument {
this.collection.id,
({
...collection,
for (int i = 0; i < ids.length; i++)...(){
final id = ids.elementAt(i);
return {id:(collection?[id] as JSON? ?? {}).merge( document(i))};
}(),
for (int i = 0; i < ids.length; i++)
...() {
final id = ids.elementAt(i);
return {
id: (collection?[id] as JSON? ?? {}).merge(document(i))
};
}(),
}),
);

Expand Down Expand Up @@ -120,9 +123,9 @@ class SharedManyDocument {
if (!skip) {
for (String id in ids) {
if (collection[id] == null) {
throw 'Unable to read document. '
'The specified document with ID `$id` does not exist. '
'To skip checking document existence, set parameter `skip` to true.';
throw '''Unable to read document.
The specified document with ID `$id` does not exist.
To skip checking document existence, set parameter `skip` to true.''';
}
}
}
Expand Down Expand Up @@ -166,19 +169,16 @@ class SharedManyDocument {

// [2] Check if collection exists or not 👻.
if (collection == null && !force) {
throw 'Unable to update documents. '
'The specified collection with ID `${this.collection.id}` does not exist. '
'To forcibly continue, '
'set the `force` parameter to true. '
'This action will create a new collection and create new documents within it.';
throw '''Unable to update documents.
The specified collection with ID `${this.collection.id}` does not exist.
To forcibly continue,
set the `force` parameter to true.
This action will create a new collection and create new documents within it.''';
}

// [3] Make the collection null safety ⛑.
collection = collection ?? {};

// [4] Check if document exist or not 🕊.
for (String id in ids) {
if (collection[id] == null && !force) {
if (collection?[id] == null && !force) {
throw 'Unable to update the document. '
'The specified document with ID `$id` does not exist. '
'To forcibly continue, '
Expand All @@ -189,9 +189,10 @@ class SharedManyDocument {

// [5] Updating the document 💼.
bool result = await Shared._create(this.collection.id, {
...collection,
...(collection ?? {}),
for (int i = 0; i < ids.length; i++)
ids.elementAt(i): (collection[ids.elementAt(i)] as JSON? ?? {}).merge(
ids.elementAt(i):
(collection?[ids.elementAt(i)] as JSON? ?? {}).merge(
document(i),
),
});
Expand Down Expand Up @@ -238,8 +239,8 @@ class SharedManyDocument {

// [2] Check if collection exists or not 👻.
if (collection == null) {
throw 'Unable to delete documents. '
'The specified collection with ID `${this.collection.id}` does not exist.';
throw '''Unable to delete documents.
The specified collection with ID `${this.collection.id}` does not exist.''';
}

// [3] Watch initial length of collection
Expand Down Expand Up @@ -293,7 +294,6 @@ class SharedManyDocument {
}
}


Future<SharedResponse> migrate(
String id, {
bool merge = false,
Expand All @@ -305,8 +305,8 @@ class SharedManyDocument {

// [2] Source collection existence.
if (source.isEmpty && !force) {
throw 'Unable to migrate documents. '
'The collection with ID `${collection.id}` does not exist.';
throw '''Unable to migrate documents.
The collection with ID `${collection.id}` does not exist.''';
}

// [3] Source and destination document cannot be identical unless forced.
Expand Down Expand Up @@ -339,8 +339,8 @@ class SharedManyDocument {
}

if (doc is! JSON) {
throw 'Unable to migrate documents. '
'Source document with ID `$docId` has invalid type.';
throw '''Unable to migrate documents.
Source document with ID `$docId` has invalid type.''';
}

migratedData = hasData ? migratedData.merge(doc) : JSON.from(doc);
Expand Down
25 changes: 19 additions & 6 deletions test/src/shared_collection_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ void main() {
// Assert: Should return these values
expect(response.success, isTrue);
expect(response.data, isA<List>());
expect(response.data, contains(equals({'key': 'updated', 'newField': 'yes', '1': '1'})));
expect(response.data,
contains(equals({'key': 'updated', 'newField': 'yes', '1': '1'})));
expect(response, isA<SharedMany>());
expect(response.message, contains('has been successfully updated'));
});
Expand Down Expand Up @@ -303,14 +304,16 @@ void main() {
expect(response, isA<SharedMany>());
});

test('Migrate Documents from Collection Using SharedManyDocument', () async {
test('Migrate Documents from Collection Using SharedManyDocument',
() async {
// Arrange: Setup source collection and documents
await collection.create();
await document.create(data);
await collection.document('document_2').create({'x': 'y'});

// Act: Migrate specific documents from source into a single target document
final response = await collection.docs([documentId, 'document_2']).migrate('merged_document');
final response = await collection
.docs([documentId, 'document_2']).migrate('merged_document');
final targetRead = await collection.doc('merged_document').read();
final sourceRead = await collection.read();

Expand All @@ -322,7 +325,13 @@ void main() {
expect(targetRead.one, containsPair('x', 'y'));
expect(sourceRead.success, isTrue);
expect(sourceRead.data, isA<List<JSON>>());
expect(sourceRead.data, contains(equals({'x': 'y', 'key': 'value1', '1': '1'}))); // merged doc should be new target not in source list
expect(
sourceRead.data,
contains(equals({
'x': 'y',
'key': 'value1',
'1': '1'
}))); // merged doc should be new target not in source list
});

test('Migrate Documents to Target With Merge', () async {
Expand All @@ -332,14 +341,18 @@ void main() {
await collection.doc('merged_document').create({'1': '2'});

// Act: Migrate with merge true into the existing target document
final response = await collection.docs([documentId]).migrate('merged_document', merge: true);
final response = await collection
.docs([documentId]).migrate('merged_document', merge: true);
final targetRead = await collection.doc('merged_document').read();

// Assert: Should merge existing target document
expect(response.success, isTrue);
expect(targetRead.success, isTrue);
expect(targetRead.one, containsPair('key', 'value1'));
expect(targetRead.one, containsPair('1', '1')); // existing value preserved by target precedence
expect(
targetRead.one,
containsPair(
'1', '1')); // existing value preserved by target precedence
});

test('Delete Collection', () async {
Expand Down
39 changes: 39 additions & 0 deletions test/src/shared_document_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,26 @@ void main() {
expect(response.message, contains('cannot be the same'));
});

test('Migrate on Missing Collection without Force fails', () async {
await collection.delete();

final response = await document.migrate(documentId2, force: false);

expect(response.success, isFalse);
expect(response, isA<SharedNone>());
expect(response.message, contains('does not exist'));
});

test('Migrate Missing Source without Force fails', () async {
await collection.create(replace: true);

final response = await document.migrate(documentId2, force: false);

expect(response.success, isFalse);
expect(response, isA<SharedNone>());
expect(response.message, contains('source document with ID'));
});

test('Migrate Missing Source With Force Creates Target', () async {
await collection.create(replace: true);

Expand Down Expand Up @@ -269,6 +289,25 @@ void main() {
expect(readResponse.success, isFalse);
});

test('Delete Document in Non-Existing Collection', () async {
// Arrange: Remove the collection entirely
await collection.delete();

// Act: Delete a document when collection is missing
final response = await document.delete();

// Assert: Should fail
expect(response.success, isFalse);
expect(response, isA<SharedNone>());
expect(response.message, contains('does not exist'));
});

test('SharedDocument.toString includes id and collection', () async {
final str = document.toString();
expect(str, contains('id: $documentId'));
expect(str, contains('collection:')); // at least mentions collection
});

test('Delete Non-Existing Document', () async {
// Arrange: Clear the collection
await collection.create(replace: true);
Expand Down
Loading
Loading