Refactor persistence library.

Added a persistence speficication cluster and implementation cluser,
Implementation MySQL.
Added test cases for mysql implementation.
This commit is contained in:
jvelilla
2014-09-15 23:27:11 -03:00
parent 46362731f0
commit 3a699b23a0
32 changed files with 196 additions and 8 deletions

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="persistence_mysql" uuid="DC757CBD-D8C4-44D6-A07F-C1148D8D233E" library_target="persistence_mysql">
<target name="persistence_mysql">
<root all_classes="true"/>
<option warning="true" void_safety="all">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<setting name="console_application" value="true"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="crypto" location="$ISE_LIBRARY\unstable\library\text\encryption\crypto\crypto-safe.ecf"/>
<library name="encoder" location="$ISE_LIBRARY\contrib\library\web\framework\ewf\text\encoder\encoder-safe.ecf"/>
<library name="json" location="$ISE_LIBRARY\contrib\library\text\parser\json\library\json-safe.ecf" readonly="false"/>
<library name="layout" location="..\..\..\layout\layout.ecf"/>
<library name="logging" location="$ISE_LIBRARY\library\runtime\logging\logging-safe.ecf"/>
<library name="mysql" location="$ISE_LIBRARY\library\store\dbms\rdbms\mysql\mysql-safe.ecf"/>
<library name="store" location="$ISE_LIBRARY\library\store\store-safe.ecf" readonly="false"/>
<library name="thread" location="$ISE_LIBRARY\library\thread\thread-safe.ecf"/>
<library name="time" location="$ISE_LIBRARY\library\time\time-safe.ecf"/>
<cluster name="persistence_mysql" location=".\src\" recursive="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
</cluster>
<cluster name="interface" location="..\..\interface\" recursive="true"/>
</target>
</system>

View File

@@ -0,0 +1 @@
Added Stored Procedures

View File

@@ -0,0 +1,105 @@
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';
-- -----------------------------------------------------
-- Schema cms
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `cms` DEFAULT CHARACTER SET latin1 ;
USE `cms` ;
-- -----------------------------------------------------
-- Table `cms`.`nodes`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `cms`.`nodes` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`publication_date` DATE NOT NULL,
`creation_date` DATE NOT NULL,
`modification_date` DATE NOT NULL,
`title` VARCHAR(255) NOT NULL,
`summary` TEXT NOT NULL,
`content` MEDIUMTEXT NOT NULL,
PRIMARY KEY (`id`))
ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `cms`.`roles`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `cms`.`roles` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`role` VARCHAR(100) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `role` (`role` ASC))
ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `cms`.`users`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `cms`.`users` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`username` VARCHAR(100) NOT NULL,
`password` VARCHAR(100) NOT NULL,
`salt` VARCHAR(100) NOT NULL,
`email` VARCHAR(250) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE INDEX `username` (`username` ASC))
ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `cms`.`users_nodes`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `cms`.`users_nodes` (
`users_id` INT(10) UNSIGNED NOT NULL,
`nodes_id` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`users_id`, `nodes_id`),
INDEX `fk_users_has_nodes_nodes1_idx` (`nodes_id` ASC),
INDEX `fk_users_has_nodes_users_idx` (`users_id` ASC),
CONSTRAINT `fk_users_has_nodes_nodes1`
FOREIGN KEY (`nodes_id`)
REFERENCES `cms`.`nodes` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_users_has_nodes_users`
FOREIGN KEY (`users_id`)
REFERENCES `cms`.`users` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;
-- -----------------------------------------------------
-- Table `cms`.`users_roles`
-- -----------------------------------------------------
CREATE TABLE IF NOT EXISTS `cms`.`users_roles` (
`users_id` INT(10) UNSIGNED NOT NULL,
`roles_id` INT(10) UNSIGNED NOT NULL,
PRIMARY KEY (`users_id`, `roles_id`),
INDEX `fk_users_has_roles_roles1_idx` (`roles_id` ASC),
INDEX `fk_users_has_roles_users1_idx` (`users_id` ASC),
CONSTRAINT `fk_users_has_roles_roles1`
FOREIGN KEY (`roles_id`)
REFERENCES `cms`.`roles` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION,
CONSTRAINT `fk_users_has_roles_users1`
FOREIGN KEY (`users_id`)
REFERENCES `cms`.`users` (`id`)
ON DELETE NO ACTION
ON UPDATE NO ACTION)
ENGINE = InnoDB
DEFAULT CHARACTER SET = latin1;
SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

View File

@@ -0,0 +1,14 @@
DROP TABLE IF EXISTS nodes;
CREATE TABLE nodes
(
id smallint unsigned NOT NULL auto_increment,
publication_date date NOT NULL, #When the article was published
creation_date date NOT NULL, #When the article was created
modification_date date NOT NULL, #When the article was updated
title varchar(255) NOT NULL, #Full title of the article
summary text NOT NULL, #A short summary of the articule
content mediumtext NOT NULL, #The HTML content of the article
PRIMARY KEY (ID)
);

View File

@@ -0,0 +1,217 @@
note
description: "Summary description for {CMS_STORAGE_MYSQL}."
date: "$Date$"
revision: "$Revision$"
class
CMS_STORAGE_MYSQL
inherit
CMS_STORAGE
REFACTORING_HELPER
create
make
feature {NONE} -- Initialization
make (a_connection: DATABASE_CONNECTION)
--
require
is_connected: a_connection.is_connected
do
log.write_information (generator+".make_with_database is database connected? "+ a_connection.is_connected.out )
create node_provider.make (a_connection)
create user_provider.make (a_connection)
post_node_provider_execution
post_user_provider_execution
end
feature -- Access: user
has_user: BOOLEAN
-- Has any user?
do
to_implement("Not implemented!!!")
end
all_users: LIST [CMS_USER]
do
to_implement("Not implemented!!!")
create {ARRAYED_LIST[CMS_USER]} Result.make (0)
end
user_by_id (a_id: like {CMS_USER}.id): detachable CMS_USER
do
Result := user_provider.user (a_id)
post_user_provider_execution
end
user_by_name (a_name: like {CMS_USER}.name): detachable CMS_USER
do
Result := user_provider.user_by_name (a_name)
post_user_provider_execution
end
user_by_email (a_email: like {CMS_USER}.email): detachable CMS_USER
do
Result := user_provider.user_by_email (a_email)
post_user_provider_execution
end
is_valid_credential (l_auth_login, l_auth_password: READABLE_STRING_32): BOOLEAN
local
l_security: SECURITY_PROVIDER
do
if attached user_provider.user_salt (l_auth_login) as l_hash then
if attached user_provider.user_by_name (l_auth_login) as l_user then
create l_security
if
attached l_user.password as l_password and then
l_security.password_hash (l_auth_password, l_hash).is_case_insensitive_equal (l_password)
then
Result := True
else
log.write_information (generator + ".login_valid User: wrong username or password" )
end
else
log.write_information (generator + ".login_valid User:" + l_auth_login + "does not exist" )
end
end
post_user_provider_execution
end
feature -- Change: user
save_user (a_user: CMS_USER)
-- Add a new user `a_user'.
do
if
attached a_user.password as l_password and then
attached a_user.email as l_email
then
user_provider.new_user (a_user.name, l_password, l_email)
else
-- set error
end
end
feature -- Access: node
nodes: LIST[CMS_NODE]
-- List of nodes.
do
create {ARRAYED_LIST[CMS_NODE]} Result.make (0)
across node_provider.nodes as c loop
Result.force (c.item)
end
post_node_provider_execution
end
recent_nodes (a_lower: INTEGER; a_count: INTEGER): LIST [CMS_NODE]
-- List of the `a_count' most recent nodes, starting from `a_lower'.
do
create {ARRAYED_LIST[CMS_NODE]} Result.make (0)
across node_provider.recent_nodes (a_lower,a_count) as c loop
Result.force (c.item)
end
post_node_provider_execution
end
node (a_id: INTEGER_64): detachable CMS_NODE
--
do
Result := node_provider.node (a_id)
post_node_provider_execution
end
feature -- Node
save_node (a_node: CMS_NODE)
-- Add a new node
do
node_provider.new_node (a_node)
post_node_provider_execution
end
delete_node (a_id: INTEGER_64)
do
node_provider.delete_node (a_id)
post_node_provider_execution
end
update_node (a_node: CMS_NODE)
do
node_provider.update_node (a_node)
post_node_provider_execution
end
update_node_title (a_id: INTEGER_64; a_title: READABLE_STRING_32)
do
node_provider.update_node_title (a_id, a_title)
post_node_provider_execution
end
update_node_summary (a_id: INTEGER_64; a_summary: READABLE_STRING_32)
do
node_provider.update_node_summary (a_id, a_summary)
post_node_provider_execution
end
update_node_content (a_id: INTEGER_64; a_content: READABLE_STRING_32)
do
node_provider.update_node_content (a_id, a_content)
post_node_provider_execution
end
feature -- User
new_user (a_user: CMS_USER)
-- Add a new user `a_user'.
do
if
attached a_user.password as l_password and then
attached a_user.email as l_email
then
user_provider.new_user (a_user.name, l_password, l_email)
else
-- set error
end
end
feature {NONE} -- Post process
post_node_provider_execution
do
if node_provider.successful then
set_successful
else
if attached node_provider.last_error then
set_last_error_from_handler (node_provider.last_error)
end
end
end
post_user_provider_execution
do
if user_provider.successful then
set_successful
else
if attached user_provider.last_error then
set_last_error_from_handler (user_provider.last_error)
end
end
end
node_provider: NODE_DATA_PROVIDER
-- Node Data provider.
user_provider: USER_DATA_PROVIDER
-- User Data provider.
end

View File

@@ -0,0 +1,132 @@
note
description: "Stored procedures paramters names"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
class
DATA_PARAMETERS_NAMES
feature -- Access
Contactid_param: STRING = "ContactID"
Username_param: STRING = "Username"
Submitter_username_param: STRING = "SubmitterUsername"
Responsibleid_param: STRING = "ResponsibleID"
Email_param: STRING = "Email"
Synopsis_param: STRING = "Synopsis"
Openonly_param: STRING = "OpenOnly"
Number_param: STRING = "Number"
Categoryid_param: STRING = "CategoryID"
Category_synopsis_param: STRING = "CategorySynopsis"
Statusid_param: STRING = "StatusID"
Private_param: STRING = "Private"
Priorityid_param: STRING = "PriorityID"
Severityid_param: STRING = "SeverityID"
Searchtext_param: STRING = "SearchText"
Searchsynopsis_param: STRING = "SearchSynopsis"
Searchdescription_param: STRING = "SearchDescription"
Reportid_param: STRING = "ReportID"
Interactionid_param: STRING = "InteractionID"
Attachmentid_param: STRING = "AttachmentID"
Fieldtitle_param: STRING = "FieldTitle"
Passwordhash_param: STRING = "PasswordHash"
Registrationtoken_param: STRING = "RegistrationToken"
Answerhash_param: STRING = "AnswerHash"
Classid_param: STRING = "Classid"
Confidential_param: STRING = "Confidential"
Release_param: STRING = "Release"
Environment_param: STRING = "Environment"
Description_param: STRING = "Description"
Toreproduce_param: STRING = "ToReproduce"
Content_param: STRING = "Content"
Alreadyexists_param: STRING = "AlreadyExists"
Firstname_param: STRING = "FirstName"
Lastname_param: STRING = "LastName"
Responsible_param: STRING = "Responsible"
Responsible_firstname_param: STRING = "ResponsibleFirstName"
Responsible_lastname_param: STRING = "ResponsibleLastName"
Length_param: STRING = "Length"
Filename_param: STRING = "Filename"
Position_param: STRING = "Position"
Address_param: STRING = "Address"
City_param: STRING = "City"
Country_param: STRING = "Country"
Region_param: STRING = "Region"
Code_param: STRING = "Code"
Tel_param: STRING = "Tel"
Fax_param: STRING = "Fax"
Name_param: STRING = "Name"
Url_param: STRING = "URL"
Token_param: STRING = "Token"
Filter_param: STRING = "Filter"
feature -- Login
Passwordsalt_param: STRING = "PasswordSalt"
Answersalt_param: STRING = "AnswerSalt"
Questionid_param: STRING = "QuestionID"
feature -- Download Parameter Names
Subject_param: STRING = "Subject"
Notes_param: STRING = "Notes"
Platform_param: STRING = "Platform"
Newsletter_param: STRING = "Newsletter"
end

View File

@@ -0,0 +1,29 @@
note
description: "Database configuration"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
deferred class
DATABASE_CONFIG
feature -- Database access
hostname: STRING = ""
-- Database hostname.
username: STRING = ""
-- Database username.
password: STRING = ""
-- Database password.
database_name: STRING = "EiffelDB"
-- Database name.
is_keep_connection: BOOLEAN
-- Keep Connection to database?
do
Result := True
end
end

View File

@@ -0,0 +1,103 @@
note
description: "Abstract class to handle a database connection"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
deferred class
DATABASE_CONNECTION
inherit
DATABASE_CONFIG
SHARED_ERROR
feature {NONE} -- Initialization
make_common
-- Create a database handler with common settings.
deferred
ensure
db_application_not_void: db_application /= Void
db_control_not_void: db_control /= Void
end
make_basic ( a_database_name: STRING)
-- Create a database handler with common settings and
-- set database_name with `a_database_name'.
require
database_name_not_void: a_database_name /= Void
database_name_not_empty: not a_database_name.is_empty
deferred
ensure
db_application_not_void: db_application /= Void
db_control_not_void: db_control /= Void
end
make (a_username: STRING; a_password: STRING; a_hostname: STRING; a_database_name: STRING; connection: BOOLEAN)
-- Create a database handler with user `a_username', password `a_password',
-- host `a_hostname', database_name `a_database_name', and keep_connection `connection'.
require
username_not_void: a_username /= Void
username_not_empty: not a_username.is_empty
password_not_void: a_password /= Void
hostname_not_void: a_hostname /= Void
hotname_not_empty: not a_hostname.is_empty
database_name_not_void: a_database_name /= Void
database_name_not_empty: not a_database_name.is_empty
deferred
ensure
db_application_not_void: db_application /= Void
db_control_not_void: db_control /= Void
end
login_with_connection_string (a_connection_string: STRING)
-- Login with `a_connection_string'
-- and immediately connect to database.
deferred
ensure
db_application_not_void: db_application /= Void
db_control_not_void: db_control /= Void
end
feature -- Database Setup
db_application: DATABASE_APPL [DATABASE]
-- Database application.
db_control: DB_CONTROL
-- Database control.
keep_connection: BOOLEAN
-- Keep connection alive?
feature -- Conection
connect
-- Connect to the database.
require else
db_control_not_void: db_control /= Void
do
if not is_connected then
db_control.connect
end
end
disconnect
-- Disconnect from the database.
require else
db_control_not_void: db_control /= Void
do
db_control.disconnect
end
is_connected: BOOLEAN
-- True if connected to the database.
require else
db_control_not_void: db_control /= Void
do
Result := db_control.is_connected
end
end

View File

@@ -0,0 +1,137 @@
note
description: "Object that handle a database connection for ODBC"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
class
DATABASE_CONNECTION_MYSQL
inherit
DATABASE_CONNECTION
redefine
db_application
end
create
make, make_common, make_basic, login_with_connection_string, login_with_schema
feature -- Initialization
make_common
-- Create a database handler for MYSQL with common settings.
local
l_retried: BOOLEAN
do
create db_application.login (username, password)
if not l_retried then
db_application.set_hostname (hostname)
db_application.set_data_source (database_name)
db_application.set_base
create db_control.make
keep_connection := is_keep_connection
if keep_connection then
connect
end
set_successful
else
create db_control.make
end
rescue
create db_control.make
set_last_error_from_exception ("Connection execution")
log.write_critical (generator + ".make_common:" + last_error_message)
if is_connected then
disconnect
end
l_retried := True
retry
end
make_basic (a_database_name: STRING)
-- Create a database handler and
-- set database_name to `a_database_name'.
local
l_retried: BOOLEAN
do
create db_application.login (username, password)
if not l_retried then
db_application.set_hostname (hostname)
db_application.set_data_source (a_database_name)
db_application.set_base
create db_control.make
keep_connection := is_keep_connection
if keep_connection then
connect
end
set_successful
else
create db_control.make
end
rescue
create db_control.make
set_last_error_from_exception ("Connection execution")
log.write_critical (generator + ".make_common:" + last_error_message)
if is_connected then
disconnect
end
l_retried := True
retry
end
make (a_username: STRING; a_password: STRING; a_hostname: STRING; a_database_name: STRING; connection: BOOLEAN)
-- Create a database handler for ODBC and set `username' to `a_username',
-- `password' to `a_password'
-- `database_name' to `a_database_name'
-- `connection' to `a_connection'
do
create db_application.login (a_username, a_password)
db_application.set_hostname (a_hostname)
db_application.set_data_source (a_database_name)
db_application.set_base
create db_control.make
keep_connection := connection
if keep_connection then
connect
end
end
login_with_connection_string (a_string: STRING)
-- Login with `a_connection_string'and immediately connect to database.
do
log.write_debug (generator +".login_with_connection_string")
create db_application.login_with_connection_string (a_string)
db_application.set_base
create db_control.make
log.write_debug (generator +".login_with_connection_string, is_keep_connection? "+ is_keep_connection.out )
keep_connection := is_keep_connection
if keep_connection then
connect
if not db_control.is_ok then
log.write_critical (generator +".login_with_connection_string:"+ db_control.error_code.out )
log.write_critical (generator +".login_with_connection_string:"+ db_control.error_message_32 )
end
log.write_debug (generator +".login_with_connection_string, After connect, is_connected? "+ is_connected.out)
end
end
login_with_schema (a_schema: STRING; a_username: STRING; a_password: STRING)
-- Login with `a_connection_string'and immediately connect to database.
do
create db_application
db_application.set_application (a_schema)
db_application.login_and_connect (a_username, a_password)
db_application.set_base
create db_control.make
keep_connection := is_keep_connection
end
feature -- Databse Connection
db_application: DATABASE_APPL [MYSQL]
-- Database application.
end

View File

@@ -0,0 +1,67 @@
note
description: "Null object to meet Void Safe."
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
class
DATABASE_CONNECTION_NULL
inherit
DATABASE_CONNECTION
redefine
db_application,
is_connected
end
create
make, make_common, make_basic
feature -- Initialization
make_common
-- Create a database handler for ODBC with common settings.
do
create db_application.login (username, password)
db_application.set_hostname (hostname)
db_application.set_data_source (database_name)
db_application.set_base
create db_control.make
end
make (a_username: STRING; a_password: STRING; a_hostname: STRING; a_database_name: STRING; connection: BOOLEAN)
-- Create a database handler for ODBC.
do
make_common
end
make_basic (a_database_name: STRING)
-- Create a database handler for ODBC.
do
make_common
end
login_with_connection_string (a_string: STRING)
-- Login with `a_connection_string'
-- and immediately connect to database.
do
make_common
end
feature -- Databse Connection
db_application: DATABASE_APPL[DATABASE_NULL]
-- Database application.
is_connected: BOOLEAN
-- True if connected to the database.
do
Result := True
end
end

View File

@@ -0,0 +1,177 @@
note
description: "Abstract Database Handler"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
deferred class
DATABASE_HANDLER
inherit
SHARED_ERROR
feature -- Access
store: detachable DATABASE_STORE_PROCEDURE
-- Database stored_procedure to handle.
query: detachable DATABASE_QUERY
-- Database query.
feature -- Modifiers
set_store (a_store: DATABASE_STORE_PROCEDURE)
-- Set `store' to `a_store' to execute.
require
store_not_void: a_store /= Void
do
store := a_store
ensure
store_set: store = a_store
end
set_query (a_query: DATABASE_QUERY)
-- Set `query' to `a_query' to execute.
require
query_not_void: a_query /= Void
do
query := a_query
ensure
query_set: query = a_query
end
feature -- Functionality Store Procedures
execute_reader
-- Execute store.
require
store_not_void: store /= void
deferred
end
execute_writer
-- Execute store.
require
store_not_void: store /= void
deferred
end
feature -- SQL Queries
execute_query
-- Execute query.
require
query_not_void: query /= void
deferred
end
execute_change
-- Execute sqlquery that update/add data.
require
query_not_void: query /= void
deferred
end
feature -- Iteration
start
-- Set the cursor on first element.
deferred
end
item: ANY
-- Item at current cursor position.
require
valid_position: not after
deferred
end
after: BOOLEAN
-- Are there no more items to iterate over?
deferred
end
forth
-- Move to next position.
require
valid_position: not after
deferred
end
feature -- Access
read_integer_32 (a_index: INTEGER): INTEGER_32
-- Retrieved value at `a_index' position in `item'.
do
if attached {DB_TUPLE} item as l_item then
if attached {INTEGER_32_REF} l_item.item (a_index) as ll_item then
Result := ll_item.item
end
end
end
read_string (a_index: INTEGER): detachable STRING
-- Retrieved value at `a_index' position in `item'.
do
if attached {DB_TUPLE} item as l_item then
if attached {STRING} l_item.item (a_index) as ll_item then
Result := ll_item
elseif attached {BOOLEAN_REF} l_item.item (a_index) as ll_item then
Result := ll_item.item.out
end
end
end
read_date_time (a_index: INTEGER): detachable DATE_TIME
-- Retrieved value at `a_index' position in `item'.
do
if attached {DB_TUPLE} item as l_item then
if attached {DATE_TIME} l_item.item (a_index) as ll_item then
Result := ll_item
end
end
end
read_boolean (a_index: INTEGER): detachable BOOLEAN
-- Retrieved value at `a_index' position in `item'.
do
if attached {DB_TUPLE} item as l_item then
if attached {BOOLEAN} l_item.item (a_index) as ll_item then
Result := ll_item
elseif attached {BOOLEAN_REF} l_item.item (a_index) as ll_item then
Result := ll_item.item
end
end
end
feature -- Status Report
has_error: BOOLEAN
-- Is there an error?
count: INTEGER
-- Number of rows, last execution.
deferred
end
feature {NODE_DATA_PROVIDER}-- Implementation
connect
-- Connect to the database.
deferred
end
disconnect
-- Disconnect from the database.
deferred
ensure
not_connected: not is_connected
end
is_connected: BOOLEAN
-- True if connected to the database.
deferred
end
end

View File

@@ -0,0 +1,284 @@
note
description: "Database handler Implementation"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
class
DATABASE_HANDLER_IMPL
inherit
DATABASE_HANDLER
REFACTORING_HELPER
create
make
feature {NONE} -- Initialization
make (a_connection: DATABASE_CONNECTION)
-- Create a database handler with connnection `connection'.
do
connection := a_connection
create last_query.make_now
set_successful
ensure
connection_not_void: connection /= Void
last_query_not_void: last_query /= Void
end
feature -- Functionality
execute_reader
-- Execute stored procedure that returns data.
local
l_db_selection: DB_SELECTION
l_retried: BOOLEAN
do
if not l_retried then
if not keep_connection then
connect
end
if attached store as l_store then
create l_db_selection.make
db_selection := l_db_selection
items := l_store.execute_reader (l_db_selection)
end
if not keep_connection then
disconnect
end
set_successful
log.write_debug ( generator+".execute_reader Successful")
end
rescue
set_last_error_from_exception ("Store procedure execution")
log.write_critical (generator+ ".execute_reader " + last_error_message)
if is_connected then
disconnect
end
l_retried := True
retry
end
execute_writer
-- Execute stored procedure that update/add data.
local
l_db_change: DB_CHANGE
l_retried : BOOLEAN
do
if not l_retried then
if not keep_connection and not is_connected then
connect
end
if attached store as l_store then
create l_db_change.make
db_update := l_db_change
l_store.execute_writer (l_db_change)
if not l_store.has_error then
db_control.commit
end
end
if not keep_connection then
disconnect
end
set_successful
log.write_debug ( generator+".execute_writer Successful")
end
rescue
set_last_error_from_exception ("Store procedure execution")
log.write_critical (generator+ ".execute_writer " + last_error_message)
if is_connected then
disconnect
end
l_retried := True
retry
end
feature -- SQL Queries
execute_query
-- Execute query.
local
l_db_selection: DB_SELECTION
l_retried: BOOLEAN
do
if not l_retried then
if not keep_connection then
connect
end
if attached query as l_query then
create l_db_selection.make
db_selection := l_db_selection
items := l_query.execute_reader (l_db_selection)
end
if not keep_connection then
disconnect
end
set_successful
end
rescue
set_last_error_from_exception ("execute_query")
log.write_critical (generator+ ".execute_query " + last_error_message)
if is_connected then
disconnect
end
l_retried := True
retry
end
execute_change
-- Execute sqlquery that update/add data.
local
l_db_change: DB_CHANGE
l_retried : BOOLEAN
do
if not l_retried then
if not keep_connection and not is_connected then
connect
end
if attached query as l_query then
create l_db_change.make
db_update := l_db_change
l_query.execute_change (l_db_change)
db_control.commit
end
if not keep_connection then
disconnect
end
set_successful
end
rescue
set_last_error_from_exception ("Store procedure execution")
log.write_critical (generator+ ".execute_writer " + last_error_message)
if is_connected then
disconnect
end
l_retried := True
retry
end
feature -- Iteration
start
-- Set the cursor on first element.
do
if attached db_selection as l_db_selection and then l_db_selection.container /= Void then
l_db_selection.start
end
end
forth
-- Move cursor to next element.
do
if attached db_selection as l_db_selection then
l_db_selection.forth
else
check False end
end
end
after: BOOLEAN
-- True for the last element.
do
if attached db_selection as l_db_selection and then l_db_selection.container /= Void then
Result := l_db_selection.after or else l_db_selection.cursor = Void
else
Result := True
end
end
item: DB_TUPLE
-- Current element.
do
if attached db_selection as l_db_selection and then attached l_db_selection.cursor as l_cursor then
create {DB_TUPLE} Result.copy (l_cursor)
else
check False then end
end
end
feature {NONE} -- Implementation
connection: DATABASE_CONNECTION
-- Database connection.
db_control: DB_CONTROL
-- Database control.
do
Result := connection.db_control
end
db_result: detachable DB_RESULT
-- Database query result.
db_selection: detachable DB_SELECTION
-- Database selection.
db_update: detachable DB_CHANGE
-- Database modification.
last_query: DATE_TIME
-- Last time when a query was executed.
keep_connection: BOOLEAN
-- Keep connection alive?
do
Result := connection.keep_connection
end
connect
-- Connect to the database.
require else
db_control_not_void: db_control /= Void
do
if not is_connected then
db_control.connect
end
end
disconnect
-- Disconnect from the database.
require else
db_control_not_void: db_control /= Void
do
db_control.disconnect
end
is_connected: BOOLEAN
-- True if connected to the database.
require else
db_control_not_void: db_control /= Void
do
Result := db_control.is_connected
end
affected_row_count: INTEGER
-- The number of rows changed, deleted, or inserted by the last statement.
do
if attached db_update as l_update then
Result := l_update.affected_row_count
end
end
feature -- Result
items : detachable LIST[DB_RESULT]
-- Query result.
count: INTEGER
-- <Precursor>
do
if attached items as l_items then
Result := l_items.count
end
end
end

View File

@@ -0,0 +1,91 @@
note
description: "External iteration cursor for {ESA_DATABASE_HANDLER}"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
class
DATABASE_ITERATION_CURSOR [G]
inherit
ITERATION_CURSOR [G]
ITERABLE [G]
create
make
feature -- Initialization
make (a_handler: DATABASE_HANDLER; a_action: like action)
-- Create an iterator and set `db_handlet' to `a_handler'
-- `action' to `a_action'
do
db_handler := a_handler
action := a_action
ensure
db_handler_set: db_handler = a_handler
action_set: action = a_action
end
feature -- Access
item: G
-- Item at current cursor position.
do
Result := action.item ([db_item])
end
db_item: DB_TUPLE
-- Current element.
do
if attached {DB_TUPLE} db_handler.item as l_item then
Result := l_item
else
check False then
end
end
end
feature -- Status report
after: BOOLEAN
-- Are there no more items to iterate over?
do
Result := db_handler.after
end
feature -- Cursor movement
start
-- Set the cursor on first element.
do
db_handler.start
end
forth
-- Move to next position.
do
db_handler.forth
end
feature -- Cursor
new_cursor: DATABASE_ITERATION_CURSOR [G]
-- <Precursor>
do
Result := twin
Result.start
end
feature -- Action
action: FUNCTION [ANY, detachable TUPLE [], G]
-- Agent to create a new item of type G.
feature {NONE} -- Implementation
db_handler: DATABASE_HANDLER
-- Associated handler used for iteration.
end

View File

@@ -0,0 +1,538 @@
note
description: "Null object to meet void safe"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
class
DATABASE_NULL
inherit
DATABASE
feature -- Acccess
database_handle_name: STRING = "NULL"
-- Handle name
feature -- For DATABASE_STATUS
is_error_updated: BOOLEAN
-- Has an NULL function been called since last update which may have
-- updated error code, error message?
is_warning_updated: BOOLEAN
-- Has an ODBC function been called since last update which may have
-- updated warning message?
found: BOOLEAN
-- Is there any record matching the last
-- selection condition used ?
clear_error
-- Reset database error status.
do
end
insert_auto_identity_column: BOOLEAN = False
-- For INSERTs and UPDATEs should table auto-increment identity columns be explicitly included in the statement?
feature -- For DATABASE_CHANGE
descriptor_is_available: BOOLEAN
do
end
feature -- For DATABASE_FORMAT
date_to_str (object: DATE_TIME): STRING
-- String representation in SQL of `object'
-- For ODBC, ORACLE
do
create Result.make_empty
end
string_format (object: detachable STRING): STRING
-- String representation in SQL of `object'
obsolete
"Use `string_format_32' instead."
do
Result := ""
end
string_format_32 (object: detachable READABLE_STRING_GENERAL): STRING_32
-- String representation in SQL of `object'
do
Result := ""
end
True_representation: STRING
-- Database representation of the boolean True
do
Result := ""
end
False_representation: STRING
-- Database representation of the boolean False
do
Result := ""
end
feature -- For DATABASE_SELECTION, DATABASE_CHANGE
normal_parse: BOOLEAN
-- Should the SQL string be normal parsed,
-- using SQL_SCAN?
do
end
feature -- DATABASE_STRING
sql_name_string: STRING
-- SQL type name of string
do
Result := ""
end
feature -- DATABASE_REAL
sql_name_real: STRING
-- SQL type name for real
do
Result := ""
end
feature -- DATABASE_DATETIME
sql_name_datetime: STRING
-- SQL type name for datetime
do
Result := ""
end
feature -- DATABASE_DECIMAL
sql_name_decimal: STRING
-- SQL type name for decimal
do
Result := ""
end
feature -- DATABASE_DOUBLE
sql_name_double: STRING
-- SQL type name for double
do
Result := ""
end
feature -- DATABASE_CHARACTER
sql_name_character: STRING
-- SQL type name for character
do
Result := ""
end
feature -- DATABASE_INTEGER
sql_name_integer: STRING
-- SQL type name for integer
do
Result := ""
end
sql_name_integer_16: STRING
-- SQL type name for integer
do
Result := ""
end
sql_name_integer_64: STRING
-- SQL type name for integer
do
Result := ""
end
feature -- DATABASE_BOOLEAN
sql_name_boolean: STRING
-- SQL type name for boolean
do
Result := ""
end
feature -- LOGIN and DATABASE_APPL only for password_ok
password_ok (upasswd: STRING): BOOLEAN
-- Can the user password be Void?
do
end
password_ensure (name, passwd, uname, upasswd: STRING): BOOLEAN
-- Is name equal to uname and passwd equal to upasswd?
do
end
feature -- For DATABASE_PROC
support_sql_of_proc: BOOLEAN
-- Does the database support SQL attachment to the stored procedure?
do
end
support_stored_proc: BOOLEAN
-- Does the database support creating a stored procedure?
do
end
sql_as: STRING
-- Creating a stored procedure "as"...
do
Result := ""
end
sql_end: STRING
-- End of the stored procedure creation string.
do
Result := ""
end
sql_execution: STRING
-- Begining of the stored procedure execution string.
do
Result := ""
end
sql_creation: STRING
-- Begining of the stored procedure creation string.
do
Result := ""
end
sql_after_exec: STRING
-- End of the stored procedure execution string.
do
Result := ""
end
support_drop_proc: BOOLEAN
-- Does the database support stored procedure dropping from server?
do
end
name_proc_lower: BOOLEAN
-- Has the name of the stored procedure to be in lower case?
do
end
map_var_between: STRING
-- @ symbol for ODBC and Sybase
do
Result := ""
end
map_var_name_32 (par_name: READABLE_STRING_GENERAL): STRING_32
-- Redefined for Sybase
do
Result := ""
end
Select_text_32 (proc_name: READABLE_STRING_GENERAL): STRING_32
-- SQL query to get stored procedure text
do
Result := ""
end
Select_exists_32 (name: READABLE_STRING_GENERAL): STRING_32
-- SQL query to test stored procedure existing
do
Result := ""
end
Selection_string (rep_qualifier, rep_owner, repository_name: STRING): STRING
-- String to select the table needed
do
Result := ""
end
sql_string: STRING
-- Database type of a string
-- with a size less than Max_char_size
do
Result := ""
end
sql_string2 (int: INTEGER): STRING
-- Database type of a string
-- with a size more than Max_char_size
do
Result := ""
end
sql_wstring: STRING
-- Database type of a string
-- with a size less than Max_char_size
do
Result := ""
end
sql_wstring2 (int: INTEGER): STRING
-- Database type of a string
-- with a size more than Max_char_size
do
Result := ""
end
feature -- External features
get_error_message: POINTER
-- Function related with the error processing
do
create Result
end
get_error_message_string: STRING_32
-- Function related with the error processing
do
Result := ""
end
get_error_code: INTEGER
-- Function related with the error processing
do
end
get_warn_message: POINTER
-- Function related with the error processing
do
create Result
end
get_warn_message_string: STRING_32
-- Function related with the error processing
do
Result := ""
end
new_descriptor: INTEGER
-- A descriptor is used to store a row fetched by FETCH command
-- Whenever perform a SELECT statement, allocate a new descriptor
-- by int_new_descriptor(), the descriptor is freed
-- when the SELECT statement terminates.
do
end
init_order (no_descriptor: INTEGER; command: READABLE_STRING_GENERAL)
-- In DYNAMICALLY EXECUTE mode perform the SQL statement
-- But this routine only get things ready for dynamic execution:
-- 1. get the SQL statement PREPAREd; and check if there are
-- warning message for the SQL statement;
-- 2. DESCRIBE the SQL statement and get enough information to
-- allocate enough memory space for the corresponding descriptor.
do
end
start_order (no_descriptor: INTEGER)
-- Finish execution of a SQL statement in DYNAMICLLY EXECUTION mode: */
-- 1. if the PREPAREd SQL statement is a NON_SELECT statement,
-- just EXECUTE it; otherwise, DEFINE a CURSOR for it and
-- OPEN the CURSOR. In the process, if error occurs, do some
-- clearence;
do
end
next_row (no_descriptor: INTEGER)
-- A SELECT statement is now being executed in DYNAMIC EXECUTION mode,
-- the routine is to FETCH a new tuple from database
-- and if a new tuple is fetched, return 1 otherwise return 0.
do
end
terminate_order (no_descriptor: INTEGER)
-- A SQL has been performed in DYNAMIC EXECUTION mode,
-- so the routine is to do some clearence:
-- 1. if the DYNAMICALLY EXECUTED SQL statement is a NON_SELECT
-- statement, just free the memory for ODBCSQLDA and clear
-- the cell in 'descriptor' to NULL; otherwise, CLOSE the CURSOR
-- and then do the same clearence.
-- 2. return error number.
do
end
close_cursor (no_descriptor: INTEGER)
-- A SQL has been performed in DYNAMIC EXECUTION mode,
-- Then if the DYNAMICALLY EXECUTED SQL statement is a SELECT
-- statement, then the cursor is closed.
-- Then one can do an other selection on the previous cursor.
do
end
exec_immediate (no_descriptor: INTEGER; command: READABLE_STRING_GENERAL)
-- In IMMEDIATE EXECUTE mode perform the SQL statement,
-- and then check if there is warning message for the execution,
do
end
put_col_name (no_descriptor: INTEGER; index: INTEGER; ar: STRING; max_len:INTEGER): INTEGER
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
put_data (no_descriptor: INTEGER; index: INTEGER; ar: STRING; max_len:INTEGER): INTEGER
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
put_data_32 (no_descriptor: INTEGER; index: INTEGER; ar: STRING_32; max_len:INTEGER): INTEGER
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
conv_type (indicator: INTEGER; index: INTEGER): INTEGER
-- Function used to get data from structure SQLDA filled by FETCH clause.
--| FIXME
--| This description really does not explain a thing...
do
end
get_count (no_descriptor: INTEGER): INTEGER
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
get_data_len (no_descriptor: INTEGER; ind: INTEGER): INTEGER
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
get_col_len (no_descriptor: INTEGER; ind: INTEGER): INTEGER
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
get_col_type (no_descriptor: INTEGER; ind: INTEGER): INTEGER
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
get_integer_data (no_descriptor: INTEGER; ind: INTEGER): INTEGER
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
get_integer_16_data (no_descriptor: INTEGER; ind: INTEGER): INTEGER_16
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
get_integer_64_data (no_descriptor: INTEGER; ind: INTEGER): INTEGER_64
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
get_float_data (no_descriptor: INTEGER; ind: INTEGER): DOUBLE
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
get_real_data (no_descriptor: INTEGER; ind: INTEGER): REAL
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
get_boolean_data (no_descriptor: INTEGER; ind: INTEGER): BOOLEAN
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
is_null_data (no_descriptor: INTEGER; ind: INTEGER): BOOLEAN
-- Is last retrieved data null?
do
end
get_date_data (no_descriptor: INTEGER; ind: INTEGER): INTEGER
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
get_hour (no_descriptor: INTEGER; ind: INTEGER): INTEGER
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
get_sec (no_descriptor: INTEGER; ind: INTEGER): INTEGER
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
get_min (no_descriptor: INTEGER; ind: INTEGER): INTEGER
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
get_year (no_descriptor: INTEGER; ind: INTEGER): INTEGER
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
get_day (no_descriptor: INTEGER; ind: INTEGER): INTEGER
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
get_month (no_descriptor: INTEGER; ind: INTEGER): INTEGER
-- Function used to get data from structure SQLDA filled by FETCH clause.
do
end
get_decimal (no_descriptor: INTEGER; ind: INTEGER): detachable TUPLE [digits: STRING_8; sign, precision, scale: INTEGER]
-- Function used to get decimal info
do
end
database_make (i: INTEGER)
-- Initialize database c-module
do
end
connect (user_name, user_passwd, data_source, application, hostname, role_id: STRING; role_passwd: detachable STRING; group_id: STRING)
-- Connect to database
do
end
connect_by_connection_string (a_connect_string: STRING)
-- Connect to database by connection string
do
end
disconnect
-- Disconnect the current connection with an database
do
end
commit
-- Commit the current transaction
do
end
rollback
-- Commit the current transaction
do
end
trancount: INTEGER
-- Return the number of transactions now active
do
end
begin
-- Begin a data base transaction
do
end
end

View File

@@ -0,0 +1,137 @@
note
description: "Abstract Database Query"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
class
DATABASE_QUERY
inherit
SHARED_LOGGER
REFACTORING_HELPER
create
data_reader
feature -- Intialization
data_reader (a_query: STRING; a_parameters: STRING_TABLE [detachable ANY])
-- SQL data reader for the query `a_query' with arguments `a_parameters'
do
log.write_information (generator + ".data_reader" + " execute query: " + a_query)
log.write_debug (generator + ".data_reader" + " arguments:" + log_parameters (a_parameters))
query := a_query
parameters := a_parameters
ensure
query_set: query = a_query
parameters_set: parameters = a_parameters
end
execute_reader (a_base_selection: DB_SELECTION): detachable LIST [DB_RESULT]
-- Execute the Current sql query.
do
to_implement ("Check test dynamic sequel. to redesign.")
create {ARRAYED_LIST [DB_RESULT]} Result.make (100)
a_base_selection.set_container (Result)
set_map_name (a_base_selection)
a_base_selection.set_query (query)
a_base_selection.execute_query
if a_base_selection.is_ok then
a_base_selection.load_result
Result := a_base_selection.container
else
log.write_error (generator + "." + a_base_selection.error_message_32)
end
unset_map_name (a_base_selection)
a_base_selection.terminate
end
execute_change (a_base_change: DB_CHANGE)
-- Execute the Current sql query .
do
to_implement ("Check test dynamic sequel. to redesign.")
set_map_name (a_base_change)
a_base_change.set_query (query)
a_base_change.execute_query
unset_map_name (a_base_change)
end
feature -- Access
query: STRING
-- SQL query to execute.
parameters: STRING_TABLE [detachable ANY]
-- query parameters.
feature -- Status Report
has_error: BOOLEAN
-- is there an error?
error_message: detachable STRING_32
-- Error message if any.
error_code: INTEGER
-- Error code.
feature {NONE} -- Implementation
set_map_name (a_base_selection: DB_EXPRESSION)
-- Store parameters `item' and their `key'.
do
from
parameters.start
until
parameters.after
loop
a_base_selection.set_map_name (parameters.item_for_iteration, parameters.key_for_iteration)
parameters.forth
end
end
unset_map_name (a_base_selection: DB_EXPRESSION)
-- Remove parameters item associated with key `key'.
do
from
parameters.start
until
parameters.after
loop
a_base_selection.unset_map_name (parameters.key_for_iteration)
parameters.forth
end
end
log_parameters (a_parameters: like parameters): STRING
-- Parameters to log with name and value
-- exclude sensitive information.
do
create Result.make_empty
from
a_parameters.start
until
a_parameters.after
loop
Result.append ("name:")
Result.append (a_parameters.key_for_iteration.as_string_32)
Result.append (", value:")
if
a_parameters.key_for_iteration.has_substring ("Password") or else
a_parameters.key_for_iteration.has_substring ("password")
then
-- Data to exclude
else
if attached a_parameters.item_for_iteration as l_item then
Result.append (l_item.out)
end
end
Result.append ("%N")
a_parameters.forth
end
end
end -- ESA_DATABASE_QUERY

View File

@@ -0,0 +1,33 @@
note
description: "Help to encode sql queries, to prevent sql injections."
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
EIS: "SQL server injection", "src=http://blogs.msdn.com/b/raulga/archive/2007/01/04/dynamic-sql-sql-injection.aspx", "protocol=url"
expanded class
DATABASE_SQL_SERVER_ENCODER
inherit
SHARED_LOGGER
feature -- Escape SQL input
encode (a_string:READABLE_STRING_32): READABLE_STRING_32
-- Escape single quote (') and braces ([,]).
local
l_string: STRING
do
l_string := a_string.twin
if not l_string.is_empty then
l_string.replace_substring_all ("[", "[[")
l_string.replace_substring_all ("]", "]]")
if l_string.index_of ('%'', 1) > 0 then
l_string.replace_substring ("[", 1, l_string.index_of ('%'', 1))
end
if l_string.last_index_of ('%'', l_string.count) > 0 then
l_string.replace_substring ("]", l_string.last_index_of ('%'', l_string.count), l_string.count)
end
end
Result := l_string
end
end

View File

@@ -0,0 +1,193 @@
note
description: "Database Store Procedure"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
class
DATABASE_STORE_PROCEDURE
inherit
SHARED_ERROR
create
data_reader, data_writer
feature -- Intialization
data_reader (a_sp: STRING; a_parameters: HASH_TABLE [ANY, STRING_32])
-- SQL data reader for the stored procedure `a_sp' with arguments `a_parameters'.
local
l_retried: BOOLEAN
do
log.write_information (generator + ".data_reader" + " execute store procedure: " + a_sp)
log.write_debug (generator + ".data_reader" + " arguments:" + log_parameters (a_parameters))
if not l_retried then
stored_procedure := a_sp
parameters := a_parameters
create proc.make (stored_procedure)
proc.load
if not a_parameters.is_empty then
proc.set_arguments_32 (a_parameters.current_keys, a_parameters.linear_representation.to_array)
end
if proc.exists then
if proc.text_32 /= Void then
debug
log.write_debug ( generator + ".data_reader: " + proc.text_32)
end
end
else
has_error := True
error_message := proc.error_message_32
error_code := proc.error_code
log.write_error (generator + ".data_witer message:" + proc.error_message_32 + " code:" + proc.error_code.out)
end
else
stored_procedure := a_sp
parameters := a_parameters
create proc.make (stored_procedure)
end
rescue
set_last_error_from_exception ("SQL execution")
log.write_critical (generator+ ".data_reader " + last_error_message)
l_retried := True
retry
end
data_writer (a_sp: STRING; a_parameters: HASH_TABLE [ANY, STRING_32])
-- SQL data reader for the stored procedure `a_sp' with arguments `a_parameters'
local
l_retried: BOOLEAN
do
log.write_information (generator + ".data_reader" + " execute store procedure: " + a_sp)
log.write_debug (generator + ".data_reader" + " arguments:" + log_parameters (a_parameters))
if not l_retried then
stored_procedure := a_sp
parameters := a_parameters
create proc.make (stored_procedure)
proc.load
proc.set_arguments_32 (a_parameters.current_keys, a_parameters.linear_representation.to_array)
if proc.exists then
if proc.text_32 /= Void then
debug
log.write_debug ( generator + ".data_writer: " + proc.text_32)
end
end
else
has_error := True
error_message := proc.error_message_32
error_code := proc.error_code
log.write_error (generator + ".data_witer message:" + proc.error_message_32 + " code:" + proc.error_code.out)
end
else
stored_procedure := a_sp
parameters := a_parameters
create proc.make (stored_procedure)
end
rescue
set_last_error_from_exception ("SQL execution")
log.write_critical (generator+ ".data_reader " + last_error_message)
l_retried := True
retry
end
execute_reader (a_base_selection: DB_SELECTION): detachable LIST [DB_RESULT]
-- Execute the Current store procedure.
do
create {ARRAYED_LIST [DB_RESULT]} Result.make (100)
a_base_selection.set_container (Result)
set_map_name (a_base_selection)
proc.execute (a_base_selection)
a_base_selection.load_result
Result := a_base_selection.container
unset_map_name (a_base_selection)
end
execute_writer (a_base_change: DB_CHANGE)
-- Execute the Current store procedure.
do
set_map_name (a_base_change)
proc.execute (a_base_change)
unset_map_name (a_base_change)
end
feature -- Access
proc: DB_PROC
-- object to create and execute stored procedure.
parameters: HASH_TABLE [detachable ANY, STRING_32]
-- Parameters to be used by the stored procedure.
stored_procedure: STRING
-- Store procedure to execute
feature -- Status Report
has_error: BOOLEAN
-- Is there an error.
error_message: detachable STRING_32
-- Last error message.
error_code: INTEGER
-- Last error code.
feature {NONE} -- Implementation
set_map_name (a_base_selection: DB_EXPRESSION)
-- Store parameters `item' and their `key'.
do
from
parameters.start
until
parameters.after
loop
a_base_selection.set_map_name (parameters.item_for_iteration, parameters.key_for_iteration)
parameters.forth
end
end
unset_map_name (a_base_selection: DB_EXPRESSION)
-- Remove parameters item associated with key `key'.
do
from
parameters.start
until
parameters.after
loop
a_base_selection.unset_map_name (parameters.key_for_iteration)
parameters.forth
end
end
log_parameters (a_parameters: like parameters): STRING
-- Parameters to log with name and value
-- exclude sensitive information.
do
create Result.make_empty
from
a_parameters.start
until
a_parameters.after
loop
Result.append ("name:")
Result.append (a_parameters.key_for_iteration)
Result.append (", value:")
if
a_parameters.key_for_iteration.has_substring ("Password") or else
a_parameters.key_for_iteration.has_substring ("password")
then
-- Data to exclude
else
if attached a_parameters.item_for_iteration as l_item then
Result.append (l_item.out)
end
end
Result.append ("%N")
a_parameters.forth
end
end
end

View File

@@ -0,0 +1,23 @@
note
description: "Helper for paramenter Names"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
deferred class
PARAMETER_NAME_HELPER
feature -- String
string_parameter (a_value: STRING; a_length: INTEGER): STRING
-- Adjust a parameter `a_value' to the lenght `a_length'.
require
valid_length: a_length > 0
do
if a_value.count <= a_length then
Result := a_value
else
create Result.make_from_string (a_value.substring (1, a_length))
end
end
end

View File

@@ -0,0 +1,114 @@
note
description: "Summary description for {NODE}."
date: "$Date$"
revision: "$Revision$"
class
CMS_NODE
create
make
feature{NONE} -- Initialization
make (a_content: READABLE_STRING_32; a_summary:READABLE_STRING_32; a_title: READABLE_STRING_32)
local
l_time: DATE_TIME
do
create l_time.make_now_utc
set_content (a_content)
set_summary (a_summary)
set_title (a_title)
set_creation_date (l_time)
set_modification_date (l_time)
set_publication_date (l_time)
ensure
content_set: content = a_content
summary_set: summary = a_summary
title_set: title = a_title
end
feature -- Access
content: READABLE_STRING_32
-- Content of the node.
summary: READABLE_STRING_32
-- A short summary of the node.
title: READABLE_STRING_32
-- Full title of the node.
modification_date: DATE_TIME
-- When the node was updated.
creation_date: DATE_TIME
-- When the node was created.
publication_date: DATE_TIME
-- When the node was published.
publication_date_output: READABLE_STRING_32
id: INTEGER_64 assign set_id
-- Unique id.
feature -- Element change
set_content (a_content: like content)
-- Assign `content' with `a_content'.
do
content := a_content
ensure
content_assigned: content = a_content
end
set_summary (a_summary: like summary)
-- Assign `summary' with `a_summary'.
do
summary := a_summary
ensure
summary_assigned: summary = a_summary
end
set_title (a_title: like title)
-- Assign `title' with `a_title'.
do
title := a_title
ensure
title_assigned: title = a_title
end
set_modification_date (a_modification_date: like modification_date)
-- Assign `modification_date' with `a_modification_date'.
do
modification_date := a_modification_date
ensure
modification_date_assigned: modification_date = a_modification_date
end
set_creation_date (a_creation_date: like creation_date)
-- Assign `creation_date' with `a_creation_date'.
do
creation_date := a_creation_date
ensure
creation_date_assigned: creation_date = a_creation_date
end
set_publication_date (a_publication_date: like publication_date)
-- Assign `publication_date' with `a_publication_date'.
do
publication_date := a_publication_date
publication_date_output := publication_date.formatted_out ("yyyy/[0]mm/[0]dd")
ensure
publication_date_assigned: publication_date = a_publication_date
end
set_id (an_id: like id)
-- Assign `id' with `an_id'.
do
id := an_id
ensure
id_assigned: id = an_id
end
end

View File

@@ -0,0 +1,68 @@
note
description: "Summary description for {USER}."
date: "$Date$"
revision: "$Revision$"
class
CMS_USER
create
make
feature {NONE} -- Initialization
make (a_name: READABLE_STRING_32)
-- Create an object with name `a_name'.
do
name := a_name
end
feature -- Access
id: INTEGER_64
-- Unique id.
name: READABLE_STRING_32
-- User name.
password: detachable READABLE_STRING_32
-- User password.
email: detachable READABLE_STRING_32
-- User email.
feature -- Change element
set_id (a_id: like id)
-- Set `id' with `a_id'.
do
id := a_id
ensure
id_set: id = a_id
end
set_name (n: like name)
-- Set `name' with `n'.
do
name := n
ensure
name_set: name = n
end
set_password (p: like password)
-- Set `password' with `p'.
do
password := p
ensure
password_set: password = p
end
set_email (m: like email)
-- Set `email' with `m'.
do
email := m
ensure
email_set: email = m
end
end

View File

@@ -0,0 +1,272 @@
note
description: "Database access for node uses cases."
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
class
NODE_DATA_PROVIDER
inherit
PARAMETER_NAME_HELPER
SHARED_ERROR
REFACTORING_HELPER
create
make
feature -- Initialization
make (a_connection: DATABASE_CONNECTION)
-- Create a data provider.
do
create {DATABASE_HANDLER_IMPL} db_handler.make (a_connection)
post_execution
end
db_handler: DATABASE_HANDLER
-- Db handler.
feature -- Status Report
is_successful: BOOLEAN
-- Is the last execution sucessful?
do
Result := db_handler.successful
end
feature -- Access
nodes: DATABASE_ITERATION_CURSOR [CMS_NODE]
-- List of nodes.
local
l_parameters: STRING_TABLE [ANY]
do
log.write_information (generator + ".nodes")
create l_parameters.make (0)
db_handler.set_query (create {DATABASE_QUERY}.data_reader (Select_nodes, l_parameters))
db_handler.execute_query
create Result.make (db_handler, agent fetch_node)
post_execution
end
recent_nodes (a_lower, a_rows: INTEGER): DATABASE_ITERATION_CURSOR [CMS_NODE]
-- The most recent `a_rows'.
local
l_parameters: STRING_TABLE [ANY]
l_query: STRING
do
log.write_information (generator + ".recent_nodes")
create l_parameters.make (2)
l_parameters.put (a_rows, "rows")
create l_query.make_from_string (select_recent_nodes)
l_query.replace_substring_all ("$offset", a_lower.out)
db_handler.set_query (create {DATABASE_QUERY}.data_reader (l_query, l_parameters))
db_handler.execute_query
create Result.make (db_handler, agent fetch_node)
post_execution
end
node (a_id: INTEGER_64): detachable CMS_NODE
-- Node for the given id `a_id', if any.
local
l_parameters: STRING_TABLE [ANY]
do
log.write_information (generator + ".nodes")
create l_parameters.make (1)
l_parameters.put (a_id,"id")
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_node_by_id, l_parameters))
db_handler.execute_query
if db_handler.count = 1 then
Result := fetch_node
end
post_execution
end
feature -- Basic operations
new_node (a_node: CMS_NODE)
-- Create a new node.
local
l_parameters: STRING_TABLE [ANY]
do
log.write_information (generator + ".nodes")
create l_parameters.make (6)
l_parameters.put (a_node.title, "title")
l_parameters.put (a_node.summary, "summary")
l_parameters.put (a_node.content, "content")
l_parameters.put (a_node.publication_date, "publication_date")
l_parameters.put (a_node.creation_date, "creation_date")
l_parameters.put (a_node.modification_date, "modification_date")
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_insert_node, l_parameters))
db_handler.execute_change
post_execution
end
update_node_title (a_id: INTEGER_64; a_title: READABLE_STRING_32)
-- Update node title for the corresponding the report with id `a_id'.
local
l_parameters: STRING_TABLE [ANY]
do
log.write_information (generator + ".nodes")
create l_parameters.make (3)
l_parameters.put (a_title, "title")
l_parameters.put (create {DATE_TIME}.make_now_utc, "modification_date")
l_parameters.put (a_id, "id")
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_update_node_title, l_parameters))
db_handler.execute_change
post_execution
end
update_node_summary (a_id: INTEGER_64; a_summary: READABLE_STRING_32)
-- Update node summary for the corresponding the report with id `a_id'.
local
l_parameters: STRING_TABLE [ANY]
do
log.write_information (generator + ".nodes")
create l_parameters.make (3)
l_parameters.put (a_summary, "summary")
l_parameters.put (create {DATE_TIME}.make_now_utc, "modification_date")
l_parameters.put (a_id, "id")
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_update_node_summary, l_parameters))
db_handler.execute_change
post_execution
end
update_node_content (a_id: INTEGER_64; a_content: READABLE_STRING_32)
-- Update node content for the corresponding the report with id `a_id'.
local
l_parameters: STRING_TABLE [ANY]
do
log.write_information (generator + ".nodes")
create l_parameters.make (3)
l_parameters.put (a_content, "content")
l_parameters.put (create {DATE_TIME}.make_now_utc, "modification_date")
l_parameters.put (a_id, "id")
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_update_node_content, l_parameters))
db_handler.execute_change
post_execution
end
update_node (a_node: CMS_NODE)
-- Update node.
local
l_parameters: STRING_TABLE [ANY]
do
log.write_information (generator + ".nodes")
create l_parameters.make (7)
l_parameters.put (a_node.title, "title")
l_parameters.put (a_node.summary, "summary")
l_parameters.put (a_node.content, "content")
l_parameters.put (a_node.publication_date, "publication_date")
l_parameters.put (a_node.creation_date, "creation_date")
l_parameters.put (create {DATE_TIME}.make_now_utc, "modification_date")
l_parameters.put (a_node.id, "id")
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_update_node, l_parameters))
db_handler.execute_change
post_execution
end
delete_node (a_id: INTEGER_64;)
-- Delete node with id `a_id'.
local
l_parameters: STRING_TABLE [ANY]
do
log.write_information (generator + ".nodes")
create l_parameters.make (1)
l_parameters.put (a_id, "id")
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_delete_node, l_parameters))
db_handler.execute_change
post_execution
end
feature -- Connection
connect
-- Connect to the database.
do
if not db_handler.is_connected then
db_handler.connect
end
end
disconnect
-- Disconnect to the database.
do
if db_handler.is_connected then
db_handler.disconnect
end
end
feature {NONE} -- Queries
Select_nodes: STRING = "select * from Nodes;"
-- SQL Query to retrieve all nodes.
Select_node_by_id: STRING = "select * from Nodes where id =:id order by id desc, publication_date desc;"
Select_recent_nodes: STRING = "select * from Nodes order by id desc, publication_date desc Limit $offset , :rows "
SQL_Insert_node: STRING = "insert into nodes (title, summary, content, publication_date, creation_date, modification_date) values (:title, :summary, :content, :publication_date, :creation_date, :modification_date);"
-- SQL Insert to add a new node.
SQL_Update_node_title: STRING ="update nodes SET title=:title, modification_date=:modification_date where id=:id;"
-- SQL update node title.
SQL_Update_node_summary: STRING ="update nodes SET summary=:summary, modification_date=:modification_date where id=:id;"
-- SQL update node summary.
SQL_Update_node_content: STRING ="update nodes SET content=:content, modification_date=:modification_date where id=:id;"
-- SQL node content.
SQL_Update_node : STRING = "update nodes SET title=:title, summary=:summary, content=:content, publication_date=:publication_date, creation_date=:creation_date, modification_date=:modification_date where id=:id;"
-- SQL node.
SQL_Delete_node: STRING = "delete from nodes where id=:id;"
feature -- New Object
fetch_node: CMS_NODE
do
create Result.make ("", "", "")
if attached db_handler.read_integer_32 (1) as l_id then
Result.set_id (l_id)
end
if attached db_handler.read_date_time (2) as l_pd then
Result.set_publication_date (l_pd)
end
if attached db_handler.read_date_time (3) as l_cd then
Result.set_creation_date (l_cd)
end
if attached db_handler.read_date_time (4) as l_md then
Result.set_modification_date (l_md)
end
if attached db_handler.read_string (5) as l_t then
Result.set_title (l_t)
end
if attached db_handler.read_string (6) as l_s then
Result.set_summary (l_s)
end
if attached db_handler.read_string (7) as l_c then
Result.set_content (l_c)
end
end
feature {NONE} -- Implementation
post_execution
-- Post database execution.
do
if db_handler.successful then
set_successful
else
if attached db_handler.last_error then
set_last_error_from_handler (db_handler.last_error)
end
end
end
end

View File

@@ -0,0 +1,182 @@
note
description: "Summary description for {USER_DATA_PROVIDER}."
date: "$Date$"
revision: "$Revision$"
class
USER_DATA_PROVIDER
inherit
PARAMETER_NAME_HELPER
SHARED_ERROR
REFACTORING_HELPER
create
make
feature -- Initialization
make (a_connection: DATABASE_CONNECTION)
-- Create a data provider.
do
create {DATABASE_HANDLER_IMPL} db_handler.make (a_connection)
post_execution
end
db_handler: DATABASE_HANDLER
-- Db handler.
feature -- Status Report
is_successful: BOOLEAN
-- Is the last execution sucessful?
do
Result := db_handler.successful
end
feature -- Basic Operations
new_user (a_user_name: READABLE_STRING_32; a_password: READABLE_STRING_32; a_email: READABLE_STRING_32)
-- Create a new node.
local
l_parameters: STRING_TABLE [detachable ANY]
l_password_salt, l_password_hash: STRING
l_security: SECURITY_PROVIDER
do
create l_security
l_password_salt := l_security.salt
l_password_hash := l_security.password_hash (a_password, l_password_salt)
log.write_information (generator + ".new_user")
create l_parameters.make (4)
l_parameters.put (a_user_name,"username")
l_parameters.put (l_password_hash,"password")
l_parameters.put (l_password_salt,"salt")
l_parameters.put (a_email,"email")
db_handler.set_query (create {DATABASE_QUERY}.data_reader (sql_insert_user, l_parameters))
db_handler.execute_change
post_execution
end
user (a_id: INTEGER_64): detachable CMS_USER
-- User for the given id `a_id', if any.
local
l_parameters: STRING_TABLE [ANY]
do
log.write_information (generator + ".nodes")
create l_parameters.make (1)
l_parameters.put (a_id,"id")
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_user_by_id, l_parameters))
db_handler.execute_query
if db_handler.count = 1 then
Result := fetch_user
end
post_execution
end
user_by_name (a_name: READABLE_STRING_32): detachable CMS_USER
-- User for the given name `a_name', if any.
local
l_parameters: STRING_TABLE [ANY]
do
log.write_information (generator + ".user_by_name")
create l_parameters.make (1)
l_parameters.put (a_name,"name")
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_user_by_name, l_parameters))
db_handler.execute_query
if db_handler.count = 1 then
Result := fetch_user
end
post_execution
end
user_by_email (a_email: detachable READABLE_STRING_32): detachable CMS_USER
-- User for the given email `a_email', if any.
local
l_parameters: STRING_TABLE [detachable ANY]
do
log.write_information (generator + ".user_by_name")
create l_parameters.make (1)
l_parameters.put (a_email,"email")
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_user_by_email, l_parameters))
db_handler.execute_query
if db_handler.count = 1 then
Result := fetch_user
end
post_execution
end
user_salt (a_username: READABLE_STRING_32): detachable READABLE_STRING_32
-- User salt for the given user `a_username', if any.
local
l_parameters: STRING_TABLE [ANY]
do
log.write_information (generator + ".nodes")
create l_parameters.make (1)
l_parameters.put (a_username,"name")
db_handler.set_query (create {DATABASE_QUERY}.data_reader (select_salt_by_username, l_parameters))
db_handler.execute_query
if db_handler.count = 1 then
if attached db_handler.read_string (1) as l_salt then
Result := l_salt.as_string_32
end
end
post_execution
end
feature -- New Object
fetch_user: CMS_USER
do
create Result.make ("")
if attached db_handler.read_integer_32 (1) as l_id then
Result.set_id (l_id)
end
if attached db_handler.read_string (2) as l_u then
Result.set_name (l_u)
end
if attached db_handler.read_string (3) as l_p then
Result.set_password (l_p)
end
if attached db_handler.read_string (5) as l_e then
Result.set_email (l_e)
end
end
feature -- Sql Queries
Select_user_by_id: STRING = "select * from Users where id =:id;"
-- Retrieve user by id if exists.
Select_user_by_name: STRING = "select * from Users where username =:name;"
-- Retrieve user by name if exists.
Select_user_by_email: STRING = "select * from Users where email =:email;"
-- Retrieve user by email if exists.
Select_salt_by_username: STRING = "select salt from Users where username =:name;"
-- Retrieve salt by username if exists.
SQL_Insert_user: STRING = "insert into users (username, password, salt, email) values (:username, :password, :salt, :email);"
-- SQL Insert to add a new node.
feature {NONE} -- Implementation
post_execution
-- Post database execution.
do
if db_handler.successful then
set_successful
else
if attached db_handler.last_error then
set_last_error_from_handler (db_handler.last_error)
end
end
end
end

View File

@@ -0,0 +1,153 @@
note
description: "Provides security routine helpers"
date: "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision: "$Revision: 95678 $"
class
SECURITY_PROVIDER
inherit
REFACTORING_HELPER
feature -- Access
token: STRING
-- Cryptographic random base 64 string.
do
Result := salt_with_size (5)
-- Remove trailing equal sign
Result.keep_head (Result.count - 1)
end
salt: STRING
-- Cryptographic random number of 16 bytes.
do
Result := salt_with_size (16)
end
password: STRING
-- Cryptographic random password of 10 bytes.
do
Result := salt_with_size (10)
-- Remove trailing equal signs
Result.keep_head (Result.count - 2)
end
password_hash (a_password, a_salt: STRING): STRING
-- Password hash based on password `a_password' and salt value `a_salt'.
do
Result := sha1_string (a_password + a_salt )
end
feature {NONE} -- Implementation
salt_with_size (a_val: INTEGER): STRING
-- Return a salt with size `a_val'.
local
l_salt: SALT_XOR_SHIFT_64_GENERATOR
l_array: ARRAY [INTEGER_8]
i: INTEGER
do
create l_salt.make (a_val)
create l_array.make_empty
i := 1
across
l_salt.new_sequence as c
loop
l_array.force (c.item.as_integer_8, i)
i := i + 1
end
Result := encode_base_64 (l_array)
end
sha1_string (a_str: STRING): STRING
-- SHA1 diggest of `a_str'.
do
sha1.update_from_string (a_str)
Result := sha1.digest_as_string
sha1.reset
end
sha1: SHA1
-- Create a SHA1 object.
once
create Result.make
end
feature -- Encoding
encode_base_64 (bytes: SPECIAL [INTEGER_8]): STRING_8
-- Encodes a byte array into a STRING doing base64 encoding.
local
l_output: SPECIAL [INTEGER_8]
l_remaining: INTEGER
i, ptr: INTEGER
char: CHARACTER
do
to_implement ("Check existing code to do that!!!.")
create l_output.make_filled (0, ((bytes.count + 2) // 3) * 4)
l_remaining := bytes.count
from
i := 0
ptr := 0
until
l_remaining <= 3
loop
l_output [ptr] := encode_value (bytes [i] |>> 2)
ptr := ptr + 1
l_output [ptr] := encode_value (((bytes [i] & 0x3) |<< 4) | ((bytes [i + 1] |>> 4) & 0xF))
ptr := ptr + 1
l_output [ptr] := encode_value (((bytes [i + 1] & 0xF) |<< 2) | ((bytes [i + 2] |>> 6) & 0x3))
ptr := ptr + 1
l_output [ptr] := encode_value (bytes [i + 2] & 0x3F)
ptr := ptr + 1
l_remaining := l_remaining - 3
i := i + 3
end
-- encode when exactly 1 element (left) to encode
char := '='
if l_remaining = 1 then
l_output [ptr] := encode_value (bytes [i] |>> 2)
ptr := ptr + 1
l_output [ptr] := encode_value (((bytes [i]) & 0x3) |<< 4)
ptr := ptr + 1
l_output [ptr] := char.code.as_integer_8
ptr := ptr + 1
l_output [ptr] := char.code.as_integer_8
ptr := ptr + 1
end
-- encode when exactly 2 elements (left) to encode
if l_remaining = 2 then
l_output [ptr] := encode_value (bytes [i] |>> 2)
ptr := ptr + 1
l_output [ptr] := encode_value (((bytes [i] & 0x3) |<< 4) | ((bytes [i + 1] |>> 4) & 0xF));
ptr := ptr + 1
l_output [ptr] := encode_value ((bytes [i + 1] & 0xF) |<< 2);
ptr := ptr + 1
l_output [ptr] := char.code.as_integer_8
ptr := ptr + 1
end
Result := ""
across
l_output as elem
loop
Result.append_character (elem.item.to_character_8)
end
end
base64_map: SPECIAL [CHARACTER_8]
-- Table for Base64 encoding.
once
Result := ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/").area
end
encode_value (i: INTEGER_8): INTEGER_8
-- Encode `i'.
do
Result := base64_map [i & 0x3F].code.as_integer_8
end
end

View File

@@ -0,0 +1,53 @@
note
description: "Summary description for {STRING_HELPER}."
date: "$Date: 2014-08-08 16:02:11 -0300 (vi., 08 ago. 2014) $"
revision: "$Revision: 95593 $"
class
STRING_HELPER
feature -- Access
is_blank (s: detachable READABLE_STRING_32): BOOLEAN
local
i,n: INTEGER
do
Result := True
if s /= Void then
from
i := 1
n := s.count
until
i > n or not Result
loop
Result := s[i].is_space
i := i + 1
end
end
end
indented_text (pre: READABLE_STRING_8; t: READABLE_STRING_8): READABLE_STRING_8
-- Indendted text.
local
s8: STRING_8
do
s8 := t.string
s8.prepend (pre)
s8.replace_substring_all ("%N", "%N" + pre)
Result := s8
end
json_encode (a_string: STRING): STRING
-- json encode `a_string'.
local
encode: SHARED_JSON_ENCODER
do
create encode
Result := encode.json_encoder.encoded_string (a_string)
debug
print ("%NResult" + Result)
end
end
end

View File

@@ -0,0 +1,55 @@
note
description : "tests application root class"
date : "$Date: 2014-08-20 15:21:15 -0300 (mi., 20 ago. 2014) $"
revision : "$Revision: 95678 $"
class
APPLICATION
inherit
ARGUMENTS
create
make
feature {NONE} -- Initialization
make
-- Run application.
local
user: USER_DATA_PROVIDER
node: NODE_DATA_PROVIDER
l_security: SECURITY_PROVIDER
do
create connection.login_with_schema ("cms", "root", "")
-- create user.make (connection)
---- user.new_user ("jv", "test","test@test.com")
-- if attached user.user (3) as l_user then
-- if attached user.user_salt ("jv") as l_salt then
-- create l_security
-- if attached l_user.password as l_password then
-- print (l_password)
-- io.put_new_line
-- print (l_security.password_hash ("test", l_salt))
-- check same_string: l_security.password_hash ("test", l_salt).is_case_insensitive_equal (l_password) end
-- end
-- end
-- end
-- if attached user.user_by_name ("jv") as l_user then
-- check l_user.id = 3 end
-- end
create node.make (connection)
across node.recent_nodes (0, 5) as c loop
print (c.item)
end
end
connection: DATABASE_CONNECTION_MYSQL
end

View File

@@ -0,0 +1,26 @@
note
description: "[
Eiffel tests that can be executed by testing tool.
]"
author: "EiffelStudio test wizard"
date: "$Date$"
revision: "$Revision$"
testing: "type/manual"
class
NODE_TEST_SET
inherit
EQA_TEST_SET
feature -- Test routines
new_test_routine
-- New test routine
do
assert ("not_implemented", False)
end
end

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="tests">
<target name="tests">
<root class="APPLICATION" feature="make"/>
<option warning="true" void_safety="conformance">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option>
<setting name="concurrency" value="thread"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="crypto" location="$ISE_LIBRARY\unstable\library\text\encryption\crypto\crypto-safe.ecf"/>
<library name="persitence_mysql" location="..\persistence_mysql.ecf" readonly="false"/>
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
<library name="process" location="$ISE_LIBRARY\library\process\process-safe.ecf"/>
<cluster name="tests" location=".\" recursive="true">
<file_rule>
<exclude>/EIFGENs$</exclude>
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</file_rule>
</cluster>
</target>
</system>

View File

@@ -0,0 +1,78 @@
note
description: "[
Eiffel tests that can be executed by testing tool.
]"
author: "EiffelStudio test wizard"
date: "$Date$"
revision: "$Revision$"
testing: "type/manual"
class
USER_TEST_SET
inherit
EQA_TEST_SET
redefine
on_prepare,
on_clean
select
default_create
end
ABSTRACT_DB_TEST
rename
default_create as default_db_test
end
feature {NONE} -- Events
on_prepare
-- <Precursor>
do
(create {CLEAN_DB}).clean_db(connection)
user_provider.new_user ("admin", "admin","admin@admin.com")
end
on_clean
-- <Precursor>
do
end
feature -- Test routines
test_user_exist
-- User admin exist
do
assert ("Not void", attached user_provider.user_by_email ("admin@admin.com"))
assert ("Not void", attached user_provider.user (1))
assert ("Not void", attached user_provider.user_by_name ("admin"))
end
test_user_not_exist
-- Uset test does not exist.
do
assert ("Void", user_provider.user_by_email ("test@admin.com") = Void)
assert ("Void", user_provider.user(2) = Void )
assert ("Void", user_provider.user_by_name ("test") = Void)
end
test_new_user
do
user_provider.new_user ("test", "test","test@admin.com")
assert ("Not void", attached user_provider.user_by_email ("test@admin.com"))
assert ("Not void", attached user_provider.user (2))
assert ("Not void", attached user_provider.user (2) as l_user and then l_user.id = 2 and then l_user.name ~ "test")
assert ("Not void", attached user_provider.user_by_name ("test"))
end
feature {NONE} -- Implementation
user_provider: USER_DATA_PROVIDER
-- user provider.
once
create Result.make (connection)
end
end

View File

@@ -0,0 +1,17 @@
note
description: "Summary description for {ABSTRACT_DB_TEST}."
date: "$Date$"
revision: "$Revision$"
class
ABSTRACT_DB_TEST
feature -- Database connection
connection: DATABASE_CONNECTION_MYSQL
-- MYSQL database connection
once
create Result.login_with_schema ("cms_dev", "root", "")
end
end

View File

@@ -0,0 +1,66 @@
note
description: "[
Setting up database tests
1. Put the database in a known state before running your test suite.
2. Data reinitialization. For testing in developer sandboxes, something that you should do every time you rebuild the system, you may want to forgo dropping and rebuilding the database in favor of simply reinitializing the source data.
You can do this either by erasing all existing data and then inserting the initial data vales back into the database, or you can simple run updates to reset the data values.
The first approach is less risky and may even be faster for large amounts of data. - See more at: http://www.agiledata.org/essays/databaseTesting.html#sthash.6yVp35g8.dpuf
]"
date: "$Date$"
revision: "$Revision$"
EIS: "name=Database Testing", "src=http://www.agiledata.org/essays/databaseTesting.html", "protocol=uri"
class
CLEAN_DB
feature
clean_db (a_connection: DATABASE_CONNECTION)
-- Clean db test.
local
l_parameters: STRING_TABLE[STRING]
do
create l_parameters.make (0)
db_handler(a_connection).set_query (create {DATABASE_QUERY}.data_reader (Sql_delete_nodes, l_parameters))
db_handler(a_connection).execute_change
-- Clean Users
db_handler(a_connection).set_query (create {DATABASE_QUERY}.data_reader (Sql_delete_users, l_parameters))
db_handler(a_connection).execute_change
-- Reset Autoincremente
db_handler(a_connection).set_query (create {DATABASE_QUERY}.data_reader (Rest_users_autoincrement, l_parameters))
db_handler(a_connection).execute_change
db_handler(a_connection).set_query (create {DATABASE_QUERY}.data_reader (Rest_nodes_autoincrement, l_parameters))
db_handler(a_connection).execute_change
end
feature -- Database Hanlder
db_handler (a_connection: DATABASE_CONNECTION): DATABASE_HANDLER
-- Db handler
once
create {DATABASE_HANDLER_IMPL} Result.make (a_connection)
end
feature -- Sql delete queries
Sql_delete_users: STRING = "delete from Users"
-- Clean Users.
Sql_delete_nodes: STRING = "delete from Nodes"
-- Clean Nodes.
Rest_users_autoincrement: STRING = "ALTER TABLE Users AUTO_INCREMENT = 1"
-- reset autoincrement
Rest_nodes_autoincrement: STRING = "ALTER TABLE Nodes AUTO_INCREMENT = 1"
-- reset autoincrement.
end