-
-
Notifications
You must be signed in to change notification settings - Fork 641
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DBCore middlewares not working as expected #1180
Comments
To catch all read-queries you must implement all functons in the DBCoreTable interface except mutate: get(req: IDBCoreGetRequest), openCursor() returns a DBCoreCursor.
If your aim is to map value results you would only need to override get, getMany, query and openCursor. As your mapping function is async, your proxy cursor may need to resolve the initial value prior to resolving the promise, as the getter of value is not async. It will also need to override start() to prefetch value using your async mapper: const myDBCoreTable = {
...table,
get: (req) => table.get(req).then(myAsyncMapper),
getMany: (req) =>
table.getMany(req).then((res) => Promise.all(res.map(myAsyncMapper))),
query: (req) =>
table.query(req).then((res) => req.values // Check if request wants values
? Promise.all(res.result.map(myAsyncMapper)).then((result) => ({
result,
}))
: res // Caller only want primary keys. res is only the keys. Don't map.
),
openCursor: (req) =>
table.openCursor(req).then((cursor) => {
if (!cursor) return cursor; // cursor is null
if (!req.values) return cursor; // caller only want to enumerate keys.
return createCursor(cursor);
}),
};
function createCursor(cursor) {
return myAsyncMapper(cursor.value).then((value) => {
return Object.create(cursor, {
key: { get: () => cursor.key }, // Added 2020-12-14: Needed to get a proper this-pointer.
primaryKey: { get: () => cursor.primaryKey }, //Added 2020-12-14: Needed to get a proper this-pointer.
value: {
get: () => value, // value is not just argument - it's changed by code within `start()`.
},
start: {
value: (onNext) => cursor.start(() =>
myAsyncMapper(cursor.value).then((val) => {
value = val; // Updating `value` to make cursor.value return new value.
onNext();
}).catch((error) => {
cursor.fail(error);
})
)
},
});
});
} I've just dry-coded this so it may contain syntax errors or bugs, but please try it and tell me if this works for you. I will need to update the docs with such a sample and it would be nice to have one that has been tested so your feedback is valuable! Edited 2020-12-14: properties Cursor.key and Cursor.primaryKey needs to be declared as well in order to get a proper this pointer |
Note: I've updated the code snippet since first reply. Still dry-coded so please verify. |
@dfahlander great! All tests are passed now. Thank you. It was not obvious for me to use a custom cursor, and at query I had wrong implementation, so your example was really helpful. Tested also at browser and there is no problems at this moment |
Ok great! Can I use my code snippet as it is in the docs or was it anything that you had to write differently? |
Yes, but I combined your example with the one from docs. From here https://dexie.org/docs/Dexie/Dexie.use()#example |
@dfahlander Hi again! Found a problem with IDBCursorWithValue Jest and fake-indexeddb doesn't show this error, so I missed it last time I think there is problem with cloning IDBCursor, maybe types of |
I see two options: add key property to new cursor (copy from original cursor):
so it will be: function createCursor(cursor) {
return myAsyncMapper(cursor.value).then((value) => {
return Object.create(cursor, {
value: {
get: () => value,
},
key: {
value: cursor.value,
},
start: {
value: (onNext) => cursor.start(() =>
myAsyncMapper(cursor.value).then((val) => {
value = val;
onNext();
}).catch((error) => {
cursor.fail(error);
})
)
},
});
});
} or copy all data from original cursor: function createCursor(cursor) {
return myAsyncMapper(cursor.value).then((value) => {
const newCursorData = Object.create(cursor, {
value: {
get: () => value,
},
start: {
value: (onNext) => cursor.start(() =>
myAsyncMapper(cursor.value).then((val) => {
value = val;
onNext();
}).catch((error) => {
cursor.fail(error);
})
)
},
});
return Object.assign(cursor, newCursorData)
});
} |
In my comment on november 29 i missed to define the It's not very obvious nor documented (will fix that), but the methods on the cursor like start(), stop(), continue(), continuePrimaryKey() etc are already bound on the lowest-level implementation of the cursor, while the readonly properties key, primaryKey and value are not. It's not possible to clone the cursor as it is mutable object so the simplest way of creating a proxy cursor is still by using Object.create() and override props and methods accordingly. Just keep in mind that the three readonly properties |
Hello again! The error: So it looks like My quick code: async function createCursor(cursor: DBCoreCursor, tableName: string, hooks: DatabaseHooks): Promise<DBCoreCursor> {
const hookFunction = <T = any>(data: T) => hooks.transform(tableName, data)
let cursorValue = await Dexie.waitFor(hookFunction(cursor.value))
return Object.create(cursor, {
value: {
get: () => cursorValue,
},
key: { get: () => cursor.key },
primaryKey: { get: () => cursor.primaryKey },
start: {
value: (onNext: () => void) => {
return cursor.start(async () => {
try {
const localCursorValue = await Dexie.waitFor(hookFunction(cursor.value))
cursorValue = localCursorValue
onNext()
} catch(error) {
console.log('Fails here')
cursor.fail(error)
}
})
},
},
})
} May be I should also rewrite all |
I can't use hooks API because of async functions to be applied for dexie results
DBCore has several middlewares: get, getMany, query... So I think I can use it instead of reading hook.
But I can't make these middlewares works.
For example, collection.toArray someway prevents these middlewares from firing:
No one of this middlewares works.
But this works well:
Is it known issue? Or may be I'm doing wrong? Should I make a repro?
General purpose is map dexie results to class factory function, which is async
The text was updated successfully, but these errors were encountered: