Browse Source

* removing boost dependencies

master
Erik Winn 8 years ago
parent
commit
17f2dcb875
7 changed files with 465 additions and 340 deletions
  1. +1
    -2
      CMakeLists.txt
  2. +56
    -59
      src/sql/drivers/wsqlitedriver.cpp
  3. +4
    -2
      src/sql/drivers/wsqlitedriver.h
  4. +361
    -225
      src/sql/wsqldatatype.h
  5. +3
    -4
      src/sql/wsqldatum.cpp
  6. +39
    -45
      src/sql/wsqldatum.h
  7. +1
    -3
      src/sql/wsqlfield.cpp

+ 1
- 2
CMakeLists.txt View File

@ -15,12 +15,11 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
find_package(MySQL)
find_package(Sqlite3)
find_package(Ctemplate REQUIRED)
find_package(Boost REQUIRED)
#ADD_DEFINITIONS(-Wall -O2)
ADD_DEFINITIONS(-Wall -g)
include_directories( ${Boost_INCLUDE_DIRS} ${WORM_INCLUDE_DIRS} ${SQLITE3_INCLUDE_DIR})
include_directories( ${WORM_INCLUDE_DIRS} ${SQLITE3_INCLUDE_DIR} )
add_subdirectory(src)
install(FILES src/orm/templates/class_declaration.tpl DESTINATION share/worm)

+ 56
- 59
src/sql/drivers/wsqlitedriver.cpp View File

@ -21,9 +21,8 @@
#include "wsqlforeignkey.h"
#include <iostream>
#include <boost/algorithm/string.hpp>
#define ROWENDTAG "-*-"
#define LOCALDEBUG 0
namespace WSql
{
@ -65,22 +64,20 @@ namespace WSql
/*! \internal - dont use this.*/
bool isForeignKeyDefinition ( std::string sql )
{
boost::to_upper ( sql );
return ( sql.find ( "FOREIGN KEY" ) != std::string::npos );
return ( WSqlDataType::iFind (sql, "FOREIGN KEY" ) != std::string::npos );
}
/*! \internal - dont use this.*/
bool isIndexDefinition ( std::string sql )
{
boost::to_upper ( sql );
return ( boost::istarts_with ( sql, "UNIQUE" )
|| boost::istarts_with ( sql, "PRIMARY KEY" )
|| boost::istarts_with ( sql, "INDEX" )
|| boost::istarts_with ( sql, "CREATE INDEX" )
|| boost::istarts_with ( sql, "CREATE PRIMARY KEY" )
|| boost::istarts_with ( sql, "CREATE UNIQUE" )
|| boost::istarts_with ( sql, "CONSTRAINT INDEX" )
|| boost::istarts_with ( sql, "CONSTRAINT UNIQUE" )
|| boost::istarts_with ( sql, "CONSTRAINT PRIMARY KEY" )
return ( WSqlDataType::iFind(sql, "UNIQUE" ) == 0
|| WSqlDataType::iFind(sql, "PRIMARY KEY" ) == 0
|| WSqlDataType::iFind(sql, "INDEX" ) == 0
|| WSqlDataType::iFind(sql, "CREATE INDEX" ) == 0
|| WSqlDataType::iFind(sql, "CREATE PRIMARY KEY" ) == 0
|| WSqlDataType::iFind(sql, "CREATE UNIQUE" ) == 0
|| WSqlDataType::iFind(sql, "CONSTRAINT INDEX" ) == 0
|| WSqlDataType::iFind(sql, "CONSTRAINT UNIQUE" ) == 0
|| WSqlDataType::iFind(sql, "CONSTRAINT PRIMARY KEY" ) == 0
);
}
@ -94,9 +91,9 @@ WSqlForeignKey createForeignKey ( std::string sqldef )
while ( pos < sz ) //sqlite is case insensitive ..
sqldef[pos] = tolower ( sqldef[pos++] );
// std::cerr << "FK def: *" << sqldef << "*" << std::endl;
if(LOCALDEBUG) std::cout << "FK def: *" << sqldef << "*" << std::endl;
//constraint "fk_comment_post" foreign key ("post_id") references "post" ("id")
boost::trim_if ( sqldef, boost::is_any_of ( "\n\t " ) );
WSqlDataType::trim ( sqldef );
size_t start = sqldef.find_first_of ( "(" );
size_t end = sqldef.find_first_of ( ")", start );
@ -104,8 +101,8 @@ WSqlForeignKey createForeignKey ( std::string sqldef )
if ( std::string::npos != start && std::string::npos != end )
{
std::string tmp = sqldef.substr ( start + 1, ( end - start ) - 1 );
boost::trim_if ( tmp, boost::is_any_of ( " '\"[]" ) );
// std::cerr << " column: trimmed *" << tmp << "*" << std::endl;
WSqlDataType::trim( tmp, std::string(" '\"[]") );
if(LOCALDEBUG) std::cerr << " column: trimmed *" << tmp << "*" << std::endl;
start = sqldef.find_first_of ( "(", end );
end = sqldef.find_first_of ( ")", start );
fkToReturn.setColumnName ( tmp );
@ -113,8 +110,8 @@ WSqlForeignKey createForeignKey ( std::string sqldef )
if ( std::string::npos != start && std::string::npos != end )
{
std::string tmp2 = sqldef.substr ( start + 1, ( end - start ) - 1 );
boost::trim_if ( tmp2, boost::is_any_of ( " '\"[]" ) );
// std::cerr << "target column: trimmed *" << tmp2 << "*" << std::endl;
WSqlDataType::trim( tmp2, std::string(" '\"[]") );
if(LOCALDEBUG) std::cerr << "target column: trimmed *" << tmp2 << "*" << std::endl;
fkToReturn.setReferencedColumnName ( tmp2 );
}
}
@ -128,8 +125,8 @@ WSqlForeignKey createForeignKey ( std::string sqldef )
start += 10;
end = sqldef.find ( "(", start );
std::string tmp3 = sqldef.substr ( start, ( end - start ) - 1 );
boost::trim_if ( tmp3, boost::is_any_of ( " '\"[]" ) );
// std::cerr << "== references table: trimmed *" << tmp3 << "*" << std::endl;
WSqlDataType::trim(tmp3, std::string(" '\"[]"));
if(LOCALDEBUG) std::cerr << "== references table: trimmed *" << tmp3 << "*" << std::endl;
fkToReturn.setReferencedTableName ( tmp3 );
}
else
@ -142,8 +139,8 @@ WSqlForeignKey createForeignKey ( std::string sqldef )
start = sqldef.find_first_of ( "'\"" );
end = sqldef.find_first_of ( "'\"", start + 1 );
std::string tmp4 = sqldef.substr ( start, ( end - start ) - 1 );
boost::trim_if ( tmp4, boost::is_any_of ( " '\"[]" ) );
// std::cerr << "constraint name: trimmed *" << tmp4 << "*" << std::endl;
WSqlDataType::trim(tmp4, std::string(" '\"[]"));
if(LOCALDEBUG) std::cerr << "constraint name: trimmed *" << tmp4 << "*" << std::endl;
fkToReturn.setKeyName ( tmp4 );
}
@ -166,10 +163,10 @@ void splitIntoDefinitions ( std::vector<std::string> &vecToFill, std::string sql
if ( sql[pos] == ',' )
{
std::string part = sql.substr ( 0, pos );
boost::trim ( part );
WSqlDataType::trim(part);
vecToFill.push_back ( part );
sql.erase ( 0, pos + 1 );
boost::trim ( sql );
WSqlDataType::trim(sql);
max = sql.size();
pos = 0;
}
@ -185,8 +182,7 @@ void splitIntoDefinitions ( std::vector<std::string> &vecToFill, std::string sql
*/
WSqlDataType::Type WSqliteDriver::sqlite3TypeToWSqlType ( std::string tname ) const
{
boost::to_lower ( tname );
WSqlDataType::toLower(tname);
//note - this includes "bigint"; that would be stored as an "integer" in sqlite
if ( tname.find ( "int" ) != std::string::npos )
return WSqlDataType::INT;
@ -464,8 +460,7 @@ WSqlTable WSqliteDriver::tableMetaData ( const std::string &tableName )
return tblToReturn;
//parse and store info from the create statement ..
std::string sqlToParse = fetchTableCreateStatement ( tableName );
parseSchema ( sqlToParse );
parseSchema ( fetchTableCreateStatement ( tableName ) );
sqlite3_stmt *statement;
std::string col_descript;
@ -545,21 +540,20 @@ bool WSqliteDriver::columnIsAutoIncrement ( const std::string &columnname ) cons
return false;
std::string col_definition = it->second;
boost::to_lower ( col_definition );
WSqlDataType::toLower ( col_definition );
if ( col_definition.find ( "autoincrement" ) != std::string::npos
|| col_definition.find ( "auto_increment" ) != std::string::npos
)
|| col_definition.find ( "auto_increment" ) != std::string::npos )
return true;
return false;
}
/*! \internal - dont use this.*/
std::string WSqliteDriver::fetchTableCreateStatement ( const std::string &tablename ) const
std::vector< std::string > WSqliteDriver::fetchTableCreateStatement ( const std::string &tablename ) const
{
sqlite3_stmt *statement;
std::string sqlToReturn;
std::vector< std::string > vecToReturn;
std::string sql ( "SELECT sql from sqlite_master WHERE tbl_name = '" );
sql.append ( tablename );
sql.append ( "';" );
@ -571,24 +565,17 @@ std::string WSqliteDriver::fetchTableCreateStatement ( const std::string &tablen
const unsigned char *safety = sqlite3_column_text ( statement, 0 );
if ( safety && SQLITE_ERROR != *safety )
{
sqlToReturn.append ( ( char * ) safety );
sqlToReturn.append ( ROWENDTAG );
}
vecToReturn.push_back(std::string( (char*) safety ) );
else
{
//this is quite weird - empty rows ..
std::cerr << "fetchTableCreateStatement - sqlite weirdness: " << tablename << std::endl;
//std::cerr << sqlite3_errmsg( _objSqlite ) << std::endl;
}
//??usleep();
}
sqlite3_finalize ( statement );
}
return sqlToReturn;
return vecToReturn;
}
/*! \internal - dont use this.*/
@ -604,35 +591,41 @@ std::string WSqliteDriver::extractStatement ( const std::string &sqlToParse, con
return sqlToReturn;
sqlToReturn = sqlToParse.substr ( pos_start + 1, pos_end - ( pos_start + 1 ) );
// std::cerr << "extract Statement sqlToReturn: " << sqlToReturn << std::endl;
if(LOCALDEBUG) std::cout << "extract Statement sqlToReturn: " << sqlToReturn << std::endl;
return sqlToReturn;
}
//eh, not graceful but mostly works
/*! \internal - dont use this. This parses the create statement for a table ..*/
void WSqliteDriver::parseSchema ( std::string &sql )
{
void WSqliteDriver::parseSchema ( std::vector<std::string> statements )
{
typedef std::vector<std::string>::iterator Iter;
std::vector<std::string> statements; //complete statements in parens
std::vector<std::string> definitions; //comma separated column defs
std::vector<std::string> columns; //stored split off columns, constraints, indices
std::vector<std::string> indices;
boost::trim_if ( sql, boost::is_any_of ( "-*" ) );
boost::split ( statements, sql, boost::is_any_of ( "-*" ), boost::token_compress_on );
Iter stmt_it = statements.begin();
for ( ; stmt_it != statements.end(); ++stmt_it )
{
std::string cur_statement = *stmt_it;
boost::trim ( cur_statement );
if(LOCALDEBUG) std::cout << "************** STATEMENT (FULL) ***************" << std::endl
<< "cur_statement: *" << cur_statement << "*" << std::endl;
WSqlDataType::trim(cur_statement);
if(LOCALDEBUG) std::cout << "************** STATEMENT (TRIMMED) ***************" << std::endl
<< "cur_statement: " << cur_statement << std::endl;
//get statement between parens - but only for the first "CREATE";
//thus avoid extracting primary key definitions like (x_id,y_id)
if ( boost::istarts_with ( cur_statement, "CREATE TABLE" ) )
if ( WSqlDataType::iFind ( cur_statement, "CREATE TABLE" ) == 0 )
cur_statement = extractStatement ( cur_statement );
if (LOCALDEBUG) std::cout << "************** STATEMENT (extracted) ***************" << std::endl
<< "cur_statement: " << cur_statement << std::endl;
//cut up by line -comma separated column definitions
splitIntoDefinitions ( definitions, cur_statement );
Iter defs_it = definitions.begin();
@ -640,20 +633,23 @@ void WSqliteDriver::parseSchema ( std::string &sql )
for ( ; defs_it != definitions.end(); ++defs_it )
{
std::string cur_definition = *defs_it;
boost::trim ( cur_definition );
WSqlDataType::trim(cur_definition);
if (LOCALDEBUG) std::cout << "************** CURRENT DEFINITION ***************" << std::endl
<< "cur_definition: " << cur_definition << std::endl;
if ( isForeignKeyDefinition ( cur_definition ) )
{
/* std::cout << "cur_definition: " << cur_definition << std::endl
<< "************** FOREIGN KEY ***************" << std::endl;*/
if (LOCALDEBUG) std::cout << "************** FOREIGN KEY ***************" << std::endl
<< "cur_definition: " << cur_definition << std::endl;
WSqlForeignKey fk = createForeignKey ( cur_definition );
_foreign_keys.push_back ( fk );
}
else
if ( isIndexDefinition ( cur_definition ) )
{
/* std::cout << "cur_definition: " << cur_definition << std::endl
<< "************** INDEX ***************" << std::endl;*/
if (LOCALDEBUG) std::cout << "************** INDEX ***************" << std::endl
<< "cur_definition: " << cur_definition << std::endl;
indices.push_back ( cur_definition );
}
else
@ -680,9 +676,10 @@ void WSqliteDriver::mapColumns ( std::vector<std::string> &vecColumnDefinitions
if ( pos != std::string::npos )
{
std::string cur_colname = cur_definition.substr ( 0, pos );
boost::trim_if ( cur_colname, boost::is_any_of ( "\n\t []`'\"" ) );
WSqlDataType::trim( cur_colname, std::string( "\n\t []`'\"" ) );
_columns_map[cur_colname] = cur_definition.erase ( 0, pos + 1 );
}
}
}
}//namespace WSql

+ 4
- 2
src/sql/drivers/wsqlitedriver.h View File

@ -52,11 +52,13 @@ class WSqliteDriver : public WSqlDriver
WSqlDataType::Type sqlite3TypeToWSqlType( std::string tname) const;
WSqlDataType::Type sqlite3TypeToWSqlType(int dtype)const;
std::string fetchTableCreateStatement(const std::string& tablename)const;
// std::string fetchTableCreateStatement(const std::string& tablename)const;
std::vector<std::string> fetchTableCreateStatement(const std::string& tablename)const;
std::string extractStatement(const std::string& sql, const char start='(', const char end=')') const;
void parseSchema( std::string& sql);
void parseSchema( std::vector< std::string > sql );
bool columnIsAutoIncrement(const std::string& columnname)const;
void mapColumns(std::vector<std::string> &column_definitions);
void sql ( const char *arg1 );
//temporary buffers; cleared after each metatable init ..
std::map<std::string, std::string> _columns_map;
std::vector<WSqlForeignKey> _foreign_keys;


+ 361
- 225
src/sql/wsqldatatype.h View File

@ -21,235 +21,371 @@
#define WSQLDATATYPE_H
#include <string>
#include <boost/algorithm/string.hpp>
#include <iostream>
#include <algorithm>
namespace WSql {
/*! \namespace WSql::WSqlDataType
* \brief WSqlDataType namespace - Utilities and definitions of supported data types
*
* This is a container for type flags and convenience functions for the supported
* SQL datatypes. In this namespace are definitions for datatypes, facilities for
* translating these to and from other naming conventions as well as facilities for
* generating transformations of datatypes into various strings used in the ORM
* generating classes.
*
* This provides a central utility namespace for transformations and definitions
* related to data types as defined in DBMSs and C++, including ORM mapping
* of table names to class names, column names and types to variable names and
* types, etc.
*
* Below is a list the ANSI SQl standard types supported by WSQL - these will be
* mapped to native C++ data types in ORM class generation. For example a
* TINYINT column will declared as a member of type "short", a VARCHAR or
* TEXT as type std::string, a DECIMAL to a double, etc. Implementers of drivers
* can use this as a guide for translating types for a particular DBMS.
*
* Writers of drivers must translate any proprietary or other data types specific to the
* DBMS of the driver to these types. Most DBMS metadata is returned in a string identifier
* of one of these types and can usually be mapped conveniently by using the functions
* toString(type) or toType(string).
*
* See the following for more information on the specific data types:
* \include datatypes.txt
*
* \ingroup WSql
*
*/
namespace WSqlDataType {
/*!\enum Type - flags representing data types
* The types currently supported - adjust this if/when new strings
* are added.
*/
enum Type {
NOTYPE = 0,
TINYINT,
SMALLINT,
MEDIUMINT,
INT,
BIGINT,
FLOAT,
DOUBLE,
DECIMAL,
DATE,
DATETIME,
YEAR,
TIME,
TIMESTAMP,
TIMESTAMPTZ,
CHAR,
VARCHAR,
NCHAR,
NVARCHAR,
TEXT,
TINYTEXT,
MEDIUMTEXT,
LONGTEXT,
ENUM,
SET,
BLOB
};
/*! \a TypeNames - array of strings representing data types
* The types currently supported in handy string format - adjust this if/when new strings
* are added.
*/
static const char * const TypeNames[] ={
"NOTYPE",
"TINYINT",
"SMALLINT",
"MEDIUMINT",
"INT",
"BIGINT",
"FLOAT",
"DOUBLE",
"DECIMAL",
"DATE",
"DATETIME",
"TIME",
"YEAR",
"TIMESTAMP",
"TIMESTAMPTZ",
"CHAR",
"VARCHAR",
"NCHAR",
"NVARCHAR",
"TEXT",
"TINYTEXT",
"MEDIUMTEXT",
"LONGTEXT",
"ENUM",
"SET",
"BLOB"
};
//! Number of types supported. \note Change this if you add types!!
static const unsigned short number_of_datatypes = 26;
//! Covenience function - returns a string for the type
static std::string toString(Type type)
{
std::string strToReturn;
if (type < 0 || type > (number_of_datatypes - 1))
strToReturn = "INVALID";
else
strToReturn = TypeNames[type]; //careful .. dont mess this up, add types and name in order.
return strToReturn;
}
//! Convenience function - translates a string to a type flag
static Type toType(std::string name)
{
boost::to_upper(name);
boost::trim(name);
//!\todo intelligence - support more type names, translate to ours ..
int i = 0;
for ( ; i < number_of_datatypes; ++i)
if ( name.compare(TypeNames[i]) == 0 )
return static_cast<Type>(i);
return static_cast<Type>(0);//NOTYPE
}
//! Attempt to return a singularized form of \a name
static std::string toSingular(const std::string& name)
{
std::string strToReturn = name;
size_t size = strToReturn.size();
if(!size)
return strToReturn;
if('s' == strToReturn[size-1] && 's' != strToReturn[size-2])//dont fix dress, address ..
{
strToReturn.erase(size-1);
if('e' == strToReturn[size-2])
{//eg. Cities to City ..
if( 'i' == strToReturn[size-3])
{
strToReturn.erase(size-3);
strToReturn.append("y");
}else if( 'h' == strToReturn[size-3])//eg. bushes .. might need fixing ..
strToReturn.erase(size-2);
}
return strToReturn;
}
/*!\todo add intelligence: std::string cmp = boost::to_lower_copy(strToReturn);
* if(cmp.compare("people") .. or some such ..*/
return strToReturn;
}
//! Attempt to return a pluralized form of \a name
static std::string toPlural(const std::string& name)
{
std::string strToReturn = name;
size_t sz = name.size();
if(sz && 's' == strToReturn[sz - 1])
strToReturn.append("es");
else if(sz > 2 && 'y' == strToReturn[sz - 1]
&& 'o' != strToReturn[sz - 2]
&& 'a' != strToReturn[sz - 2])
{
strToReturn.erase(sz - 1);
strToReturn.append("ies");
}
else
strToReturn.append("s");
//!\todo make me a little smarter .. people, fish, sheep etc.
return strToReturn;
}
/*! \brief Returns a suitable variable name transformed from \a columnname
*
* This translates a column name as defined in a database to a variable name.
* A column name should have the format "name" or "some_name", eg. "user" or
* "order_id" - these will be rendered as "user" and "orderId". Note that in contrast
* to tableNameToClass() the first letter is not capitalized and plural are left plural.
*
* \param std::string - columnname - the name to transform
* \retval std::string - a string suitable for a variable name
*/
static std::string columnNameToVariable(const std::string& columnname)
{
std::string strToReturn = columnname;
size_t pos = 0;
pos = strToReturn.find('_');
while(pos != std::string::npos)
{
strToReturn.erase(pos,1);
if((pos + 1) < strToReturn.size())
strToReturn[pos]= toupper(strToReturn[pos]);
pos = strToReturn.find('_');
}
return strToReturn;
}
/*! \brief Returns a transformed table name as a class name
*
* This translates a table name as defined in a database to a class name.
* A table name should have the format "names" or "some_names", eg. "users" or
* "phone_numbers" - these will be rendered as "User" and "PhoneNumber".
* Note that in keeping with accepted convention the table names are plural;
* these will also be singularized; this results in the table "orders" being
* rendered as "Order" and "order_items" as "OrderItem"
*
* \note This assumes that tables are named according to convention as
* found also in Rails - tablenames without this convention are left as
* is - they will be rendered but may cause problems with class instance
* declarations in generated output.
*
* \param std::string tablename - the name to transform
* \retval std::string - a string suitable for a class name
*/
static std::string tableNameToClass(const std::string& tablename)
{
std::string strToReturn = toSingular(tablename);
strToReturn[0] = toupper(strToReturn[0]);
return columnNameToVariable(strToReturn);
}
namespace WSql
{
/*! \namespace WSql::WSqlDataType
* \brief WSqlDataType namespace - Utilities and definitions of supported data types
*
* This is a container for type flags and convenience functions for the supported
* SQL datatypes. In this namespace are definitions for datatypes, facilities for
* translating these to and from other naming conventions as well as facilities for
* generating transformations of datatypes into various strings used in the ORM
* generating classes.
*
* This provides a central utility namespace for transformations and definitions
* related to data types as defined in DBMSs and C++, including ORM mapping
* of table names to class names, column names and types to variable names and
* types, etc.
*
* Below is a list the ANSI SQl standard types supported by WSQL - these will be
* mapped to native C++ data types in ORM class generation. For example a
* TINYINT column will declared as a member of type "short", a VARCHAR or
* TEXT as type std::string, a DECIMAL to a double, etc. Implementers of drivers
* can use this as a guide for translating types for a particular DBMS.
*
* Writers of drivers must translate any proprietary or other data types specific to the
* DBMS of the driver to these types. Most DBMS metadata is returned in a string identifier
* of one of these types and can usually be mapped conveniently by using the functions
* toString(type) or toType(string).
*
* See the following for more information on the specific data types:
* \include datatypes.txt
*
* \ingroup WSql
*
*/
namespace WSqlDataType
{
/*!\enum Type - flags representing data types
* The types currently supported - adjust this if/when new strings
* are added.
*/
enum Type
{
NOTYPE = 0,
TINYINT,
SMALLINT,
MEDIUMINT,
INT,
BIGINT,
FLOAT,
DOUBLE,
DECIMAL,
DATE,
DATETIME,
YEAR,
TIME,
TIMESTAMP,
TIMESTAMPTZ,
CHAR,
VARCHAR,
NCHAR,
NVARCHAR,
TEXT,
TINYTEXT,
MEDIUMTEXT,
LONGTEXT,
ENUM,
SET,
BLOB
};
/*! \a TypeNames - array of strings representing data types
* The types currently supported in handy string format - adjust this if/when new strings
* are added.
*/
static const char *const TypeNames[] =
{
"NOTYPE",
"TINYINT",
"SMALLINT",
"MEDIUMINT",
"INT",
"BIGINT",
"FLOAT",
"DOUBLE",
"DECIMAL",
"DATE",
"DATETIME",
"TIME",
"YEAR",
"TIMESTAMP",
"TIMESTAMPTZ",
"CHAR",
"VARCHAR",
"NCHAR",
"NVARCHAR",
"TEXT",
"TINYTEXT",
"MEDIUMTEXT",
"LONGTEXT",
"ENUM",
"SET",
"BLOB"
};
//! Number of types supported. \note Change this if you add types!!
static const unsigned short number_of_datatypes = 26;
/*! Transform a string to all upper case
*/
static void toUpper ( std::string &s )
{
std::transform ( s.begin(), s.end(), s.begin(), ::toupper );
}
/*! Transform a string to all lower case
*/
static void toLower ( std::string &s )
{
std::transform ( s.begin(), s.end(), s.begin(), ::tolower );
}
/*! Case insensitive find string in string
*/
static size_t iFind ( std::string haystack, std::string needle, size_t pos = 0 )
{
toUpper(haystack);
toUpper(needle);
return haystack.find ( needle, pos );
}
/*! Trim whitespace from beginning of string ..
*/
static void lTrim ( std::string &s )
{
size_t pos = 0;
size_t len = s.length();
while(pos < len && isspace( s[pos] ) )
pos++;
if(pos && pos < len)
s.erase(0, pos);
}
/*! Trim whitespace from end of string ..
*/
static void rTrim ( std::string &s )
{
size_t pos = s.length() - 1;
if(!pos)//ingnore empty strings
return;
while( isspace( s[pos] ) )
pos--;
if(pos != s.length() -1)
s.erase(pos + 1);
}
/*! Trim whitespace from string ..
*/
static void trim ( std::string &s )
{
lTrim(s);
rTrim(s);
}
/*! Trim chars in findme from beginning of string s..
*/
static void lTrim ( std::string &s, std::string removeme )
{
if(removeme.empty())
return lTrim(s);
size_t pos = 0;
size_t len = s.length();
size_t removeme_len = removeme.length();
for(int i = 0; i < removeme_len; i++)
for(pos = 0; pos < len; pos++)
{
if( s[pos] != removeme[i] )
{
if(pos)
{
s.erase(0, pos);
len = s.length();
}
break;
}
}
}
/*! Trim chars in findme from end of string s..
*/
static void rTrim ( std::string &s, std::string removeme )
{
if(removeme.empty())
return rTrim(s);
size_t pos = 0;
size_t len = s.length();
size_t removeme_len = removeme.length();
for(int i = 0; i < removeme_len; i++)
for(pos = len; pos; )
{
if( s[--pos] != removeme[i] )
{
if(pos != len - 1 )
{
s.erase(pos + 1);
len = s.length();
}
break;
}
}
}
/*! Trim chars in removeme from string ..
*/
static void trim ( std::string &s, std::string removeme )
{
lTrim(s, removeme);
rTrim(s, removeme);
}
//! Covenience function - returns a string for the type
static std::string toString ( Type type )
{
std::string strToReturn;
if ( type < 0 || type > ( number_of_datatypes - 1 ) )
strToReturn = "INVALID";
else
strToReturn = TypeNames[type]; //careful .. dont mess this up, add types and name in order.
return strToReturn;
}
//! Convenience function - translates a string to a type flag
static Type toType ( std::string name )
{
WSqlDataType::toUpper ( name );
WSqlDataType::trim ( name );
//!\todo intelligence - support more type names, translate to ours ..
int i = 0;
for ( ; i < number_of_datatypes; ++i )
if ( name.compare ( TypeNames[i] ) == 0 )
return static_cast<Type> ( i );
return static_cast<Type> ( 0 ); //NOTYPE
}
//! Attempt to return a singularized form of \a name
static std::string toSingular ( const std::string &name )
{
std::string strToReturn = name;
size_t size = strToReturn.size();
if ( !size )
return strToReturn;
if ( 's' == strToReturn[size - 1] && 's' != strToReturn[size - 2] ) //dont fix dress, address ..
{
strToReturn.erase ( size - 1 );
if ( 'e' == strToReturn[size - 2] )
{
//eg. Cities to City ..
if ( 'i' == strToReturn[size - 3] )
{
strToReturn.erase ( size - 3 );
strToReturn.append ( "y" );
}
else
if ( 'h' == strToReturn[size - 3] ) //eg. bushes .. might need fixing ..
strToReturn.erase ( size - 2 );
}
return strToReturn;
}
/*!\todo add intelligence: std::string cmp = to_lower(strToReturn);
* if(cmp.compare("people") .. or some such ..*/
return strToReturn;
}
//! Attempt to return a pluralized form of \a name
static std::string toPlural ( const std::string &name )
{
std::string strToReturn = name;
size_t sz = name.size();
if ( sz && 's' == strToReturn[sz - 1] )
strToReturn.append ( "es" );
else
if ( sz > 2 && 'y' == strToReturn[sz - 1]
&& 'o' != strToReturn[sz - 2]
&& 'a' != strToReturn[sz - 2] )
{
strToReturn.erase ( sz - 1 );
strToReturn.append ( "ies" );
}
else
strToReturn.append ( "s" );
//!\todo make me a little smarter .. people, fish, sheep etc.
return strToReturn;
}
/*! \brief Returns a suitable variable name transformed from \a columnname
*
* This translates a column name as defined in a database to a variable name.
* A column name should have the format "name" or "some_name", eg. "user" or
* "order_id" - these will be rendered as "user" and "orderId". Note that in contrast
* to tableNameToClass() the first letter is not capitalized and plural are left plural.
*
* \param std::string - columnname - the name to transform
* \retval std::string - a string suitable for a variable name
*/
static std::string columnNameToVariable ( const std::string &columnname )
{
std::string strToReturn = columnname;
size_t pos = 0;
pos = strToReturn.find ( '_' );
while ( pos != std::string::npos )
{
strToReturn.erase ( pos, 1 );
if ( ( pos + 1 ) < strToReturn.size() )
strToReturn[pos] = toupper ( strToReturn[pos] );
pos = strToReturn.find ( '_' );
}
return strToReturn;
}
/*! \brief Returns a transformed table name as a class name
*
* This translates a table name as defined in a database to a class name.
* A table name should have the format "names" or "some_names", eg. "users" or
* "phone_numbers" - these will be rendered as "User" and "PhoneNumber".
* Note that in keeping with accepted convention the table names are plural;
* these will also be singularized; this results in the table "orders" being
* rendered as "Order" and "order_items" as "OrderItem"
*
* \note This assumes that tables are named according to convention as
* found also in Rails - tablenames without this convention are left as
* is - they will be rendered but may cause problems with class instance
* declarations in generated output.
*
* \param std::string tablename - the name to transform
* \retval std::string - a string suitable for a class name
*/
static std::string tableNameToClass ( const std::string &tablename )
{
std::string strToReturn = toSingular ( tablename );
strToReturn[0] = toupper ( strToReturn[0] );
return columnNameToVariable ( strToReturn );
}
} //namespace WSqlDataType
}// namespace WSql
#endif // WSQLDATATYPE_H

+ 3
- 4
src/sql/wsqldatum.cpp View File

@ -28,10 +28,9 @@ namespace WSql
* be instatiated to hold the types supported by WSqlDataType. It includes methods for conversion
* to various types on demand.
*
* \todo - resolve: whether to use boost::any instead of string for internal storage .. or, revert to the
* previous void pointer version? why? unsure of data integrity, eg. blob to string, longlong, etc .. contrary
* to initial assumptions, some dbms may return types in the api (sqlite?) rather than string reps thereof.
* regardless, blob is another issue, may be huge .. or streamable .. think on this.
* \todo - resolve: revert to the previous void pointer version? why? unsure of data integrity, eg. blob to string, longlong,
* etc .. contrary to initial assumptions, some dbms may return types in the api (sqlite?) rather than string reps thereof.
* regardless, blob is another issue
*
* \ingroup WSql
* \sa WSqlDataType WSqlField WSqlColumn


+ 39
- 45
src/sql/wsqldatum.h View File

@ -20,7 +20,7 @@
#define WSQLDATUM_H
#include <string>
#include <boost/lexical_cast.hpp>
#include <sstream>
namespace WSql
{
@ -28,53 +28,47 @@ namespace WSql
class WSqlDatum
{
public:
WSqlDatum();
WSqlDatum( const WSqlDatum& other );
virtual ~WSqlDatum();
virtual WSqlDatum& operator=( const WSqlDatum& other );
virtual bool operator==( const WSqlDatum& other ) const;
inline bool operator!=( const WSqlDatum &other ) const {
return !operator==( other );
}
template <typename T> void setData( const T t ) {
try {
_data = boost::lexical_cast<std::string>( t );
}
catch ( boost::bad_lexical_cast &e ) {
//!\todo handle exception
}
};
template <typename T> T data()const {
try {
return boost::lexical_cast<T>( _data );
}
catch ( boost::bad_lexical_cast &e ) {
//!\todo handle exception
//well, gotta do _something ..
return T();
}
};
short toShort()const {return data<short>(); }
int toInt()const {return data<int>(); }
long toLong()const {return data<long>(); }
float toFloat()const {return data<float>(); }
double toDouble()const {return data<double>(); }
unsigned short toUShort()const {return data<unsigned short>(); }
unsigned int toUInt()const {return data<unsigned int>(); }
unsigned long toULong()const {return data<unsigned long>(); }
std::string toString()const {return data<std::string>(); }
void clear();
private:
std::string _data;
public:
WSqlDatum();
WSqlDatum( const WSqlDatum& other );
virtual ~WSqlDatum();
virtual WSqlDatum& operator=( const WSqlDatum& other );
virtual bool operator==( const WSqlDatum& other ) const;
inline bool operator!=( const WSqlDatum &other ) const {
return !operator==( other );
}
template <typename T> void setData( const T t ) {
_converter << t;
_data = _converter.str();
};
template <typename T> T data(){
T result;
_converter << _data;
_converter >> result;
return result;
};
short toShort() {return data<short>(); }
int toInt() {return data<int>(); }
long toLong() {return data<long>(); }
float toFloat() {return data<float>(); }
double toDouble() {return data<double>(); }
unsigned short toUShort() {return data<unsigned short>(); }
unsigned int toUInt() {return data<unsigned int>(); }
unsigned long toULong() {return data<unsigned long>(); }
std::string toString() {return data<std::string>(); }
void clear();
private:
std::string _data;
std::stringstream _converter;
};
}//namespace WSql
#endif // WSQLDATUM_H

+ 1
- 3
src/sql/wsqlfield.cpp View File

@ -66,9 +66,7 @@ namespace WSql
* all setting the data with the supported types. Note that the types are coverted to string
* and stored in the WSqlDatum.
*
* \todo maybe should implement deep copy of _data ..? also, missing copy ctor .. this only
* applies if WSqlDatum changes the internal storage from string to boost::any ..
*
* \todo maybe should implement deep copy of _data ..?
*
* \ingroup WSql
* \sa data() name() columnName() setData()


Loading…
Cancel
Save