Skip to content

Instantly share code, notes, and snippets.

@morten-olsen
Last active March 22, 2017 23:03
Show Gist options
  • Select an option

  • Save morten-olsen/5fb4369676f39fdc1bbf8556608ec8c9 to your computer and use it in GitHub Desktop.

Select an option

Save morten-olsen/5fb4369676f39fdc1bbf8556608ec8c9 to your computer and use it in GitHub Desktop.
Dexie as middleware
class DexieAction {
constructor(collection, filters = [], mode = 'all') {
this.collection = collection;
this.filters = filters;
this.mode = mode;
}
set(name, args) {
this.filters.push({
type: name,
values: args,
});
}
}
const handler = {
get: (target, name) => {
if (name === 'toAction') {
return (type) => ({
type: '@@DB/QUERY',
payload: {
responseType: type,
collection: target.collection,
filters: target.filters,
},
});
} else if (name === 'setMode') {
return (mode) => {
target.mode = mode;
return proxyWrap(target);
}
} else {
return (...args) => {
target.set(name, args);
return proxyWrap(target);
}
}
}
}
const proxyWrap = (target) => {
return new Proxy(target, handler);
}
export const createQuery = (collection) => proxyWrap(new DexieAction(collection));
import Dexie from 'dexie';
export default ({
name = 'db',
schema,
version = 1,
}) => ({ dispatch }) => {
let ready = false;
let queue = [];
const db = new Dexie(name);
db.version(version).stores(schema);
db.open()
.then(() => {
ready = true;
queue.forEach((item) => {
item.resolve(dispatch(item.action));
});
queue = [];
})
.catch(function(error) {
console.error('Uh oh : ' + error);
});
return (next) => (action) => {
const prefix = action.type.substring(0, '@@DB/'.length);
if (prefix === '@@DB/') {
if (!ready) {
let resolver = null;
const response = new Promise(resolve => {
resolver = resolve;
});
queue.push({
action,
resolve: resolver,
});
return response;
} else if (action.type === '@@DB/QUERY') {
const collection = db[action.payload.collection];
let query = collection;
action.payload.filters.forEach((filter) => {
query = query[filter.type](filter.values);
});
return query.toArray().then(items => dispatch({
type: action.payload.responseType,
payload: items,
}));
} else if (action.type === '@@DB/INSERT') {
const collection = db[action.payload.collection];
return Promise.all(action.payload.documents.map(document => collection.add(document)))
.then(ids => ids.map((id, i) => ({
...action.payload.documents[i],
id,
})))
.then(items => items.map(item => dispatch({
type: action.payload.responseType,
payload: items,
})));
}
} else {
return next(action);
}
}
}
import { createStore, applyMiddleware } from 'redux';
import dexieAsMiddleware from 'dexie-as-middleware';
import { createQuery, insert } from 'dexie-as-actions';

const store = createStore(
  reducers,
  applyMiddleware(
    dexieAsMiddleware({
      name: 'demo-db',
      version: 1,
      schema: {
        people: 'name, age',
      },
    }),
  ),
);

await store.dispatch(insert('PEOPLE_INSERTED', 'people', [
  { name: 'Frank', age: 20 },
  { name: 'Thomas', age: 33 },
  { name: 'Todd', age: 33 },
  { name: 'John', age: 28 },
  { name: 'Peter', age: 33 },
  { name: 'George', age: 28 },
]));

await store.dispatch(
  createQuery('people')
    .where('age')
    .above(25)
    .toAction('PEOPLE_SEARCH')
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment