Containerization

More likely than not, the application keeps its data in some kind of container, perhaps a std::vector or std::list. Populating and saving them with an ordinary C library can be a royal pain in the tucus.

The simplest way to fill and save a container uses dbstream::read and dbstream::write. [1] The technique relies on read & write methods in the container's value_type class to implement the logic to write/read one row to/from the database. In this example, the object's write method is general enough that it can also be used to write to a std::iostream.

Example 2-2. Container Example

		class example_row
		{
			int i;
			double d;
			std::string s;
		public:
			template <typename OS>
				OS& read( OS& os ) {
				os 	>> c("t") >> i
					>> c("r") >> d
					>> c("s") >> s;
				return os;
			}
			template <typename OS>
				OS& write( OS& os ) const {
				os 	<< i
					<< d
					<< s << endl;
				return os;
			}
		};

		std::deque<example_row> rowset;

		dbstream<dbstatus> db(provider, username, password);
		db.open( servername, catalog );	
		if( !db )
			throw db.status();

		/* (Table T was created and populated in the first example.) */
		
		q = "select * from T ";
		db << q;
		if( !db ) {
			throw db.status();
		}

		db.read( rowset );
		
		db.table("T");
		db.write( rowset );
		if( !db ) {
			throw db.status();
		}

		db.close();
		
	

Elements of Filling and Saving a Container

Container's value_type

class example_row
{
	int i;
	double d;
	std::string s;
public:
	template <typename OS>
		OS& read( OS& os ) {
		os 	>> c("t") >> i
			>> c("r") >> d
			>> c("s") >> s;
		return os;
	}
	template <typename OS>
		OS& write( OS& os ) const {
		os 	<< i
			<< d
			<< s << endl;
		return os;
	}
};

std::deque<example_row> rowset; 

Something, somewhere, somehow has to define how the container's data map onto a row in the database. In this paradigm, that's done by the container element class.

The mapping function must be called read and write, and they must take a dbstream as their only argument.

Read into a Container

db.read( rowset );			

The dbstream::read function accepts any kind of container for which iterators and push_back are defined. Perhaps the code is easier to understand than the description, so here is the definition of dbstream::read:

template <typename CONTAINER>
dbstream<STATUS> 
read( CONTAINER& container ) 
{
	while( status() && !status().eof() ) {
		CHECK_PROVIDER(); 
		typename CONTAINER::value_type element;
		element.read( *this );
		container.push_back( element );
		pprovider->next_row();
	}
	return *this;
} 

Although there's some implementation detail here, it's not important to understanding how the function works. For every row in the stream, the container's value_type::read function is called, and the (now populated) object is appended to the container.

Write a Container to the database

db.table("T");
db.write( rowset );			

Open the table and write the container. The logic is the mirror of reading.

Notes

[1]

A more general method, using iterators, is planned but not yet implemented.