Просмотр исходного кода

1.增加了update类,用于update语句
2.column进行检查,表中没有的列抛出异常

tanghai 14 лет назад
Родитель
Сommit
f6211aa2b5

+ 1 - 0
Cpp/Platform/Orm/CMakeLists.txt

@@ -13,6 +13,7 @@ SET(OrmSrc
 	DbResult.cc
 	Expr.cc
 	MessageField.cc
+	Update.cc
 )
 
 ADD_LIBRARY(Orm ${OrmSrc})

+ 35 - 5
Cpp/Platform/Orm/Column.cc

@@ -1,7 +1,12 @@
 // Copyright: All Rights Reserved
 // Author: egametang@gmail.com (tanghai)
 
+#include <boost/foreach.hpp>
+#include <boost/format.hpp>
+#include <google/protobuf/descriptor.h>
+#include "Base/Marcos.h"
 #include "Orm/Column.h"
+#include "Orm/Exception.h"
 
 namespace Egametang {
 
@@ -9,33 +14,58 @@ Column::Column()
 {
 }
 
-Column::Column(const std::string& name): columnStr(name)
+Column::Column(const std::string& name)
 {
+	columns.push_back(name);
 }
 
 Column::Column(const Column& column)
 {
-	columnStr = column.columnStr;
+	columns = column.columns;
 }
 
 Column::~Column()
 {
 }
 
-Column& Column::operator()(std::string& name)
+Column& Column::operator()(const std::string& name)
 {
-	columnStr = columnStr + ", " + name;
+	columns.push_back(name);
 	return *this;
 }
 
 bool Column::Empty() const
 {
-	return columnStr.empty();
+	return !columns.size();
 }
 
 std::string Column::ToString() const
 {
+	std::string columnStr;
+	foreach (const std::string& column, columns)
+	{
+		columnStr += column + ", ";
+	}
+	columnStr.resize(columnStr.size() - 2);
 	return columnStr;
 }
 
+void Column::CheckAllColumns(const google::protobuf::Message& message) const
+{
+	const google::protobuf::Descriptor* descriptor = message.GetDescriptor();
+	foreach (const std::string& column, columns)
+	{
+		if (column == "*")
+		{
+			continue;
+		}
+		if (!descriptor->FindFieldByName(column))
+		{
+			boost::format format("message: %1%, field: %2%");
+			format % message.GetTypeName() % column;
+			throw MessageHasNoSuchFeildException() << MessageHasNoSuchFeildErrStr(format.str());
+		}
+	}
+}
+
 } // namespace Egametang

+ 5 - 3
Cpp/Platform/Orm/Column.h

@@ -4,6 +4,7 @@
 #ifndef ORM_COLUMN_H
 #define ORM_COLUMN_H
 
+#include <list>
 #include <string>
 #include "Orm/Expr.h"
 
@@ -12,16 +13,17 @@ namespace Egametang {
 class Column
 {
 private:
-	std::string columnStr;
+	std::list<std::string> columns;
 
 public:
 	Column();
 	Column(const std::string& name);
 	Column(const Column& column);
 	~Column();
-	Column& operator()(std::string& name);
 	bool Empty() const;
+	Column& operator()(const std::string& name);
 	std::string ToString() const;
+	void CheckAllColumns(const google::protobuf::Message& message) const;
 
 	template <typename T>
 	Expr operator>(const T& value)
@@ -59,7 +61,7 @@ public:
 		return Oper(*this, "=", value);
 	}
 
-	Expr like(const std::string value)
+	Expr like(const std::string& value)
 	{
 		return Oper(*this, "like", value);
 	}

+ 1 - 1
Cpp/Platform/Orm/DbResult.h

@@ -19,7 +19,7 @@ private:
 	void FillMessage(ProtobufMessagePtr message);
 
 public:
-	DbResult(ResultSetPtr resultSet);
+	explicit DbResult(ResultSetPtr resultSet);
 
 	void One(ProtobufMessagePtr message);
 

+ 0 - 1
Cpp/Platform/Orm/DbResultTest.cc

@@ -43,7 +43,6 @@ TEST_F(DbResultTest, One)
 			LOG(WARNING) << *str;
 		}
 	}
-
 }
 
 } // namespace Egametang

+ 12 - 0
Cpp/Platform/Orm/Exception.h

@@ -20,6 +20,18 @@ struct SqlNoDataException: virtual Exception
 typedef boost::error_info<struct TagSqlNoDataErrNO, int> SqlNoDataErrNO;
 typedef boost::error_info<struct TagSqlNoDataErrStr, std::string> SqlNoDataErrStr;
 
+struct MessageNoFeildIsSetException: virtual Exception
+{
+};
+typedef boost::error_info<struct TagMessageNoFeildIsSetErrNO, int> MessageNoFeildIsSetErrNO;
+typedef boost::error_info<struct TagMessageNoFeildIsSetErrStr, std::string> MessageNoFeildIsSetErrStr;
+
+struct MessageHasNoSuchFeildException: virtual Exception
+{
+};
+typedef boost::error_info<struct TagMessageHasNoSuchFeildErrNO, int> MessageHasNoSuchFeildErrNO;
+typedef boost::error_info<struct TagMessageHasNoSuchFeildErrStr, std::string> MessageHasNoSuchFeildErrStr;
+
 }
 
 #endif // ORM_EXCEPTION_H

+ 37 - 0
Cpp/Platform/Orm/Expr.cc

@@ -1,10 +1,15 @@
 // Copyright: All Rights Reserved
 // Author: egametang@gmail.com (tanghai)
 
+#include <boost/foreach.hpp>
 #include <boost/lexical_cast.hpp>
+#include <boost/format.hpp>
 #include <glog/logging.h>
+#include <google/protobuf/descriptor.h>
+#include "Base/Marcos.h"
 #include "Orm/Column.h"
 #include "Orm/Expr.h"
+#include "Orm/Exception.h"
 
 namespace Egametang {
 
@@ -23,6 +28,28 @@ bool Expr::Empty() const
 	return exprStr.empty();
 }
 
+void Expr::SaveColumn(const Expr& expr)
+{
+	foreach (const Column& column, expr.columns)
+	{
+		columns.push_back(column);
+	}
+}
+
+void Expr::SaveColumn(const Column& column)
+{
+	columns.push_back(column);
+}
+
+void Expr::CheckAllColumns(const google::protobuf::Message& message) const
+{
+	const google::protobuf::Descriptor* descriptor = message.GetDescriptor();
+	foreach (const Column& column, columns)
+	{
+		column.CheckAllColumns(message);
+	}
+}
+
 std::string Expr::ToString() const
 {
 	return exprStr;
@@ -31,36 +58,46 @@ std::string Expr::ToString() const
 Not::Not(const Expr& expr)
 {
 	exprStr = "not (" + expr.ToString() + ") ";
+	this->SaveColumn(expr);
 }
 
 And::And(const Expr& left, const Expr& right)
 {
 	exprStr = "(" + left.ToString() + ") and" + " (" + right.ToString() + ") ";
+	SaveColumn(left);
+	SaveColumn(right);
 }
 
 Or::Or(const Expr& left, const Expr& right)
 {
 	exprStr = "(" + left.ToString() + ") or" + " (" + right.ToString() + ") ";
+	SaveColumn(left);
+	SaveColumn(right);
 }
 
 Oper::Oper(const Column& left, const std::string& op, const std::string& right)
 {
 	exprStr = left.ToString() + " " + op + " '" + right + "'";
+	SaveColumn(left);
 }
 
 Oper::Oper(const Column& left, const std::string& op, const Column& right)
 {
 	exprStr = left.ToString() + " " + op + " " + right.ToString();
+	SaveColumn(left);
+	SaveColumn(right);
 }
 
 Oper::Oper(const Column& left, const std::string& op, int right)
 {
 	exprStr = left.ToString() + " " + op + " " + boost::lexical_cast<std::string>(right);
+	SaveColumn(left);
 }
 
 Oper::Oper(const Column& left, const std::string& op, double right)
 {
 	exprStr = left.ToString() + " " + op + " " + boost::lexical_cast<std::string>(right);
+	SaveColumn(left);
 }
 
 } // namespace Egametang

+ 13 - 5
Cpp/Platform/Orm/Expr.h

@@ -4,13 +4,20 @@
 #ifndef ORM_EXPRESSION_H
 #define ORM_EXPRESSION_H
 
+#include <list>
 #include <string>
+#include <boost/unordered_set.hpp>
+#include <google/protobuf/message.h>
 
 namespace Egametang {
 
+class Column;
+
 class Expr
 {
 protected:
+	// 记录表达式中用到的列名
+	std::list<Column> columns;
 	std::string exprStr;
 
 public:
@@ -18,28 +25,29 @@ public:
 	Expr& operator=(const Expr& expr);
 	std::string ToString() const;
 	bool Empty() const;
+	void SaveColumn(const Expr& expr);
+	void SaveColumn(const Column& column);
+	void CheckAllColumns(const google::protobuf::Message& message) const;
 };
 
 class Not: public Expr
 {
 public:
-	Not(const Expr& expr);
+	explicit Not(const Expr& expr);
 };
 
 class And: public Expr
 {
 public:
-	And(const Expr& left, const Expr& right);
+	explicit And(const Expr& left, const Expr& right);
 };
 
 class Or: public Expr
 {
 public:
-	Or(const Expr& left, const Expr& right);
+	explicit Or(const Expr& left, const Expr& right);
 };
 
-class Column;
-
 // > < >= <= != like
 class Oper: public Expr
 {

+ 12 - 6
Cpp/Platform/Orm/Select.h

@@ -6,8 +6,10 @@
 
 #include <string>
 #include <vector>
+#include <boost/foreach.hpp>
 #include <boost/lexical_cast.hpp>
 #include <google/protobuf/descriptor.h>
+#include "Base/Marcos.h"
 #include "Orm/Expr.h"
 #include "Orm/Column.h"
 
@@ -28,12 +30,13 @@ private:
 	int offset;
 
 public:
-	Select(Column columns):
-		select(columns), distinct(false),
-		groupBy(), orderBy(),
-		desc(false), limit(0),
-		offset(0)
+	explicit Select(Column columns):
+		select(columns),
+		distinct(false), groupBy(),
+		orderBy(), desc(false),
+		limit(0), offset(0)
 	{
+		columns.CheckAllColumns(Table::default_instance());
 	}
 
 	Select<Table>& Distinct()
@@ -44,24 +47,28 @@ public:
 
 	Select<Table>& Where(Expr expr)
 	{
+		expr.CheckAllColumns(Table::default_instance());
 		where = expr;
 		return *this;
 	}
 
 	Select<Table>& GroupBy(Column columns)
 	{
+		columns.CheckAllColumns(Table::default_instance());
 		groupBy = columns;
 		return *this;
 	}
 
 	Select<Table>& Having(Expr expr)
 	{
+		expr.CheckAllColumns(Table::default_instance());
 		having = expr;
 		return *this;
 	}
 
 	Select<Table>& OrderBy(Column columns)
 	{
+		columns.CheckAllColumns(Table::default_instance());
 		orderBy = columns;
 		return *this;
 	}
@@ -86,7 +93,6 @@ public:
 
 	std::string ToString() const
 	{
-		// TODO: 加入异常处理机制
 		std::string sql = "select ";
 		if (!select.Empty())
 		{

+ 3 - 3
Cpp/Platform/Orm/SelectTest.cc

@@ -42,7 +42,7 @@ TEST_F(RpcServerTest, SelectDistinct)
 TEST_F(RpcServerTest, SelectTwoColumn)
 {
 	std::string expectedSql;
-	Select<Person> selectQuery(Column("age, name"));
+	Select<Person> selectQuery(Column("age")("name"));
 	expectedSql = "select age, name distinct from Egametang.Person where age > 10";
 	selectQuery.Distinct().Where(Column("age") > 10);
 	EXPECT_EQ(expectedSql, selectQuery.ToString());
@@ -51,7 +51,7 @@ TEST_F(RpcServerTest, SelectTwoColumn)
 TEST_F(RpcServerTest, LimitOffset)
 {
 	std::string expectedSql;
-	Select<Person> selectQuery(Column("age, name"));
+	Select<Person> selectQuery(Column("age")("name"));
 	expectedSql = "select age, name distinct from Egametang.Person where age > 10 limit 1 offset 10";
 	selectQuery.Distinct().Where(Column("age") > 10).Limit(1).Offset(10);
 	EXPECT_EQ(expectedSql, selectQuery.ToString());
@@ -60,7 +60,7 @@ TEST_F(RpcServerTest, LimitOffset)
 TEST_F(RpcServerTest, GroupByHaving)
 {
 	std::string expectedSql;
-	Select<Person> selectQuery(Column("age, name"));
+	Select<Person> selectQuery(Column("age")("name"));
 	expectedSql =
 			"select age, name distinct from Egametang.Person"
 			" group by age having age > 10 limit 1 offset 10";

+ 55 - 0
Cpp/Platform/Orm/Update.cc

@@ -0,0 +1,55 @@
+// Copyright: All Rights Reserved
+// Author: egametang@gmail.com (tanghai)
+
+#include <google/protobuf/descriptor.h>
+#include "Orm/Update.h"
+#include "Orm/Column.h"
+#include "Orm/Exception.h"
+#include "Orm/MessageField.h"
+
+namespace Egametang {
+
+Update::Update(google::protobuf::Message& message): message(message)
+{
+}
+
+Update& Update::Where(Expr expr)
+{
+	expr.CheckAllColumns(message);
+	where = expr;
+	return *this;
+}
+
+std::string Update::ToString() const
+{
+	int fieldIsSetCount = 0;
+	std::string sql = "update " + message.GetDescriptor()->full_name();
+	sql += " set ";
+	const google::protobuf::Descriptor* descriptor = message.GetDescriptor();
+	const google::protobuf::Reflection* reflection = message.GetReflection();
+	for (int i = 0; i < descriptor->field_count(); ++i)
+	{
+		const google::protobuf::FieldDescriptor* field = descriptor->field(i);
+		if (!reflection->HasField(message, field))
+		{
+			continue;
+		}
+		++fieldIsSetCount;
+		MessageField messageField(message, field);
+		sql += field->name() + " = " + messageField.GetField() + ", ";
+	}
+
+	if (fieldIsSetCount == 0)
+	{
+		throw MessageNoFeildIsSetException() << MessageNoFeildIsSetErrStr("no field is set");
+	}
+	// 去除最后的逗号和空格
+	sql.resize(sql.size() - 2);
+	if (!where.Empty())
+	{
+		sql += " where " + where.ToString();
+	}
+	return sql;
+}
+
+} // namespace Egametang

+ 27 - 0
Cpp/Platform/Orm/Update.h

@@ -0,0 +1,27 @@
+// Copyright: All Rights Reserved
+// Author: egametang@gmail.com (tanghai)
+
+#ifndef ORM_UPDATE_H
+#define ORM_UPDATE_H
+
+#include <google/protobuf/message.h>
+#include "Orm/Expr.h"
+
+namespace Egametang {
+
+class Update
+{
+private:
+	google::protobuf::Message& message;
+	Expr where;
+
+public:
+	explicit Update(google::protobuf::Message& message);
+
+	Update& Where(Expr expr);
+
+	std::string ToString() const;
+};
+
+} // namespace Egametang
+#endif // ORM_UPDATE_H

+ 8 - 0
Cpp/Platform/Orm/UpdateTest.cc

@@ -0,0 +1,8 @@
+// Copyright: All Rights Reserved
+// Author: egametang@gmail.com (tanghai)
+
+#include "Update.h"
+
+namespace Egametang {
+
+} // namespace Egametang

+ 0 - 1
Cpp/Platform/Rpc/RpcServer.cc

@@ -1,5 +1,4 @@
 #include <boost/asio.hpp>
-#include <boost/foreach.hpp>
 #include <boost/bind.hpp>
 #include <boost/make_shared.hpp>
 #include <google/protobuf/service.h>