Skip to content

Commit

Permalink
Merge pull request #43
Browse files Browse the repository at this point in the history
dart2_3
  • Loading branch information
alextekartik authored Nov 26, 2022
2 parents e44c50a + 3095559 commit 80accdb
Show file tree
Hide file tree
Showing 24 changed files with 424 additions and 167 deletions.
5 changes: 5 additions & 0 deletions idb_shim/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## 2.1.0

* Fix io implementation for generated key internal storage
* Requires dart 2.18+

## 2.0.1+1

* New lint supports
Expand Down
24 changes: 17 additions & 7 deletions idb_shim/lib/src/sembast/sembast_object_store.dart
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,15 @@ class ObjectStoreSembast extends ObjectStore with ObjectStoreWithMetaMixin {
return key;
}

/// Fix the key in map
/// Need for add without explicit key
Object fixKeyInValueImpl(Object value, Object key) {
if ((keyPath != null) && (value is Map)) {
return cloneValue(value, keyPath, key);
}
return value;
}

/// Only key the if key path is null
dynamic getUpdateKeyIfNeeded(value, [key]) {
if (keyPath == null) {
Expand Down Expand Up @@ -114,9 +123,15 @@ class ObjectStoreSembast extends ObjectStore with ObjectStoreWithMetaMixin {
}
}
}
return Future.wait(futures).then((_) {
return Future.wait(futures).then((_) async {
if (key == null) {
return sdbStore.add(sdbClient, value as Object);
// Handle the case where a generated key is added
// We are in a transaction so the key is safe
// Make sure the key field is added
var generatedKey = await sdbStore.generateKey(sdbClient);
var fixedValue = fixKeyInValueImpl(value!, generatedKey);
await sdbStore.record(generatedKey).add(sdbClient, fixedValue);
return generatedKey;
} else {
return sdbStore
.record(key)
Expand Down Expand Up @@ -216,11 +231,6 @@ class ObjectStoreSembast extends ObjectStore with ObjectStoreWithMetaMixin {
return null;
} else {
var value = record.value;
// Add key if _keyPath is not null
if ((keyPath != null) && (value is Map)) {
value = cloneValue(value, keyPath, record.key);
}

return fromSembastValue(value);
}
}
Expand Down
4 changes: 2 additions & 2 deletions idb_shim/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
name: idb_shim
version: 2.0.1+1
version: 2.1.0
description: indexed_db dart base interface with implementation for native (browser), file (io) and in memory.
homepage: https://github.com/tekartik/idb_shim.dart/tree/master/idb_shim

environment:
sdk: '>=2.14.0 <3.0.0'
sdk: '>=2.18.0 <3.0.0'

dependencies:
sembast: '>=3.0.0 <5.0.0'
Expand Down
79 changes: 79 additions & 0 deletions idb_shim/test/sembast_impl_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import 'package:idb_shim/idb_shim.dart';
import 'package:idb_shim/utils/idb_import_export.dart';

import 'idb_test_common.dart';

void main() {
group('sembast_impl', () {
var idbFactory = idbFactoryMemory;
group('key_path_auto', () {
const keyPath = 'my_key';
const dbName = 'sembast_impl_key_path_auto.db';
late Database db;

Transaction? transaction;
late ObjectStore objectStore;

void dbCreateTransaction() {
transaction = db.transaction(testStoreName, idbModeReadWrite);
objectStore = transaction!.objectStore(testStoreName);
}

// prepare for test
Future setupDeleteDb() async {
await idbFactory.deleteDatabase(dbName);
}

// generic tearDown
Future dbTearDown() async {
db.close();
}

Future dbSetUp() async {
await setupDeleteDb();

void onUpgradeNeeded(VersionChangeEvent e) {
final db = e.database;
db.createObjectStore(testStoreName,
keyPath: keyPath, autoIncrement: true);
}

db = await idbFactory.open(dbName,
version: 1, onUpgradeNeeded: onUpgradeNeeded);
}

tearDown(dbTearDown);

// Make sure the sembast record contains the key (additional test for issue #42)
test('add_read_no_key', () async {
await dbSetUp();
dbCreateTransaction();
final value = {'test': 'test_value'};
var key = await objectStore.add(value);
expect(key, 1);
expect(((await sdbExportDatabase(db))['stores'] as List)[1], {
'name': 'test_store',
'keys': [1],
'values': [
{'test': 'test_value', 'my_key': 1}
]
});
});

test('add_read_explicit_key', () async {
await dbSetUp();
dbCreateTransaction();
final value = {'test': 'test_value', keyPath: 1};
var key = await objectStore.add(value);
expect(key, 1);
expect(((await sdbExportDatabase(db))['stores'] as List)[1], {
'name': 'test_store',
'keys': [1],
'values': [
{'test': 'test_value', 'my_key': 1}
]
});
});
});
});
}
4 changes: 4 additions & 0 deletions idb_test/dart_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
concurrency: 1
platforms:
- vm
- chrome
153 changes: 146 additions & 7 deletions idb_test/lib/cursor_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ void defineTests(TestContext ctx) {
// prepare for test
Future setupDeleteDb() async {
dbName = ctx.dbName;
await idbFactory!.deleteDatabase(dbName);
await idbFactory.deleteDatabase(dbName);
}

Future dbTearDown() async {
Expand Down Expand Up @@ -102,8 +102,8 @@ void defineTests(TestContext ctx) {
db.createObjectStore(testStoreName, keyPath: keyPath);
}

db = await idbFactory!
.open(dbName, version: 1, onUpgradeNeeded: onUpgradeNeeded);
db = await idbFactory.open(dbName,
version: 1, onUpgradeNeeded: onUpgradeNeeded);
}

tearDown(dbTearDown);
Expand Down Expand Up @@ -182,7 +182,7 @@ void defineTests(TestContext ctx) {
group('update', () {
test('key_path_cursor_update', () async {
var dbName = 'key_path_cursor_update.db';
await idbFactory!.deleteDatabase(dbName);
await idbFactory.deleteDatabase(dbName);

final db = await idbFactory.open(dbName, version: 1,
onUpgradeNeeded: (VersionChangeEvent change) {
Expand Down Expand Up @@ -225,7 +225,72 @@ void defineTests(TestContext ctx) {

test('key_path_auto_cursor_update', () async {
var dbName = 'key_path_auto_cursor_update.db';
await idbFactory!.deleteDatabase(dbName);
await idbFactory.deleteDatabase(dbName);

final db = await idbFactory.open(dbName, version: 1,
onUpgradeNeeded: (VersionChangeEvent change) {
change.database
.createObjectStore('store1', keyPath: 'key', autoIncrement: true);
});
try {
final obj = <String, Object?>{
'key': 1,
'someval': 'lorem',
};
final obj2 = <String, Object?>{
'key': 1,
'someval': 'ipsem',
};
final t1 = db.transaction('store1', idbModeReadWrite);
final store1 = t1.objectStore('store1');
unawaited(store1.put(obj));
await t1.completed;

final t2 = db.transaction('store1', idbModeReadWrite);
final store2 = t2.objectStore('store1');
unawaited(store2.openCursor().forEach((cv) {
expect(cv.key, 1);
expect(cv.primaryKey, 1);
expect(cv.value, obj);

cv.update(obj2);
}));
await t2.completed;

final t3 = db.transaction('store1', idbModeReadOnly);
final store3 = t3.objectStore('store1');
final ret = await store3.getObject(1);

expect(ret, equals(obj2));

// Key cursor
{
final t = db.transaction('store1', idbModeReadWrite);
var store = t.objectStore('store1');
await store.openKeyCursor().forEach((cursor) async {
expect(cursor.key, 1);
expect(cursor.primaryKey, 1);

/*
try {
await cursor.update(obj3);
fail('should fail - update not supported on key cursor');
} catch (e) {
expect(e, isNot(const TypeMatcher<TestFailure>()));
devPrint('${e.runtimeType}');
}
*/
cursor.next();
});
}
} finally {
db.close();
}
});

test('key_path_auto_cursor_update', () async {
var dbName = 'key_path_auto_cursor_update.db';
await idbFactory.deleteDatabase(dbName);

final db = await idbFactory.open(dbName, version: 1,
onUpgradeNeeded: (VersionChangeEvent change) {
Expand Down Expand Up @@ -305,8 +370,8 @@ void defineTests(TestContext ctx) {
db.createObjectStore(testStoreName, autoIncrement: true);
}

db = await idbFactory!
.open(dbName, version: 1, onUpgradeNeeded: onUpgradeNeeded);
db = await idbFactory.open(dbName,
version: 1, onUpgradeNeeded: onUpgradeNeeded);
}

test('empty cursor', () async {
Expand Down Expand Up @@ -508,5 +573,79 @@ void defineTests(TestContext ctx) {
}
});
});

group('issue#42', () {
Future<Database> getDb() async {
var dbName = 'key_path_cursor_update_issue48.db';
await idbFactory.deleteDatabase(dbName);

return idbFactory.open(dbName, version: 1,
onUpgradeNeeded: (VersionChangeEvent change) {
change.database
.createObjectStore('store', keyPath: 'key', autoIncrement: true);
});
}

Future<Object> insert(Database db, Map<String, Object?> obj) async {
final t = db.transaction('store', idbModeReadWrite);
final store = t.objectStore('store');

final ret = await store.put(obj);
await t.completed;
return ret;
}

Future<Object> update(Database db, Map<String, Object?> obj) async {
final t = db.transaction('store', idbModeReadWrite);
final store = t.objectStore('store');

final ret = store.openCursor().forEach((cv) {
cv.update(obj);
});
await t.completed;
return ret;
}

Future<Object?> get(Database db, Object? key) {
final t = db.transaction('store', idbModeReadWrite);
final store = t.objectStore('store');

return store.getObject(1);
}

test('key_path_cursor_update_with_explicit_id', () async {
final db = await getDb();

try {
final obj = <String, Object?>{'key': 1, 'someval': 'lorem'};
final obj2 = <String, Object?>{'key': 1, 'someval': 'ipsem'};

await insert(db, obj);
await update(db, obj2);
final ret = await get(db, 1);

expect(ret, equals(obj2));
} finally {
db.close();
}
});

test('key_path_cursor_update_with_auto_incremented_id', () async {
final db = await getDb();

try {
final obj = <String, Object?>{'someval': 'lorem'};
final key = await insert(db, obj);
final obj2 = <String, Object?>{'key': key, 'someval': 'ipsem'};

await update(db, obj2);
final ret = await get(db, 1);

expect(ret, equals(obj2));
} finally {
db.close();
}
});
});
});
}
Loading

0 comments on commit 80accdb

Please sign in to comment.