Skip to content

Commit 67d2a2a

Browse files
authored
Merge pull request #62 from micro-analytics/feat/add-support-for-adapter-cli-config
Add support for adapter cli config
2 parents eafa365 + 530d443 commit 67d2a2a

File tree

13 files changed

+202
-70
lines changed

13 files changed

+202
-70
lines changed

adapter-tests/unit-tests.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,43 @@ module.exports = function testAdapter(options) {
4343
expect(adapter.put('/a-key', {}).constructor.name).toEqual("Promise")
4444
})
4545

46+
if (typeof adapter.options !== "undefined") {
47+
test('options should be an array of args options', () => {
48+
expect(Array.isArray(adapter.options)).toBe(true)
49+
if (adapter.options.length >= 0) {
50+
let counter = 0
51+
adapter.options.forEach(option => {
52+
expect(option.name).toBeDefined()
53+
expect(option.description).toBeDefined()
54+
counter++
55+
})
56+
57+
// if the forEach somehow breaks the test should break
58+
expect(counter).toBe(adapter.options.length)
59+
}
60+
})
61+
62+
test('init should be a defined when options is defined', () => {
63+
expect(typeof adapter.init).not.toBe("undefined");
64+
})
65+
} else {
66+
test.skip('options should be an array of args options', () => {})
67+
test.skip('init should be a defined when options is defined', () => {})
68+
}
69+
70+
if (typeof adapter.init !== "undefined") {
71+
test('init should be a function', () => {
72+
expect(typeof adapter.init).toBe("function");
73+
})
74+
75+
test('call init should not throw', () => {
76+
adapter.init(options.initOptions || {})
77+
})
78+
} else {
79+
test.skip('init should be a function', () => {})
80+
test.skip('call init should not throw', () => {})
81+
}
82+
4683
it('should save and read', async () => {
4784
await adapter.put('/a-key', { views: [{ time: 1490623474639 }] });
4885

@@ -167,6 +204,9 @@ module.exports = function testAdapter(options) {
167204
value: { views: [{ time: 1490623474639 }] },
168205
});
169206
});
207+
} else {
208+
it.skip('should allow subscription with observables', () => {})
209+
it.skip('should allow multiple subscription with observables and handle unsubscribption', () => {})
170210
}
171211
});
172212
};

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
"args": "^2.3.0",
3838
"flat-file-db": "^1.0.0",
3939
"micro": "6.1.0",
40-
"micro-analytics-adapter-flat-file-db": "^1.2.1",
40+
"micro-analytics-adapter-flat-file-db": "^1.3.0",
4141
"promise": "^7.1.1",
4242
"shelljs": "^0.7.6",
4343
"sse-channel": "^2.0.6",
@@ -51,6 +51,7 @@
5151
"babel-polyfill": "^6.20.0",
5252
"babel-preset-node6": "^11.0.0",
5353
"jest": "^19.0.2",
54+
"micro-analytics-adapter-memory": "^0.1.0",
5455
"nodemon": "^1.11.0",
5556
"request-promise": "^4.1.1"
5657
}

src/db.js

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,21 @@
11
const promise = require('promise')
22

3-
function initDbAdapter(adapterName) {
4-
let adapter
5-
const repeatCharacter = (char, n) => `${Array(n + 1).join(char)}`
6-
7-
try {
8-
adapter = require(`micro-analytics-adapter-${adapterName}`)
9-
} catch (err) {
10-
if (err.code === 'MODULE_NOT_FOUND') {
11-
// Console.error a warning message, but normally exit the process to avoid printing ugly npm ERR lines and stack trace.
12-
console.error(`\n${repeatCharacter(' ', 22)}⚠️ ERROR ⚠️\n${repeatCharacter('-', 55)}\nYou specified "${adapterName}" as the DB_ADAPTER, but no package\ncalled "micro-analytics-adapter-${adapterName}" was found.\n\nPlease make sure you spelled the name correctly and\nhave "npm install"ed the necessary adapter package!\n${repeatCharacter('-', 55)}\n`)
13-
process.exit(0)
14-
} else {
15-
throw err
16-
}
17-
}
3+
function initDbAdapter(options) {
4+
const adapterName = options.adapter
5+
const adapter = require(`micro-analytics-adapter-${adapterName}`)
186

197

20-
module.exports.get = adapter.get;
21-
module.exports.getAll = adapter.getAll;
22-
module.exports.put = adapter.put;
23-
module.exports.has = adapter.has;
24-
module.exports.keys = adapter.keys;
25-
module.exports.subscribe = adapter.subscribe;
26-
module.exports.hasFeature = (feature) => typeof adapter[feature] === "function";
8+
module.exports.get = adapter.get
9+
module.exports.getAll = adapter.getAll
10+
module.exports.put = adapter.put
11+
module.exports.has = adapter.has
12+
module.exports.keys = adapter.keys
13+
module.exports.subscribe = adapter.subscribe
14+
module.exports.hasFeature = (feature) => typeof adapter[feature] === "function"
2715

16+
if (module.exports.hasFeature('init')) {
17+
adapter.init(options)
18+
}
2819
}
2920

3021
module.exports = {

src/index.js

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,26 @@ const micro = require('micro')
33
const parseArgs = require('./parseArgs')
44
const db = require('./db');
55

6-
const flags = parseArgs(process.argv)
6+
try {
7+
const flags = parseArgs(process.argv)
78

8-
db.initDbAdapter(flags.adapter)
9+
db.initDbAdapter(flags)
910

10-
const handler = require('./handler')
11-
const server = micro(handler)
11+
const handler = require('./handler')
12+
const server = micro(handler)
1213

13-
server.listen(flags.port, flags.host, (error) => {
14-
if (error) {
15-
console.error(error)
16-
process.exit(1)
17-
}
18-
19-
console.log(
20-
'micro-analytics listening on ' + flags.host + ':' + flags.port + '\n' +
21-
' with adapter ' + flags.adapter +
22-
(db.hasFeature("subscribe") ? '\n with server side events' : '')
23-
)
24-
})
14+
server.listen(flags.port, flags.host, (error) => {
15+
if (error) {
16+
console.error(error)
17+
process.exit(1)
18+
}
19+
console.log(
20+
'micro-analytics listening on ' + flags.host + ':' + flags.port + '\n' +
21+
' with adapter ' + flags.adapter +
22+
(db.hasFeature("subscribe") ? '\n with server side events' : '')
23+
)
24+
})
25+
} catch (error) {
26+
console.error(error.message)
27+
process.exit(1)
28+
}

src/parseArgs.js

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,42 @@
1-
21
const args = require('args');
32

3+
const repeatCharacter = (char, n) => `${Array(n + 1).join(char)}`
4+
5+
function adapterNameFromArgs(argv) {
6+
for (let i = 0; i < argv.length; i++) {
7+
const arg = argv[i]
8+
if (arg === '-a' || arg === '--adapter') {
9+
return argv[i + 1]
10+
}
11+
if (/--adapter=/.test(arg)) {
12+
return arg.split('=')[1]
13+
}
14+
}
15+
16+
return process.env.DB_ADAPTER || 'flat-file-db'
17+
}
18+
419
module.exports = function parseArgs(argv) {
20+
const adapterName = adapterNameFromArgs(argv);
21+
let options = []
22+
23+
try {
24+
const adapter = require(`micro-analytics-adapter-${adapterName}`)
25+
if (adapter.options) {
26+
options = adapter.options
27+
}
28+
} catch (err) {
29+
if (err.code === 'MODULE_NOT_FOUND') {
30+
throw new Error(`\n${repeatCharacter(' ', 22)}⚠️ ERROR ⚠️\n${repeatCharacter('-', 55)}\nYou specified "${adapterName}" as the DB_ADAPTER, but no package\ncalled "micro-analytics-adapter-${adapterName}" was found.\n\nPlease make sure you spelled the name correctly and\nhave "npm install"ed the necessary adapter package!\n${repeatCharacter('-', 55)}\n`)
31+
} else {
32+
throw err
33+
}
34+
}
35+
536
return args
637
.option(['p', 'port'], 'Port to listen on', process.env.PORT || 3000, Number)
738
.option(['H', 'host'], 'Host to listen on', process.env.HOST ||'0.0.0.0')
839
.option(['a', 'adapter'], 'Database adapter used', process.env.DB_ADAPTER || 'flat-file-db')
40+
.options(options)
941
.parse(argv, { name: 'micro-analytics' })
1042
}

tests/__snapshots__/parseArgs.test.js.snap

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,23 @@ Object {
55
"H": "0.0.0.0",
66
"a": "flat-file-db",
77
"adapter": "flat-file-db",
8+
"d": "views.db",
9+
"dbName": "views.db",
810
"host": "0.0.0.0",
911
"p": 3000,
1012
"port": 3000,
1113
}
1214
`;
15+
16+
exports[`parseArgs should throw on non existing adapter 1`] = `
17+
"
18+
⚠️ ERROR ⚠️
19+
-------------------------------------------------------
20+
You specified \\"not-a-real-adapter\\" as the DB_ADAPTER, but no package
21+
called \\"micro-analytics-adapter-not-a-real-adapter\\" was found.
22+
23+
Please make sure you spelled the name correctly and
24+
have \\"npm install\\"ed the necessary adapter package!
25+
-------------------------------------------------------
26+
"
27+
`;

tests/atomicity.test.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ const db = require('../src/db')
66
const service = require('../src/handler')
77
let url
88

9-
db.initDbAdapter('flat-file-db');
9+
beforeAll(() => {
10+
db.initDbAdapter({ adapter: 'flat-file-db' });
11+
})
1012

1113
beforeEach(async () => {
1214
url = await listen(service)

tests/errors.test.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ const service = require('../src/handler')
55
const db = require('../src/db')
66
let url
77

8-
db.initDbAdapter('flat-file-db');
8+
beforeAll(() => {
9+
db.initDbAdapter({ adapter: 'flat-file-db' });
10+
})
911

1012
beforeEach(async () => {
1113
url = await listen(service)

tests/items.test.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ const db = require('../src/db')
66
const service = require('../src/handler')
77
let url
88

9-
db.initDbAdapter('flat-file-db');
9+
beforeAll(() => {
10+
db.initDbAdapter({ adapter: 'flat-file-db' });
11+
})
1012

1113
beforeEach(async () => {
1214
mockDb._reset()

tests/parseArgs.test.js

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
11
jest.mock('pkginfo', () => () => ({version: '1.0.0'}))
22
const parseArgs = require('../src/parseArgs')
33

4-
54
describe('parseArgs', () => {
65
it("should have correct defaults", () => {
76
expect(parseArgs(['node', 'micro-analytics'])).toMatchSnapshot();
87
})
98

9+
it('should throw on non existing adapter', () => {
10+
expect(() => {
11+
parseArgs(['node', 'micro-analytics', '-a', 'not-a-real-adapter'])
12+
}).toThrowErrorMatchingSnapshot()
13+
});
14+
1015
it("should use DB_ADAPTER environment variable as default if set", () => {
11-
process.env.DB_ADAPTER = 'redis'
12-
expect(parseArgs(['node', 'micro-analytics']).adapter).toEqual('redis');
16+
process.env.DB_ADAPTER = 'memory'
17+
expect(parseArgs(['node', 'micro-analytics']).adapter).toEqual('memory');
1318
delete process.env.DB_ADAPTER
1419
})
1520

@@ -24,4 +29,25 @@ describe('parseArgs', () => {
2429
expect(parseArgs(['node', 'micro-analytics']).host).toEqual('localhost');
2530
delete process.env.HOST
2631
})
32+
33+
it('should use get adapter option when using -a', () => {
34+
process.env.DB_ADAPTER = 'redis'
35+
const args = ['node', 'micro-analytics', '-a', 'flat-file-db']
36+
expect(Object.keys(parseArgs(args))).toContain('dbName');
37+
delete process.env.DB_ADAPTER
38+
});
39+
40+
it('should use get adapter option when using --adapter', () => {
41+
process.env.DB_ADAPTER = 'redis'
42+
const args = ['node', 'micro-analytics', '--adapter', 'flat-file-db']
43+
expect(Object.keys(parseArgs(args))).toContain('dbName');
44+
delete process.env.DB_ADAPTER
45+
});
46+
47+
it('should use get adapter option when using --adapter=', () => {
48+
process.env.DB_ADAPTER = 'redis'
49+
const args = ['node', 'micro-analytics', '--adapter=flat-file-db']
50+
expect(Object.keys(parseArgs(args))).toContain('dbName');
51+
delete process.env.DB_ADAPTER
52+
});
2753
})

0 commit comments

Comments
 (0)