Model
. The Model
is probably what most people will be using the majority of the time. The Model
is basically an wrapper entity around a table. So 1 table will likely equal to 1 model. A users
table will have a User
model and a articles
table will have an Article
model.Model
is that its just a shell around the QueryBuilder
class. The majority of the time you call something on the Model
it's actually just building a query builder class immediately and passing the rest of the call off. This is important to understand:.get()
which is basically an executionary command:get
, the query builder will pass everything you built up (1 select, 2 where statements) and pass those into a Grammar
class. The Grammar
class is responsible for looping through the 3 statements and compiling them into a SQL query that will run. So the Grammar
class will compile a query that looks like this:user.name
we will get the name of the user. Think of it as loading the dictionary into the class to be used later during accession and setting.QueryBuilder
class) and then passed to the connection class to make the database call and return the result. Again the grammar class is only responsible for compiling the query into a string. Simply taking attributes passed to it and looping through them and compiling them into a query.(18,)
. This helps protect against SQL injection attacks. All queries passed to the connection class should be the qmark query. Compiling SQL is really for debugging purposes while developing. Passing straight SQL into the connection class could leave queries open to SQL injection.'?'
and then adding the value to the bindings. The grammar class knows it should be qmarked by passing the qmark boolean variable throughout the grammar class.BaseGrammar
class. Child classes (like MySQLGrammar
and PostgresGrammar
, etc) really just contain the formatting of the sql strings.{joins}
, {group_by}
etc:LIMIT X
and Microsoft is TOP X
. We can accomplish this by specifying the differences in their own method. Remember these are all in the subclasses of the grammar class. Mysql is in MySQLGrammar
and Microsoft is in MSSQLGrammar
BaseGrammar
class (which calls the supported grammar class we built above).select_format
methodsprocess_
or _compile_
so let's explain what those are.BaseGrammar
class which is the parent grammar class and really the engine behind compiling the queries for all grammars.BaseGrammar
class is responsible for doing the actual compiling in the above section. So this class really just has a bunch of classes like process_wheres
, process_selects
etc. These are more supporting methods that help process the sql strings for the _compile_
methods._compile_
. These are for responsable for compiling the actual respective queries. The heart of this class really lies in the _compile_select
, _compile_create
, _compile_update
, _compile_delete
methods._compile
methods in place:_compile
methods but they are mainly just for supporting the main compiling of the select, create or alter statements.QueryBuilder
class immediately.QueryBuilder
. Most methods on the model simply call the QueryBuilder
so we will focus on the QueryBuilder
.cls
) and an object instance. Be sure to read the section below.Model
class (the base class that all of your User
and Article
models will inherit). What this does is essentially creates a middleware between first calling methods. Since its really hard to do everything while handling different class instantances and class classes it's easier to catch the call and turn it into an instance before moving on.Model.py
class we have a meta class inherited (you'll notice if you look at the file) which actually does a bit of magic and actually instanitates the class before any methods are called. This is similiar to any normal Python hook you can tie into like __getattr__
.cls
and self
much easier. Although there are special use cases where we need to handle cls directly which is why you will see some @classmethod
decorators on some model methods.User.where(..)
it will call the where on the User class. Since theres actually no where
method on the model class it will hook into the __getattr__
on the model class. From there we catch a bunch of different methods located in the __passthrough__
attribute on the model and pass that right off to the query builder. This is important to understand.QueryBuilder
class is responsible for building up the query so it will have a whole bunch of attributes on it that will eventually be passed off to the grammar class and compiled to SQL. That SQL will then be passed to the connection class and will do the database call to return the result.QueryBuilder
class is really the meat and potatoes of the ORM and really needs to be perfect and will have the most features and will take the most time to build out and get right.where
on the model it will pass the info to the query builder and return this QueryBuilder
class..get()
it will return a collection of results.first()
it will return a single model:QueryBuilder
to build up a query and then later execute it.BaseGrammar
class, since we use things like isinstance checks and attribute conditionals. You will not be using these directly when developing applications. These classes are:QueryExpression
- Used for compiling of where statementsHavingExpression
- Used for the compiling of Having statementsJoinExpression
- Used for the compiling of Join statementsUpdateExpression
- Used for the compiling of Update statements.SubSelectExpression
- Used for compiling sub selects. Sub selects can be placed inside where statements to make complex where statements more powerfulSubGroupExpression
- Used to be passed into a callable to be executed on later. This is useful again for sub selects but just a layer of abstraction for callables_compile_wheres
, _compile_update
and other methods are ran on the grammar class, these just make it more simple to fetch the needed data and are not too generic to make difficult use cases challenging to code for..get()
or .first()
, all the wheres, selects, group_by's etc are passed off to the correct grammar class like MySQLGrammar
which will then compile down to a SQL string.QueryBuilder
object when returning the response is also responsible for hydrating your models if a model is passed in. If no model is passed into the initializer then it will just return a dictionary or list. Hydrating is really just a fancy word for filling dummy models with data. We really don't want to work with dictionaries in our project so we take the dictionary response and shove it into a Model and return the model. Now we have a class much more useful than a simple dictionary..hydrate()
method which creates a new instance and hydrates the instance with the dictionary.__get__
magic method which is called whenever an attribute is accessed. We can then hijack this hook and return whatever we need. In this case, a fully hydrated model or a query builder.BaseRelationship
class which really just contains all the magic we need for the actual decorator to work.BelongsTo
relationship (which is imported as belongs_to
in the __init__.py
file so this is where the name change comes from in the decorator) which has a simple apply_query
method with does the query needed to return the connection using the models QueryBuilder
. Here we have foreign
and owner
variables. foreign
is the relationship class (In this case, Profile
) and owner
is the current model (in this case User
).where
and limit
. Instead of have things in the format of:Blueprint
class which really is the same thing as the relationship between Model
and QueryBuilder
. The Schema class is also responsible for setting either the create
or alter
modes. This is set if you either use Schema.create('users')
or Schema.table('users')
respectively.Blueprint
class is similiar to the QueryBuilder
class because both simply build up a bunch of columns to to act on. One is just used for fetching data and the other is used for changing or creating tables.Table
class. If we are updating a table then we will be setting attributes on the TableDiff
class.SQLitePlatform
, MySQLPlatform
, etc. These class have a compile_create_sql and compile_alter_sql methods. These methods take a single table class. The same table class the blueprint class built up.blueprint.to_sql()
which will either build a create
or alter
query depending on what was originally set by the Schema
class before.