From f64b66b7a079aa4aae8c60b4af9c7b6864d72e2c Mon Sep 17 00:00:00 2001
From: randomdan <randomdan@localhost>
Date: Wed, 15 Dec 2010 01:54:01 +0000
Subject: Add support for non-default Sql merge inserter and row numbers in row
 sets and functional row properties in variables and custom column sub/super
 sets in views and isNull by column name Fix somee constnesses

---
 project2/fileRows.cpp     |  8 +++++++
 project2/fileRows.h       |  1 +
 project2/perRowValues.cpp |  9 +++++++-
 project2/perRowValues.h   |  5 ++++
 project2/sqlMergeTask.cpp | 32 +++++++++++++++++++++++++
 project2/sqlRows.cpp      |  8 +++++++
 project2/sqlRows.h        |  1 +
 project2/urlRows.cpp      |  9 ++++++++
 project2/urlRows.h        |  1 +
 project2/variables.cpp    | 59 ++++++++++++++++++++++++++++++++++++++++++++---
 project2/variables.h      |  8 +++++--
 project2/view.cpp         | 23 ++++++++++++++----
 project2/view.h           |  4 ++++
 project2/xmlRows.cpp      |  9 ++++++++
 project2/xmlRows.h        |  1 +
 15 files changed, 168 insertions(+), 10 deletions(-)

diff --git a/project2/fileRows.cpp b/project2/fileRows.cpp
index 2f4d6cf..3a16ed6 100644
--- a/project2/fileRows.cpp
+++ b/project2/fileRows.cpp
@@ -51,6 +51,7 @@ _FileRows::getColumnName(unsigned int col) const
 void
 _FileRows::execute(const RowProcessor * rp) const
 {
+	rowNum = 0;
 	FileStarChannel c(doOpen());
 	c.set_encoding(encoding);
 	c.set_line_term(newline);
@@ -105,6 +106,7 @@ _FileRows::execute(const RowProcessor * rp) const
 				curCol++;
 			}
 			rp->rowReady();
+			rowNum += 1;
 		}
 		values.clear();
 	}
@@ -122,6 +124,12 @@ _FileRows::isNull(unsigned int col) const
 	return false;
 }
 
+bool
+_FileRows::isNull(const Glib::ustring & col) const
+{
+	return false;
+}
+
 const Glib::ustring &
 _FileRows::getCurrentValue(const Glib::ustring & id) const
 {
diff --git a/project2/fileRows.h b/project2/fileRows.h
index 60916ac..899205c 100644
--- a/project2/fileRows.h
+++ b/project2/fileRows.h
@@ -24,6 +24,7 @@ class _FileRows : public PerRowValues {
 		const Glib::ustring & getCurrentValue(const Glib::ustring & id) const;
 		const Glib::ustring & getCurrentValue(unsigned int col) const;
 		bool isNull(unsigned int col) const;
+		bool isNull(const Glib::ustring & id) const;
 
 		typedef std::set<gunichar> CharSet;
 		const Variable path;
diff --git a/project2/perRowValues.cpp b/project2/perRowValues.cpp
index 82b46bc..4666735 100644
--- a/project2/perRowValues.cpp
+++ b/project2/perRowValues.cpp
@@ -7,7 +7,8 @@
 PerRowValues::RowValuesStack PerRowValues::stack;
 
 PerRowValues::PerRowValues(const xmlpp::Element * p) :
-	_SourceObject(p)
+	_SourceObject(p),
+	rowNum(-1)
 {
 }
 
@@ -51,6 +52,12 @@ PerRowValues::rowChanged() const
 	}
 }
 
+unsigned int
+PerRowValues::getRowNum() const
+{
+	return rowNum;
+}
+
 RowUser::RowUser()
 {
 }
diff --git a/project2/perRowValues.h b/project2/perRowValues.h
index abd1507..52b6024 100644
--- a/project2/perRowValues.h
+++ b/project2/perRowValues.h
@@ -48,6 +48,8 @@ class PerRowValues : public virtual _SourceObject {
 		virtual const Glib::ustring & getCurrentValue(const Glib::ustring & id) const = 0;
 		virtual const Glib::ustring & getCurrentValue(unsigned int col) const = 0;
 		virtual bool isNull(unsigned int col) const = 0;
+		virtual bool isNull(const Glib::ustring & id) const = 0;
+		unsigned int getRowNum() const;
 		virtual void execute(const RowProcessor *) const = 0;
 		void use(const RowUser * r) const;
 		void finish(const RowUser * r) const;
@@ -57,6 +59,9 @@ class PerRowValues : public virtual _SourceObject {
 		static void endRow(const PerRowValues * r);
 		void rowChanged() const;
 
+	protected:
+		mutable unsigned int rowNum;
+
 	private:
 		static RowValuesStack stack;
 		mutable std::set<const RowUser *> rowUsers;
diff --git a/project2/sqlMergeTask.cpp b/project2/sqlMergeTask.cpp
index 279fa05..360c98b 100644
--- a/project2/sqlMergeTask.cpp
+++ b/project2/sqlMergeTask.cpp
@@ -10,7 +10,30 @@
 bool _SqlMergeTask::defaultUseTempTable = true;
 static void attach(Iterate i, ModifyCommand * insert);
 
+class _SqlMergeInsert;
+typedef boost::intrusive_ptr<_SqlMergeInsert> SqlMergeInsert;
+class _SqlMergeInsert : public IHaveParameters, public virtual _SourceObject, public _Task {
+	public:
+		_SqlMergeInsert(const xmlpp::Element * p) :
+			_SourceObject(p),
+			IHaveParameters(p),
+			_Task(p) {
+		}
+		void loadComplete(const CommonObjects*) {
+		}
+		void execute() const {
+			unsigned int col = 0;
+			BOOST_FOREACH(const Parameters::value_type & v, parameters) {
+				insert->bindParamS(col++, v.second->value);
+			}
+		}
+	private:
+		friend void attach(SqlMergeInsert i, ModifyCommand * insert);
+		ModifyCommand * insert;
+};
+
 ElementLoaderImpl<_SqlMergeTask> sqlmergeLoader("sqlmerge");
+ElementLoaderImpl<_SqlMergeInsert> sqlmergeinsertLoader("sqlmergeinsert");
 
 // Conversion logic
 _SqlMergeTask::_SqlMergeTask(const xmlpp::Element * p) :
@@ -232,6 +255,14 @@ class _Populate : public _NoOutputExecute {
 };
 typedef boost::intrusive_ptr<_Populate> Populate;
 
+void
+attach(SqlMergeInsert i, ModifyCommand * insert)
+{
+	if (i) {
+		i->insert = insert;
+	}
+}
+
 static void
 attach(Iterate i, ModifyCommand * insert)
 {
@@ -244,6 +275,7 @@ attach(Iterate i, ModifyCommand * insert)
 	else {
 		BOOST_FOREACH(const NoOutputExecutes::value_type & n, i->subNOEs) {
 			attach(boost::dynamic_pointer_cast<_Iterate>(n.second), insert);
+			attach(boost::dynamic_pointer_cast<_SqlMergeInsert>(n.second), insert);
 		}
 	}
 }
diff --git a/project2/sqlRows.cpp b/project2/sqlRows.cpp
index 9244a9c..1924207 100644
--- a/project2/sqlRows.cpp
+++ b/project2/sqlRows.cpp
@@ -57,6 +57,12 @@ _SqlRows::isNull(unsigned int col) const
 	return (*query)[col].isNull();
 }
 
+bool
+_SqlRows::isNull(const Glib::ustring & col) const
+{
+	return (*query)[col].isNull();
+}
+
 unsigned int
 _SqlRows::columnCount() const
 {
@@ -72,6 +78,7 @@ _SqlRows::getColumnName(unsigned int col) const
 void
 _SqlRows::execute(const RowProcessor * rp) const
 {
+	rowNum = 0;
 	unsigned int offset = 0;
 	Glib::ustring sql;
 	sqlCommand.writeSql(sql);
@@ -79,6 +86,7 @@ _SqlRows::execute(const RowProcessor * rp) const
 	sqlCommand.bindParams(rp, query, offset);
 	while (query->fetch()) {
 		rp->rowReady();
+		rowNum += 1;
 	}
 	delete query;
 }
diff --git a/project2/sqlRows.h b/project2/sqlRows.h
index b983743..a00c8ce 100644
--- a/project2/sqlRows.h
+++ b/project2/sqlRows.h
@@ -23,6 +23,7 @@ class _SqlRows : public PerRowValues {
 		const Glib::ustring & getCurrentValue(const Glib::ustring & id) const;
 		const Glib::ustring & getCurrentValue(unsigned int col) const;
 		bool isNull(unsigned int col) const;
+		bool isNull(const Glib::ustring & id) const;
 
 		const std::string dataSource;
 
diff --git a/project2/urlRows.cpp b/project2/urlRows.cpp
index 8381d68..94ee05e 100644
--- a/project2/urlRows.cpp
+++ b/project2/urlRows.cpp
@@ -67,6 +67,12 @@ _UrlRows::isNull(unsigned int col) const
 	return false;
 }
 
+bool
+_UrlRows::isNull(const Glib::ustring & col) const
+{
+	return false;
+}
+
 const Glib::ustring &
 _UrlRows::getCurrentValue(const Glib::ustring & id) const
 {
@@ -109,6 +115,7 @@ _UrlRows::handleData(const RowProcessor * rp, const char * bytes, size_t bytesLe
 						values.push_back(ValPtr(new Glib::ustring()));
 					}
 					rp->rowReady();
+					rowNum += 1;
 				}
 				else {
 					mkCols = false;
@@ -167,6 +174,7 @@ _UrlRows::addColumn(const Glib::ustring & rawtok) const
 void
 _UrlRows::execute(const RowProcessor * rp) const
 {
+	rowNum = 0;
 	CurlHandle::Ptr c = new CurlHandle();
 	c->setopt(CURLOPT_URL, url.c_str());
 	//c->setopt(CURLOPT_PROXY, proxy.c_str());
@@ -194,6 +202,7 @@ _UrlRows::execute(const RowProcessor * rp) const
 			values.push_back(ValPtr(new Glib::ustring()));
 		}
 		rp->rowReady();
+		rowNum += 1;
 		values.clear();
 	}
 	values.clear();
diff --git a/project2/urlRows.h b/project2/urlRows.h
index 08acffc..83c11ce 100644
--- a/project2/urlRows.h
+++ b/project2/urlRows.h
@@ -20,6 +20,7 @@ class _UrlRows : public PerRowValues {
 		const Glib::ustring & getCurrentValue(const Glib::ustring & id) const;
 		const Glib::ustring & getCurrentValue(unsigned int col) const;
 		bool isNull(unsigned int col) const;
+		bool isNull(const Glib::ustring & id) const;
 
 		typedef std::set<gunichar> CharSet;
 		const Glib::ustring url;
diff --git a/project2/variables.cpp b/project2/variables.cpp
index 09ea36e..c6a65f1 100644
--- a/project2/variables.cpp
+++ b/project2/variables.cpp
@@ -8,6 +8,9 @@
 #include <boost/tokenizer.hpp>
 #include <boost/foreach.hpp>
 #include <boost/algorithm/string/predicate.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
 
 class VariableLiteral : public VariableImpl {
 	public:
@@ -19,6 +22,7 @@ class VariableLiteral : public VariableImpl {
 class VariableImplDyn : public VariableImpl {
 	public:
 		VariableImplDyn(const Glib::ustring & src) : VariableImpl(src), cacheValid(false) { }
+		VariableImplDyn(const Glib::ustring & src, boost::optional<Glib::ustring> def) : VariableImpl(src, def), cacheValid(false) { }
 		virtual const Glib::ustring & value() const = 0;
 
 	protected:
@@ -94,6 +98,15 @@ class VariableParent : public VariableImplDyn, public RowUser {
 			depth(src.length() - source.length()),
 			dep(d)
 		{
+			bind();
+		}
+		VariableParent(const Glib::ustring & name, unsigned int d) :
+			VariableImplDyn(name, NULL),
+			row(NULL),
+			depth(d),
+			dep(NULL)
+		{
+			bind();
 		}
 		~VariableParent()
 		{
@@ -120,7 +133,7 @@ class VariableParent : public VariableImplDyn, public RowUser {
 							row->use(dep);
 						}
 					}
-					cache = row->getCurrentValue(name);
+					getValue(cache, row);
 				}
 				catch (PerRowValues::ParentOutOfRange) {
 					if (!defaultValue) {
@@ -143,9 +156,31 @@ class VariableParent : public VariableImplDyn, public RowUser {
 			cacheValid = false;
 		}
 	protected:
+		static void assignHelper(Glib::ustring & dest, const Glib::ustring & src) {
+			dest = src;
+		}
+		void bind()
+		{
+			if (name[0] == '!') {
+				if (name == "!rownum") {
+					getValue = boost::bind(&assignHelper, _1,
+							boost::bind(&boost::lexical_cast<Glib::ustring, unsigned int>,
+								boost::bind(&PerRowValues::getRowNum, _2)));
+				}
+				else {
+					throw PerRowValues::FieldDoesNotExist();
+				}
+			}
+			else {
+				typedef const Glib::ustring & (PerRowValues::*gCV)(const Glib::ustring &) const;
+				getValue = boost::bind(&assignHelper, _1,
+						boost::bind((gCV)&PerRowValues::getCurrentValue, _2, name));
+			}
+		}
 		mutable const PerRowValues * row;
 		const size_t depth;
 		const RowUser * dep;
+		boost::function2<void, Glib::ustring &, const PerRowValues *> getValue;
 };
 
 class VariableParse : public VariableImplDyn, public RowUser {
@@ -190,16 +225,21 @@ Variable::Variable(const Glib::ustring & s) :
 {
 }
 
-Variable::Variable(xmlpp::Attribute * a) :
+Variable::Variable(const xmlpp::Attribute * a) :
 	var(create(a->get_value()))
 {
 }
 
-Variable::Variable(xmlpp::Element * e) :
+Variable::Variable(const xmlpp::Element * e) :
 	var(create(e->get_child_text()->get_content()))
 {
 }
 
+Variable::Variable(VariableImpl * v) :
+	var(v)
+{
+}
+
 Variable::VariableImplPtr
 Variable::create(const Glib::ustring & s, RowUser * dep)
 {
@@ -224,6 +264,19 @@ Variable::create(const Glib::ustring & s, RowUser * dep)
 	}
 }
 
+Variable
+Variable::makeParent(const Glib::ustring & n, unsigned int d)
+{
+	return Variable(new VariableParent(n, d));
+}
+
+VariableImpl::VariableImpl(const Glib::ustring & src, boost::optional<Glib::ustring> def) :
+	source(src),
+	name(src),
+	defaultValue(def)
+{
+}
+
 VariableImpl::VariableImpl(const Glib::ustring & src) :
 	source(src)
 {
diff --git a/project2/variables.h b/project2/variables.h
index c927ae6..c728284 100644
--- a/project2/variables.h
+++ b/project2/variables.h
@@ -16,6 +16,7 @@ class VariableImpl : public virtual IntrusivePtrBase {
 
 	protected:
 		VariableImpl(const Glib::ustring & src);
+		VariableImpl(const Glib::ustring & src, boost::optional<Glib::ustring> def);
 		virtual ~VariableImpl() = 0;
 
 		const Glib::ustring source;
@@ -27,15 +28,18 @@ class Variable {
 	public:
 		typedef boost::intrusive_ptr<VariableImpl> VariableImplPtr;
 
-		Variable(xmlpp::Attribute *);
-		Variable(xmlpp::Element *);
+		Variable(const xmlpp::Attribute *);
+		Variable(const xmlpp::Element *);
 		Variable(const Glib::ustring & s);
 
+		static Variable makeParent(const Glib::ustring & name, unsigned int depth);
+
 		operator const Glib::ustring & () const { return var->value(); }
 		const Glib::ustring & operator()() const { return var->value(); }
 		const Glib::ustring * operator->() const { return &var->value(); }
 
 	private:
+		Variable(VariableImpl *);
 		friend class VariableParse;
 		static VariableImplPtr create(const Glib::ustring & s, RowUser * dep = NULL);
 		VariableImplPtr var;
diff --git a/project2/view.cpp b/project2/view.cpp
index 06eb6cc..d32b275 100644
--- a/project2/view.cpp
+++ b/project2/view.cpp
@@ -21,6 +21,12 @@ _RowView::_RowView(const xmlpp::Element * p) :
 	rootName(p->get_attribute_value("rootname")),
 	recordName(p->get_attribute_value("recordname"))
 {
+	BOOST_FOREACH(xmlpp::Node * node, p->find("columns/column")) {
+		const xmlpp::Element * elem = dynamic_cast<const xmlpp::Element *>(node);
+		if (elem) {
+			viewColumns.insert(Columns::value_type(elem->get_attribute_value("name"), Variable::makeParent(elem->get_child_text()->get_content(), 0)));
+		}
+	}
 	LoaderBase loader("http://project2.randomdan.homeip.net", true);
 	loader.supportedStorers.insert(Storer::into(&subViews));
 	loader.collectAll(p, true);
@@ -40,10 +46,19 @@ void
 _RowView::rowReady() const
 {
 	presenter->pushSub(recordName);
-	unsigned int cols = source->columnCount();
-	for (unsigned int c = 0; c < cols; c += 1) {
-		if (!source->isNull(c)) {
-			presenter->addField(source->getColumnName(c), source->getCurrentValue(c));
+	if (viewColumns.empty()) {
+		unsigned int cols = source->columnCount();
+		for (unsigned int c = 0; c < cols; c += 1) {
+			if (!source->isNull(c)) {
+				presenter->addField(source->getColumnName(c), source->getCurrentValue(c));
+			}
+		}
+	}
+	else {
+		BOOST_FOREACH(const Columns::value_type & col, viewColumns) {
+			if (!source->isNull(col.first)) {
+				presenter->addField(col.first, col.second);
+			}
 		}
 	}
 	executeChildren();
diff --git a/project2/view.h b/project2/view.h
index 332e13f..081cf13 100644
--- a/project2/view.h
+++ b/project2/view.h
@@ -7,6 +7,7 @@
 #include "sourceObject.h"
 #include "xmlObjectLoader.h"
 #include "perRowValues.h"
+#include "variables.h"
 
 class Presenter;
 class _View;
@@ -34,6 +35,9 @@ class _RowView : public _View, public RowProcessor {
 		const Glib::ustring recordName;
 
 	protected:
+		typedef std::map<Glib::ustring, Variable> Columns;
+		Columns viewColumns;
+
 		void executeChildren() const;
 		Views subViews;
 		mutable const Presenter * presenter;
diff --git a/project2/xmlRows.cpp b/project2/xmlRows.cpp
index 63a14cc..bfccca1 100644
--- a/project2/xmlRows.cpp
+++ b/project2/xmlRows.cpp
@@ -86,6 +86,12 @@ _XmlRows::isNull(unsigned int col) const
 	return (values.find(fieldNames[col]) == values.end());
 }
 
+bool
+_XmlRows::isNull(const Glib::ustring & col) const
+{
+	return (values.find(col) == values.end());
+}
+
 unsigned int
 _XmlRows::columnCount() const
 {
@@ -110,6 +116,7 @@ store(const _XmlRows::Path & position, _XmlRows::Values & values, const _XmlRows
 void
 _XmlRows::execute(const RowProcessor * rp) const
 {
+	rowNum = 0;
 	xmlTextReaderPtr reader = xmlReaderForFile(filename.c_str(), NULL, 0);
 	if (reader == NULL) {
 		throw std::runtime_error("Failed to open file");
@@ -136,6 +143,7 @@ _XmlRows::execute(const RowProcessor * rp) const
 					if (empty) {
 						if (position == trigger) {
 							rp->rowReady();
+							rowNum += 1;
 						}
 						if (position == root) {
 							values.clear();
@@ -153,6 +161,7 @@ _XmlRows::execute(const RowProcessor * rp) const
 				if (enableCapture) {
 					if (position == trigger) {
 						rp->rowReady();
+						rowNum += 1;
 					}
 					if (position == root) {
 						values.clear();
diff --git a/project2/xmlRows.h b/project2/xmlRows.h
index 05c127d..6e671de 100644
--- a/project2/xmlRows.h
+++ b/project2/xmlRows.h
@@ -23,6 +23,7 @@ class _XmlRows : public PerRowValues {
 		const Glib::ustring & getCurrentValue(const Glib::ustring & id) const;
 		const Glib::ustring & getCurrentValue(unsigned int col) const;
 		bool isNull(unsigned int col) const;
+		bool isNull(const Glib::ustring & id) const;
 
 		const Glib::ustring recordRoot;
 		const Glib::ustring recordTrigger;
-- 
cgit v1.2.3