>> So, with that being said,
just sort of a simple introduction to prototypes
and the JavaScript object model.
We're not going to shift gears a little bit to talk
about more JavaScript on the server and the Bookshelf Library
and the connection Knex Library.
So, you can actually just--
if you search for Bookshelf.js it should be pretty easy
to find, should be first result, and Bookshelf
as David mentioned just gives a lot of structure
around JavaScript objects and working with them relationally
in relational databases.
So, a lot of similar features who's actually heavily inspired
by Laravel's ORM as well as the Backbone.js,
which is a front end MVC library which allows you
to structure your code, similar to what I was showing
with the examples of the prototypes where you can--
instead of just arbitrarily throwing classes
on your views here and there.
It gives you models and collections of those models
which are supposed to act as sort of a single point of truth
about the data for your application.
And then you listen to, as those models changes, you say, OK,
re-render this template here and this one over here
and not just add class here, add class there and sort of pick
on selectors and make the spiderweb of jQuery code.
It gives more of a class-based structure to individual pieces,
but a important component of that library is the models
which have a similar structure to what Bookshelf models do.
So, if you're familiar with the Bookshelf you're pretty also
pretty familiar with Backbone.js models,
and I would recommend taking a look at this.
So, some of the major features
that it gives you are just the ability to set data on an object
to call fetch, which returns an individual record
from the database, create relations as similar
to what you dealt within in Laravel
where you can say a patient set a record method
and say this has won record
where the record object is table name health records.
Let's see.
Has many-- it belongs to--
just stuff that you're pretty similar--
pretty familiar with already, but in JavaScript.
And under the hood, for Bookshelf,
it uses a query builder called Knex.js.
So, that's Knex, knexjs.org.
It's a reference to the toy if anyone's ever played with this.
But it allows you to-- in a similar fashion, to jQuery,
you just sort of create a chain of different methods
that you're calling on your database row so you can--
you started out by saying Knex and the table name.
So, for example, Knex users, select which columns you'd like,
where, and have different where conditionals and you can have
AND where, OR where, where between, where not,
you now, down the line.
You can specify different joins between your database tables
which Bookshelf uses internally to set up sort of magic
around the hasOne, hasMany, belongsTo, belongsToMany.
And so the combination
of the two let you do pretty much what you'd be used
to in framework like Laravel in terms
of functionality working with databases.
So, let's go ahead and take a look at a simple example
for an Express app which makes use of these models
and collections of Bookshelf jazz [phonetic].
So, I've set up just a simple application here.
I stripped out some of the stuff that was initializing express
and move that into an init directory which I created.
One of the nice things about working with Express as supposed
to Laravel is that there's really not much enforced
on you conventionalized.
So you can create directories--
it doesn't really give you a whole lot to work off of.
You've got just sort of some basic settings and then--
but it doesn't care where you put them.
You don't have to have controller's directory.
You don't need to have a models directory, a config directory.
You can sort of create those as your project needs
and set things up the way that make sense most to you.
So instead of having all this express boilerplate
in the main app.js I just said app equals require init/express.
And so in the init,
the initializing folder I just have Express here,
and this requires Express, calls the setup function, calls the--
sets up the view engine, JSON parser, all that.
So now, let's continue down.
So I'm requiring the course instructor meeting
and requirements models.
So these are in a folder that I just decided to name models.
It doesn't have to be that way however it makes sense,
but models is just pretty common so I would recommend it.
But-- So let's go for the course.
I think I'm using-- yeah, and the examples
down here are all based around the course model.
So let's just take a look at that.
So, now, just of the first line of this model,
I'm already requiring something else.
So if you'll notice in node you should be requiring
or you're going to end up requiring a whole bunch
of different files that are located
in different places in your application.
And the relative paths to wherever you are
in your current application,
unless it is a top level already defined as in you install it
with MPM like Bookshelf or Knex or Express or something,
those are not relative.
Yes? Zoom in more?
OK. OK. So, you're going to end up requiring a whole bunch
of just different files in your code, which is good and bad.
In a good way you know where things are and it's not sort
of magic as to what's going on under the hood,
which can really be confusing
when you have a very heavy Java--
or very heavy framework like Laravel, which sort of says,
we're going to take care of this so you don't have
to require everything but you have
to know how everything works in order to use it.
Where as in this case, it's very straightforward as to
where everything is, they're just ends
up being a little more typing.
Just as in the side I like to use, there's a plugin
if you use a blind text
where you can instal the node modules helper and you can start
to type like Instructor and it creates the relative path
to where you are to that code file, kind of useful.
So, the course model is requiring base here
and then base intern requires init/bookshelf
and then the Bookshelf, it requires the top level Bookshelf
and then initializes it with the initialized Knex instance,
which sets the client name
and the connection settings for the database.
So I'm just using a simple instance of Sequel Pro which--
of MySQL, I'm accessing it with Sequel Pro and it has just sort
of a similar database setup as we had
in the first sample application with the course catalogue.
So, I set my connection settings here,
and these are all documented on the Knex.js project page
as to how to setup these connections.
So, I now have my base model.
And as I mentioned with the prototype change,
so that can actually be kind of a lot to--
adds a lot of boilerplate to your code so convention
that has been adapted by Backbone.js
and now Bookshelf.js is to add this extend method
as a static property on your JavaScript objects,
which gives it a sort of almost class-based inheritance nature
where if you call extend you can set up any
of the prototype methods that you'd like here
and then you can-- any extra static methods
that you might want, you can just set them yourselves
out here so I can extend it with-- so if for example,
multiple models needed display name and this get name.
So, here, I'm saying the display name for model
by default is whatever its name property is otherwise return
no name.
And now on every model that is a--
that extends this base model, I now have a display name method
on the prototype chain somewhere.
And if I want to overwrite it I can just set it-- set what--
getname would be here.
And it allows you to mimic classical inheritance
in JavaScript, which can be nice particular for things
that are lend themselves being class based like object models.
So let's jump back into the application code.
So I've got a route for just slash, just for my index
and then slash courses.
And both of these are calling the renderCourses method.
So again, functions are first class and can be passed
as arguments to methods.
So, in this app.get, I'm calling--
I'm passing renderCourses as the argument.
And render-- or functions can be setup like var--
as I was doing earlier var renderCourses equals function
or they can be just function renderCourses.
It doesn't make too much of a difference.
You can actually have what are called name function
expressions, which are var renderCourses equals
function renderCourses.
And, the reason to want to have name functions particularly
in node is that it gives you a cleaner--
more readable stack trace.
So if you have a whole bunch
of anonymous functions it will say--
when you have an error in your code you'll--
you won't know which function it's calling you'd have to look
at the code number and the line number
and it's sometimes easier just to visually parse
when you actually have names
for the functions themselves on the server side.
So this renderCourses, let's call node apps--
so I'm listening on Core 3000 [phonetic].
And so all this is doing right here is just getting all the
courses from the database.
I'm not even limiting it so it's doing a huge number
of rows it's returning.
And in order to do this,
on the course model there is a static property
called collection.
And so I just call it-- I said create a new collection
for this course, and then fetch it,
and then return the courses collection here in the promise.
So internally, David in-- the last half taught a little bit
about promises and promises are used very heavily in both Knex
and Bookshelf because it lends the--
it gives you the ability to have a bunch
of different asynchronous calls and sort of join then together
or fetch something, and then
with that call another asynchronous database call
and return that value and then jump to the next then
and next then and then have a catch at the very end to sort
of mimic asynchronous try catch behavior with asynchronous code,
because you're seeing it now
but it's even harder once you start to deal with it.
Asynchronous code is just everywhere
in server side JavaScript and really to a much greater degree
than you're used to if you've done JavaScript
on the client side.
So that really, really helped you out there.
But just to show you the debugger statement
that I was talking about in the node inspector tools,
I'm going to go ahead and throw a debugger line here
in the renderCourses function and see where that leads me
when I-- so node inspector can be installed
by doing NPM Install with a G flag,
which means Global Node Inspector.
And it'll fetch it for NMP and install it globally
for your applications so you can just call it
from the command line.
I've already installed it so I'll go ahead and--
actually it might have to wait it'll just take,
take two seconds.
And what node inspector again allows you
to do is have this headless version of the debugger console
that you're used to when working on the client side and be able
to stop, just add specified points in your code.
Stop execution and take a look at what's going on,
which would have really come in handy if the feature
like that were available
when debugging your PHP code I'm sure.
So let's just take a look at that.
So I can just call node inspector
and it'll say visit this URL port 5858 to start debugging,
that's just the default for how it starts up.
So, I've now got-- there's nothing going on here
because I need to start.
So node impasse [phonetic] the debug flag and then app.js.
So it says debugger listening on port 5858,
Express server listening on 3000.
So we're good to go.
Let me just refresh this.
And now I can see the app.js code that I was just looking at
but here in the console.
So now, if I try to run this, you can see it, it stops.
It's just waiting because its entire code execution is now
stopped on this debugger line that I've put in there.
And I can now server--
[ Inaudible Remark ]
Oh, yeah. What is the keyword shortcut to zoom screen?
Oh there is.
Got it. OK.
[ Pause ]
Oh, it's not looking [phonetic] that.
So, courses is really big
because I'm not doing a limit clause or anything,
it's just fetching the entire database of courses
which are a lot of them.
And so-- which is object
that actually might crash the note inspector instance.
It's-- OK.
Let me do a limit and then we can take a look
when it's not fetching hundreds of courses.
So, kill the server and inspector
and I'll do course collection query limit 20.
So, in Bookshelf, unlike in Laravel
where you can just call limit directly or call any
of these SQL methods that you use
to directly on the ORM instance.
Anytime that you're using just SQL method which is provided
in Knex, you have to call the query to sort
of tap into the query chain.
And this can be invoked with either a function,
so you can say, function this limit 10 or you call it
by specifying which method you'd like to call
on the Knex instance and then which value.
So we're going to do limit 20 and then set.
We actually don't need debugger here
because we can just set breakpoints
and that makes it easier.
All right.
So, let's set a breakpoint right here and try to load it.
Wrong line.
Right here.
[ Pause ]
OK. So it stopped again.
So now, courses is an object with length of 20
and we can see all the different models that it's fetched
from the database right here so I've got a model object
which has, inside the attributes property
on the Object are all the things that it's found in the database.
Any events that have been registered
so you can register different events,
for example when the model is being deleted
or when it's being fetched,
you can set different properties or modify things.
There's a lot of different hooks and these are all documented
in the Bookshelf.js documentation that allow you
to do sort of anything that you really want to do
with your models and collections.
You can-- they're meant to be really customizable
and really easy for you to adapt them
to the needs of your application.
But just looking through here,
I can see what the different courses are available.
And in this case, I actually didn't fetch
with any other data other than just the courses themselves.
But in similar fashion to the Eloquent ORM you can set
up relations, so the course belongs to many instructor.
So, if I go ahead and stop the application,
jump to this fetch call, you can specify different options
that you'd like to pass along to it.
And one of them is the ability to load related code
by specifying withRelated instructors then courses.
So let's go back and fresh this here and stop again.
So now, the courses object, same number of models,
but now each model has a relations hash
which has the instructors that it's related to.
So this course for example
which is course 082 has two related instructor models.
And you can already see how much easier this is to sort
of visually work with than when you're dealing with stuff
that you sort of change the code and then try it again in PHP.
The fact that you can just stop execution entirely
and evaluate what's here and the-- in the console, the--
zoom out, courses is, you know,
what that the local scope variables are available
and this is currently the global object because as you saw it,
unless you call with a specific context, it's not going
to have something relevant here.
And then, the-- let me show a few more examples
implementing promises.
So instead of doing this withRelated instructors here I'm
going to go ahead and move this to fetch and then the courses,
I'm going to return courses.load instructors.
And then-- then you call then.
[ Pause ]
So then at this point, the courses should be loaded
with the instructors, which is asynchronous action.
But because we're returning it from a promise, the next value
for then is whatever this asynchronous call returns
which in this case load is a method in Bookshelf
that actually returns the collection itself.
So it's loading the instructors on there
and then you can specify-- if it's just one property,
you can specify this as string, otherwise,
you can do instructors and requirements
as a method-- sorry, as an array.
And then if you'd like to get really fancy and constrain any
of these given fetches, you can specify it as a hash
with instructors and then what you like to limit the query on.
So, I'd like to load all instructors on courses where--
so QB for query builder where status is active.
And you can get really fancy with any
of the related queries you'd like to build.
But, just for now, we're going to stick to just instructors
and we're returning that value
so then the next then should have all the courses loaded
up properly.
And if there was an error at any step in that chain,
it would jump down to the catch.
So let's go ahead and run that.
So each time-- unlike in PHP, one downside is the
"because node" is a long running process, you actually need
to stop the node process as you update your code,
because the version that it's running in the run time is,
the version of the code that was loaded
when started not what you have sort
of updated your code with since then.
OK. We'll set a breakpoint here, here and refresh.
[ Pause ]
Oh, I actually didn't refresh this page either
so it was on the old process.
So you refresh both this and the node inspector.
So now we see courses.
If we just take sample of one of these models,
we can see that the relations object is empty, but now--
and the reason that you need to set breakpoints is, well,
I mentioned that you can jump into the stack trace
and see you know, where it's going in the app.
So now I can see what's happening in the load method,
which I've defined on the collections.
It sort of "Eager loads relationships onto an already".
And you can step through and see line by line
where this stuff is going which is great.
If you have something that's broken in your code,
it's throwing some error and you're like, I really want
to see where this is going.
But as soon as you run into something asynchronous, the--
it goes to the next tick of the event loop
and you'll lose your-- you lose your place
in the node inspector.
So you need to say, "OK, once I lose this,
it needs to stop now at this line again."
'Cause if I kept hitting down, down the stack,
it would have eventually just gone away had I not set this
line 22 blue break line.
So now, if I look at courses here,
it should on relation instructors
and then have the instructors attach them.
So, you can see that I returned a promise from the first promise
and then you can continually do that down the line.
So the different promise, promise libraries,
I used one called Bluebird which is really useful.
It adds a lot of nice of this for changing asynchronous--
changing call back base code into stuff
that works well with promises.
But-- sorry [inaudible] what I was going to say it there.
Let's take a look though at the--
so let's say that there was a problem when fetching something.
So I have this other route to find called course ID.
So let's do course 2.
Can I get-- JSON course.
And this does [inaudible].
[ Pause ]
I smell something wrong here.
Not on 3000, I was on the Chrome inspector tab.
OK. So let's go to course-- JSON course 1.
And this returns just in JSON format, the course loaded
up with some instructors.
But the example I wanted to give here is that,
I am doing JSON course ID.
And in the fetch parameters, I'm specifying require true,
which is an option that's documented in Bookshelf
where it's saying that, "If, I try and find this course
and it's not there, then throw an error."
And that should be caught by the catch block down here.
So let's go ahead and jump back into the node inspector and try
and break this and see what we got.
So let's set a break here on the JSON course.
All right.
I'll go to JSON course and I would just put in some--
[ Pause ]
It can be a little tricky sometimes when you're trying
to manage which one has been refreshed
and which have not-- let's see.
So it's calling error empty response.
[ Pause ]
Let's throw a debugger in here.
Because of how node actually optimizes
for the JavaScript runtime to be so fast on the server,
sometimes the node debugger has some errors when you try
and set breakpoints dynamically and you actually do need
to use a debugger and not the line-by-line.
So let's see if this gets us what we want.
So I set, app.get json course id,
and I've set my debugger there
in the catch statement at the bottom.
Fetch require true, it should-- all right, there we go, broke.
So, now I can see that it stopped
at this final catch block because the withRelated--
or because the require true specified and there is no course
with ID of this large number through an exception
which is now Emessage.
And each error in JavaScript has a stack property
that comes along with it.
So it's often useful to for example,
console log out e.stack.
And I can actually see when I hit an error.
So I get error empty response, that's the message
that was sent via Bookshelf.
But now, I can take a look at the, at call stack and see
that in Bookshelf dialects SQL model 83,
this empty response error was thrown.
And this is where I mentioned, it's dot anonymous
because it's an anonymous function.
If that were a name function you would have better ideas
to which function actually through without having to go
into the model.js code.
Although it's meant to be fairly, fairly readable,
so I can see that online.
What did they tell me was line 83.
So, if options.require and the response didn't exist,
it now throws a new empty response error.
So you can see pretty straightforward how that works.
And internally in Bookshelf,
there're just a whole bunch of use of promises.
So you can specify Promise.method
with the Bluebird library which keeps the correct context
of this while returning a promise.
And so I have-- I'm binding the value of this similar
to what I'd mentioned earlier, but using promises
and then I can-- is new.
It can be asynchronous or not if I want.
And then I do some other things which may
or may not be asynchronous and then sorts of jumps down this.
So Promise.all is a helper that a lot of popular libraries have
where you can have an array of potentially may
or may not be promises.
And once all those are completed, you return that
and then it jumps to the next line
and you can see how it really flattens out the pyramid
that you get, the callback hell as its known
if you're doing everything with callbacks line by line.
There are ways to get around that but promises are one
of the best ways in my opinion
to really keep your code clean and easy to read.
So that is just a short introduction to JavaScript
and to Bookshelf and Knex in general.
And, if there's any questions, I know it's a ton of material
to sort of try and cover especially since the languages,
unlike most that you are familiar with so I just wanted
to make it so that at least if you're having problems
with your code, you can sort of jump in--
that's what I like to do, is sort of jump into the libraries
that I'm using and see how things are structured.
There's one that I had mentioned earlier called Backbone.js
and actually it's [inaudible] on the client side
to help give model view controller structure
to your code.
But it actually has annotated documentation source
which allows you to sort of see.
It's really well documented, what's going on,
how it's augmenting the Ajax functionality
or the event functionality or the models and collections sort
of explaining what's going on in the process.
And if you understand the basics of JavaScript
like the prototypal inheritance and just how functions are used
as both objects and values and classes and everything.
It makes it a lot easier to understand what's going
on potentially in the libraries that you're using
and debugger code and be able to not be banging your head
against the wall because you don't understand how the
different pieces are working, so.