1 – Initialization
latest RH node instructionsolder instructions
Install Node version 16 or greater:
dnf module enable nodejs:20 ; ## installing version 20 in this example. dnf module list nodejs ; ## optional step! dnf install nodejs ; node --version ; npm --version ;
install the feathers command-line interpreter (CLI):
npm install -g feathersjs/cli ; ### or --global
npm install feathersjs/cli -g ; ### for generating apps (notice g trails…. i think only this one actually works!
npm install feathersjs/cli4.8.0 —global ; ## 2023-04-19 install a SPECIFIC VERSION!
npm install @feathersjs/feathers —save ; ## save is no longer needed
##https://stackoverflow.com/questions/19578796/what-is-the-save-option-for-npm-install
export PATH=$PATH:/usr/local/bin/ ; ## 2024-09-24 — this was required!
which feathers ; ##
feathersjs —version ; ##
Optionally disable or modify the firewall
systemctl stop firewalld; ## or just authorize port 3030 ## --or--- firewall-cmd --add-port=3030/tcp ;. ## --- or---- firewall-cmd --add-port=3030/tcp --permanent ;
Generate an app using the CLI
feathers generate app ; ## notice that NO npm install's are used
npx feathers generate ; ## apparently another method (2024-09-24
feathers generate service ;
## select 'knex' or 'objection' (see below)
### connection string should look like this: "mysql://knexUser:knexPassword@localhost:3306/comptonTransAnlys"
DEBUG=* npm start ; ## test that app starts successfully, optional DEBUG
DEBUG=knex:query npm start ;
2 – modify this files
./config/default.js
"paginate": {
"default": 0,
"max": 0
3a – modify these files for KNEX
./src/services/tester/tester.class.js – KNEX
super({
...options,
name: 'tableName' /* changed this name to reflect the ACTUAL table name */
, id: 'tableNameAutoIncr' /* added this line to reflect the primary key */
});
./src/models/tester.model.js – KNEX
module.exports = function (app) {
return app.get('knexClient'); /* this is MUCH shorter than original! */
};
3b – modify these files for OBJECTION
./src/services/tester/tester.class.js – OBJECTION
add actual table name and unique id column name
model: Model
, 'name' : 'marksTestTable' , 'id' : 'marksTestTableAutoIncr' // line added by mark!!
./src/models/tester.model.js – OBJECTION
line 8: [specify REAL table name]
static get tableName() {
return 'marksTestTable'; // make SURE table name is correct !! (had to remove underscores)
}
line 14 old: [specify column names in array]
required: ['text'],line 17 new:
required: ['columnOne', 'columnTwo'], /* original: required: ['text'], */
line 17 old: [specify column types {type: ‘string’ } { type: ‘number’ } { type: ‘timestamp’} ]
text: { type: 'string' }
line 17 new:
'columnOne': { type: 'string' } , 'columnTwo': { type: 'number' } /* original: text: { type: 'string' } */
see: https://knexjs.org/guide/schema-builder.html#date line 22: comment out lines: ( or add .slice(0, 19).replace(‘T’, ‘ ‘); to dates.)
$beforeInsert() {
/* original: this.createdAt = this.updatedAt = new Date().toISOString(); */
// or possibly add this:
this.createdAt = this.updatedAt = new Date().toISOString().slice(0, 19).replace(‘T’, ‘ ‘);
$beforeUpdate() {
/* original: this.updatedAt = new Date().toISOString(); */
// or possibly add this:
this.updatedAt = new Date().toISOString().slice(0, 19).replace(‘T’, ‘ ‘);
per https://stackoverflow.com/questions/5129624/convert-js-date-time-to-mysql-datetimeline 35: [ eliminate the ‘create table’ stuff ]
/* most likely db.schema.createTable can be SKIPPED unless a table actually needs to be created this way! */
const db = app.get('knex');
db.schema.hasTable('marksTestTable').then(exists => {
if (!exists) {
console.error('table marksTestTable missing!');
/*
db.schema.createTable('shit', table => {
table.increments('id');
table.string('text');
table.timestamp('createdAt');
table.timestamp('updatedAt');
})
*/
.then(() => console.log('Created shit table')) // eslint-disable-line no-console
.catch(e => console.error('Error creating shit table', e)); // eslint-disable-line no-console
}
})
.catch(e => console.error('Error creating shit table', e)); // eslint-disable-line no-console
it should ONLY contain:
module.exports = function (app) {
return [class name];
}
4 – Start the app
DEBUG=knex:query npm start ; ## run the app, optional DEBUG DEBUG=* npm start ; ## run the app, optional DEBUG
5 -Test the app
DONT USE “PUT”, USE “PATCH” INSTEAD!
Postman: Body—->x-www-form-url-urlencoded to POST (create)
POST: http://192.168.123.220:3030/teachers?lastName=Edwards&firstName=Lori (create)
PATCH: http://192.168.123.220:3030/teachers/2/?firstName=Marky (patch)
POST – http://192.168.123.220:3030/tester?columnOne=Column One Value&columnTwo=Column Two Value (add new value)
GET – http://192.168.123.220:3030/tester/1/ ( get by primary id)
GET – http://192.168.123.220:3030/tester/?columnOne=column One Value (find by column value)
GET (find) – be sure “Body—>xx-www-form-urlencode” is blank
GET (get) – be sure “Params” is blank
PATCH – be SURE “Params” is blank, only use “Body—>xx-www-form-urlencode”
## a complicated one!
http://192.168.123.220:3030/tester/
? testerAutoIncr=1
& $select[]=columnTwo
& $select[]=columnOne
& $sort[columnOne]=-1
## will produce:
## select `columnTwo`, `columnOne`, `tester`.`testerAutoIncr` from `tester` where `testerAutoIncr` = ? order by `columnOne`
## https://stackoverflow.com/questions/11889997/how-to-send-an-array-in-url-request/11890080#11890080
## ? col0 = val1 & col1 = val2 & col2 = val3
## will produce:
## WHERE col= ‘val1’ OR col=‘val2’ OR col=‘val3’
### reference: https://dove.feathersjs.com/api/databases/querying.html#select
6 – Create a “before” hook to manipulate the SELECT statement.
feathers “before” hook: [i think that is required by Objection]
./src/hooks/tester.js
// Use this hook to manipulate incoming or outgoing data.
// For more information on hooks see: http://docs.feathersjs.com/api/hooks.html
// eslint-disable-next-line no-unused-vars
module.exports = (options = {}) => {
return async context => {
context.params.query = { // added by mark
…context.params.query, // added by mark
$select: [‘columnTwo’,‘columnOne’], // added by mark
$sort: { ‘columnOne’ : 1 } // added by mark
} // added by mark
return context;
};
};
or: (much better:) https://knexjs.org/guide/query-builder.html
module.exports = (options = {}) => {
return async context => {
const query = context.service.createQuery(context.params) ;
// https://knexjs.org/guide/query-builder.html#knex
query .clear(‘select’) // remove ALL existing columns from queryBuilder
.select({ ‘languageNormsName’ : ‘languageNormsName’ } )
// or just .select(‘languageNormsName’)
.distinct()
.orderBy(‘languageNormsName’)
;
context.params.knex = query ;
return context;
};
};
[i think this is required for knex (not objection]
// https://feathersjs.com/api/databases/knex.html#createquery-params
// https://knexjs.org/guide/query-builder.html#clear
// https://stackoverflow.com/questions/47263583/how-can-i-retrieve-unique-values-from-a-column-with-knex-js
/* old fashioned way to clear select statements, use ` .clear('select') ` instead!
for ( index in query._statements.filter ( val => val['grouping'] === 'columns' ) )
{ query._statements.splice(index,1) // remove the "default" column selection
} ;
*/
==========================================================
#####################npm init —yes ;
################npm install @feathersjs/feathers —save ;
######### ???????? npm install knex —save ;
############npm install feathers-knex —save ;