Skip to content

Commit 6a52efa

Browse files
committed
initial http polling implementation
0 parents  commit 6a52efa

34 files changed

+6000
-0
lines changed

Diff for: .eslintrc.json

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"env": {
3+
"browser": true,
4+
"commonjs": true,
5+
"es6": true,
6+
"node": true
7+
},
8+
"extends": "eslint:recommended",
9+
"parserOptions": {
10+
"ecmaVersion": 8,
11+
"sourceType": "module"
12+
},
13+
"rules": {
14+
"no-console":0,
15+
"indent": [
16+
"error",
17+
2
18+
],
19+
"linebreak-style": [
20+
"error",
21+
"unix"
22+
],
23+
"quotes": [
24+
"error",
25+
"single"
26+
],
27+
"semi": [
28+
"error",
29+
"always"
30+
]
31+
}
32+
}

Diff for: .gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
node_modules

Diff for: adapters/.sync-adapter.js.swp

12 KB
Binary file not shown.

Diff for: adapters/sync-adapter.js

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
const ChangeTypeConstants = require('../src/change-type-constants');
2+
3+
module.exports = function syncAdapter(Model) {
4+
return async (req, res) => {
5+
try {
6+
console.log('req body', req.body);
7+
8+
let deletedItems = req.body.modified.filter(item => item.change_type === ChangeTypeConstants.ChangeTypeDeleted);
9+
let createdItems = req.body.modified.filter(item => item.change_type === ChangeTypeConstants.ChangeTypeCreated);
10+
let updatedItems = req.body.modified.filter(item => item.change_type === ChangeTypeConstants.ChangeTypeUpdated);
11+
12+
13+
const deletedServerItems = await Model.query((qb) => {
14+
qb.whereIn('id', deletedItems.map((item) => item.id));
15+
});
16+
17+
let createdServerItems = {};
18+
19+
for (let i = 0, l = createdItems; i < l; i++) {
20+
let oldId = createdItems[i].id;
21+
delete createdItems[i].id;
22+
delete createdItems[i].change_type;
23+
let newModel = new Model(createdItems[i]);
24+
let savedItem = await newModel.save();
25+
createdServerItems[oldId] = savedItem.id;
26+
}
27+
28+
let updatedServerItems = [];
29+
for (let i = 0, l = updatedItems; i < l; i++) {
30+
let updatedModel = new Model(updatedItems[i]);
31+
let updatedItem = await updatedModel.save();
32+
updatedServerItems.push(updatedItem);
33+
}
34+
35+
//
36+
// TODO send item to client which were added since last update
37+
//
38+
39+
40+
res.status(200).json({createdServerItems, updatedServerItems, deletedServerItems});
41+
}
42+
catch (err) {
43+
console.error(err);
44+
}
45+
}
46+
};

Diff for: build/webpack.base.config.js

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
const VueLoaderPlugin = require('vue-loader/lib/plugin');
2+
const webpack = require('webpack');
3+
4+
module.exports = {
5+
mode: 'development',
6+
module: {
7+
rules: [
8+
// ... other rules
9+
{
10+
test: /\.vue$/,
11+
loader: 'vue-loader',
12+
options: {
13+
hotReload: true,
14+
preserveWhitespace: false,
15+
postcss: [
16+
require('autoprefixer')({
17+
browsers: ['last 3 versions']
18+
})
19+
]
20+
}
21+
},
22+
{
23+
test: /\.js$/,
24+
loader: 'babel-loader'
25+
},
26+
{
27+
test: /\.css$/,
28+
use: [
29+
'vue-style-loader',
30+
'css-loader'
31+
]
32+
},
33+
{
34+
test: /\.css$/,
35+
use: ['vue-style-loader', 'css-loader', 'resolve-url-loader']
36+
}, {
37+
test : /\.scss$/,
38+
loaders: ['style-loader', 'css-loader',
39+
'resolve-url-loader', 'sass-loader?sourceMap']
40+
},
41+
{
42+
test : /\.worker\.js$/,
43+
use: 'worker-loader'
44+
}
45+
]
46+
},
47+
plugins: [
48+
// make sure to include the plugin!
49+
new VueLoaderPlugin(),
50+
new webpack.HotModuleReplacementPlugin(),
51+
//new webpack.NoEmitErrorsPlugin()
52+
]
53+
};

Diff for: build/webpack.dist.config.js

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const merge = require('webpack-merge');
2+
const webpackBase = require('./webpack.base.config');
3+
const path = require('path');
4+
5+
module.exports = merge(webpackBase, {
6+
entry: {
7+
index: './src/index.js'
8+
},
9+
output: {
10+
path: path.resolve(__dirname, '../dist'),
11+
publicPath: '/dist/',
12+
filename: 'index.js'
13+
}
14+
});

Diff for: build/webpack.test.config.js

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
const merge = require('webpack-merge');
2+
const webpackBase = require('./webpack.base.config');
3+
const path = require('path');
4+
5+
module.exports = merge(webpackBase, {
6+
entry: {
7+
index: [
8+
'./test/entry.js',
9+
'webpack-hot-middleware/client'
10+
]
11+
},
12+
output: {
13+
path: path.resolve(__dirname, '../dist'),
14+
publicPath: '/dist/',
15+
filename: 'test-entry.js',
16+
globalObject: '(typeof self !== \'undefined\' ? self : this)'
17+
}
18+
});

Diff for: package.json

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"name": "mk-vue-dexie-sync-plugin",
3+
"version": "0.0.1",
4+
"main": "dist/index.js",
5+
"license": "MIT",
6+
"scripts": {
7+
"dev": "NODE_ENV=development node test/server.js",
8+
"build": "NODE_ENV=production webpack --config build/webpack.dist.config.js --progress --hide-modules"
9+
},
10+
"devDependencies": {
11+
"@babel/core": "^7.2.2",
12+
"autoprefixer": "^9.4.7",
13+
"axios": "^0.18.0",
14+
"babel-loader": "^8.0.5",
15+
"body-parser": "^1.18.3",
16+
"bookshelf": "^0.14.2",
17+
"bookshelf-scopes": "^1.5.1",
18+
"chokidar": "^2.0.4",
19+
"css-loader": "^2.1.0",
20+
"dexie": "^2.0.4",
21+
"dexie-observable": "^1.0.0-beta.5",
22+
"express": "^4.16.4",
23+
"knex": "^0.14.6",
24+
"mysql": "^2.16.0",
25+
"node-sass": "^4.11.0",
26+
"resolve-url-loader": "^3.0.0",
27+
"sass-loader": "^7.1.0",
28+
"style-loader": "^0.23.1",
29+
"vue": "^2.5.22",
30+
"vue-loader": "^15.6.2",
31+
"vue-style-loader": "^4.1.2",
32+
"vue-template-compiler": "^2.5.22",
33+
"vuex": "^3.1.0",
34+
"webpack": "^4.29.0",
35+
"webpack-cli": "^3.2.1",
36+
"webpack-dev-middleware": "^3.5.1",
37+
"webpack-hot-middleware": "^2.24.3",
38+
"webpack-merge": "^4.2.1",
39+
"worker-loader": "^2.0.0"
40+
},
41+
"dependencies": {}
42+
}

Diff for: src/.create-store-module.js.swp

32 KB
Binary file not shown.

Diff for: src/.db-sync.js.swp

12 KB
Binary file not shown.

Diff for: src/change-type-constants.js

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const ChangeTypeDeleted = 1;
2+
const ChangeTypeCreated = 2;
3+
const ChangeTypeUpdated = 3;
4+
5+
module.exports = {
6+
ChangeTypeDeleted,
7+
ChangeTypeCreated,
8+
ChangeTypeUpdated
9+
};

Diff for: src/create-store-module.js

+162
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
import Vue from 'vue';
2+
import uuid from 'uuid';
3+
import ChangeTypeConstants from './change-type-constants';
4+
import DateTimeConstants from './date-time-constants';
5+
import moment from 'moment';
6+
7+
export default function StoreModule(dbTable) {
8+
return {
9+
10+
namespaced: true,
11+
12+
state: () => ({
13+
index: -1,
14+
search: '',
15+
list: [], // all tables – paginated
16+
pagination: {
17+
page: 1,
18+
pageSize: 10
19+
} // tables pagination
20+
}),
21+
getters: {
22+
// (state, allGetters, rootState) => rootState.route.params
23+
current(state, allGetters, rootState) {
24+
return state.list[this.index];
25+
},
26+
// returns all items which are not marked as deleted
27+
undeleted(state, allGetters) {
28+
return state.list.filter(item => item.change_type !== ChangeTypeConstants.ChangeTypeDeleted);
29+
}
30+
31+
},
32+
actions: {
33+
fetchOne({state, commit}, index) {
34+
35+
if (state.list.length === 0) {
36+
return Promise.resolve(null);
37+
}
38+
// index is optional
39+
// in case index was passed
40+
commit('SET_INDEX', 0 || index);
41+
42+
if (state.index === -1 || state.index >= state.list.length) {
43+
commit('SET_INDEX', 0);
44+
}
45+
46+
let listItem = state.list[state.index];
47+
48+
console.log('listItem', listItem);
49+
50+
return Promise.resolve(listItem);
51+
},
52+
search({commit, dispatch}, search) {
53+
commit('SET_SEARCH', search);
54+
dispatch('fetch', search);
55+
},
56+
fetch({commit, state}) {
57+
// TODO implement search with state.search
58+
dbTable.where('change_type')
59+
.notEqual(ChangeTypeConstants.ChangeTypeDeleted)
60+
.offset((state.pagination.page - 1) * state.pagination.pageSize)
61+
.limit(state.pagination.pageSize).toArray()
62+
.then((records) => {
63+
commit('CLEAR');
64+
for (let i = 0, l = records.length; i < l; i++) {
65+
commit('ADD', records[i]);
66+
}
67+
}).catch((err) => {
68+
console.error(err);
69+
});
70+
},
71+
create({commit}, initialFields) {
72+
const newItem = {
73+
id: uuid(),
74+
created_at: moment().format(DateTimeConstants.MySqlFormat),
75+
updated_at: moment().format(DateTimeConstants.MySqlFormat),
76+
change_type: ChangeTypeConstants.ChangeTypeCreated
77+
};
78+
79+
if (initialFields) {
80+
for (let key in initialFields) {
81+
newItem[key] = initialFields[key];
82+
}
83+
}
84+
commit('CREATE', newItem);
85+
},
86+
delete({commit}, {id, change_type}) {
87+
// if the record is a new one
88+
// then it can get immediately deleted
89+
// because it's not stored on the server yet
90+
if (change_type === ChangeTypeConstants.ChangeTypeCreated) {
91+
commit('DELETE', id);
92+
}
93+
// the record is not really deleted
94+
// just marked as deleted so the server
95+
// can be informed about deletion upon
96+
// syncing
97+
else {
98+
const fields = {
99+
change_type: ChangeTypeConstants.ChangeTypeDeleted,
100+
updated_at: moment().format(DateTimeConstants.MySqlFormat)
101+
};
102+
commit('PATCH', {id, fields});
103+
}
104+
},
105+
patch({commit}, {id, fields}) {
106+
// only mark as updated if it is not a new record
107+
// new records must keep new-Type
108+
console.log('fields ', fields);
109+
console.log('fields.change_type', fields.change_type);
110+
console.log('ChangeTypeConstants.ChangeTypeCreated', ChangeTypeConstants.ChangeTypeCreated);
111+
112+
if (fields.change_type !== ChangeTypeConstants.ChangeTypeCreated) {
113+
fields.change_type = ChangeTypeConstants.ChangeTypeUpdated;
114+
}
115+
fields.updated_at = moment().format(DateTimeConstants.MySqlFormat);
116+
commit('PATCH', {id, fields});
117+
},
118+
setPage({commit}, page) {
119+
commit('SET_PAGE', page);
120+
},
121+
setIndex({commit}, index) {
122+
commit('SET_INDEX', index);
123+
},
124+
},
125+
mutations: {
126+
SET_INDEX(state, index) {
127+
state.index = index;
128+
},
129+
SET_PAGE(state, page) {
130+
state.pagination.page = page;
131+
},
132+
SET_SEARCH(state, search) {
133+
state.search = search;
134+
},
135+
CLEAR(state) {
136+
state.list.splice(0);
137+
},
138+
ADD(state, table) {
139+
state.list.push(table);
140+
},
141+
SET_PAGINATION_ITEM(state, {key, value}) {
142+
Vue.set(state.pagination, key, value);
143+
},
144+
CREATE(state, newItem) {
145+
state.list.push(newItem);
146+
},
147+
PATCH(state, {id, fields}) {
148+
console.log('id', id);
149+
const index = state.list.findIndex(item => item.id === id);
150+
console.log('index', index);
151+
for (let key in fields) {
152+
state.list[index][key] = fields[key];
153+
}
154+
},
155+
DELETE(state, id) {
156+
const index = state.list.findIndex(item => item.id === id);
157+
state.list.splice(index, 1);
158+
}
159+
}
160+
};
161+
}
162+

Diff for: src/date-time-constants.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default {
2+
MySqlFormat: 'YYYY-MM-DD HH:mm:ss.SSS'
3+
};

0 commit comments

Comments
 (0)