R/class_definitions.R

#'
#' @importFrom methods new selectMethod setRefClass is
#' @import DBI
NULL


#' Class ModelDefinition (and methods)
#'
#' @description This class must be used to create the models
#' used by your programs.
#'
#'
#' @section Fields:
#' \describe{
#'
#' \item{\code{table}:}{Object of class \code{"character"}, the name of
#' the table. This field will be used to determine the name of the
#' resulting generated class}
#'
#' \item{\code{fields}:}{Object of class \code{"list"}, a named list.
#' The names are the fields of the table and the values are the SQL type
#' of the field (REAL, BOOLEAN, INTEGER, BLOB, or TEXT)}
#'
#' \item{\code{fk}:}{Object of class \code{"list"}, a simple list.
#' It contains the name of the tables that needs to be references by
#' this table.
#' Mutual references create linkage table.
#' One-way references create an fk field, named table_name_id.
#' }
#'
#' }
#' @export ModelDefinition
#' @exportClass ModelDefinition
#' @examples
#'
#' models <- list(
#'     person=ModelDefinition(
#'         table="person",
#'         fields=list(
#'             name="TEXT",
#'             family_name="TEXT"
#'         ), many=list("adress")
#'         ## One person possibly has multiple adress. Or none...
#'         ## "many" fields defines the creation of a linkage table
#'         ##   (many_to_many or one_to_many).
#'         ## "one" fields defines a fk field enforced by a foreign key
#'         ## restriction (one_to_one)
#'         ## "many" fields mustn't be duplicated. So, "adress" must not
#'         ## reference the "person" table.
#'     ),
#'     adress=ModelDefinition(
#'         table="adress",
#'         fields=list(
#'             number="INTEGER",
#'             street="TEXT"
#'         )
#'     )
#' )
ModelDefinition <- setRefClass(
    "ModelDefinition",
    fields=c(
        table="character",
        fields="list",
        many="list",
        one="list",
        defaults="list"
    )
)

#' Class ORM (and methods)
#'
#' ORM class is the main class of the orm package.
#' This is one of the only class that should be used by programmers
#'
#' @export ORM
#' @exportClass ORM
#'
#' @examples
#'
#' library(RSQLite)
#'
#' models <- list(
#'     person=ModelDefinition(
#'         table="person",
#'         fields=list(
#'             name="TEXT",
#'             family_name="TEXT"
#'         ), many=list("adress")
#'         ## One person possibly has multiple adress. Or none...
#'         ## "many" fields defines the creation of a linkage table
#'         ## (many_to_many or one_to_many).
#'         ## "one" fields defines a fk field enforced by a foreign key
#'         ## restriction (one_to_one)
#'         ## "many" fields mustn't be duplicated. So, "adress" must not
#'         ## reference the "person" table.
#'     ),
#'     adress=ModelDefinition(
#'         table="adress",
#'         fields=list(
#'             number="INTEGER",
#'             street="TEXT"
#'         )
#'     )
#' )
#' DB_PATH <- "person.sqlite"
#' orm <- ORM(connection_params=list(DB_PATH), model_definitions=models)
#'
#' ## like this, we'll see the requests generated by the orm
#' print(orm$create_database())
#' ## the tables has been generated, fks and their restrictions has been
#' ## defined and linked table has been created if necessary
#'
#' ## we've created a person who's name is Alice Smith.
#' ## Alice has been saved into the database.
#' alice <- orm$person(name="Alice", family_name="smith")$save()
#'
#' ## Alice has been successfully added to and loaded from the database.
#' print(orm$person()$load_by(name="Alice"))
#'
#' ## The id is 1, because it's the first person to be inserted into the
#' ## "person" table.
#' ## The orm has generated an "INSERT" query.
#' print(alice$get_id())
#'
#' ## He's a boy, so he's changed his name to "Bob". Suits him better.
#' ## Fields must always be setted with "model$set_field_name(value)".
#' ## otherwise the orm will not see the modifications, and will not save
#' ## them in the database.
#' bob <- alice$set_name("bob")$save()
#'
#' ## still 1. Because the orm did not add new database entry.
#' ## The orm has generated an "UPDATE" query.
#' print(bob$get_id())
#'
#' ## prints an empty list()
#' ## no adress has been assigned to him for the moment.
#' print(bob$get_adress())
#'
#' ## let's give him a home
#' bob$add_adress(
#'     ## the orm sanitizes the user's inputs and prevent sql injections.
#'     orm$adress(number=42, street="Second street ; -- drop table person")
#' )
#' ## The orm detects that the adress object assigned to bob is not saved
#' ## yet in the database.
#' ## So, the orm will register the adress, and then create a link between
#' ## bob and the adress through a linkage table.
#' bob$save()
#'
#'
#' ## now Bob is happy because he has an adress
#' ## prints: list(<adress id: 1> ...) etc.
#' print(adress <- bob$get_adress())
#'
#' ## the street name is still somewat strange...
#' ## let's make it less strange
#' bob$get_adress(
#'     ## we select the adress with a strange name...
#'     street="Second street ; -- drop table person"
#'
#' ## we set a more... usual name. And we save it (the adress).
#' )[[1]]$set_street("Second street")$save()
#' print(bob$get_adress())
#'
#' ## never forget to disconnect when your're finished!
#' orm$disconnect()
#'
#' ## not to forget, there's a little trick:
#' ## this call orm$connect()
#' ## and at the end of the block, it calls orm$disconnect()
#' ## so you never foget to disconnect from the database.
#' orm <- ORM(connection_params=list(DB_PATH), model_definitions=models, connect=FALSE)
#' orm$with_connection({
#'     bob <- orm$person()$load_by(name="bob")$first()
#'     bob$add_adress(
#'         ## he's has a second residence
#'         orm$adress(number=2, street="the squirel's path")
#'     )$save()
#'     print(bob$get_adress())
#'
#'     ## finily he decided to live in his second house, and sold the
#'     ## first one.
#'     print(bob$get_adress(street="Second street"))
#'     bob$remove_adress(bob$get_adress(street="Second street")$first())
#'     bob$save()
#'     print(bob$get_adress())
#'
#' })
## now, you're disconnected from the database.
#' file.remove(DB_PATH)
#'
ORM <- setRefClass(
    "ORM",
    fields=c(
        model_definitions_="list",
        model_objects_="list",
        in_memory="logical",
        connected_="logical",
        connection_parameters_="list",
        connection_="DBIConnection",
        # database_path="character",
        request_pool="list",
        execution_context="list",
        sql="list",
        DELETE_ALL_TABLES="character",
        IF_NO_EXISTS="character",
        CREATE_TABLE_TEMPLATE="character",
        CREATE_LINKAGE_TABLE_TEMPLATE="character",
        SELECT_WHERE_TEMPLATE="character",
        DELETE_WHERE_TEMPLATE="character",
        INSERT_WHERE_TEMPLATE="character",
        UPDATE_WHERE_TEMPLATE="character",
        FK_CONSTRAINT_TEMPLATE="character",
        GROUP_BY_TEMPLATE="character",
        OPERATORS="list",
        LOGICAL_CONNECTORS="list",
        escape_values__must_be_true__="logical",
        dbms__="character",
        SQLITE="character",
        POSTGRESQL="character",
        MARIADB="character",
        MYSQL="character",
        DBMS_PACKAGES="list",
        DBMS_METHODS="list",

        dbms_env="environment"
        # is_connected="function",
        # set_connection_parameters="function",
        # connect="function",
        # disconnect="function",
        # clear_result="function",
        # execute="function",
        # send_query="function",
        # get_query="function",
        # send_statement="function",
        # escape="function"
    )
)

#' Class ModelMeta (and methods)
#'
#' @description This class is the super class of classes generated by
#' the model builder
#'
#'
ModelMeta <- setRefClass(
    "ModelMeta",
    fields=c(
        modified__="list",
        sql_model__="ModelDefinition",
        table__="character",
        orm__="ORM",
        model_name__="character",
        fields__="list",
        loaded__="logical",
        cache_read__="list",
        cache_remove__="list",
        cache_add__="list",
        NOT_CREATED="numeric",
        NOT_RETRIEVED="numeric",
        id="numeric",
        field_converters__="list",
        defaults="list"
    )
)


#' Class ResultSet (and methods)
#' @export ResultSet
#' @exportClass ResultSet
#'
#' @description This class contains a list of ModelMeta instances,
#' extracted from the database.
#'
#' @examples
#'
#' library(RSQLite)
#'
#' models <- list(
#'     person=ModelDefinition(
#'         table="person",
#'         fields=list(
#'             name="TEXT",
#'             family_name="TEXT"
#'         ), many=list("adress")
#'         ## One person possibly has multiple adress. Or none...
#'         ## "many" fields defines the creation of a linkage table
#'         ## (many_to_many or one_to_many).
#'         ## "one" fields defines a fk field enforced by a foreign key
#'         ## restriction (one_to_one)
#'         ## "many" fields mustn't be duplicated. So, "adress" must not
#'         ## reference the "person" table.
#'     ),
#'     adress=ModelDefinition(
#'         table="adress",
#'         fields=list(
#'             number="INTEGER",
#'             street="TEXT"
#'         )
#'     )
#' )
#' DB_PATH <- "person.sqlite"
#' orm <- ORM(connection_params=list(in_memory=TRUE), model_definitions=models)
#'
#' ## like this, we'll see the requests generated by the orm
#' print(orm$create_database())
#' ## the tables has been generated, fks and their restrictions has been
#' ## defined and linked table has been created if necessary
#'
#' ## we've created a person who's name is Alice Smith.
#' ## Alice has been saved into the database.
#' orm$person(name="Alice", family_name="smith")$save()
#' print(orm$person()$load_by(name="Alice"))
ResultSet <- setRefClass(
    "ResultSet",
    fields=c(
        result_set__="list",
        length__="numeric",
        df_built__="logical",
        df_cache__="data.frame"
    )
)



#' Class TableField (and methods)
#'
#' A class that defines a table's field. Translates to 'table'.'field'
#'
#' @export TableField
#' @exportClass TableField
#'
#' @examples
#'
#' library(RSQLite)
#' orm <- ORM(connection_params=list(in_memory=TRUE))
#' print(TableField(orm, "test", "field")$as.request)
TableField <- setRefClass(
    "TableField",
    fields=c(
        table="character",
        field="character"
    )
)

#' Class OperatorClause (and methods)
#'
#' OperatorClause class defines a right and left TableFields and an
#' operator.
#' It translates to 'left'.'field' {{operator}} 'right'.'field'
#'
#' @export OperatorClause
#' @exportClass OperatorClause
#'
#' @examples
#'
#' library(RSQLite)
#' orm <- ORM(connection_params=list(in_memory=TRUE))
#' f1 <- TableField(orm, "test", "field")
#' f2 <- TableField(orm, "test2", "field2")
#' print(OperatorClause(
#'     orm,
#'     left=f1,
#'     right=f2,
#'     operator=orm$OPERATORS$GE
#' )$as.request)
OperatorClause <- setRefClass(
    "OperatorClause",
    fields=c(
        left="TableField",
        right="TableField",
        operator="character"
    )
)


#' Class JoinClause (and methods)
#'
#' JoinClause class defines a join clause between two tables.
#'
#' @export JoinClause
#' @exportClass JoinClause
#'
#' @examples
#'
#' library(RSQLite)
#' orm <- ORM(connection_params=list(in_memory=TRUE))
#' f1 <- TableField(orm, "test", "field")
#' f2 <- TableField(orm, "test2", "field2")
#' op <- OperatorClause(
#'     orm,
#'     left=f1,
#'     right=f2,
#'     operator=orm$OPERATORS$GE
#' )
#' print(JoinClause(orm, table="test", on=op))
JoinClause <- setRefClass(
    "JoinClause",
    fields=c(
        table="character",
        on="OperatorClause",
        as="character",
        kind="character"
    )
)


#' Class WhereClause (and methods)
#'
#' WhereClause class defines a Where clause, that can encapsulate other
#' where clause(s)
#'
#' @export WhereClause
#' @exportClass WhereClause
#'
#' @examples
#'
#' library(RSQLite)
#' orm <- ORM(connection_params=list(in_memory=TRUE))
#'
#' print(WhereClause(
#'     orm,
#'     field=TableField(
#'         orm,
#'         table="linkage_table_name",
#'         field=sprintf("%s_id", "table_1")
#'     ),
#'     operator=orm$OPERATORS$EQ,
#'     value="id_1",
#'     next_connector=orm$LOGICAL_CONNECTORS$AND,
#'     next_clause=WhereClause(
#'         orm,
#'         field=TableField(
#'             orm,
#'             table="linkage_table_name",
#'             field=sprintf("%s_id", "table_2")
#'         ),
#'         operator=orm$OPERATORS$EQ,
#'         value="id_2"
#'     )
#' ))
WhereClause <- setRefClass(
    "WhereClause", fields=c(
        field="TableField",
        operator="character",
        value="character",
        next_connector="character",
        next_clause="character"
    )
)
LainPavot/DBModelR documentation built on Sept. 29, 2021, 11:04 a.m.