-
Notifications
You must be signed in to change notification settings - Fork 8
Architecture
Turbinado is composed of:
- Controllers receive requests, retrieve Models and put together data to be used by the Views.
- Models are mappings of the database tables to Haskell datatypes.
- Views produce XML, HTML, etc.
- Components are modular, reusable Controllers and Views which are designed to be used within other Views.
Turbinado uses a large Environment datatype to hold Server, Application and Request-specific data. The Environment is composed of a large number of fields to hold DatabaseConnection, Request, Response, etc. Each of the fields in the Environment is held within a Maybe datatype in order to allow the Environment to be partially constructed. For example, when the Server starts up, it constructs a partially completed Environment which contains only the fields which are used by the Server. As requests come in, the Server hands to the appropriate Controller an Environment which is specialized for that Controller’s Request. As the Controllers and Views operate, they fill in the Response field of the Environment.
A partial listing of fields in the Environment is:
- CodeStore: cached, compiled versions of Models, Views, Controllers and Components.
- Database: the connection to the database.
- Request: the parsed HTTP Request.
- Response: the HTTP Response generated by the Controller or View.
- Settings: settings which are derived from the current request.
- ViewData: data which is sent from the Controller to the View for display.
The Environment also includes an AppEnvironment field for a application specific data type.
The Environment is accessible to both Controllers and Views because each is an instance of the HasEnvironment class and implements [get|set]Environment.
At startup, the server:
- Binds to the specified port;
- Builds the route table;
- Builds the MIME type dictionary;
- Initializes the Logger and CodeStore;
- Runs any application specific setup filters.
- (1) Waits for a request.
- After receiving a request, a WorkerThread is created (if the WorkerPool is empty) and handed the partially constructed Environment and the request connection.
- Goto (1)
When the connection is handed to the WorkerThread, the WorkerThread:
- Continues building the Environment;
- Receives and parses the inbound Request;
- Tries to retrieve static content (e.g. an image) to satisfy the Request;
- Runs any application specific customPreFilters;
- Retrieves and runs the Controller specified by the Routes;
- Retrieves and runs the Layout (which should insertDefaultView);
- Runs any application specific customPostFilters;
- Sends back to the client the Response contained within the Environment.
Turbinado provides a code generator to generate an Object Relational Mapping (http://en.wikipedia.org/wiki/Object-relational_mapping) from a database to a set of Models (Haskell datatypes and database functions).
Following the example set by .netTiers, each model is composed of multiple files (using the Page model as an example):
- Page.hs: the editable portion of the Page Model, which imports the various pieces of the Page Model. See http://github.com/alsonkemp/turbinado-website/tree/master/App/Models/Page.hs.
- Bases/Page*.hs: the automatically generated “base” code which represents the database table “page” and its functions and relations. These file should not be edited. See Bases/PageType.hs, Bases/PageFunctions.hs and Bases/PageRelations.hs.
The ORM automates basic CRUD functionality, provides standard Haskell datatypes for database tables and uses the database’s foreign keys to determine table-table relationships. As an example ofhow to retrieve all Pages order by “title” where the “_id” starts with “prefix”:
pages <- findAllWhereOrderBy "_id like ?" [toSql $ prefix ++ "%"] "title"
A Page is defined by the ORM as:
data Page = Page { _id :: String, authorId :: Maybe Int64, content :: String, title :: String, version :: Int64} deriving (Eq, Show)