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 -gfeathersjs/cli ; ### or --global npm install
feathersjs/cli -g ; ### for generating apps (notice g trails…. i think only this one actually works! npm installfeathersjs/cli
4.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 namemodel: 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-datetime
line 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-consoleit 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 ;