κ·Έλμ λλ feathers νλ μμν¬λ‘ μ±μ κ°λ°νμ΅λλ€. λ€λ₯Έ μλΉμ€μ λ°μ΄ν°μ μ‘μΈμ€νλ €λ λ°μ΄ν°λ² μ΄μ€ μλΉμ€μ μ°κ²°λ νν¬κ° μμ΅λλ€. μ΄κ²μ΄ κ°λ₯νκ³ μ¬μ΄κ°μ? ν΄λΉ μλΉμ€κ° μ¬λ¬ neDB νμΌμ μ‘μΈμ€ν μ μκΈ°λ₯Ό λ°λλλ€. μ΄λ»κ² ν΄μΌ νλμ?
'use strict';
module.exports = function(options) {
return function(hook) {
// access other db files here and get data
hook.data = {
putDataHere: newData
};
};
};
μ. κ΄λ ¨ νλͺ©μ κ°μ Έμ€λ λ°©λ² μ hook.app.service('servicename')
λ₯Ό ν΅ν΄ λ€λ₯Έ μλΉμ€μ μ‘μΈμ€νκ³ νμν λ©μλλ₯Ό νΈμΆν μ μμ΅λλ€. νν¬κ° λκΈ°νλ €λ©΄ λͺ¨λ μλΉμ€ λ©μλκ° μ΄λ―Έ μννλ νΈλ¦¬ν Promise( hook
κ°μ²΄λ‘ ν΄κ²°)λ₯Ό λ°νν μ μμ΅λλ€.
module.exports = function(options) {
return function(hook) {
return hook.app.service('otherservice').find({
query: { name: 'David' }
}).then(page => {
const davids = page.data;
hook.data.davids = davids;
// Or you can replace all the data with
hook.data = { davids };
// IMPORTANT: always return the `hook` object in the end
return hook;
});
};
};
@daffl μ λ§ κ°μ¬ν©λλ€. μ΄λ κ² μ¬μΈ κ±°λΌκ³ μκ°νλλ° μ€λͺ μμμ μ°Ύμ μ μμμ΅λλ€. λμ³€μ κ²μ λλ€.
μ’μ, μ΄κ²μ λ΄κ° νν¬ μ μ μ΄κ²μ κ°μ§κ³ μλ μ°ΎκΈ° νΈμΆμ λλ€(κ·Έ μ λ³΄κ° νμν κ²½μ°μλ§)
λλ λ¨μ§ 25κ°λ₯Ό μ»μμ§λ§ μλ°±κ°κ° μλ€. μ νμ μ κ±°νλ©΄ 5κ°μ νλͺ©λ§ μ»μ΅λλ€.
λ¬΄μ¨ μΌμ΄ μΌμ΄λκ³ μ΄λ»κ² λͺ¨λ κ²μ μ»μ μ μμ΅λκΉ?
module.exports = function(options) {
return function(hook) {
const dataSet = hook.params.query.dataSet;
const userVector = hook.params.query.userVector;
return hook.app.service('data').find({
query: { dataSet: dataSet, $limit:2000 }
}).then(page => {
// lots of magic here
//console.log(page.data);
hook.result = page.data;
return hook;
});
};
};
ꡬμ±μμ paginate.max
μ λν΄ μ€μ ν μ΅μ
μ λ°λΌ λ€λ¦
λλ€. λκ΅°κ°κ° μ격μΌλ‘ μλ°±λ§ κ°μ λ μ½λλ₯Ό μμ²ν μ μλλ‘ νλ λ³΄νΈ μ₯μΉμ
λλ€. λͺ¨λ μ΅μ μ΄λν°μμλ λ€μ κ³Ό κ°μ΄ λͺ¨λ λ μ½λλ₯Ό μ»κΈ° μν΄ νμ΄μ§ 맀κΉμ λ μ μμ΅λλ€.
return hook.app.service('data').find({
paginate: false,
query: { dataSet: dataSet }
}).then(data => {
// data is an array
});
λ΄κ° ν λ λλ 0 κ°μ λ μ½λλ₯Ό μ»μ΅λλ€. νμ΄μ§ 맀κΉ: falseλ₯Ό μ κ±°νλ©΄ 25κ° λ©λλ€.
npm ls feathers-nedb
λ v2.4.1μ νμν©λκΉ? κ·Έλ μ§ μλ€λ©΄ κ·Έμ λ°λΌ package.json
λ₯Ό μ
λ°μ΄νΈν΄μΌ ν μλ μμ΅λλ€.
βββ [email protected]
λ°©κΈ paginate: false
κ° λ€μ μμμ μλνλμ§ νμΈνμ΅λλ€.
const feathers = require('feathers');
const rest = require('feathers-rest');
const socketio = require('feathers-socketio');
const hooks = require('feathers-hooks');
const nedb = require('feathers-nedb');
const bodyParser = require('body-parser');
const handler = require('feathers-errors/handler');
const NeDB = require('nedb');
// A Feathers app is the same as an Express app
const app = feathers();
const db = new NeDB({
filename: './data/messages.db',
autoload: true
});
// Parse HTTP JSON bodies
app.use(bodyParser.json());
// Parse URL-encoded params
app.use(bodyParser.urlencoded({ extended: true }));
// Register hooks module
app.configure(hooks());
// Add REST API support
app.configure(rest());
// Configure Socket.io real-time APIs
app.configure(socketio());
// Register our memory "users" service
app.use('/todos', nedb({
Model: db,
paginate: {
default: 20,
max: 50
}
}));
// Register a nicer error handler than the default Express one
app.use(handler());
const promises = [];
for(let i = 0; i < 700; i++) {
promises.push(app.service('todos').create({ text: `Item #${i}`}));
}
Promise.all(promises).then(function() {
app.service('todos').find({
paginate: false,
query: {}
}).then(data => console.log(data));
});
// Start the server
app.listen(3333);
μ½μμ 700κ°μ νλͺ©μ΄ κΈ°λ‘λ©λλ€. κΈ°λ³Έ 맀κ°λ³μ λμ 쿼리μ μ€μλ‘ paginate: false
λ₯Ό μΆκ°νμ΅λκΉ?
μ΄κ²μ΄ λ΄κ° ν μΌμ λλ€.
'use strict';
module.exports = function(options) {
return function(hook) {
const dataSet = hook.params.query.dataSet;
const userVector = hook.params.query.userVector;
return hook.app.service('data').find({
paginate: false,
query: { dataSet: dataSet, $limit:2000 }
}).then(page => {
// lots of magic here
console.log(page.data);
hook.result = page.data;
return hook;
});
};
};
μ¬μ ν νμ΄μ§ λ§€κΉ λ³μκ° μλ 0κ°μ κ²°κ³Όμ 25κ°μ κ²°κ³Ό λ° μ ν μλ 5κ°μ κ²°κ³Όλ₯Ό μ»μ΅λλ€.
κ·Έλ¬λ λ€μκ³Ό κ°μ΄ μμ νμ΅λλ€.
'use strict';
module.exports = function(options) {
return function(hook) {
const dataSet = hook.params.query.dataSet;
const userVector = hook.params.query.userVector;
return hook.app.service('data').find({
paginate: false,
query: { dataSet: dataSet }
}).then(page => {
// lots of magic here
console.log(page);
hook.result = page;
return hook;
});
};
};
보μλ€μνΌ κ²°κ³Όλ λ μ΄μ page.dataκ° μλλΌ νμ΄μ§ λ³μμλ§ μμ΅λλ€.
κ΅νμ μ»μμ΅λλ€ :)
μ κ·Έλ¦¬κ³ λμμ μ£Όμ @dafflλκ» κ°μ¬λ립λλ€.
ν΄λΌμ΄μΈνΈ μΈ‘μμλ μλνμ§ μμ΅λλ€. ( paginate: false,
λ³μ).
ν΄λΌμ΄μΈνΈμ μλ² κ°μλ query
λ§ μ λ¬λ©λλ€. λλ ν΄λΌμ΄μΈνΈκ° λͺ¨λ μ 체λ₯Ό μμ²νλλ‘ νμ§ μμΌλ €κ³ λ
Έλ ₯ν κ²μ
λλ€(λ°μ΄ν°λ² μ΄μ€μ λ°±λ§ κ°μ λ μ½λκ° μλ κ²½μ° μλ²μ ν΄λΌμ΄μΈνΈ λͺ¨λλ₯Ό μ£½μΌ κ²μ
λλ€). μ°νν λ°©λ²μ΄ μμΌλ©΄ params.query
μμ μλ²μ νν¬ μμ params
λ‘ νΉμ 쿼리 맀κ°λ³μ(μ: $paginate
)λ₯Ό 맀νν΄μΌ ν©λλ€.
app.service('data').before({
find(hook) {
if(hook.params.query && hook.params.query.$paginate) {
hook.params.paginate = hook.params.query.$paginate === 'false' || hook.params.query.$paginate === false;
delete hook.params.query.$paginate;
}
}
});
ν΄λΌμ΄μΈνΈ μΈ‘μμ νμ΄μ§ 맀κΉμ νμ©νμ§ μλλ€λ κ²½κ³ λ₯Ό μ΄ν΄νμ§λ§, μ κ° λ§λ€κ³ μλ λꡬλ λ‘컬μμ μ€ννκΈ° μν κ²μ λλ€. λͺ¨λ κ²μ λ€μ ν λ² κ°μ¬λ립λλ€.
@daffl μλ νμΈμ, μ¬μ©μκ° κ²μν κ²μλ¬Όμ κ²μνκΈ° μν΄ κ²μν μ½λλ₯Ό μ¬μ©νκ³ μμ΅λλ€.
module.exports = function(options) {
return function(hook) {
// hook.getPosts = true;
const id = hook.result.id;
console.log("id");
return hook.app.service('posts').find({
paginate: false,
query: { postedBy: id }
}).then(function(posts){
console.log("posts");
// Set the posts on the user property
hook.result.posts = posts.data;
// Always return the hook object or `undefined`
return hook;
});
};
};
κ·Έλ¬λ μ΄λ‘ μΈν΄ μλ²κ° 무ν 루νμ λΉ μ§κ³ λ Έλ μ±μ΄ κΆκ·Ήμ μΌλ‘ μΆ©λν©λλ€.
Sequelizeλ‘ μ°κ²°λ DBλ‘ MySQLμ μ¬μ©νκ³ μμ΅λλ€.
λ΄κ° λ μλͺ»νκ³ μμ£ ?
postedBy
νλλ₯Ό κΈ°λ°μΌλ‘ μ¬μ©μ νλλ₯Ό μ±μ°κΈ° μν΄ κ²μλ¬Όμ λν΄ μ μ¬ν νν¬λ₯Ό μ€μ νμ΅λλ€. λ°λΌμ μ¬μ©μ νν¬κ° ν¬μ€νΈ νν¬λ₯Ό νΈλ¦¬κ±°νμ¬ μλ μ¬μ©μ νν¬λ₯Ό νΈλ¦¬κ±°νκ³ λ£¨νκ° κ³μλμ΄ λ¬΄ν 루νμ λ©λͺ¨λ¦¬ μ€λ²νλ‘κ° λ°μνλ κ² κ°μ΅λλ€.
μμ κ΄λ ¨ νλͺ©λ§ μ±μ°λ λ°©λ²μ λν μμ΄λμ΄, μ¦ νν¬λ 첫 λ²μ§Έ μμ€μμλ§ κ΄λ ¨ νλͺ©μ λμ΄μ΅λλ€.
@daffl μ½λκ° μλνμ§ μμμ§λ§ μμ΄λμ΄λ νλ₯ν©λλ€.
μλνλ €λ©΄ hook.paginateλ₯Ό hook.params.paginateλ‘ λ³κ²½ν΄μΌ νμ΅λλ€.
κ·Έλ¦¬κ³ μνλ λλ‘ λ³΄λΌ μ μλλ‘ μ½κ° λ³κ²½νμ΅λλ€.
κ·Έλμ $paginate : {value: false} νμ΄μ§ 맀κΉμ λΉνμ±ννκ±°λ
$paginate: { value: {default: 100, max: 2000}} νμ΄μ§ λ§€κΉ μ¬μ μ
app.service('data').before({
find(hook) {
if(hook.params.query.$paginate) {
hook.params.paginate = hook.params.query.$paginate.value;
delete hook.params.query.$paginate;
}
}
});
ν κ°μ§ λ κ³ λ €ν΄μΌ ν μ μ νμ΄μ§ 맀κΉμ΄ λΉνμ±νλλ©΄ λ°μ΄ν°κ° res.dataκ° μλλΌ res μ체μ μλ€λ κ²μ λλ€.
@fortunes-technology λΉμ μ΄ λ§μ΅λλ€. μ½λ μ€λν«μ μ λ°μ΄νΈνμ΅λλ€. μ΄κ²μ μλν΄μΌ ν©λλ€:
app.service('data').before({
find(hook) {
if(hook.params.query && hook.params.query.$paginate) {
hook.params.paginate = hook.params.query.$paginate === 'false' || hook.params.query.$paginate === false;
delete hook.params.query.$paginate;
}
}
});
$paginateκ° falseλ‘ μ€μ λμ΄ μμΌλ©΄(μ΄ νν¬λ₯Ό λΉνμ±ννκΈ° μν΄... ) ifλ falseκ° λ κ²μ λλ€. μλ§λ
app.service('data').before({
find(hook) {
if(hook.params.query && hook.params.query.hasOwnProperty('$paginate')) {
hook.params.paginate = hook.params.query.$paginate === 'false' || hook.params.query.$paginate === false;
delete hook.params.query.$paginate;
}
}
});
μλ
νμΈμ. νλ μλΉμ€μ findOne κΈ°λ₯μ΄ μλμ§ λλ ꡬν λ°©λ²μ μλ €μ£Όμ€ μ μλμ? κ°μ¬ ν΄μ!
cc @daffl
findOne
λ¨μ§ μΈ find
Aλ₯Ό $limit
1 :
app.service('myservice').find({ query: { name: 'test', $limit: 1 } })
.then(page => page.data[0])
.then(result => console.log('Got', result);
@daffl mongooseμ findOneμ΄ μκΈ° λλ¬Έμ λ¬Όμκ³ μ΄λ―Έ μ°Ύμ κ²μ΄ μμΌλ©΄ λͺ¨λ λλ¨Έμ§ μ»¬λ μ μ κ²μνμ§ μλλ€κ³ μ μνμ΅λλ€. κ·Έλμ findOneμ limit=1λ‘ κ²μνλ κ²λ³΄λ€ λ λλν κ²μΌλ‘ μκ°νμ΅λλ€. κ·Έλμ μ κ° μ§λ¬Ένμ΅λλ€.
λλ λ³΄ν΅ λΉ λ₯Έ findOneμ μν΄ μ΄κ²μ ν©λλ€:
const employee = (await context.app.service('employees').find({ query: { userId: user.id }, paginate: false }))[0];
λ°©κΈ .findOne()
λ©μλμ© νλ¬κ·ΈμΈμ λ§λ€μμ΅λλ€: feathers-findone
ν΄λΌμ΄μΈνΈμ λν΄ $paginate ν΄κ²° λ°©λ²μ μΆκ°νλ λ°©λ²μ λν μλ₯Ό μ°Ύμ μ μμ΅λλ€. κ·Έλμ app.hooks.js νμΌμμ μ€νλλ λΉν¬ νν¬λ₯Ό λͺ κ°μ§ μμ νμ¬ λ§λ€μμ΅λλ€.
module.exports = function () {
return context => {
if (context.params.query && hook.params.query.hasOwnProperty('$paginate')) {
context.params.paginate = context.params.query.$paginate === 'false' || context.params.query.$paginate === false;
delete context.params.query.$paginate;
}
};
};
μ΄λ₯Ό μν λ¨μ λλ ν΅ν© ν μ€νΈλ₯Ό μμ±νλ λ°©λ²μ 무μμ λκΉ?
Feathersμ λν λ€λ₯Έ ν μ€νΈλ₯Ό μμ±νλ κ²κ³Ό λμΌν©λλ€.
κ·Έλμ λ΄ νν¬μ λ€μμ΄μλ κ²½μ°
const records = getItems(context);
records.authors = await context.app.service('users') .find({ query: { _id: { $in: records.authorIds } } }, context.params);
λ΄ λ¨μ ν μ€νΈμμ μ΄λ»κ² context.app.serviceλ₯Ό "μ‘°λ‘±"ν©λκΉ?
λ΄ contextBefore κ°μ²΄μ μΆκ°ν΄μΌ ν©λκΉ?
contextBefore = {
type: 'before',
params: { provider: 'socketio', user: { _id: 1 } },
data: {
_id: 1,
},
};
λλ feathers-plus μμ±κΈ°μμ μμ±λ λ¨μ ν
μ€νΈ μλμ μ¬μ©νκ³ μμ΅λλ€.
https://generator.feathers-plus.com/get-started/#unit -test-for-a-hook
μλλ©΄ ν΅ν© ν μ€νΈλ₯Ό λμ μ¬μ©ν΄μΌ ν©λκΉ?
λλ μΌλ§ μ μ μ‘°λ‘±μ κΈΈμ κ°λ€. μμ£Ό λμ μκ°μ΄λΌκ³ μκ°ν©λλ€. κ²°κ΅ μ μ λ λ§μ Feathersλ₯Ό μ‘°λ‘±ν΄μΌ ν κ²μ λλ€. λͺ¨μ κΈ°λ₯μ΄ κΉνΈμ²λΌ μλνλ€λ 보μ₯μ μμΌλ©° μ μ²λΌ κ±°μ§ λΆμ μ μ»μ μ μμ΅λλ€.
Feathers μ±μ μΈμ€ν΄μ€ννλ κ²μ λ§€μ° λΉ λ₯΄λ―λ‘ λͺ¨μ λμ Feathersλ₯Ό μ¬μ©νμμμ€. μ΄κ²μ΄ cli+ ν μ€νΈμ μ κ·Ό λ°©μμ λλ€.
λλ μ΄κ²μ μΈκΈνλ κΈ°μ¬λ₯Ό μΌλ€. https://medium.com/feathers-plus/automatic-tests-with-feathers-plus-cli-4844721a29cf
κ³ λ§μ eddyy, λλ κ·Έκ²μ 보μκ³ , μ’μ κΈ°μ¬λ μ λ§λ‘ λμμ΄λμμ΅λλ€.
λ΄ μ»¨ν μ€νΈ κ°μ²΄μ μ±μ μΆκ°νλ λ°©λ²μ λν΄ κ³ μ¬νκ³ μμμ§λ§ κ²°κ΅ ν΄κ²°ν κ² κ°μμ!
const app = feathers();
contextBefore = {
type: 'before',
params: { provider: 'socketio', user: { _id: 1 } },
data: {
_id: 1,
},
app,
};
κ·Έλ° λ€μ λΉλκΈ°λ₯Ό μ¬μ©νλλ‘ ν μ€νΈλ₯Ό μμ ν΄μΌ νμ΅λλ€.
it('patch test', async () => {
contextBefore.app.use('users', {
async find() {
return { data: [ { expectedResultObj1 }, { expectedResultObj2 } ] };
}
});
contextBefore.data = {
_id: 1,
};
assert(true);
await hookToTest()(contextBefore);
assert.deepEqual(contextBefore.data, {
_id: 1,
expectedResultObject1,
expectedResultObject2,
});
});
κ·Έκ²μ΄ μ¬λ°λ₯Έ λ°©λ²μ λκΉ μλλ©΄ λ λμ λ°©λ²μ΄ μμ΅λκΉ?
μ’μ 보μΈλ€
@fortunes-technology λΉμ μ΄ λ§μ΅λλ€. μ½λ μ€λν«μ μ λ°μ΄νΈνμ΅λλ€. μ΄κ²μ μλν΄μΌ ν©λλ€:
app.service('data').before({ find(hook) { if(hook.params.query && hook.params.query.$paginate) { hook.params.paginate = hook.params.query.$paginate === 'false' || hook.params.query.$paginate === false; delete hook.params.query.$paginate; } } });
쿼리 $limitλ₯Ό μ¬μ©ν μ μμ΅λλ€. nullλ 무μν©λλ€.
κ°μ₯ μ μ©ν λκΈ
μ. κ΄λ ¨ νλͺ©μ κ°μ Έμ€λ λ°©λ² μ
hook.app.service('servicename')
λ₯Ό ν΅ν΄ λ€λ₯Έ μλΉμ€μ μ‘μΈμ€νκ³ νμν λ©μλλ₯Ό νΈμΆν μ μμ΅λλ€. νν¬κ° λκΈ°νλ €λ©΄ λͺ¨λ μλΉμ€ λ©μλκ° μ΄λ―Έ μννλ νΈλ¦¬ν Promise(hook
κ°μ²΄λ‘ ν΄κ²°)λ₯Ό λ°νν μ μμ΅λλ€.