devinivy / dogwater Goto Github PK
View Code? Open in Web Editor NEWA hapi plugin integrating Waterline ORM
License: MIT License
A hapi plugin integrating Waterline ORM
License: MIT License
I want to put forth the idea of a very simple plugin-like structure for dogwater. There are cases in which one may want to modularize different areas of their model/configurations, and I would like dogwater to cater to that.
I would also like plugins to be able to consume non-standard Waterline model and attribute properties in a safe way so that dogwater plugins may extend the functionality of Waterline as it lives in the hapi ecosystem.
I'm taking suggestions here as to how to implement this, and spec out a working first-draft API. I'd like to see this as the main feature of 1.2.0 or 2.0.0.
When I run my project that uses dogwater, I get the following error logged:
Warning: `connections` is no longer supported. Please use `datastores` instead.
I get what you mean, so I temporarily renamed it for you this time, but here is a stack trace
so you know where this is coming from in the code, and can change it to prevent future warnings:
Error
at Object.initialize (/home/chbr1/Projects/cuca-service/node_modules/waterline/lib/waterline.js:143:12)
at internals.initialize (/home/chbr1/Projects/cuca-service/node_modules/dogwater/lib/index.js:118:15)
at Items.serial (/home/chbr1/Projects/cuca-service/node_modules/hapi/lib/server.js:418:18)
at iterate (/home/chbr1/Projects/cuca-service/node_modules/items/lib/index.js:36:13)
at Object.exports.serial (/home/chbr1/Projects/cuca-service/node_modules/items/lib/index.js:39:9)
at module.exports.internals.Server.internals.Server._invoke (/home/chbr1/Projects/cuca-service/node_modules/hapi/lib/server.js:415:11)
at Items.parallel (/home/chbr1/Projects/cuca-service/node_modules/hapi/lib/server.js:272:14)
at done (/home/chbr1/Projects/cuca-service/node_modules/items/lib/index.js:63:25)
at process.nextTick (/home/chbr1/Projects/cuca-service/node_modules/hoek/lib/index.js:854:22)
at _combinedTickCallback (internal/process/next_tick.js:131:7)
at process._tickCallback (internal/process/next_tick.js:180:9)
at Function.Module.runMain (module.js:686:11)
at startup (bootstrap_node.js:187:16)
at bootstrap_node.js:608:3
Versions:
[email protected]
[email protected]
[email protected]
I know waterline is .1 above the recommended version range from dogwater, but I figured if they're following semver then it should be fine (right? RIGHT?)
It will be helpful for validating data into request
We need a way to tear down adapters' connections for reuse, particularly in tests. See https://github.com/devinivy/bedwetter/blob/master/test/options/actAsUser.js#L539.
This would be baller– anyone with the time, give 'er a whirl!
I ran into this issue the other day, for each controller i tend to use the same models to generally get information and perform queries, updates, and creates with waterline models. I was wondering if there was a way to declare the models globally so that they can be used without having to pull them from the request.server.model. Something along the lines of a var pet = getModel['pet'] at the top of the document. and then you can do pet.create(), pet.findOne, etc
Hello guys,
I have some troubles using NES with jwt authentication using Waterline/Dogwater.
here is my server.js:
'use strict'
const Hapi = require('hapi')
const Hoek = require('hoek')
const hapiAuthJWT = require('hapi-auth-jwt2')
const Dogwater = require('dogwater')
const sailsmysql = require('sails-mysql')
const Nes = require('nes')
// load models
const config = require('./configs/test_credentials')
const router = require('./routes/router').router
const validate = require('./lib/validate').validate
const server = new Hapi.Server()
server.connection({ port: 8000, routes: { cors: true } })
server.register(require('inert'), (err) => {
Hoek.assert(!err, err)
})
server.register({
register: Dogwater,
options: {
adapters: {
dndDisk: sailsmysql
},
connections: {
dndDB: .....................
}
}
}, (err) => {
Hoek.assert(!err, err)
})
server.register(hapiAuthJWT, (err) => {
Hoek.assert(!err, err)
})
server.auth.strategy('jwt', 'jwt',
{ key: config.jwtsecret,
validateFunc: validate,
verifyOptions: { ignoreExpiration: true },
headerKey: 'authentication-token'
})
server.register(Nes, (err) => {
Hoek.assert(!err, err)
})
server.auth.default('jwt')
server.dogwater([ CreditCard, Passenger, FavoriteLocation, Trip, Driver, TripRoute, PaymentLog, Promotion, DriverRating, PassengerRating, Administrator, Country, CountryPrice, LatestDriverLocation, Language ])
server.route(router)
server.start((err) => {
Hoek.assert(!err, err)
console.log('Server started at:', server.info.uri)
})
My route for the socket is:
{
method: 'GET',
path: '/ws',
config: {
id: 'hello',
auth: 'jwt',
handler: function (request, reply) {
return reply('world!');
}
}
}
validate function is:
function validate (decoded, request, callback) {
const passenger = request.collections().passenger
passenger.findOne(decoded.id)
.then((passenger) => {
if ((decoded.username) === (passenger.username)) {
return callback(null, true)
} else {
return callback(null, false)
}
})
}
and client is:
var Nes = require('nes')
var client = new Nes.Client('ws://localhost:8000')
client.connect({auth: {headers: {'Authentication-Token': 'token'}}}, (err) => {
if (err) return console.log(err)
client.request('hello', (err, payload) => {
if (err) return console.log('err is ' + err)
console.log(payload)
})
})
when I run the client, using valid token (I am testing it with other routes) it gives the following error:
{ Error: An internal server error occurred
at new NesError (/Users/vgenev/Projects/dnd-server/node_modules/nes/lib/client.js:77:19)
at parse (/Users/vgenev/Projects/dnd-server/node_modules/nes/lib/client.js:616:25)
at parse (/Users/vgenev/Projects/dnd-server/node_modules/nes/lib/client.js:48:16)
at Client._onMessage (/Users/vgenev/Projects/dnd-server/node_modules/nes/lib/client.js:603:9)
at WebSocket.ws.onmessage (/Users/vgenev/Projects/dnd-server/node_modules/nes/lib/client.js:261:25)
at WebSocket.onMessage (/Users/vgenev/Projects/dnd-server/node_modules/ws/lib/WebSocket.js:442:14)
at emitTwo (events.js:106:13)
at WebSocket.emit (events.js:191:7)
at Receiver.ontext (/Users/vgenev/Projects/dnd-server/node_modules/ws/lib/WebSocket.js:841:10)
at /Users/vgenev/Projects/dnd-server/node_modules/ws/lib/Receiver.js:536:18
type: 'server',
statusCode: 401,
data:
{ error: 'Unauthorized',
message: 'An internal server error occurred' },
headers: undefined,
path: undefined }
and the server error is:
Debug: internal, implementation, error
TypeError: Cannot read property 'findOne' of undefined
at Object.validate [as validateFunc] (/Users/vgenev/Projects/dnd-server/lib/validate.js:4:12)
at /Users/vgenev/Projects/dnd-server/node_modules/hapi-auth-jwt2/lib/index.js:87:23
at /Users/vgenev/Projects/dnd-server/node_modules/jsonwebtoken/verify.js:27:18
at _combinedTickCallback (internal/process/next_tick.js:67:7)
at process._tickDomainCallback (internal/process/next_tick.js:122:9)
What I have seen is that actually the passenger is not created by: const passenger = request.collections().passenger
in the validate function, although the token is correctly decoded.
After I posted the question in Nes repo, they adviced me to use request.collections(true).passenger
and it fixed the problem. But is it a good practice and how can be avoided?
Base closely on hapijs org contrib.
for some reason, most of the tutorial and working samples are referring to documentation here,
https://github.com/devinivy/dogwater/tree/v0.4.7
it took me a while to figure that out.
To be specific, Dogwater requires unextended Waterline collections, and this
is not properly bound. Therefore, models like this will not work (highly simplified to show the point):
module.exports = {
attributes: {
firstName: 'string',
lastName: 'string',
getFullName: function() { return this.firstName + ' ' + this.lastName; }
}
}
This may be difficult fix without major API changes, however, so this may be of use for future releases only.
It would be really great if you could make a small example app showing how this works. It looks interesting and I would love to be able to use it but i'm sort of new to node/hapi/js so I can't quite piece it together.
Much appreciated,
Charles
The changes in dogwater 2.0.0 focus around the ability to define and use models on a per-plugin basis. It has also been brought into the world of node.js v4+, now taking advantage of ES6 features in line with the current hapi style guide. You should also find improved docs, tests, code, and a leaner, meaner API.
server.plugins.dogwater
no longer exposes collections, connections, the schema, and a teardown method. Instead just access these goodies on server.waterline
. #44onPreStart
server extension and server.dependency(deps, after)
callback) rather than during plugin registration. #37request.collections
should be replaced with request.collections([all])
. Pass all
as true
to obtain access to every collection registered with dogwater, or omit all
to obtain access only to the collections defined within the same plugin/realm as request.route
. #37server.dogwater()
with server.waterline
in scope or reference the ORM within collection lifecycle callbacks and methods as this.waterline
. #43server.dogwater(config)
allows plugins to define adapters, connections, and their own models. See the readme for more detailed info.server.collections([all])
provides sandboxed (or not sandboxed) access to the collections defined in the active plugin/realm.request.collections([all])
provides sandboxed (or not sandboxed) access to the collections defined in the realm/plugin of request.route
.teardownOnStop
registration option may be used to specify whether or not Waterline connections should be torn-down when the server stops. Defaults true
.Beyond linting, also see outmoded/hapi-contrib#31
Hi,
I was wondering if dogwater and/or waterline provide a way for database migrations like, for example, sequelize-cli does for Sequelize ORM.
What I would like to do is to run, for example, db:migrate --env=development
and all tables and rows and columns are created automatically based on my models.
Thanks in advance.
Dogwater 1.0.0 has better documentation, a cleaner interface, spiffier code, better tests, and a few new features.
request.model
has been renamed to request.collections
to be more consistent with Waterline's terminology.server.methods.getWaterline(cb)
should be replaced by using the server decoration server.waterline
.data
option has been renamed to fixtures
to be less ambiguous.models
options are incorrectly specified as neither a string path nor an array, dogwater will throw
rather than pass a soft error to the plugin's callback.server.plugins.dogwater
no longer exposes each Waterline collection. It is now an object containing the following:
collections
connections
schema
teardown(cb)
fixtures
option (formerly data
) now alternately accepts an array directly specifying data fixtures in the format prescribed by waterline-fixtures (which can be seen in the readme's usage example).models
option may now be relative or absolute. This is with rejoice manifests in mind.server.plugins.dogwater.teardown(cb)
) which tears down every connection on every adapter. This is particularly useful when writing tests or when recovering from errors and re-instantiating Waterline.Right now, the fixtures seem to be loading every time the server starts, even if migrate: safe
is set in the models. If there are no unique fields, then it duplicates the data. If there are unique fields, then the plugin fails on server startup. I'd like the option to just load the fixtures on a blank database only.
Hi guys,
I want to combine few collections and return to the reply interface. But below code doesn't stringify the object right -
(request, reply) => {
/*
get the current filters
get the current effects
get the trigger categories
*/
const response = {
triggers: {
categories: []
}
};
const user = {};
const promise = Promise.promisify(ConfigurationAPI(request.server).getCategoriesAPI)(user).then((categories) => {
response.triggers.categories = categories;
return response;
});
return reply(promise);
}
Prints below -
{
triggers: {
categories: [ [Object] ]
}
}
Cheers~
Now waterline 0.11 and 0.12 are out– they are all supportable by dogwater, so users should make the choice themselves.
Dogwater should aggregate connections and model definitions, and only initialize waterline during onPreStart
. Collections should possibly appear on the realm rather than the root server.
I understand, one can use request.collections.<table_name> to access underlying sql table. But if one needs to access a table view in a query how do we do that?
Help wanted—feel free to submit a PR!
I have the following 2 models defined:
'user strict';
module.exports = {
identity: 'user',
connection: 'dbCSQA',
tableName: 'User',
migrate: 'safe',
autoPK: false,
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
userId: {
type: 'integer',
primaryKey: true,
autoIncrement: true,
unique: true
},
name: {
type : 'string',
required : true,
unique: true,
maxLength: 100
},
organisationId: {
type : 'integer',
required : false
},
positionId: {
type : 'integer',
required : false
},
authId: {
type : 'string',
required : false
}
}
}
and
'user strict';
module.exports = {
identity: 'organisation',
connection: 'dbCSQA',
tableName: 'Organisation',
migrate: 'safe',
autoPK: false,
autoCreatedAt: false,
autoUpdatedAt: false,
attributes: {
organisationId: {
type: 'integer',
primaryKey: true,
autoIncrement: true,
unique: true
},
name: {
type : 'string',
required : true,
unique: true,
maxLength: 50
},
users: {
collection: 'user',
via: 'organisationId'
}
}
}
The payload for /api/organisations/1
returns all the fields, as specified in the organisation
model, but the users
field is an empty array.
Have I missed something with the association config?
PS: I'm using [email protected]
Apologies for the newbie question, just learning hapi / dogwater / waterline.
All crud methods are working fine for me, except when I mixed models in different plugins.
I have a plugin called Facebook
and a plugin called Person
and I'd like to be able to reference Person
from Facebook
in order to find or create a person based on whether they exist in some form in the Facebook
table.
So in Facebook
I'm using:
const Person = request.collections(true).person;
console.log('person identity: ' + Person.identity);
// it prints, so it seems to work?
// person identity: person
However, if I try and call .create
on that Person
collection, it does nothing / doesn't throw an error and then if I try and print the result it says:
const zePerson = yield Person.create({
firstName: firstName,
lastName: lastName,
email: email
});
console.log('zePerson: ' + zePerson);
zePerson: TypeError: request.collections is not a function
What am I missing here? Thanks for the help!
If you are not aware yet, Hapi v17 is making the transition from callbacks to async
/await
, as well as deprecating some other rarely used functionality. This is a breaking change that may make your plugin no longer compatible with the Hapi API.
Draft release notes can be found here: hapijs/hapi#3658
The target release date for v17 is the beginning of November.
async
/await
compatible using the v17
branch from Hapi for testing
npm link
within the Hapi reponpm link hapi
within your plugin repov17
of Hapi branch for testsnpm
. Please use a major version increment as this will be a breaking change and it would be terrible for it to sneak into current versions of Hapi.<8.0.0
.v16
will continue to be supported for as long as there exists a Node LTS actively being supported that is not compatible with v17
.This is much cleaner, more hapi-idiomatic than before.
The waterline-fixtures module needs some love and some tests. It's just not up to snuff! Maybe provide info/example of how it can still be used with dogwater in docs.
Sends to a blank page on the sailsjs site.
hey, would you be kind enough to provide an example where the fixtures populate an associaltions,
i know this is not a dog-water issue, but please bare your example on the readme is good and understandable, but after that, there is very little documentation on the internet on how to make associaltions in fixtures, 1:m,m:m,m:1 and any more
this is very usefull for any user who intends to use dogwater for a project, can you refrence any examples on ho i can do associations in fixtures?
im getting this err
Debug: internal, implementation, error
Error: Uncaught error: Encountered unexpected error while building join instructions for `.populate("users")`
Details:
[Error: In `.populate("users")`, attempting to populate an attribute that doesn't exist]
when trying to follow waterlines docs , please consider this :-)
https://github.com/hapijs/hoek/blob/master/lib/index.js#L868 meets https://github.com/devinivy/dogwater/blob/master/lib/index.js#L21. This change will make dogwater more airtight, esp. in the case of Windows machines and use of trailing slashes. I assume the current implementation that I suggested has something that will manifest as a bug for somebody out there...
If waterline init returns an error with it's callback no errors are thrown, but Hapi will not handle any requests. I was seeing this with NODE_ENV=production without setting a migration strategy. Waterline returned an error that safe migrations must be used in production but it was swallowed during plugin registration.
This will be made obsolete by #37– the plugin will have waterline in context, so the models will (can) as well. Additionally, it turns out it's usually not necessary to pass waterline to the collections because it is available as this.waterline
within collection methods.
When I run my project that uses dogwater, I get the following message on the console:
Warning: As of Waterline 0.13, `loadCollection()` is now `registerModel()`. Please call that instead.
I get what you mean, so I temporarily renamed it for you this time, but here is a stack trace
so you know where this is coming from in the code, and can change it to prevent future warnings:
Error
at Object.heyThatsDeprecated [as loadCollection] (/home/chbr1/Projects/cuca-service/node_modules/waterline/lib/waterline.js:92:8)
at Object.keys.forEach (/home/chbr1/Projects/cuca-service/node_modules/dogwater/lib/index.js:108:19)
at Array.forEach (<anonymous>)
at internals.initialize (/home/chbr1/Projects/cuca-service/node_modules/dogwater/lib/index.js:104:35)
at Items.serial (/home/chbr1/Projects/cuca-service/node_modules/hapi/lib/server.js:418:18)
at iterate (/home/chbr1/Projects/cuca-service/node_modules/items/lib/index.js:36:13)
at Object.exports.serial (/home/chbr1/Projects/cuca-service/node_modules/items/lib/index.js:39:9)
at module.exports.internals.Server.internals.Server._invoke (/home/chbr1/Projects/cuca-service/node_modules/hapi/lib/server.js:415:11)
at Items.parallel (/home/chbr1/Projects/cuca-service/node_modules/hapi/lib/server.js:272:14)
at done (/home/chbr1/Projects/cuca-service/node_modules/items/lib/index.js:63:25)
at process.nextTick (/home/chbr1/Projects/cuca-service/node_modules/hoek/lib/index.js:854:22)
at _combinedTickCallback (internal/process/next_tick.js:131:7)
at process._tickCallback (internal/process/next_tick.js:180:9)
at Function.Module.runMain (module.js:686:11)
at startup (bootstrap_node.js:187:16)
at bootstrap_node.js:608:3
Versions:
[email protected]
[email protected]
[email protected]
I know waterline is .1 above the recommended version range from dogwater, but I figured if they're following semver then it should be fine (right? RIGHT?)
(PS: I opened two tickets for this issue even though they are both related to updating waterline, because they are technically independent of one another and can be fixed separately)
It's possible to add extended waterline models to dogwater ?
Hi!
I'm from this issue:
outmoded/discuss#188
How to specify adapter with dogwater
? I want to use new ES6 waterline:
https://github.com/waterlinejs/postgresql-adapter
Need some useful examples.
In my situation I already have postgres DB with test data and want to quickly create REST API on Hapi.js. Maybe this tool also can help me?
https://github.com/devinivy/bedwetter
But I don't clearly understand how this can help me =))
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.