I have the following Objection.js models:
Appointment:
'use strict'
const { Model } = require('objection')
class Appointment extends Model {
// Table name is the only required property.
static get tableName() {
return 'appointment'
}
static get idColumn() {
return 'appointmentId';
}
// This object defines the relations to other models.
static get relationMappings() {
// One way to prevent circular references
// is to require the model classes here.
const AppointmentType = require('./AppointmentType')
return {
appointmentType: {
relation: Model.BelongsToOneRelation,
// The related model. This can be either a Model subclass constructor or an
// absolute file path to a module that exports one.
modelClass: AppointmentType,
join: {
from: 'appointment.appointmentTypeId',
to: 'appointmentType.appointmentTypeId'
}
},
}
}
}
module.exports = Appointment
AppointmentType:
'use strict'
const { Model } = require('objection')
class AppointmentType extends Model {
// Table name is the only required property.
static get tableName() {
return 'appointmentType'
}
static get idColumn() {
return 'appointmentTypeId';
}
}
module.exports = AppointmentType
Using the following query:
await Appointment.query().withGraphJoined({appointmentType: true})
I get the following results:
{
"appointmentId": 1,
"duration": 12,
"appointmentTypeId": 2,
"appointmentType": {
"appointmentTypeId": 2,
"appointmentTypeName": "Type Name"
}
....
}
In most cases, the default return from objection is useful but in this one not so much. Would it be possible to return something like:
{
"appointmentId": 1,
"duration": 12,
"appointmentTypeName": "Type Name" // or "typeName": "Type Name"
...
}
I think this is not possible yet. I ll just parse the object again, or use it just like that. I'll leave this here in case someone has found a nice way
you can select the columns you want and they'll return as one flat object
const appointments = await Appointment.query().select('appointmentId','duration', 'appointmentTypeName').leftJoinRelated('appointmentType');
but this is vulnerable to duplicates only if an appointment has many types. be careful
Related
I've got a question: If I have a constructor in a class:
module.exports = class ClassA{
constructor(stuffA, stuffB) {
this.stuffA = stuffA;
this.stuffB = stuffB;
}
NonStaticMethod() {
console.log(this);
}
static StaticMethod(stuffA, stuffB) {
const element = new ClassA(stuffA, stuffB);
console.log(element)
element.NonStaticMethod();
});
}
};
So, the NonStaticMethod prints other information for the object than the StaticMethod. So two questions:
Can I call the constructor from a static method from the same class?
What should be the correct way of calling the non-static method from the static method?
The following code prints "true", so in NonStaticMethod this.stuffA rely correctly on value defined in constructor:
class ClassA{
constructor(stuffA, stuffB) {
this.stuffA = stuffA;
this.stuffB = stuffB;
}
NonStaticMethod() {
console.log(this.stuffA === "a");
}
static StaticMethod(stuffA, stuffB) {
const element = new ClassA(stuffA, stuffB);
element.NonStaticMethod();
};
}
ClassA.StaticMethod("a","b")
I have 2 files,
extendableError.js
class ExtendableError extends Error {
constructor(message) {
super(message)
this.name = this.constructor.name
this.message = message
if (typeof Error.captureStackTrace === 'function') {
Error.captureStackTrace(this, this.constructor)
} else {
this.stack = new Error(message).stack
}
}
}
module.exports = ExtendableError
duplicatedError.js
const ExtendableError = require('./ExtendableError')
class DuplicatedError extends ExtendableError {
constructor(message) {
super(message)
}
}
module.exports = DuplicatedError
Below is my testing code,
const DuplicatedError = require('./duplicatedError');
const ExtendableError = require('./ExtendableError');
const ExtendableError1 = require('./extendableError');
try{
throw new DuplicatedError('hahah');
}catch(err){
console.log(err instanceof ExtendableError); // true
console.log(err instanceof ExtendableError1); // false
}
The test is on my mac book, why is that happen? Only the 1st charater was uppercase has different results. i don't understand.
Macs are based on BSD UNIX, so the file system is case sensitive.
As a side note, it’s common to not use camecase for file names, eg:
var extendableError = require(‘./extendable-error’)
Firstly, for compatibility reason, macOS chose a case-insensitive file system. But it doesn't mean you have to bear it, Disk Utility can be used to reformat the partition to case-sensitive mode. If You do that, node.js will report error to you because of the wrong module name you are trying to require.
Then, let's talk about your test result. The key issue is which one you require in duplicatedError.js, if you change it a little bit:
//change the required name to lowercase extendableError
const ExtendableError = require('./extendableError')
class DuplicatedError extends ExtendableError {
constructor(message) {
super(message)
}
}
module.exports = DuplicatedError
The test result will be:
false
true
You can even try to modify duplicatedError.js like below:
//change the required name to extENDableError
const ExtendableError = require('./extENDableError')
class DuplicatedError extends ExtendableError {
constructor(message) {
super(message)
}
}
module.exports = DuplicatedError
The result shall be
false
false
So i think it's not about module caching, you have two things to be clear here:
macOX is case-insensitive file system by default
even you have only one file extendableError.js, but you require twice with different names, like: require(./extendableError), require(./ExtendableError), require(./extENDableError), trey will be treated as three modules.
I've tried to search for instance caching and singletons on Google and StackOverflow without success, seeing only posts about module.exports, if you know a post that answers this question, feel free to reference it. Thank you!
I have an application that needs to work on a set of objects that rarely change, and hence need to be cached for performance optimisation.
Here is a toy example where a single property is set directly.
When I call the application, I export an object that will contain the set of cached objects in assets_cached.js:
const Assets = {};
module.exports.Assets = Assets;
In another module of the application I have an ES6 class:
const _ = require('lodash')
const { Assets } = require('./assets_cached')
class Asset {
constructor(id, some_property) {
if (id in Assets) {
// Update instance data with cached properties
_.assign(this, Assets_cached[id]);
} else {
// If it's not cached, create a new object
this.id = id;
this.some_property = some_property;
// Cache this object
Assets_cached[id] = this;
}
}
getProperty() {
return this.some_property;
}
setProperty(value) {
this.some_property = value;
// Is there a way of avoiding having to do this double assignment?
Assets_cached[id].some_property = value;
}
}
module.exports = Asset;
How may I avoid having to set the some_property twice (in the current instance and the cache, while ensuring that other instances are updated in parallel)?
Ideally I'd like to do something like:
if (id in Assets) {
this = Assets.cached[id]
}
inside the constructor, but this is not possible.
What's the most elegant and correct way of making this work?
Ideally I'd like to do something like this = Assets.cached[id] inside the constructor
The magic keyword here is return. You can just return an arbitrary object from the constructor and it will be used instead of this.
constructor(id, some_property) {
if (id in Assets) {
// use cached instance instead of creating a new one
return Assets_cached[id];
} else {
this.id = id;
this.some_property = some_property;
// Cache this object
Assets_cached[id] = this;
}
}
Here is the approach to the comment that was made some half an hour ago ...
const { Assets_cached } = require('./assets_cached');
// const { AssetStore } = require('./assetstore');
class Asset {
constructor(id, some_property) { // clean/lean constructor.
this.id = id;
this.some_property = some_property;
}
getProperty() {
return this.some_property;
}
setProperty(value) {
this.some_property = value;
}
}
function isAsset(type) {
// poor man's approach ... change to something more feasible.
return (type instanceof Asset);
}
function createAsset(id, some_property) { // factory that also handles caching.
var
asset = Assets_cached[id];
// asset = AssetStore.get(id);
if (!(asset && isAsset(asset))) {
asset = Assets_cached[id] = (new Asset(id, some_property));
// AssetStore.put(id, (asset = new Asset(id, some_property)));
}
return asset;
}
module.exports = {
create : createAsset,
isAsset : isAsset
};
Note
One also should consider providing a minimal API to Assets_cached, something like put/set, get and delete instead of Assets_cached being an entirely exposed, plain key-value store.
I see they use this kind of code to call restful URLs.
Let's say we have /users/{userId}/tasks to create task for a user.
To call this they create another class instead of calling request directly as shown below:
MyAPP.prototype.users = function (userId) {
return {
tasks: function (taskId) {
return this.usersTasks(userId, taskId);
}
}
}
MyAPP.prototype.usersTasks = function (userId, taskId) {
return {
create: function (task, cb) {
make request POST call
}
}
}
Then we can call this as myapp.users('123').tasks().create(task, cb);
What is this kind of coding called and is there any way to automatically generate the code from the URL structure itself?
That is a way of making classes, but I suggest you look into ES6 classes
Defining a class :
class MyAPP {
//:called when created
constructor(name) {
this.name = name;
console.log("[created] MyAPP :",name);
//(a in memory database stored in MyAPP : for example purpose)
this.DB = {'user000':{'tasks':{'task000':'do pizza'},{'task001':'code some magik'}}}
}
//: Get specific taskID for userID
getTask(userID, taskID) {
console.log("[get task]",taskID,"[from user]",userID)
return (this.DB[userID][taskID])
}
//: Get all tasks for userID
allTasks(userID) {
console.log("[get all tasks from user]",userID)
return (this.DB[userID].tasks)
}
//: Create a taskID with taskContent for userID
newTask(userID, taskID, taskContent) {
this.DB[userID].tasks[taskID] = taskContent
}
}
Creating a MyAPP instance :
var myapp = new MyAPP('Pizza API'); //creates a MyAPP with a name
And then (maybe I got your question wrong) using express you would make a server and listen for requests (GET, POST, PUT, ...)
app.get("/APIv1/:userID/:actionID", function(req, res) {
switch(req.params.actionID){
case 'all':
res.send(myapp.allTasks(req.params.userID));
break
default :
res.send("The "+myapp.name+" doesn't support that (yet)")
break
}
});
I defined a object A in which i need to store some objects.
How can i assign the query result to the property of the object.
Here is my example code.
function A(Job){
this.job = Job;
this.location ={};
models.locations.findOne({
where:{
job_id:this.job.id
}
}).then(function(location){
//what should i do here to store it in A.locaiton
}
}
Hold the reference of this into a that property (or any other name you prefer) and then use that.location. For example:
function A(Job) {
var that = this;
that.job = Job;
that.location = {};
models.locations.findOne({
where: {
job_id: this.job.id
}
}).then(function (location) {
that.location = location;
});
}
Hope this helps.