rootintootin/rootintootin.d [ Modules ]

[ Top ] [ Modules ]

NAME

    rootintootin.d

FUNCTION

    This file contains the core functionality that is used by
    the server and applications.

rootintootin/base_get_real_url [ Functions ]

[ Top ] [ Functions ]

FUNCTION

    Returns the url

INPUTS

    controller - The controller processing the request.
    url        - The url to redirect to.

EXAMPLE

    ControllerBase controller = new UserController();
    string real_url = base_get_real_url(controller, "/users");

SOURCE

public static string base_get_real_url(ControllerBase controller, string url) {
    // Get the format from the controller
    string format = "";
    if(controller.request.was_format_specified)
        format = "." ~ controller.request.format;

    // Get the url with the real format
    string url_before = before(url, "?");
    string url_after = after(url, "?");
    if(url_after.length > 0)
        url_after = "?" ~ url_after;
    return url_before ~ format ~ url_after;
}

rootintootin/Clause [ Classes ]

[ Top ] [ Classes ]

NAME

    Clause

FUNCTION

    A class used to create SQL clauses for a query.

rootintootin/Clause.this [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    A constructor.

INPUTS

    value       - the string that makes up this part of the SQL clause.

SOURCE

    public this(string value) {
        if(contains(value, ";"))
            throw new Exception("Sql clauses cannot contain ';'.");

        if(contains(value, "--"))
            throw new Exception("Sql clauses cannot contain '--'.");

        if(contains(value, "union"))
            throw new Exception("Sql clauses cannot contain 'union'.");

        _value = value;
    }

    unittest {
        describe("rootintootin#Clause", 
            it("Should not allow the sql injection '--'", function() {
                bool has_thrown = false;
                try {
                    new Clause("--");
                } catch(Exception err) {
                    has_thrown = true;
                    assert(err.msg == "Sql clauses cannot contain '--'.");
                }
                assert(has_thrown);
            }),
            it("Should not allow the sql injection ';'", function() {
                bool has_thrown = false;
                try {
                    new Clause(";");
                } catch(Exception err) {
                    has_thrown = true;
                    assert(err.msg == "Sql clauses cannot contain ';'.");
                }
                assert(has_thrown);
            }),
            it("Should not allow the sql injection 'union'", function() {
                bool has_thrown = false;
                try {
                    new Clause("union");
                } catch(Exception err) {
                    has_thrown = true;
                    assert(err.msg == "Sql clauses cannot contain 'union'.");
                }
                assert(has_thrown);
            })
        );
    }

rootintootin/ControllerBase [ Classes ]

[ Top ] [ Classes ]

NAME

    ControllerBase

FUNCTION

    The base class for controllers.

rootintootin/ControllerBase.flash_error [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Gets the current flash error message.

SOURCE

    public string flash_error() { return this.get_flash("flash_error"); }

rootintootin/ControllerBase.flash_error( string ) [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Sets the current flash error message.

SOURCE

    public void flash_error(string value) { this.set_flash(value, "flash_error"); }

rootintootin/ControllerBase.flash_notice [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Gets the current flash notice message.

SOURCE

    public string flash_notice() { return this.get_flash("flash_notice"); }

rootintootin/ControllerBase.flash_notice(string) [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Sets the current flash notice message.

SOURCE

    public void flash_notice(string value) { this.set_flash(value, "flash_notice"); }

rootintootin/ControllerBase.get_flash [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Gets the flash from the session.
    Just returns "" if the request is null.

SOURCE

    private string get_flash(string name) {
        if(_request && name in _request._sessions) {
            string value = _request._sessions[name];
            _request._sessions.remove(name);
            return value;
        } else {
            return "";
        }
    }

rootintootin/ControllerBase.redirect_to [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Sends a redirect response to the client.

INPUTS

    url        - The url to redirect to.

EXAMPLE

    redirect_to("users.html");

SOURCE

    public void redirect_to(string url) {
        throw new RenderRedirectException(url);
    }

rootintootin/ControllerBase.render_text [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Sends a text response to the client.

INPUTS

    text        - The text to render.
    status      - The response HTTP status code.

EXAMPLE

    render_text("blah", 200);

SOURCE

    public void render_text(string text, ushort status) {
        throw new RenderTextException(text, status);
    }

rootintootin/ControllerBase.render_view [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Sends a view response to the client.

INPUTS

    name        - The name of the view to render.
    status      - The response HTTP status code.

EXAMPLE

    render_view("show", 200);

SOURCE

    public void render_view(string name, ushort status) {
        throw new RenderViewException(name, status);
    }

rootintootin/ControllerBase.request [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Gets the current request.

SOURCE

    public Request request() { return this._request; }

rootintootin/ControllerBase.request( Request ) [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Sets the current request.

SOURCE

    public void request(Request value) { this._request = value; }

rootintootin/ControllerBase.respond_with [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Sends the response to the client based on the state of the model.
    This method is for one model.
    Will automatically use the same format as the request.

INPUTS

    model       - The model to generate the response from.
    view_name   - The name of the view to render.
    status      - The response HTTP status code.
    formats     - An array of formats to render in.

EXAMPLE

    respond_with(_user, "edit", 200, ["html", "json", "xml"]);

SOURCE

    public void respond_with(ModelBase model, string view_name, ushort status, string[] formats) {
        switch(_request.format) {
            case("html"): render_view(view_name, status); break;
            case("json"): render_text(model.to_json(), status); break;
            case("xml"): render_text(model.to_xml(), status); break;
            default: render_text("Unknown format. Try html, json, xml, et cetera.", 404); break;
        }
    }

rootintootin/ControllerBase.respond_with 2 [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Sends the response to the client based on the state of the models.
    This method is for a group of models.
    Will automatically use the same format as the request.

INPUTS

    table_name  - The database table name.
    models      - The models to generate the response from.
    view_name   - The name of the view to render.
    status      - The response HTTP status code.
    formats     - An array of formats to render in.

EXAMPLE

    respond_with("users", _users, "index", 200, ["html", "json", "xml"]);

SOURCE

    public void respond_with(string table_name, ModelBase[] models, string view_name, ushort status, string[] formats) {
        switch(_request.format) {
            case("html"): render_view(view_name, status); break;
            case("json"): render_text(ModelBase.to_json(models), status); break;
            case("xml"): render_text(ModelBase.to_xml(models, table_name), status); break;
            default: render_text("Unknown format. Try html, json, xml, et cetera.", 404); break;
        }
    }

rootintootin/ControllerBase.respond_with_redirect [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Sends a redirect response to the client for the model.
    Will automatically use the same format as the request.

INPUTS

    models      - The models to generate the response from.
    url         - The name of the view to render.
    status      - The response HTTP status code.
    formats     - An array of formats to render in.

EXAMPLE

    respond_with_redirect(_user, "/users/" ~ to_s(_user.id), 200, ["html"]);

SOURCE

    public void respond_with_redirect(ModelBase model, string url, ushort status, string[] formats) {
        string real_url = base_get_real_url(this, url);
        switch(_request.format) {
            case("html"): redirect_to(real_url); break;
            case("json"): render_text(model.to_json(), status); break;
            case("xml"): render_text(model.to_xml(), status); break;
            default: render_text("Unknown format. Try html, json, xml, et cetera.", 404); break;
        }
    }

rootintootin/ControllerBase.respond_with_redirect 2 [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Sends a redirect response to the client.
    Will automatically use the same format as the request.

INPUTS

    url         - The name of the view to render.
    status      - The response HTTP status code.
    formats     - An array of formats to render in.

EXAMPLE

    respond_with_redirect("/users", 200, ["html", "json", "xml"]);

SOURCE

    public void respond_with_redirect(string url, ushort status, string[] formats) {
        string real_url = base_get_real_url(this, url);
        switch(_request.format) {
            case("html"): redirect_to(real_url); break;
            case("json"): render_text("", status); break;
            case("xml"): render_text("", status); break;
            default: render_text("Unknown format. Try html, json, xml, et cetera.", 404); break;
        }
    }

rootintootin/ControllerBase.set_flash [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Sets the flash into the session.
    Just returns if the request is null.

SOURCE

    private void set_flash(string value, string name) {
        if(!_request) return;
        _request._sessions[name] = value;
    }

rootintootin/ControllerBase.use_layout [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Returns true if it will use the default layout when rendering.

SOURCE

    public bool use_layout() { return _use_layout; }

rootintootin/group_by [ Functions ]

[ Top ] [ Functions ]

FUNCTION

    Returns a clause that holds the 'group by' part of the SQL query.

INPUTS

    field_name     - the name of the field to group by.

SOURCE

Clause group_by(string field_name) {
    // Make sure the field is not null or blank
    if(field_name is null || trim(field_name) == "") {
        throw new Exception("The field name cannot be blank or null.");
    }

    return new Clause("GROUP BY " ~ field_name);
}

unittest {
    describe("rootintootin#group_by", 
        it("Should create an SQL group by clause", function() {
            string clause = group_by("name")._value;
            assert(clause == "GROUP BY name");
        }),
        it("Should throw if the field is null", function() {
            bool has_thrown = false;
            try {
                string clause = group_by(null)._value;
            } catch(Exception err) {
                has_thrown = true;
                assert(err.msg == "The field name cannot be blank or null.");
            }
            assert(has_thrown);
        }),
        it("Should throw if the field is blank", function() {
            bool has_thrown = false;
            try {
                string clause = group_by(" ")._value;
            } catch(Exception err) {
                has_thrown = true;
                assert(err.msg == "The field name cannot be blank or null.");
            }
            assert(has_thrown);
        })
    );
}

rootintootin/limit [ Functions ]

[ Top ] [ Functions ]

FUNCTION

    Returns a clause that holds the 'limit' part of the SQL query.

INPUTS

    value     - the max number of rows to return.

SOURCE

Clause limit(ulong value) {
    // Make sure the value is not zero
    if(value == 0) {
        throw new Exception("The value must be greater than zero.");
    }

    return new Clause("LIMIT " ~ to_s(value));
}

unittest {
    describe("rootintootin#limit", 
        it("Should create an SQL limit clause", function() {
            string clause = limit(2)._value;
            assert(clause == "LIMIT 2");
        }),
        it("Should throw if the value is 0", function() {
            bool has_thrown = false;
            try {
                string clause = limit(0)._value;
            } catch(Exception err) {
                has_thrown = true;
                assert(err.msg == "The value must be greater than zero.");
            }
            assert(has_thrown);
        })
    );
}

rootintootin/ModelArrayMixin [ Classes ]

[ Top ] [ Classes ]

NAME

    ModelArrayMixin

FUNCTION

    This template mixin is used to create classes that hold arrays of models
     of a specific type. Because we can't know the type before hand, and we 
    don't want to use the generic ModelBase type, we create a template. 
    Typically this is all generated for you.

EXAMPLE

  // The strongly typed Pets class is used instead of Pet[].
  public class Pets {
      mixin ModelArrayMixin!(PersonBase, PetBase);
  }
  
  // The pet model class in your application
  public class Pet : PetBase {
  }

  // The person model class in your application
  public class Person : PersonBase {
      public Pets pets;

      public this() {
          this.pets = new Pets([]);
      }
  }

  // The generated base model that was created from the database schema.
  public class PetBase : ModelBase {
      mixin ModelBaseMixin!(Pet, "pet", "pets");
      protected static string[] _field_names;
      protected static string[] _unique_field_names;

      public string name;
      public string email;
      protected PersonBase _person = null;

      public void parent(PersonBase value) {
          _person = value;
      }
      public PersonBase parent() {
          return _person;
      }

      public void set_field_by_name(string field_name, string value, bool must_check_database_first = true) {
      }
      public string get_field_by_name(string field_name) {
          return null;
      }
  }

  // The generated base model that was created from the database schema.
  public class PersonBase : ModelBase {
      mixin ModelBaseMixin!(Person, "person", "people");
      protected static string[] _field_names;
      protected static string[] _unique_field_names;

      public void set_field_by_name(string field_name, string value, bool must_check_database_first = true) {
      }
      public string get_field_by_name(string field_name) {
          return null;
      }
  }

  // Now we can create pets and add them to persons.
  auto person = new Person();
  person.pets ~= new Pet();

rootintootin/ModelArrayMixin.length [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Returns the length of the list of models.

SOURCE

    public size_t length() {
        return _models.length;
    }

rootintootin/ModelArrayMixin.opCatAssign [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Adds a model to the list of models.

INPUTS

    model    - A model object to add.

SOURCE

    public void opCatAssign(ModelClass model) {
        model.parent = _parent;
        _models ~= model;
    }

rootintootin/ModelArrayMixin.this [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    A constructor.

INPUTS

    models    - An array of models to initialize the object.

SOURCE

    public this(ModelClass[] models) {
        _models = models;
    }

rootintootin/ModelBase [ Classes ]

[ Top ] [ Classes ]

NAME

    ModelBase

FUNCTION

    This class is the base of all the model classes.

rootintootin/ModelBase.errors [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Returns the list of errors that were set in the 
    ModelBase.validate method.

SOURCE

    public string[] errors() {
        return this._errors;
    }

rootintootin/ModelBase.id [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Returns the model's database id. Will be zero if it has not
    been saved. See ModelBaseMixin.is_saved.

SOURCE

    public ulong id() {
        return _id;
    }

rootintootin/ModelBase.is_valid [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    This methhod is called in ModelBase.is_valid. By default
    it does nothing. But you can override it i your models to
    do custom validation.

SOURCE

    public bool is_valid() {
        this.validate();
        return this._errors.length == 0;
    }

rootintootin/ModelBase.to_json [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Returns the model converted to json.
    This method should be overridden by the inheriting class.

SOURCE

    public string to_json() {
        return null;
    }

rootintootin/ModelBase.to_json 2 [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Returns an array of models converted to json.

INPUTS

    models    - An array of models.

SOURCE

    public static string to_json(ModelBase[] models) {
        string[] retval;
        foreach(ModelBase model ; models) {
            retval ~= model.to_json();
        }
        return "[" ~ join(retval, ", ") ~ "]";
    }

rootintootin/ModelBase.to_xml [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Returns the model converted to xml.
    This method should be overridden by the inheriting class.

SOURCE

    public string to_xml() {
        return null;
    }

rootintootin/ModelBase.to_xml 2 [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Returns an array of models converted to xml.

INPUTS

    models    - An array of models.

SOURCE

    public static string to_xml(ModelBase[] models, string table_name) {
        string[] retval;
        foreach(ModelBase model ; models) {
            retval ~= model.to_xml();
        }

        string name = table_name;

        return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" ~ 
                "<" ~ name ~ " type=\"array\">" ~ 
                join(retval, "") ~ 
                "</" ~ name ~ ">";
    }

rootintootin/ModelBase.validate [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    This method is called in ModelBase.is_valid. By default
    it does nothing. But you can override it in your models to
    do validation. 

    To set an error here, add a string to the _errors instance variable.

EXAMPLE

    // Use one of the validate functions to do validation.
    public class User : UserBase {
        public void validate() {
            _errors = [];
            validates_presence_of(["name", "email"]);
        }
    }
 
    // Or do the validation your own way.
    public class User : UserBase {
        public void validate() {
            string field = this.get_field_by_name("name");
            if(field == "Tim")
                _errors = ["I don't think so Tim."];
        }
    }

SOURCE

    public void validate() {
    }

rootintootin/ModelBaseMixin [ Classes ]

[ Top ] [ Classes ]

NAME

    ModelBaseMixin

FUNCTION

    A template mixin that adds common functionality to models.

rootintootin/ModelBaseMixin.destroy [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Deletes the model in the database. It also will add a 
    foreign key error if a constraint is broken.

    Returns true on success, or false on failure.

SOURCE

    bool destroy() {
        // Create the delete query
        string query = "";
        query ~= "delete from " ~ typeof(this)._table_name;
        query ~= " where id=" ~ to_s(this._id) ~ ";";

        // Run the query
        db.QueryResult result;
        Db.delete_query(query, result);

        if(result == db.QueryResult.success) {
            return true;
        } else if(result == db.QueryResult.foreign_key_constraint_error) {
            this._errors ~= "Failed to delete because of foreign key constraints.";
            return false;
        }

        return false;
    }

rootintootin/ModelBaseMixin.ensure_was_pulled_from_database [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    This method should be called in the start of each field property 
    method. It ensures that the object has gotten its initial values 
    from the database if it should have. Or it throws a ModelException.

SOURCE

    private void ensure_was_pulled_from_database() {
        // Just return if is was already pulled
        if(_was_pulled_from_database == true)
            return;

        if(_id < 1)
            throw new ModelException(_model_name ~ "The id has not been set.");

        // Get the model from the database and copy all its fields to this model
        T model = T.find(_id);

        foreach(string field_name; model._unique_field_names) {
            this.set_field_by_name(field_name, model.get_field_by_name(field_name), false);
        }
        _was_pulled_from_database = true;
    }

rootintootin/ModelBaseMixin.field_names_as_comma_string [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Returns all the model's field names in a comma separated string.

SOURCE

    static string field_names_as_comma_string() {
        return join(_field_names, ", ");
    }

rootintootin/ModelBaseMixin.find [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Returns a single model that matches the id, or throws if not found.

INPUTS

    id    - The database id of the object to find.

SOURCE

    static T find(ulong id) {
        T model = find_by_id(id);
        if(model is null) {
            throw new ModelException("No '" ~ _model_name ~ "' with the id '" ~ to_s(id) ~ "' was found.");
        } else {
            return model;
        }
    }

rootintootin/ModelBaseMixin.find_all [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Returns all the models.

INPUTS

    clauses  - The clauses to use to create the SQL select query.
               Such as where, order by, and limit.

NOTES

    For more info on variadic arguments see:
    http://digitalmars.com/d/1.0/function.html#variadic

SOURCE

    static T[] find_all(Clause[] clauses ...) {
        string[] retval;
        foreach(clause; clauses)
            retval ~= clause._value;

        // Create the query and run it
        T[] all = [];
        string query = "select " ~ field_names_as_comma_string ~ " from " ~ _table_name;
        if(retval.length)
            query ~= " " ~ join(retval, " ");
        query ~= ";";
        int row_len, col_len;
        char*** result = Db.query_with_result(query, row_len, col_len);

        // Copy all the fields into each model
        T model = null;
        for(int i=0; i<row_len; i++) {
            model = new T();
            model._was_pulled_from_database = false;
            for(int j=0; j<col_len; j++) {
                model.set_field_by_name(_field_names[j], tango.stdc.stringz.fromStringz(result[i][j]), false);
            }
            model._was_pulled_from_database = true;
            model.after_this();
            all ~= model;
        }

        Db.free_query_with_result(result, row_len, col_len);

        return all;
    }

    unittest {
        describe("ModelBaseMixin.find_all", 
            it("Should find everything with no parameters", function() {
                assert(false);
            }),
            it("Should find one model with the id", function() {
                assert(false);
            })
        );
    }

rootintootin/ModelBaseMixin.find_by_id [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Returns a single model that matches the id, or null if not found.

INPUTS

    id          - The database id of the object to find.

SOURCE

    static T find_by_id(ulong id) {
        // Create the query and run it
        string query = "select " ~ field_names_as_comma_string ~ " from " ~ T._table_name;
        query ~= " where id=" ~ to_s(id) ~ ";";
        int row_len, col_len;
        char*** result = Db.query_with_result(query, row_len, col_len);

        // Just return null if there was none found
        if(row_len == 0) {
            Db.free_query_with_result(result, row_len, col_len);
            return null;
        }

        // Copy all the fields into the model
        T model = new T();
        model._was_pulled_from_database = false;
        for(int i=0; i<col_len; i++) {
            model.set_field_by_name(_field_names[i], tango.stdc.stringz.fromStringz(result[0][i]), false);
        }
        model._was_pulled_from_database = true;
        model.after_this();

        Db.free_query_with_result(result, row_len, col_len);

        return model;
    }

rootintootin/ModelBaseMixin.find_first [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Returns the first model found, or null if not found.

SOURCE

    static T find_first(Clause[] clauses ...) {
        T[] models = find_all(clauses ~ limit(1));
        if(models.length > 0) {
            return models[0];
        } else {
            return null;
        }
    }

rootintootin/ModelBaseMixin.is_saved [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Returns true if the id is greater than zero.

SOURCE

    bool is_saved() {
        return _id > 0;
    }

rootintootin/ModelBaseMixin.save [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Saves the model to the database. It will automatically determine if 
    it needs to use an insert or update query. It checks the model to see
    if it is valid. It also will add a unique field error if a uniqueness
    constraint is broken.

    Returns true on success, or false on failure.

SOURCE

    bool save() {
        // Return false if the validation failed
        if(this.is_valid() == false)
            return false;

        string query = "";
        db.QueryResult result;

        // If there is no id, use an insert query
        if(!this.is_saved) {
            query ~= "insert into " ~ typeof(this)._table_name ~ "(" ~ unique_field_names_as_comma_string ~ ")";
            query ~= " values(";
            query ~= this.unique_fields_as_comma_string();
            query ~= ");";

            // Run the query, and save the id
            _id = Db.insert_query_with_result_id(query, result);
        } else {
        // If there is an id, use an update query
            query ~= "update " ~ typeof(this)._table_name ~ " set ";
            uint counter = 0;
            foreach(string field_name ; typeof(this)._unique_field_names) {
                counter++;
                query ~= field_name ~ "='" ~ this.get_field_by_name(field_name) ~ "'";
                if(counter < typeof(this)._unique_field_names.length) {
                    query ~= ", ";
                }
            }
            query ~= " where id=" ~ to_s(this._id) ~ ";";

            // Run the query
            Db.update_query(query, result);
        }

        if(result == db.QueryResult.success) {
            return true;
        } else if(result == db.QueryResult.not_unique_error) {
            char[] message = Db.get_error_message();
            char[] field = before(after(message, "for key 'uc_"), "'");
            this._errors ~= "The " ~ field ~ " is already used.";
            return false;
        }

        return false;
    }

rootintootin/ModelBaseMixin.unique_field_names_as_comma_string [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Returns all the model's unique field names in a comma separated 
    string.

SOURCE

    static string unique_field_names_as_comma_string() {
        return join(_unique_field_names, ", ");
    }

rootintootin/ModelBaseMixin.unique_fields_as_comma_string [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Returns all the model's unique fields in a comma separated 
    string.

SOURCE

    string unique_fields_as_comma_string() {
        string[] fields;
        foreach(string field_name; _unique_field_names) {
            fields ~= "'" ~ this.get_field_by_name(field_name) ~ "'";
        }

        return join(fields, ", ");
    }

rootintootin/ModelBaseMixin.validates_presence_of [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    If the field is null or white space, a message is added to 
    the _errors array.
    EG: "The name cannot be blank."

INPUTS

    field_name   - The name of the field to validates.

SOURCE

    void validates_presence_of(string field_name) {
        char[] field = this.get_field_by_name(field_name);

        if(field == null || trim(field).length == 0) {
            _errors ~= "The " ~ field_name ~ " cannot be blank.";
        }
    }

rootintootin/ModelBaseMixin.validates_presence_of 2 [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    Does validates_presence_of for an array of fields.

INPUTS

    field_names   - The names of the fields to validates.

SOURCE

    void validates_presence_of(string[] field_names) {
        foreach(string field_name; field_names) {
            validates_presence_of(field_name);
        }
    }

rootintootin/ModelException [ Classes ]

[ Top ] [ Classes ]

NAME

    ModelException

FUNCTION

    This exception is thrown when there is an error relating to models.

rootintootin/ModelException.this [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    A constructor.

INPUTS

    message    - The message to throw.

SOURCE

    public this(string message) {
        super(message);
    }

rootintootin/order_by [ Functions ]

[ Top ] [ Functions ]

FUNCTION

    Returns a clause that holds the 'order by' part of the SQL query.

INPUTS

    field_name     - the name of the field to sort by.

SOURCE

Clause order_by(string field_name) {
    // Make sure the field is not null or blank
    if(field_name is null || trim(field_name) == "") {
        throw new Exception("The field name cannot be blank or null.");
    }

    return new Clause("ORDER BY " ~ field_name);
}

unittest {
    describe("rootintootin#order_by", 
        it("Should create an SQL order by clause", function() {
            string clause = order_by("name")._value;
            assert(clause == "ORDER BY name");
        }),
        it("Should throw if the field is null", function() {
            bool has_thrown = false;
            try {
                string clause = order_by(null)._value;
            } catch(Exception err) {
                has_thrown = true;
                assert(err.msg == "The field name cannot be blank or null.");
            }
            assert(has_thrown);
        }),
        it("Should throw if the field is blank", function() {
            bool has_thrown = false;
            try {
                string clause = order_by(" ")._value;
            } catch(Exception err) {
                has_thrown = true;
                assert(err.msg == "The field name cannot be blank or null.");
            }
            assert(has_thrown);
        })
    );
}

rootintootin/RenderNoActionException [ Classes ]

[ Top ] [ Classes ]

NAME

    RenderNoActionException

FUNCTION

    This exception is thrown when there is no action to route to.

rootintootin/RenderNoActionException.this [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    A constructor.

SOURCE

    public this() {
        super("");
    }

rootintootin/RenderNoControllerException [ Classes ]

[ Top ] [ Classes ]

NAME

    RenderNoControllerException

FUNCTION

    This exception is thrown when there is no controller to route to.

rootintootin/RenderNoControllerException.this [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    A constructor.

INPUTS

    controllers    - An array that holds the names of all the known controllers.

SOURCE

    public this(string[] controllers) {
        super("");
        _controllers = controllers;
    }

rootintootin/RenderRedirectException [ Classes ]

[ Top ] [ Classes ]

NAME

    RenderRedirectException

FUNCTION

    This exception is thrown when an action wants redirect to another url.

rootintootin/RenderRedirectException.this [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    A constructor.

INPUTS

    url                - the url to redirect to.

SOURCE

    public this(string url) {
        super("");
        _url = url;
    }

rootintootin/RenderTextException [ Classes ]

[ Top ] [ Classes ]

NAME

    RenderTextException

FUNCTION

    This exception is thrown when an action wants to render text directly.

rootintootin/RenderTextException.this [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    A constructor.

INPUTS

    text                - the text to render.
    status              - the http status.

SOURCE

    public this(string text, ushort status) {
        super("");
        _text = text;
        _status = status;
    }

rootintootin/RenderViewException [ Classes ]

[ Top ] [ Classes ]

NAME

    RenderViewException

FUNCTION

    This exception is thrown when an action wants to render a view.

rootintootin/RenderViewException.this [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    A constructor.

INPUTS

    name                - the name of the view to render.
    status              - the http status.

SOURCE

    public this(string name, ushort status) {
        super("");
        _name = name;
        _status = status;
    }

rootintootin/RunnerBase [ Classes ]

[ Top ] [ Classes ]

NAME

    RunnerBase

FUNCTION

    A base class for the generated application class.

rootintootin/RunnerBase.this [ Methods ]

[ Top ] [ Methods ]

FUNCTION

    A constructor.

INPUTS

    request             - the request that was routed to this runner.
    controller_name     - the name of the controller to route to.
    action_name         - the name of the action to route to.
    id                  - the id of the resource to route to. Use null for no id.
    events_to_trigger   - a list of events to trigger for long poll.

NOTES

    id will be removed because it is duplicating the id in the 
    request.params, and not even used.
    events_to_trigger will be removed soon.

SOURCE

    public string run_action(Request request, string controller_name, string action_name, string id, out string[] events_to_trigger) {
        return null;
    }

rootintootin/where [ Functions ]

[ Top ] [ Functions ]

FUNCTION

    Returns a clause that holds the 'where' part of the SQL query.

INPUTS

    query     - the conditional part of the SQL query.
    values    - the values to put into the query.

EXAMPLE

    Clause clause = where("name = ? and age = ?", "tim", 57);

SOURCE

Clause where(T ...)(string query, T values) {
    string[] retval;

    // Make sure the query is not null or blank
    if(trim(query) == "") {
        throw new Exception("The query cannot be blank.");
    }

    // Make sure the number of params and arguments match
    size_t question_count = count(query, "?");
    if(question_count != values.length) {
        throw new Exception("There were " ~ to_s(question_count) ~ " parameter(s) expected, but " ~ to_s(values.length) ~ " parameter(s) provided.");
    }

    size_t i = 0;
    string[] parts = split(query, "?");
    foreach(value; values) {
        retval ~= parts[i++];
        // FIXME: Sanitize this as it is untrusted.
        retval ~= "'" ~ to_s(value) ~ "'";
    }
    retval ~= parts[i++];
    return new Clause("WHERE " ~ join(retval, ""));
}

unittest {
    describe("rootintootin#where", 
        it("Should create an SQL where clause", function() {
            string clause = where("name = ? and age = ?", "tim", 56)._value;
            assert(clause == "WHERE name = 'tim' and age = '56'");
        }),
        it("Should throw if there are too few arguments", function() {
            bool has_thrown = false;
            try {
                string clause = where("name = ? and age = ?", "tim")._value;
            } catch(Exception err) {
                has_thrown = true;
                assert(err.msg == "There were 2 parameter(s) expected, but 1 parameter(s) provided.");
            }
            assert(has_thrown);
        }),
        it("Should throw if there are too many arguments", function() {
            bool has_thrown = false;
            try {
                string clause = where("name = ? and age = ?", "tim", "bob", "frank")._value;
            } catch(Exception err) {
                has_thrown = true;
                assert(err.msg == "There were 2 parameter(s) expected, but 3 parameter(s) provided.");
            }
            assert(has_thrown);
        }),
        it("Should throw if the query is blank", function() {
            bool has_thrown = false;
            try {
                string clause = where(" ")._value;
            } catch(Exception err) {
                has_thrown = true;
                assert(err.msg == "The query cannot be blank.");
            }
            assert(has_thrown);
        })
    );
}