commit
9d494a1887
|
|
@ -1,6 +1,10 @@
|
|||
#Based on https://github.com/pcolby/libqtaws/blob/master/.travis.yml
|
||||
language: cpp
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -1 +1 @@
|
|||
Subproject commit f9d81fcc6244271b3926891b0c86554e1e6b967e
|
||||
Subproject commit e0bdec4a7c93b4d4307fd89200000ff817a86c99
|
||||
104
README.md
104
README.md
|
|
@ -2,14 +2,8 @@
|
|||
|
||||
# Nut
|
||||
|
||||
## Build result
|
||||
| Branch | Status |
|
||||
| ------------- |:-------------:|
|
||||
| master | [](https://travis-ci.org/HamedMasafi/Nut) |
|
||||
| dev | [](https://travis-ci.org/HamedMasafi/Nut) |
|
||||
|
||||
[](https://travis-ci.org/HamedMasafi/Nut)
|
||||
[](https://gitlicense.com/license/hamedmasafi/nut)
|
||||
|
||||
[](https://www.codacy.com/app/HamedMasafi/Nut?utm_source=github.com&utm_medium=referral&utm_content=HamedMasafi/Nut&utm_campaign=Badge_Grade)
|
||||
|
||||
|
|
@ -23,95 +17,15 @@ Badge](https://api.codacy.com/project/badge/Grade/f3802610beb946068f6cd2c2b6608a
|
|||
- Automatically create and update database
|
||||
- IDE auto complete support, No hard-code nedded
|
||||
- Table join detect
|
||||
- Supported types:
|
||||
- Suppor every Qt types. [Full list](doc/datatypes.md)
|
||||
|
||||
| Type | Sqlite | MySql | Postgresql| Ms Sql server |
|
||||
|--------|--------|--------|--------|--------|
|
||||
| QBitArray | BLOB | VARBINARY | BYTEA | VARBINARY (MAX) |
|
||||
| QByteArray | BLOB | BLOB | BYTEA | VARBINARY (MAX) |
|
||||
| QChar | NCHAR(1) | CHAR(1) | CHAR(1) | CHAR(1) |
|
||||
| QColor | TEXT | TEXT | TEXT | TEXT |
|
||||
| QDate | DATE | DATE | DATE | DATE |
|
||||
| QDateTime | DATETIME | DATETIME | TIMESTAMP | DATETIME |
|
||||
| QJsonArray | TEXT | TEXT | JSON | TEXT |
|
||||
| QJsonDocument | TEXT | TEXT | JSON | TEXT |
|
||||
| QJsonObject | TEXT | TEXT | JSON | TEXT |
|
||||
| QJsonValue | TEXT | TEXT | JSON | TEXT |
|
||||
| QLine | TEXT | TEXT | LINE | TEXT |
|
||||
| QLineF | TEXT | TEXT | LINE | TEXT |
|
||||
| QPoint | TEXT | POINT | POINT | GEOMETRY |
|
||||
| QPointF | TEXT | POINT | POINT | GEOMETRY |
|
||||
| QPolygon | TEXT | POLYGON | POLYGON | TEXT |
|
||||
| QPolygonF | TEXT | POLYGON | POLYGON | TEXT |
|
||||
| QRect | TEXT | TEXT | BOX | TEXT |
|
||||
| QRectF | TEXT | TEXT | BOX | TEXT |
|
||||
| QSize | TEXT | TEXT | TEXT | TEXT |
|
||||
| QSizeF | TEXT | TEXT | TEXT | TEXT |
|
||||
| QString | TEXT | TEXT | TEXT | NVARCHAR(MAX) |
|
||||
| QStringList | TEXT[^*] | TEXT | TEXT[] | TEXT |
|
||||
| QTime | TIME | TIME | TIME | TIME |
|
||||
| QUrl | TEXT | TEXT | TEXT | TEXT |
|
||||
| QUuid | TEXT | VARCHAR(64) | UUID | UNIQUEIDENTIFIER |
|
||||
| bool | BOOLEAN | BOOLEAN | BOOLEAN | BIT |
|
||||
| char | TINYINT | CHAR(1) | CHAR(1) | CHAR(1) |
|
||||
| double | DOUBLE | REAL | REAL | REAL |
|
||||
| float | FLOAT | FLOAT | FLOAT | FLOAT(24) |
|
||||
| int | INT | INT | INTEGER | INT |
|
||||
| long | MEDIUMINT | BIGINT | BIGINT | BIGINT |
|
||||
| qlonglong | BIGINT | BIGINT | BIGINT | BIGINT |
|
||||
| qulonglong | BIGINT UNSIGNED | BIGINT | BIGINT | BIGINT |
|
||||
| short | SMALLINT | SMALLINT | SMALLINT | SMALLINT |
|
||||
| signed char | TINYINT | TINYINT | SMALLINT | TINYINT |
|
||||
| uchar | TINYINT UNSIGNED | TINYINT | SMALLINT | TINYINT |
|
||||
| uint | INT UNSIGNED | INT | INTEGER | INT |
|
||||
| ulong | MEDIUMINT UNSIGNED | BIGINT | BIGINT | BIGINT |
|
||||
| ushort | SMALLINT UNSIGNED | SMALLINT | SMALLINT | SMALLINT |
|
||||
|
||||
[^*]: Using internal store/restore serialization
|
||||
|
||||
|
||||
## Sample Codes
|
||||
### Read data from database:
|
||||
|
||||
```cpp
|
||||
auto q = db.posts()->createQuery();
|
||||
q->setWhere(Post::idField() == postId);
|
||||
auto posts = q->toList();
|
||||
// now posts is a QList<Post*> contain all posts in
|
||||
// database that has id equal to postId variable
|
||||
auto post = q->first();
|
||||
// post is first row in database that its id is equal to postId
|
||||
```
|
||||
|
||||
### Adding to database:
|
||||
```cpp
|
||||
Post *newPost = new Post;
|
||||
newPost->setTitle("post title");
|
||||
|
||||
db.posts()->append(newPost);
|
||||
|
||||
for(int i = 0 ; i < 3; i++){
|
||||
Comment *comment = new Comment;
|
||||
comment->setMessage("comment #" + QString::number(i));
|
||||
|
||||
newPost->comments()->append(comment);
|
||||
}
|
||||
db.saveChanges();
|
||||
```
|
||||
|
||||
### Modify database data:
|
||||
```cpp
|
||||
auto q = db.posts()->createQuery();
|
||||
q->setWhere(Post::idField() == postId);
|
||||
Post *post = q->first();
|
||||
|
||||
if(post) {
|
||||
post->setTitle("new name");
|
||||
db.saveChanges();
|
||||
} else {
|
||||
qWarning("No post found!");
|
||||
}
|
||||
```
|
||||
## Getting start
|
||||
* [Sample codes](doc/start.md)
|
||||
* [Shared pointer and regular mode](sharedpointer.md)
|
||||
* [Create database class](database.md)
|
||||
* [Create table class](table.md)
|
||||
* [Using queries](query.md)
|
||||
* [Supported data types](datatypes.md)
|
||||
|
||||
### Donate
|
||||
Butcoin address: 1Dn1WHKkaxanXe4cTGDk4cFRRABxLUpEVj
|
||||
|
|
|
|||
|
|
@ -1 +1,3 @@
|
|||
#QT -= gui
|
||||
|
||||
DEFINES += NUT_PATH=\\\"$$PWD/../../\\\"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
Database class must inherits from Nut::Database class.
|
||||
Database class can have NUT_DB_VERSION for declaring version number, version will be stored in database if upgrade needed.
|
||||
```cpp
|
||||
NUT_DB_VERSION(major, minor)
|
||||
```
|
||||
|
||||
for every table in database NUT_DECLARE_TABLE macro should be use, usage:
|
||||
```cpp
|
||||
NUT_DECLARE_TABLE(class_name, table_name)
|
||||
```
|
||||
|
||||
Sample database class:
|
||||
```cpp
|
||||
#include <Database>
|
||||
|
||||
class Post;
|
||||
class Comment;
|
||||
class WeblogDatabase : public Nut::Database
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
NUT_DB_VERSION(1)
|
||||
|
||||
NUT_DECLARE_TABLE(Post, post)
|
||||
NUT_DECLARE_TABLE(Comment, comment)
|
||||
|
||||
public:
|
||||
WeblogDatabase();
|
||||
};
|
||||
```
|
||||
|
||||
Child tables should initalize in constructor, Example:
|
||||
```cpp
|
||||
WeblogDatabase::WeblogDatabase() : Nut::Database()
|
||||
, m_posts(new TableSet<Post>(this))
|
||||
, m_comments(new TableSet<Comment>(this))
|
||||
{
|
||||
}
|
||||
```
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
| Type | Sqlite | MySql | Postgresql| Ms Sql server |
|
||||
|--------|--------|--------|--------|--------|
|
||||
| bool | BOOLEAN | BOOLEAN | BOOLEAN | BIT |
|
||||
| QBitArray | BLOB | VARBINARY | BYTEA | VARBINARY (MAX) |
|
||||
| QByteArray | BLOB | BLOB | BYTEA | VARBINARY (MAX) |
|
||||
| QDate | DATE | DATE | DATE | DATE |
|
||||
| QDateTime | DATETIME | DATETIME | TIMESTAMP | DATETIME |
|
||||
| QTime | TIME | TIME | TIME | TIME |
|
||||
| double | DOUBLE | REAL | REAL | REAL |
|
||||
| float | FLOAT | FLOAT | FLOAT | FLOAT(24) |
|
||||
| signed char | TINYINT | TINYINT | SMALLINT | tinyint |
|
||||
| char | TINYINT | CHAR(1) | CHAR(1) | CHAR(1) |
|
||||
| uchar | TINYINT UNSIGNED | TINYINT | SMALLINT | tinyint |
|
||||
| short | SMALLINT | SMALLINT | SMALLINT | smallint |
|
||||
| ushort | SMALLINT UNSIGNED | SMALLINT | SMALLINT | smallint |
|
||||
| int | INT | INT | INTEGER | INT |
|
||||
| uint | INT UNSIGNED | INT | INTEGER | INT |
|
||||
| long | MEDIUMINT | BIGINT | BIGINT | bigint |
|
||||
| ulong | MEDIUMINT UNSIGNED | BIGINT | BIGINT | bigint |
|
||||
| qlonglong | BIGINT | BIGINT | BIGINT | bigint |
|
||||
| qulonglong | BIGINT UNSIGNED | BIGINT | BIGINT | bigint |
|
||||
| QChar | NCHAR(1) | CHAR(1) | CHAR(1) | CHAR(1) |
|
||||
| QUrl | TEXT | TEXT | TEXT | TEXT |
|
||||
| QJsonArray | TEXT | TEXT | JSONB | TEXT |
|
||||
| QJsonValue | TEXT | TEXT | JSONB | TEXT |
|
||||
| QJsonObject | TEXT | TEXT | JSONB | TEXT |
|
||||
| QJsonDocument | TEXT | TEXT | JSONB | TEXT |
|
||||
| QPoint | TEXT | TEXT | POINT | GEOMETRY |
|
||||
| QPointF | TEXT | TEXT | POINT | GEOMETRY |
|
||||
| QSize | TEXT | TEXT | TEXT | TEXT |
|
||||
| QSizeF | TEXT | TEXT | TEXT | TEXT |
|
||||
| QLine | TEXT | TEXT | LINE | TEXT |
|
||||
| QLineF | TEXT | TEXT | LINE | TEXT |
|
||||
| QRect | TEXT | TEXT | BOX | TEXT |
|
||||
| QRectF | TEXT | TEXT | BOX | TEXT |
|
||||
| QPolygon | TEXT | TEXT | POLYGON | TEXT |
|
||||
| QPolygonF | TEXT | TEXT | POLYGON | TEXT |
|
||||
| QStringList | TEXT | TEXT | TEXT[] | TEXT |
|
||||
| QColor | TEXT | TEXT | TEXT | TEXT |
|
||||
| QUuid | TEXT | TEXT | UUID | UNIQUEIDENTIFIER |
|
||||
| QString | TEXT | TEXT | TEXT | NVARCHAR(MAX) |
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
# Creating query
|
||||
```cpp
|
||||
auto q = db.posts().query();
|
||||
```
|
||||
|
||||
You can also create query in one command:
|
||||
```cpp
|
||||
auto result = db.posts().query()
|
||||
->where(Post::idField() == 1)
|
||||
->toList();
|
||||
```
|
||||
Now, _result_ contains **QList\<QSharedPointer\<Post\>\>** and can be used in code. query has other commands like: sum, avg, max, min and etc
|
||||
|
||||
## Getting first record in query
|
||||
```cpp
|
||||
auto post = db.posts().query()
|
||||
->setWhete(Post::idField() == 1)
|
||||
->first();
|
||||
|
||||
if(post)
|
||||
qDebug() << "Post found in database";
|
||||
else
|
||||
qDebug() << "No post found!";
|
||||
|
||||
```
|
||||
## Sorting result
|
||||
```cpp
|
||||
auto posts = db.posts().query()
|
||||
->whete(Post::idField() == 1)
|
||||
->orderBy(Post::idField())
|
||||
->toList();
|
||||
```
|
||||
Also you can sort descending by adding **!** to field name
|
||||
```cpp
|
||||
auto posts = db.posts().query()
|
||||
->whete(Post::idField() == 1)
|
||||
->orderBy(!Post::idField())
|
||||
->toList();
|
||||
```
|
||||
|
||||
## Selecting single field
|
||||
```cpp
|
||||
auto ids = db.posts().query()
|
||||
->select(Post::idField());
|
||||
//ids is type of QList<int>
|
||||
```
|
||||
## Getting sum, count, min, max
|
||||
```cpp
|
||||
auto q = db.posts().query();
|
||||
auto sum = q.sum(Post::idField());
|
||||
auto max = q.max(Post::idField());
|
||||
auto min = q.min(Post::idField());
|
||||
auto count = q.count(Post::idField());
|
||||
```
|
||||
|
||||
## Checking field exists in list of values
|
||||
```cpp
|
||||
auto post = db.posts().query()
|
||||
->where(Post::idField().in(QList<int>() << 1 << 2 << 3 << 4) || Post::isAccepted())
|
||||
->first();
|
||||
```
|
||||
Or
|
||||
```cpp
|
||||
auto post = db.posts().query()
|
||||
->where(Post::idField().in({1, 2, 3, 4}) || Post::isAccepted())
|
||||
->first();
|
||||
```
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
Nut can compile in *shared pointer* mode or *regular* mode
|
||||
|
||||
In *shared pointer* mode reqults of queries is QList<QSharedPointer<T>> and in *regular* mode results are QList<T*>
|
||||
|
||||
Almost in every case shared pointer mode is better, But nut support regular mode for backward comptability.
|
||||
|
||||
To compiling in *shared pointer* define **NUT_SHARED_POINTER** macro
|
||||
|
||||
Nut has template alias
|
||||
|
||||
```cpp
|
||||
#ifdef NUT_SHARED_POINTER
|
||||
template <class T>
|
||||
using RowList = QList<QSharedPointer<T>>;
|
||||
|
||||
template <typename T>
|
||||
using Row = QSharedPointer<T>;
|
||||
#else
|
||||
template <typename T>
|
||||
using RowList = QList<T*>;
|
||||
|
||||
template <typename T>
|
||||
using Row = T*;
|
||||
#endif
|
||||
```
|
||||
|
||||
In other words these types are defined by this table:
|
||||
|
||||
| Mode | Nut::Row | Nut::RowList |
|
||||
|------ |----- |--------- |
|
||||
|Regular|T* | QList\<T\*\> |
|
||||
|Shared pointer|QSharedPointer\<T\> | QList\<QSharedPointer\<T\>\> |
|
||||
|
||||
For the integration of your source, you can use these aliases.
|
||||
|
||||
Ans also Nut::create<T>() method are defined for two mode
|
||||
|
||||
```cpp
|
||||
#ifdef NUT_SHARED_POINTER
|
||||
template<class T>
|
||||
inline Row<T> create(QObject *parent) {
|
||||
return QSharedPointer<T>(new T(parent));
|
||||
}
|
||||
#else
|
||||
template<class T>
|
||||
inline Row<T> create() {
|
||||
return new T;
|
||||
}
|
||||
#endif
|
||||
```
|
||||
|
||||
So you can use the Nut::create function without considering in what way the library is being compiled. Example:
|
||||
```cpp
|
||||
auto post = Nut::create<Post>();
|
||||
```
|
||||
|
||||
In above example if *NUT_SHARED_POINTER* is defined *post* is *QSharedPointer<Post>* else is *Post\**
|
||||
|
||||
I recommand use *NUT_SHARED_POINTER* always!
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
### Read data from database:
|
||||
|
||||
```cpp
|
||||
auto posts = db.posts()->query()
|
||||
->where(Post::idField() == postId)
|
||||
->toList();
|
||||
// now posts is a QList<Post*> contain all posts in
|
||||
// database that has id equal to postId variable
|
||||
auto post = q->first();
|
||||
// post is first row in database that its id is equal to postId
|
||||
```
|
||||
|
||||
### Adding to database:
|
||||
```cpp
|
||||
auto newPost = Nut::create<Post>();
|
||||
newPost->setTitle("post title");
|
||||
|
||||
db.posts()->append(newPost);
|
||||
|
||||
for(int i = 0 ; i < 3; i++){
|
||||
// Below line same as new Comment in non shared pointer mode
|
||||
// or QSharedPointer<Comment>(new Comment) in shared_pointer mode
|
||||
|
||||
auto comment = Nut::create<Comment>();
|
||||
comment->setMessage("comment #" + QString::number(i));
|
||||
|
||||
newPost->comments()->append(comment);
|
||||
}
|
||||
db.saveChanges();
|
||||
```
|
||||
|
||||
### Modify database data:
|
||||
```cpp
|
||||
auto post = db.posts()->query()
|
||||
->where(Post::idField() == postId)
|
||||
->first();
|
||||
|
||||
if(post) {
|
||||
post->setTitle("new name");
|
||||
db.saveChanges();
|
||||
} else {
|
||||
qWarning("No post found!");
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
The class must inherits from Table class
|
||||
|
||||
## Add primary key field
|
||||
Primary key can be auto increment
|
||||
|
||||
```cpp
|
||||
NUT_PRIMARY_AUTO_INCREMENT(id)
|
||||
NUT_DECLARE_FIELD(int, id, id, setId)
|
||||
```
|
||||
|
||||
for declaring primary key use _NUT_PRIMARY_KEY_ macro, if primary key is auto increment use _NUT_PRIMARY_AUTO_INCREMENT_
|
||||
|
||||
| Macro | Description |
|
||||
| ----------------------------- |:------------------------------------------------|
|
||||
| NUT_PRIMARY_KEY(x) | The field *x* is primary key |
|
||||
| NUT_AUTO_INCREMENT(x) | The field *x* is auto increment |
|
||||
| NUT_PRIMARY_AUTO_INCREMENT(x) | The field *x* is primary key and auto increment |
|
||||
|
||||
## Declare field
|
||||
```cpp
|
||||
NUT_DECLARE_FIELD(type, property_name, read_method_name, write_method_name)
|
||||
```
|
||||
## Additional meta data
|
||||
| Macro | Description |
|
||||
| ----------------------------- |:-------------------------------------------------|
|
||||
| NUT_NOT_NULL(x) | The field *x* is not allowed to store NULL value |
|
||||
| NUT_LEN(x, len) | Max length of *x* is *len* in string types and in numeric typed field *x* will be store in *len* bytes |
|
||||
| NUT_DEFAULT_VALUE(x, def) | Default value of *x* is *def* |
|
||||
| NUT_UNIQUE(x) | Field *x* is unique (Not imlemented yet!) |
|
||||
| NUT_DISPLAY_NAME(field, name) | Sets display name for field (used in model creation |
|
||||
|
||||
## Sample table
|
||||
```cpp
|
||||
class Post : public Table
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
NUT_PRIMARY_AUTO_INCREMENT(id)
|
||||
NUT_DECLARE_FIELD(int, id, id, setId)
|
||||
|
||||
NUT_NOT_NULL(title)
|
||||
NUT_LEN(title, 50)
|
||||
NUT_DECLARE_FIELD(QString, title, title, setTitle)
|
||||
|
||||
NUT_DECLARE_FIELD(QDateTime, saveDate, saveDate, setSaveDate)
|
||||
|
||||
NUT_LEN(body, 200)
|
||||
NUT_DECLARE_FIELD(QString, body, body, setBody)
|
||||
public:
|
||||
explicit Post(QObject *tableSet = 0);
|
||||
|
||||
};
|
||||
```
|
||||
|
||||
## Declare child table
|
||||
If current table has one-to-many relation ship it must be declared. For example post table has a slave table named comment, every post has many comment:
|
||||
```cpp
|
||||
NUT_DECLARE_CHILD_TABLE(Comment, comments)
|
||||
```
|
||||
|
||||
First argument id table name and second is field name, m_comments must be initalized in constructor:
|
||||
```cpp
|
||||
Post::Post(QObject *parent) : Table(parent),
|
||||
m_comments(new TableSet<Comment>(this)), m_id(0), m_title("")
|
||||
{
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
For more example take a look at _tests/common_ folder
|
||||
|
|
@ -87,12 +87,53 @@ public: \
|
|||
NUT_DECLARE_FIELD(keytype, name##Id, read##Id, write##Id) \
|
||||
NUT_INFO(__nut_FOREIGN_KEY, name, type) \
|
||||
Nut::Row<type> m_##name; \
|
||||
public: \
|
||||
public slots: \
|
||||
Nut::Row<type> read() const { return m_##name ; } \
|
||||
void write(Nut::Row<type> name){ \
|
||||
Q_INVOKABLE void write(Nut::Row<type> name){ \
|
||||
m_##name = name; \
|
||||
}
|
||||
|
||||
#define NUT_FOREIGN_KEY_DECLARE(type, keytype, name, read, write) \
|
||||
NUT_INFO(__nut_FIELD, name##Id, 0) \
|
||||
NUT_INFO(__nut_FOREIGN_KEY, name, type) \
|
||||
Nut::Row<type> m_##name; \
|
||||
keytype m_##name##Id; \
|
||||
Q_PROPERTY(Nut::Row<type> name READ read WRITE write) \
|
||||
Q_PROPERTY(keytype name##Id READ read##Id WRITE write##Id) \
|
||||
public: \
|
||||
Nut::Row<type> read() const; \
|
||||
void write(Nut::Row<type> name); \
|
||||
static NUT_WRAP_NAMESPACE(FieldPhrase<keytype>)& name##Id ## Field(){ \
|
||||
static NUT_WRAP_NAMESPACE(FieldPhrase<keytype>) f = \
|
||||
NUT_WRAP_NAMESPACE(FieldPhrase<keytype>) \
|
||||
(staticMetaObject.className(), #name); \
|
||||
return f; \
|
||||
} \
|
||||
keytype read##Id() const; \
|
||||
void write##Id(keytype name##Id);
|
||||
|
||||
#define NUT_FOREIGN_KEY_IMPLEMENT(class, type, keytype, name, read, write) \
|
||||
\
|
||||
Nut::Row<type> class::read() const { return m_##name ; } \
|
||||
void class::write(Nut::Row<type> name){ \
|
||||
propertyChanged(QT_STRINGIFY2(name##Id)); \
|
||||
m_##name = name; \
|
||||
m_##name##Id = name->primaryValue().value<keytype>(); \
|
||||
} \
|
||||
\
|
||||
keytype class::read##Id() const{ \
|
||||
if (m_##name) \
|
||||
return m_##name->primaryValue().value<keytype>(); \
|
||||
return m_##name##Id; \
|
||||
} \
|
||||
void class::write##Id(keytype name##Id){ \
|
||||
propertyChanged(QT_STRINGIFY2(name##Id)); \
|
||||
m_##name##Id = name##Id; \
|
||||
m_##name = nullptr; \
|
||||
propertyChanged(QT_STRINGIFY2(name##Id)); \
|
||||
}
|
||||
|
||||
|
||||
#define NUT_DECLARE_CHILD_TABLE(type, n) \
|
||||
private: \
|
||||
NUT_WRAP_NAMESPACE(TableSet)<type> *m_##n; \
|
||||
|
|
@ -110,9 +151,20 @@ public: \
|
|||
}
|
||||
|
||||
#define NUT_FIELD(name) NUT_INFO(__nut_FIELD, name, 0)
|
||||
#define NUT_PRIMARY_KEY(x) NUT_INFO(__nut_PRIMARY_KEY, x, 0)
|
||||
#define NUT_PRIMARY_KEY(x) NUT_INFO(__nut_PRIMARY_KEY, x, 0) \
|
||||
public: \
|
||||
QVariant primaryValue() const override { \
|
||||
return property(#x); \
|
||||
} \
|
||||
void setPrimaryValue(const QVariant &value) override { \
|
||||
setProperty(#x, value); \
|
||||
} \
|
||||
private:
|
||||
|
||||
|
||||
#define NUT_AUTO_INCREMENT(x) NUT_INFO(__nut_AUTO_INCREMENT, x, 0)
|
||||
#define NUT_PRIMARY_AUTO_INCREMENT(x) NUT_INFO(__nut_PRIMARY_KEY_AI, x, 0)
|
||||
#define NUT_PRIMARY_AUTO_INCREMENT(x) NUT_INFO(__nut_PRIMARY_KEY_AI, x, 0)\
|
||||
NUT_PRIMARY_KEY(X) NUT_AUTO_INCREMENT(X)
|
||||
#define NUT_DISPLAY_NAME(field, name) NUT_INFO(__nut_DISPLAY, field, name)
|
||||
#define NUT_UNIQUE(x) NUT_INFO(__nut_UNIQUE, x, 0)
|
||||
#define NUT_LEN(field, len) NUT_INFO(__nut_LEN, field, len)
|
||||
|
|
@ -250,6 +302,32 @@ inline T *get(const QSharedPointer<T> row) {
|
|||
|
||||
#endif
|
||||
|
||||
//template<class C, typename T>
|
||||
//struct ForeignKeyData {
|
||||
// Nut::Row<C> _table;
|
||||
// T _id;
|
||||
|
||||
// ForeignKeyData() : _table(nullptr)
|
||||
// {}
|
||||
|
||||
// void setTable(Nut::Row<C> t) {
|
||||
// _table = t;
|
||||
// _id = t->primaryValue().value<T>();
|
||||
// }
|
||||
// Nut::Row<C> table() const {
|
||||
// return _table;
|
||||
// }
|
||||
// void setValue(const T& val) {
|
||||
// _table = nullptr;
|
||||
// _id = val;
|
||||
// }
|
||||
// T value() const {
|
||||
// if (_table)
|
||||
// return _table->primaryValue().value<T>();
|
||||
// return _id;
|
||||
// }
|
||||
//};
|
||||
|
||||
NUT_END_NAMESPACE
|
||||
|
||||
#endif // SYNTAX_DEFINES_H
|
||||
|
|
|
|||
|
|
@ -290,4 +290,41 @@ bool MySqlGenerator::readInsideParentese(QString &text, QString &out)
|
|||
// return command;
|
||||
//}
|
||||
|
||||
QString MySqlGenerator::createConditionalPhrase(const PhraseData *d) const
|
||||
{
|
||||
if (!d)
|
||||
return QString();
|
||||
|
||||
PhraseData::Condition op = d->operatorCond;
|
||||
//apply not (!)
|
||||
if (d->isNot) {
|
||||
if (op < 20)
|
||||
op = static_cast<PhraseData::Condition>((op + 10) % 20);
|
||||
}
|
||||
|
||||
if (d->type == PhraseData::WithVariant) {
|
||||
if (op == PhraseData::AddYears)
|
||||
return QString("DATE_ADD(%2, INTERVAL %1 YEAR)")
|
||||
.arg(d->operand.toString(), createConditionalPhrase(d->left));
|
||||
else if (op == PhraseData::AddMonths)
|
||||
return QString("DATE_ADD(%2, INTERVAL %1 MONTH)")
|
||||
.arg(d->operand.toString(), createConditionalPhrase(d->left));
|
||||
else if (op == PhraseData::AddDays)
|
||||
return QString("DATE_ADD(%2, INTERVAL %1 DAY)")
|
||||
.arg(d->operand.toString(), createConditionalPhrase(d->left));
|
||||
else if (op == PhraseData::AddHours)
|
||||
return QString("DATE_ADD(%2, INTERVAL %1 HOUR)")
|
||||
.arg(d->operand.toString(), createConditionalPhrase(d->left));
|
||||
else if (op == PhraseData::AddMinutes)
|
||||
return QString("DATE_ADD(%2, INTERVAL %1 MINUTE)")
|
||||
.arg(d->operand.toString(), createConditionalPhrase(d->left));
|
||||
else if (op == PhraseData::AddSeconds)
|
||||
return QString("DATE_ADD(%2, INTERVAL %1 SECOND)")
|
||||
.arg(d->operand.toString(), createConditionalPhrase(d->left));
|
||||
|
||||
}
|
||||
|
||||
return SqlGeneratorBase::createConditionalPhrase(d);
|
||||
}
|
||||
|
||||
NUT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -31,11 +31,12 @@ class MySqlGenerator : public SqlGeneratorBase
|
|||
public:
|
||||
explicit MySqlGenerator(Database *parent = 0);
|
||||
|
||||
QString fieldType(FieldModel *field);
|
||||
QString escapeValue(const QVariant &v) const;
|
||||
QVariant unescapeValue(const QMetaType::Type &type, const QVariant &dbValue);
|
||||
QString fieldType(FieldModel *field) override;
|
||||
QString escapeValue(const QVariant &v) const override;
|
||||
QVariant unescapeValue(const QMetaType::Type &type, const QVariant &dbValue) override;
|
||||
// QString phrase(const PhraseData *d) const;
|
||||
// QString selectCommand(AgregateType t, QString agregateArg, QString tableName, QList<WherePhrase> &wheres, QList<WherePhrase> &orders, QList<RelationModel *> joins, int skip, int take);
|
||||
QString createConditionalPhrase(const PhraseData *d) const override;
|
||||
private:
|
||||
bool readInsideParentese(QString &text, QString &out);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -328,12 +328,38 @@ QString PostgreSqlGenerator::createConditionalPhrase(const PhraseData *d) const
|
|||
if (!d)
|
||||
return QString();
|
||||
|
||||
PhraseData::Condition op = d->operatorCond;
|
||||
//apply not (!)
|
||||
if (d->isNot) {
|
||||
if (op < 20)
|
||||
op = static_cast<PhraseData::Condition>((op + 10) % 20);
|
||||
}
|
||||
|
||||
if (d->type == PhraseData::WithVariant) {
|
||||
if (isPostGisType(d->operand.type()) && d->operatorCond == PhraseData::Equal) {
|
||||
return QString("%1 ~= %2")
|
||||
.arg(SqlGeneratorBase::createConditionalPhrase(d->left),
|
||||
escapeValue(d->operand));
|
||||
}
|
||||
if (op == PhraseData::AddYears)
|
||||
return QString("DATEADD(year, %1, %2)")
|
||||
.arg(d->operand.toString(), createConditionalPhrase(d->left));
|
||||
else if (op == PhraseData::AddMonths)
|
||||
return QString("DATEADD(month, %1, %2)")
|
||||
.arg(d->operand.toString(), createConditionalPhrase(d->left));
|
||||
else if (op == PhraseData::AddDays)
|
||||
return QString("DATEADD(day, %1, %2)")
|
||||
.arg(d->operand.toString(), createConditionalPhrase(d->left));
|
||||
else if (op == PhraseData::AddHours)
|
||||
return QString("DATEADD(hour, %1, %2)")
|
||||
.arg(d->operand.toString(), createConditionalPhrase(d->left));
|
||||
else if (op == PhraseData::AddMinutes)
|
||||
return QString("DATEADD(minute, %1, %2)")
|
||||
.arg(d->operand.toString(), createConditionalPhrase(d->left));
|
||||
else if (op == PhraseData::AddSeconds)
|
||||
return QString("DATEADD(second, %1, %2)")
|
||||
.arg(d->operand.toString(), createConditionalPhrase(d->left));
|
||||
|
||||
}
|
||||
|
||||
return SqlGeneratorBase::createConditionalPhrase(d);
|
||||
|
|
|
|||
|
|
@ -446,16 +446,17 @@ QString SqlGeneratorBase::insertRecord(Table *t, QString tableName)
|
|||
|
||||
QStringList values;
|
||||
|
||||
foreach (QString f, t->changedProperties())
|
||||
if (f != key)
|
||||
values.append(escapeValue(t->property(f.toLatin1().data())));
|
||||
|
||||
QString changedPropertiesText = QString();
|
||||
QSet<QString> props = t->changedProperties();
|
||||
foreach (QString s, props) {
|
||||
QString changedPropertiesText = QString();
|
||||
foreach (QString f, props) {
|
||||
if (f == key)
|
||||
continue;
|
||||
|
||||
values.append(escapeValue(t->property(f.toLatin1().data())));
|
||||
|
||||
if (changedPropertiesText != "")
|
||||
changedPropertiesText.append(", ");
|
||||
changedPropertiesText.append(s);
|
||||
changedPropertiesText.append(f);
|
||||
}
|
||||
sql = QString("INSERT INTO %1 (%2) VALUES (%3)")
|
||||
.arg(tableName, changedPropertiesText, values.join(", "));
|
||||
|
|
@ -784,6 +785,31 @@ void SqlGeneratorBase::removeTableNames(QString &command)
|
|||
command = command.replace("[" + m->className() + "].", "");
|
||||
}
|
||||
|
||||
QString SqlGeneratorBase::dateTimePartName(const PhraseData::Condition &op) const
|
||||
{
|
||||
switch (op) {
|
||||
case PhraseData::AddYears:
|
||||
case PhraseData::AddYearsDateTime:
|
||||
return "YEAR";
|
||||
case PhraseData::AddMonths:
|
||||
case PhraseData::AddMonthsDateTime:
|
||||
return "MONTH";
|
||||
case PhraseData::AddDays:
|
||||
case PhraseData::AddDaysDateTime:
|
||||
return "DAY";
|
||||
case PhraseData::AddHours:
|
||||
case PhraseData::AddHoursDateTime:
|
||||
return "HOUR";
|
||||
case PhraseData::AddMinutes:
|
||||
case PhraseData::AddMinutesDateTime:
|
||||
return "MINUTE";
|
||||
case PhraseData::AddSeconds:
|
||||
case PhraseData::AddSecondsDateTime:
|
||||
return "SECOND";
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
//QString SqlGeneratorBase::deleteCommand(QList<WherePhrase> &wheres,
|
||||
// QString tableName)
|
||||
//{
|
||||
|
|
@ -972,7 +998,7 @@ QString SqlGeneratorBase::createConditionalPhrase(const PhraseData *d) const
|
|||
break;
|
||||
|
||||
case PhraseData::WithVariant:
|
||||
if (op == PhraseData::AddYears)
|
||||
/* if (op == PhraseData::AddYears)
|
||||
ret = QString("DATEADD(year, %1, %2)")
|
||||
.arg(d->operand.toString(), createConditionalPhrase(d->left));
|
||||
else if (op == PhraseData::AddMonths)
|
||||
|
|
@ -990,7 +1016,12 @@ QString SqlGeneratorBase::createConditionalPhrase(const PhraseData *d) const
|
|||
else if (op == PhraseData::AddSeconds)
|
||||
ret = QString("DATEADD(second, %1, %2)")
|
||||
.arg(d->operand.toString(), createConditionalPhrase(d->left));
|
||||
else if (op == PhraseData::DatePartYear)
|
||||
else */if (op == PhraseData::Between) {
|
||||
QVariantList list = d->operand.toList();
|
||||
ret = QString("%1 BETWEEN %2 AND %3")
|
||||
.arg(createConditionalPhrase(d->left), escapeValue(list.at(0)), escapeValue(list.at(1)));
|
||||
|
||||
} else if (op == PhraseData::DatePartYear)
|
||||
ret = QString("DATEPART(year, %1)")
|
||||
.arg(d->operand.toString());
|
||||
else if (op == PhraseData::DatePartMonth)
|
||||
|
|
|
|||
|
|
@ -162,6 +162,7 @@ protected:
|
|||
|
||||
void replaceTableNames(QString &command);
|
||||
void removeTableNames(QString &command);
|
||||
QString dateTimePartName(const PhraseData::Condition &op) const;
|
||||
};
|
||||
|
||||
NUT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -205,4 +205,116 @@ QString SqliteGenerator::primaryKeyConstraint(const TableModel *table) const
|
|||
// return sql;
|
||||
}
|
||||
|
||||
QString SqliteGenerator::createConditionalPhrase(const PhraseData *d) const
|
||||
{
|
||||
if (!d)
|
||||
return QString();
|
||||
|
||||
PhraseData::Condition op = d->operatorCond;
|
||||
//apply not (!)
|
||||
if (d->isNot) {
|
||||
if (op < 20)
|
||||
op = static_cast<PhraseData::Condition>((op + 10) % 20);
|
||||
}
|
||||
|
||||
if (d->type == PhraseData::WithVariant) {
|
||||
switch (op) {
|
||||
case PhraseData::AddYears:
|
||||
case PhraseData::AddMonths:
|
||||
case PhraseData::AddDays: {
|
||||
int i = d->operand.toInt();
|
||||
return QString("DATE(%1,'%2 %3')")
|
||||
.arg(createConditionalPhrase(d->left),
|
||||
(i < 0 ? "" : "+") + QString::number(i),
|
||||
dateTimePartName(op));
|
||||
break;
|
||||
}
|
||||
case PhraseData::AddHours:
|
||||
case PhraseData::AddMinutes:
|
||||
case PhraseData::AddSeconds: {
|
||||
int i = d->operand.toInt();
|
||||
return QString("TIME(%1,'%2 %3')")
|
||||
.arg(createConditionalPhrase(d->left),
|
||||
(i < 0 ? "" : "+") + QString::number(i),
|
||||
dateTimePartName(op));
|
||||
break;
|
||||
}
|
||||
case PhraseData::AddYearsDateTime:
|
||||
case PhraseData::AddMonthsDateTime:
|
||||
case PhraseData::AddDaysDateTime:
|
||||
case PhraseData::AddHoursDateTime:
|
||||
case PhraseData::AddMinutesDateTime:
|
||||
case PhraseData::AddSecondsDateTime: {
|
||||
int i = d->operand.toInt();
|
||||
return QString("DATETIME(%1,'%2 %3')")
|
||||
.arg(createConditionalPhrase(d->left),
|
||||
(i < 0 ? "" : "+") + QString::number(i),
|
||||
dateTimePartName(op));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (d->type == PhraseData::WithoutOperand) {
|
||||
switch (op) {
|
||||
case PhraseData::DatePartYear:
|
||||
return QString("CAST(strftime('%Y', %1) AS INT)")
|
||||
.arg(createConditionalPhrase(d->left));
|
||||
|
||||
case PhraseData::DatePartMonth:
|
||||
return QString("CAST(strftime('%m', %1) AS INT)")
|
||||
.arg(createConditionalPhrase(d->left));
|
||||
|
||||
case PhraseData::DatePartDay:
|
||||
return QString("CAST(strftime('%d', %1) AS INT)")
|
||||
.arg(createConditionalPhrase(d->left));
|
||||
|
||||
case PhraseData::DatePartHour:
|
||||
return QString("CAST(strftime('%H', %1) AS INT)")
|
||||
.arg(createConditionalPhrase(d->left));
|
||||
|
||||
case PhraseData::DatePartMinute:
|
||||
return QString("CAST(strftime('%M', %1) AS INT)")
|
||||
.arg(createConditionalPhrase(d->left));
|
||||
|
||||
case PhraseData::DatePartSecond:
|
||||
return QString("CAST(strftime('%S', %1) AS INT)")
|
||||
.arg(createConditionalPhrase(d->left));
|
||||
|
||||
// case PhraseData::DatePartMilisecond:
|
||||
// return QString("CAST(strftime('%Y', %1) AS INT)")
|
||||
// .arg(createConditionalPhrase(d->left));
|
||||
}
|
||||
}
|
||||
|
||||
return SqlGeneratorBase::createConditionalPhrase(d);
|
||||
}
|
||||
|
||||
QString SqliteGenerator::escapeValue(const QVariant &v) const
|
||||
{
|
||||
if (v.type() == QVariant::Time)
|
||||
return "'" + v.toTime().toString("HH:mm:ss") + "'";
|
||||
|
||||
if (v.type() == QVariant::Date)
|
||||
return "'" + v.toDate().toString("yyyy-MM-dd") + "'";
|
||||
|
||||
if (v.type() == QVariant::DateTime)
|
||||
return "'" + v.toDateTime().toString("yyyy-MM-dd HH:mm:ss") + "'";
|
||||
|
||||
return SqlGeneratorBase::escapeValue(v);
|
||||
}
|
||||
|
||||
QVariant SqliteGenerator::unescapeValue(const QMetaType::Type &type, const QVariant &dbValue)
|
||||
{
|
||||
if (type == QMetaType::QDateTime)
|
||||
return dbValue.toDateTime();
|
||||
|
||||
if (type == QMetaType::QTime)
|
||||
return dbValue.toTime();
|
||||
|
||||
if (type == QMetaType::QDate)
|
||||
return dbValue.toDate();
|
||||
|
||||
return SqlGeneratorBase::unescapeValue(type, dbValue);
|
||||
}
|
||||
|
||||
NUT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -41,6 +41,10 @@ public:
|
|||
QString primaryKeyConstraint(const TableModel *table) const override;
|
||||
QStringList diff(TableModel *oldTable, TableModel *newTable) override;
|
||||
|
||||
QString createConditionalPhrase(const PhraseData *d) const override;
|
||||
|
||||
QString escapeValue(const QVariant &v) const override;
|
||||
QVariant unescapeValue(const QMetaType::Type &type, const QVariant &dbValue) override;
|
||||
};
|
||||
|
||||
NUT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -20,3 +20,128 @@
|
|||
|
||||
#include "datephrase.h"
|
||||
|
||||
NUT_BEGIN_NAMESPACE
|
||||
|
||||
FieldPhrase<QDate>::FieldPhrase(const char *className, const char *s) :
|
||||
AbstractFieldPhrase(className, s)
|
||||
{}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QDate>::addYears(int years) {
|
||||
return ConditionalPhrase(this, PhraseData::AddYears, years);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QDate>::addMonths(int months) {
|
||||
return ConditionalPhrase(this, PhraseData::AddMonths, months);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QDate>::addDays(int days) {
|
||||
return ConditionalPhrase(this, PhraseData::AddDays, days);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QDate>::year() {
|
||||
return ConditionalPhrase(this, PhraseData::DatePartYear);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QDate>::month() {
|
||||
return ConditionalPhrase(this, PhraseData::DatePartMonth);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QDate>::day() {
|
||||
return ConditionalPhrase(this, PhraseData::DatePartDay);
|
||||
}
|
||||
|
||||
FieldPhrase<QTime>::FieldPhrase(const char *className, const char *s) :
|
||||
AbstractFieldPhrase(className, s)
|
||||
{}
|
||||
|
||||
|
||||
ConditionalPhrase FieldPhrase<QTime>::addHours(int hours) {
|
||||
return ConditionalPhrase(this, PhraseData::AddHours, hours);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QTime>::addMinutes(int minutes) {
|
||||
return ConditionalPhrase(this, PhraseData::AddMinutes, minutes);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QTime>::addSeconds(int seconds) {
|
||||
return ConditionalPhrase(this, PhraseData::AddSeconds, seconds);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QTime>::hour() {
|
||||
return ConditionalPhrase(this, PhraseData::DatePartHour);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QTime>::minute() {
|
||||
return ConditionalPhrase(this, PhraseData::DatePartMinute);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QTime>::second() {
|
||||
return ConditionalPhrase(this, PhraseData::DatePartSecond);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QTime>::msec() {
|
||||
return ConditionalPhrase(this, PhraseData::DatePartMilisecond);
|
||||
}
|
||||
|
||||
FieldPhrase<QDateTime>::FieldPhrase(const char *className, const char *s) :
|
||||
AbstractFieldPhrase(className, s)
|
||||
{}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QDateTime>::addYears(int years) {
|
||||
return ConditionalPhrase(this, PhraseData::AddYearsDateTime, years);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QDateTime>::addMonths(int months) {
|
||||
return ConditionalPhrase(this, PhraseData::AddMonthsDateTime, months);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QDateTime>::addDays(int days) {
|
||||
return ConditionalPhrase(this, PhraseData::AddDaysDateTime, days);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QDateTime>::addHours(int hours) {
|
||||
return ConditionalPhrase(this, PhraseData::AddHoursDateTime, hours);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QDateTime>::addMinutes(int minutes) {
|
||||
return ConditionalPhrase(this, PhraseData::AddMinutesDateTime, minutes);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QDateTime>::addSeconds(int seconds) {
|
||||
return ConditionalPhrase(this, PhraseData::AddSecondsDateTime, seconds);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QDateTime>::year() {
|
||||
return ConditionalPhrase(this, PhraseData::DatePartYear);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QDateTime>::month() {
|
||||
return ConditionalPhrase(this, PhraseData::DatePartMonth);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QDateTime>::day() {
|
||||
return ConditionalPhrase(this, PhraseData::DatePartDay);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QDateTime>::hour() {
|
||||
return ConditionalPhrase(this, PhraseData::DatePartHour);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QDateTime>::minute() {
|
||||
return ConditionalPhrase(this, PhraseData::DatePartMinute);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QDateTime>::second() {
|
||||
return ConditionalPhrase(this, PhraseData::DatePartSecond);
|
||||
}
|
||||
|
||||
ConditionalPhrase FieldPhrase<QDateTime>::msec() {
|
||||
return ConditionalPhrase(this, PhraseData::DatePartMilisecond);
|
||||
}
|
||||
|
||||
|
||||
COMMON_OPERATORS_IMPL(QDate)
|
||||
COMMON_OPERATORS_IMPL(QTime)
|
||||
COMMON_OPERATORS_IMPL(QDateTime)
|
||||
|
||||
NUT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -27,145 +27,96 @@
|
|||
|
||||
NUT_BEGIN_NAMESPACE
|
||||
|
||||
#define COMMON_OPERATORS_DECL(T) \
|
||||
AssignmentPhrase operator =(const T &other); \
|
||||
ConditionalPhrase operator <(const QVariant &other); \
|
||||
ConditionalPhrase operator <=(const QVariant &other); \
|
||||
ConditionalPhrase operator >(const QVariant &other); \
|
||||
ConditionalPhrase operator >=(const QVariant &other); \
|
||||
ConditionalPhrase between(const QVariant &min, const QVariant &max);
|
||||
|
||||
template<typename>
|
||||
struct __is_date_helper
|
||||
: public std::false_type { };
|
||||
#define COMMON_OPERATORS_IMPL(T) \
|
||||
AssignmentPhrase FieldPhrase<T>::operator =(const T &other) { \
|
||||
return AssignmentPhrase(this, other); \
|
||||
} \
|
||||
ConditionalPhrase FieldPhrase<T>::operator <(const QVariant &other) { \
|
||||
return ConditionalPhrase(this, PhraseData::Less, other); \
|
||||
} \
|
||||
ConditionalPhrase FieldPhrase<T>::operator <=(const QVariant &other) { \
|
||||
return ConditionalPhrase(this, PhraseData::LessEqual, other); \
|
||||
} \
|
||||
ConditionalPhrase FieldPhrase<T>::operator >(const QVariant &other) { \
|
||||
return ConditionalPhrase(this, PhraseData::Greater, other); \
|
||||
} \
|
||||
ConditionalPhrase FieldPhrase<T>::operator >=(const QVariant &other) { \
|
||||
return ConditionalPhrase(this, PhraseData::GreaterEqual, other); \
|
||||
} \
|
||||
ConditionalPhrase FieldPhrase<T>::between(const QVariant &min, const QVariant &max) \
|
||||
{ \
|
||||
return ConditionalPhrase(this, PhraseData::Between, \
|
||||
QVariantList() << min << max); \
|
||||
}
|
||||
|
||||
template<>
|
||||
struct __is_date_helper<QTime>
|
||||
: public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_date_helper<QDate>
|
||||
: public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct __is_date_helper<QDateTime>
|
||||
: public std::true_type { };
|
||||
|
||||
template<typename _Tp>
|
||||
struct is_date
|
||||
: public __is_date_helper<typename std::remove_cv<_Tp>::type>::type
|
||||
{ };
|
||||
|
||||
|
||||
template <class T, class P>
|
||||
inline bool is_valid_template() {return false;}
|
||||
|
||||
template <>
|
||||
inline bool is_valid_template<QDateTime, QTime>() {return true;}
|
||||
|
||||
template <>
|
||||
inline bool is_valid_template<QDateTime, QDate>() {return true;}
|
||||
|
||||
template <>
|
||||
inline bool is_valid_template<QDate, QDate>() {return true;}
|
||||
|
||||
template <>
|
||||
inline bool is_valid_template<QTime, QTime>() {return true;}
|
||||
|
||||
template <typename T>
|
||||
class NUT_EXPORT FieldPhrase<T, typename std::enable_if<is_date<T>::value>::type>
|
||||
: public AbstractFieldPhrase
|
||||
class NUT_EXPORT FieldPhrase<QDate> : public AbstractFieldPhrase
|
||||
{
|
||||
public:
|
||||
FieldPhrase(const char *className, const char *s) :
|
||||
AbstractFieldPhrase(className, s)
|
||||
{}
|
||||
FieldPhrase(const char *className, const char *s);
|
||||
|
||||
AssignmentPhrase operator =(const T &other) {
|
||||
return AssignmentPhrase(this, other);
|
||||
}
|
||||
COMMON_OPERATORS_DECL(QDate)
|
||||
|
||||
ConditionalPhrase operator <(const QVariant &other) {
|
||||
return ConditionalPhrase(this, PhraseData::Less, other);
|
||||
}
|
||||
ConditionalPhrase operator <=(const QVariant &other) {
|
||||
return ConditionalPhrase(this, PhraseData::LessEqual, other);
|
||||
}
|
||||
ConditionalPhrase operator >(const QVariant &other) {
|
||||
return ConditionalPhrase(this, PhraseData::Greater, other);
|
||||
}
|
||||
ConditionalPhrase operator >=(const QVariant &other) {
|
||||
return ConditionalPhrase(this, PhraseData::GreaterEqual, other);
|
||||
}
|
||||
ConditionalPhrase addYears(int years);
|
||||
ConditionalPhrase addMonths(int months);
|
||||
ConditionalPhrase addDays(int days);
|
||||
|
||||
ConditionalPhrase between(const QVariant &min, const QVariant &max)
|
||||
{
|
||||
return ConditionalPhrase(this, PhraseData::Between,
|
||||
QVariantList() << min << max);
|
||||
}
|
||||
ConditionalPhrase year();
|
||||
ConditionalPhrase month();
|
||||
ConditionalPhrase day();
|
||||
};
|
||||
|
||||
// template<class P = T,
|
||||
// class std::enable_if<std::is_same<P, QDateTime>::value, int>::type = 0>
|
||||
ConditionalPhrase addYears(int val) {
|
||||
if (!is_valid_template<T, QDate>())
|
||||
return ConditionalPhrase();
|
||||
return ConditionalPhrase(this, PhraseData::AddYears, val);
|
||||
}
|
||||
ConditionalPhrase addMonths(int val) {
|
||||
if (!is_valid_template<T, QDate>())
|
||||
return ConditionalPhrase();
|
||||
return ConditionalPhrase(this, PhraseData::AddMonths, val);
|
||||
}
|
||||
ConditionalPhrase addDays(int val) {
|
||||
if (!is_valid_template<T, QDate>())
|
||||
return ConditionalPhrase();
|
||||
return ConditionalPhrase(this, PhraseData::AddDays, val);
|
||||
}
|
||||
template<>
|
||||
class NUT_EXPORT FieldPhrase<QTime> : public AbstractFieldPhrase
|
||||
{
|
||||
public:
|
||||
FieldPhrase(const char *className, const char *s);
|
||||
|
||||
ConditionalPhrase addHours(int val) {
|
||||
if (!is_valid_template<T, QTime>())
|
||||
return ConditionalPhrase();
|
||||
return ConditionalPhrase(this, PhraseData::AddHours, val);
|
||||
}
|
||||
ConditionalPhrase addMinutes(int val) {
|
||||
if (!is_valid_template<T, QTime>())
|
||||
return ConditionalPhrase();
|
||||
return ConditionalPhrase(this, PhraseData::AddMinutes, val);
|
||||
}
|
||||
ConditionalPhrase addSeconds(int val) {
|
||||
if (!is_valid_template<T, QTime>())
|
||||
return ConditionalPhrase();
|
||||
return ConditionalPhrase(this, PhraseData::AddSeconds, val);
|
||||
}
|
||||
COMMON_OPERATORS_DECL(QTime)
|
||||
|
||||
ConditionalPhrase year() {
|
||||
if (!is_valid_template<T, QDate>())
|
||||
return ConditionalPhrase();
|
||||
return ConditionalPhrase(this, PhraseData::DatePartYear);
|
||||
}
|
||||
ConditionalPhrase month() {
|
||||
if (!is_valid_template<T, QDate>())
|
||||
return ConditionalPhrase();
|
||||
return ConditionalPhrase(this, PhraseData::DatePartMonth);
|
||||
}
|
||||
ConditionalPhrase day() {
|
||||
if (!is_valid_template<T, QDate>())
|
||||
return ConditionalPhrase();
|
||||
return ConditionalPhrase(this, PhraseData::DatePartDay);
|
||||
}
|
||||
ConditionalPhrase hour() {
|
||||
if (!is_valid_template<T, QTime>())
|
||||
return ConditionalPhrase();
|
||||
return ConditionalPhrase(this, PhraseData::DatePartHour);
|
||||
}
|
||||
ConditionalPhrase minute() {
|
||||
if (!is_valid_template<T, QTime>())
|
||||
return ConditionalPhrase();
|
||||
return ConditionalPhrase(this, PhraseData::DatePartMinute);
|
||||
}
|
||||
ConditionalPhrase second() {
|
||||
if (!is_valid_template<T, QTime>())
|
||||
return ConditionalPhrase();
|
||||
return ConditionalPhrase(this, PhraseData::DatePartSecond);
|
||||
}
|
||||
ConditionalPhrase msec() {
|
||||
if (!is_valid_template<T, QTime>())
|
||||
return ConditionalPhrase();
|
||||
return ConditionalPhrase(this, PhraseData::DatePartMilisecond);
|
||||
}
|
||||
ConditionalPhrase addHours(int hours);
|
||||
ConditionalPhrase addMinutes(int minutes);
|
||||
ConditionalPhrase addSeconds(int seconds);
|
||||
|
||||
ConditionalPhrase hour();
|
||||
ConditionalPhrase minute();
|
||||
ConditionalPhrase second();
|
||||
ConditionalPhrase msec();
|
||||
};
|
||||
|
||||
template<>
|
||||
class NUT_EXPORT FieldPhrase<QDateTime> : public AbstractFieldPhrase
|
||||
{
|
||||
public:
|
||||
FieldPhrase(const char *className, const char *s);
|
||||
|
||||
COMMON_OPERATORS_DECL(QDateTime)
|
||||
|
||||
ConditionalPhrase addYears(int year);
|
||||
ConditionalPhrase addMonths(int months);
|
||||
ConditionalPhrase addDays(int days);
|
||||
|
||||
|
||||
ConditionalPhrase addHours(int hours);
|
||||
ConditionalPhrase addMinutes(int minutes);
|
||||
ConditionalPhrase addSeconds(int seconds);
|
||||
|
||||
ConditionalPhrase year();
|
||||
ConditionalPhrase month();
|
||||
ConditionalPhrase day();
|
||||
|
||||
ConditionalPhrase hour();
|
||||
ConditionalPhrase minute();
|
||||
ConditionalPhrase second();
|
||||
ConditionalPhrase msec();
|
||||
};
|
||||
|
||||
NUT_END_NAMESPACE
|
||||
|
|
|
|||
|
|
@ -64,6 +64,14 @@ public:
|
|||
AddMinutes,
|
||||
AddSeconds,
|
||||
|
||||
// sqlite need to know works with qdate, qtime or qdatetime
|
||||
AddYearsDateTime,
|
||||
AddMonthsDateTime,
|
||||
AddDaysDateTime,
|
||||
AddHoursDateTime,
|
||||
AddMinutesDateTime,
|
||||
AddSecondsDateTime,
|
||||
|
||||
DatePartYear,
|
||||
DatePartMonth,
|
||||
DatePartDay,
|
||||
|
|
|
|||
29
src/query.h
29
src/query.h
|
|
@ -289,11 +289,13 @@ Q_OUTOFLINE_TEMPLATE RowList<T> Query<T>::toList(int count)
|
|||
|
||||
//create table row
|
||||
Table *table;
|
||||
Row<T> shp;
|
||||
if (data.table->className() == d->className) {
|
||||
table = new T();
|
||||
#ifdef NUT_SHARED_POINTER
|
||||
auto shp = QSharedPointer<T>(qobject_cast<T*>(table));
|
||||
shp = QSharedPointer<T>(qobject_cast<T*>(table));
|
||||
returnList.append(shp);
|
||||
d->tableSet->add(shp);
|
||||
#else
|
||||
returnList.append(dynamic_cast<T*>(table));
|
||||
#endif
|
||||
|
|
@ -317,12 +319,27 @@ Q_OUTOFLINE_TEMPLATE RowList<T> Query<T>::toList(int count)
|
|||
|
||||
for (int i = 0; i < data.masters.count(); ++i) {
|
||||
int master = data.masters[i];
|
||||
table->setProperty(data.masterFields[i].toLocal8Bit().data(),
|
||||
#ifdef NUT_SHARED_POINTER
|
||||
QString mName = QString("set%1").arg(levels[master].lastRow->metaObject()->className());
|
||||
QString type = QString("Nut::Row<%1>").arg(levels[master].lastRow->metaObject()->className());
|
||||
bool ok = table->metaObject()->invokeMethod(table,
|
||||
mName.toLocal8Bit().data(),
|
||||
QGenericArgument(type.toLatin1().data(), levels[master].lastRow));
|
||||
#else
|
||||
bool ok = table->setProperty(data.masterFields[i].toLocal8Bit().data(),
|
||||
QVariant::fromValue(levels[master].lastRow));
|
||||
#endif
|
||||
|
||||
table->setParentTableSet(
|
||||
levels[master].lastRow->childTableSet(
|
||||
data.table->className()));
|
||||
if (!ok)
|
||||
qWarning("Unable to set property %s::%s",
|
||||
table->metaObject()->className(), data.masterFields[i].toLocal8Bit().data());
|
||||
|
||||
auto tableset = levels[master].lastRow->childTableSet(
|
||||
data.table->className());
|
||||
table->setParentTableSet(tableset);
|
||||
#ifdef NUT_SHARED_POINTER
|
||||
tableset->add(qSharedPointerCast<Table>(shp));
|
||||
#endif
|
||||
}
|
||||
|
||||
table->setStatus(Table::FeatchedFromDB);
|
||||
|
|
@ -330,7 +347,7 @@ Q_OUTOFLINE_TEMPLATE RowList<T> Query<T>::toList(int count)
|
|||
table->clear();
|
||||
|
||||
//set last created row
|
||||
data.lastRow = table;
|
||||
data.lastRow = /*QSharedPointer<Table>*/(table);
|
||||
} //while
|
||||
} // while
|
||||
|
||||
|
|
|
|||
|
|
@ -73,27 +73,10 @@ QVariant SqlModel::data(const QModelIndex &index, int role) const
|
|||
if (role == Qt::DisplayRole) {
|
||||
Row<Table> t = d->rows.at(index.row());
|
||||
QVariant v = t->property(d->model->field(index.column())->name.toLocal8Bit().data());
|
||||
// emit beforeShowText(index.column(), v);
|
||||
|
||||
if (_renderer != nullptr)
|
||||
v = _renderer(index.column(), v);
|
||||
return v;
|
||||
// LogData *d = dataList.at(index.row());
|
||||
|
||||
// switch (index.column()) {
|
||||
// case COL_ID:
|
||||
// return index.row() + 1;
|
||||
// case COL_Type: {
|
||||
// return typeText(d->type);
|
||||
// }
|
||||
// case COL_TITLE:
|
||||
// return d->title;
|
||||
// case COL_File:
|
||||
// return d->file;
|
||||
// case COL_Function:
|
||||
// return d->function;
|
||||
// case COL_Line:
|
||||
// return d->line;
|
||||
// }
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
|
@ -101,9 +84,11 @@ QVariant SqlModel::data(const QModelIndex &index, int role) const
|
|||
void SqlModel::setRows(RowList<Table> rows)
|
||||
{
|
||||
d.detach();
|
||||
beginRemoveRows(QModelIndex(), 0, d->rows.count());
|
||||
d->rows.clear();
|
||||
endRemoveRows();
|
||||
if (d->rows.count()) {
|
||||
beginRemoveRows(QModelIndex(), 0, d->rows.count());
|
||||
d->rows.clear();
|
||||
endRemoveRows();
|
||||
}
|
||||
beginInsertRows(QModelIndex(), 0, rows.count());
|
||||
d->rows = rows;
|
||||
endInsertRows();
|
||||
|
|
|
|||
10
src/table.h
10
src/table.h
|
|
@ -55,14 +55,8 @@ public:
|
|||
|
||||
int save(Database *db);
|
||||
|
||||
// Q_DECL_DEPRECATED
|
||||
// QString primaryKey() const;
|
||||
|
||||
// Q_DECL_DEPRECATED
|
||||
// bool isPrimaryKeyAutoIncrement() const;
|
||||
|
||||
// Q_DECL_DEPRECATED
|
||||
// QVariant primaryValue() const;
|
||||
virtual QVariant primaryValue() const = 0;
|
||||
virtual void setPrimaryValue(const QVariant &value) = 0;
|
||||
|
||||
Status status() const;
|
||||
void setStatus(const Status &status);
|
||||
|
|
|
|||
|
|
@ -42,6 +42,9 @@ TableSetBase::~TableSetBase()
|
|||
{
|
||||
foreach (Table *t, data->tables)
|
||||
t->setParentTableSet(nullptr);
|
||||
|
||||
foreach (Row<Table> t, data->childs)
|
||||
t->setParentTableSet(nullptr);
|
||||
}
|
||||
|
||||
int TableSetBase::save(Database *db, bool cleanUp)
|
||||
|
|
@ -61,9 +64,12 @@ int TableSetBase::save(Database *db, bool cleanUp)
|
|||
|| t->status() == Table::Modified
|
||||
|| t->status() == Table::Deleted){
|
||||
rowsAffected += t->save(db);
|
||||
|
||||
if(cleanUp)
|
||||
#ifndef NUT_SHARED_POINTER
|
||||
t->deleteLater();
|
||||
#else
|
||||
remove(t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,7 +82,7 @@ int TableSetBase::save(Database *db, bool cleanUp)
|
|||
void TableSetBase::clearChilds()
|
||||
{
|
||||
#ifndef NUT_SHARED_POINTER
|
||||
foreach (Table *t, data->_childRows)
|
||||
foreach (Table *t, data->childRows)
|
||||
t->deleteLater();
|
||||
#endif
|
||||
data->childRows.clear();
|
||||
|
|
@ -98,6 +104,18 @@ void TableSetBase::remove(Table *t)
|
|||
data->childRows.removeOne(get(t));
|
||||
}
|
||||
|
||||
void TableSetBase::add(Row<Table> t)
|
||||
{
|
||||
data.detach();
|
||||
data->childs.append(t);
|
||||
}
|
||||
|
||||
void TableSetBase::remove(Row<Table> t)
|
||||
{
|
||||
data.detach();
|
||||
data->childs.removeOne(t);
|
||||
}
|
||||
|
||||
QString TableSetBase::childClassName() const
|
||||
{
|
||||
return data->childClassName;
|
||||
|
|
|
|||
|
|
@ -57,10 +57,13 @@ protected:
|
|||
// QString _childClassName;
|
||||
QExplicitlySharedDataPointer<TableSetBaseData> data;
|
||||
|
||||
private:
|
||||
public://TODO: change this to private
|
||||
void add(Table* t);
|
||||
void remove(Table *t);
|
||||
|
||||
void add(Row<Table> t);
|
||||
void remove(Row<Table> t);
|
||||
|
||||
friend class Table;
|
||||
friend class QueryBase;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
#include "comment.h"
|
||||
#include "post.h"
|
||||
#include "user.h"
|
||||
|
||||
Comment::Comment(QObject *parent) : Table(parent),
|
||||
m_author(Q_NULLPTR), m_post(Q_NULLPTR)
|
||||
Comment::Comment(QObject *parent) : Table(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
NUT_FOREIGN_KEY_IMPLEMENT(Comment, Post, int, post, post, setPost)
|
||||
NUT_FOREIGN_KEY_IMPLEMENT(Comment, User, int, author, author, setAuthor)
|
||||
|
|
|
|||
|
|
@ -21,8 +21,8 @@ class Comment : public Table
|
|||
NUT_DECLARE_FIELD(QDateTime, saveDate, saveDate, setSaveDate)
|
||||
NUT_DECLARE_FIELD(qreal, point, point, setPoint)
|
||||
|
||||
NUT_FOREGION_KEY(Post, int, post, post, setPost)
|
||||
NUT_FOREGION_KEY(User, int, author, author, setAuthor)
|
||||
NUT_FOREIGN_KEY_DECLARE(Post, int, post, post, setPost)
|
||||
NUT_FOREIGN_KEY_DECLARE(User, int, author, author, setAuthor)
|
||||
|
||||
public:
|
||||
Q_INVOKABLE explicit Comment(QObject *parentTableSet = nullptr);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
#include "score.h"
|
||||
#include "user.h"
|
||||
#include "post.h"
|
||||
|
||||
Score::Score(QObject *parent) : Nut::Table(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
NUT_FOREIGN_KEY_IMPLEMENT(Score, Post, int, post, post, setPost)
|
||||
NUT_FOREIGN_KEY_IMPLEMENT(Score, User, QUuid, author, author, setAuthor)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef SCORE_H
|
||||
#define SCORE_H
|
||||
|
||||
#include <QUuid>
|
||||
#include "table.h"
|
||||
|
||||
class User;
|
||||
|
|
@ -14,8 +15,8 @@ class Score : public Nut::Table
|
|||
|
||||
NUT_DECLARE_FIELD(int, score, score, setScore)
|
||||
|
||||
NUT_FOREGION_KEY(Post, int, post, post, setPost)
|
||||
NUT_FOREGION_KEY(User, QUuid, author, author, setAuthor)
|
||||
NUT_FOREIGN_KEY_DECLARE(Post, int, post, post, setPost)
|
||||
NUT_FOREIGN_KEY_DECLARE(User, QUuid, author, author, setAuthor)
|
||||
|
||||
public:
|
||||
Q_INVOKABLE Score(QObject *parent = Q_NULLPTR);
|
||||
|
|
|
|||
|
|
@ -3,12 +3,11 @@ TEMPLATE = subdirs
|
|||
SUBDIRS += \
|
||||
tst_basic \
|
||||
tst_benckmark \
|
||||
# tst_commands \
|
||||
tst_datatypes \
|
||||
#tst_join \
|
||||
tst_phrases \
|
||||
tst_quuid \
|
||||
tst_generators \
|
||||
tst_upgrades \
|
||||
tst_json
|
||||
tst_json \
|
||||
tst_datetime
|
||||
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ void BasicTest::createPost()
|
|||
comment->setMessage("comment #" + QString::number(i));
|
||||
comment->setSaveDate(QDateTime::currentDateTime());
|
||||
comment->setAuthorId(user->id());
|
||||
db.comments()->append(comment);
|
||||
newPost->comments()->append(comment);
|
||||
}
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
auto score = Nut::create<Score>();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
#include "db.h"
|
||||
|
||||
#include "sampletable.h"
|
||||
|
||||
DB::DB() : Nut::Database (),
|
||||
m_sampleTables(new Nut::TableSet<SampleTable>(this))
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
#ifndef DB_H
|
||||
#define DB_H
|
||||
|
||||
#include "database.h"
|
||||
|
||||
class SampleTable;
|
||||
class DB : public Nut::Database
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
NUT_DB_VERSION(1)
|
||||
|
||||
NUT_DECLARE_TABLE(SampleTable, sampleTables)
|
||||
|
||||
public:
|
||||
DB();
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(DB*)
|
||||
|
||||
#endif // DB_H
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#include "sampletable.h"
|
||||
|
||||
SampleTable::SampleTable(QObject *parent) : Nut::Table (parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef SAMPLETABLE_H
|
||||
#define SAMPLETABLE_H
|
||||
|
||||
#include <QTime>
|
||||
#include <QDateTime>
|
||||
#include <QDate>
|
||||
|
||||
#include "table.h"
|
||||
|
||||
class SampleTable : public Nut::Table
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
NUT_PRIMARY_AUTO_INCREMENT(id)
|
||||
NUT_DECLARE_FIELD(int, id, id, setId)
|
||||
|
||||
NUT_DECLARE_FIELD(QDate, d, d, setD)
|
||||
NUT_DECLARE_FIELD(QTime, t, t, setT)
|
||||
NUT_DECLARE_FIELD(QDateTime, dt, dt, setDT)
|
||||
|
||||
public:
|
||||
Q_INVOKABLE SampleTable(QObject *parent = Q_NULLPTR);
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(SampleTable*)
|
||||
|
||||
#endif // SAMPLETABLE_H
|
||||
|
|
@ -0,0 +1,211 @@
|
|||
#include <QtTest>
|
||||
#include <QDebug>
|
||||
#include <QSqlError>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include "consts.h"
|
||||
|
||||
#include "tst_datetime.h"
|
||||
#include "query.h"
|
||||
#include "tableset.h"
|
||||
#include "tablemodel.h"
|
||||
#include "databasemodel.h"
|
||||
|
||||
#include "sampletable.h"
|
||||
|
||||
DateTimeTest::DateTimeTest(QObject *parent) : QObject(parent)
|
||||
{
|
||||
_baseDateTime = QDateTime::currentDateTime();
|
||||
}
|
||||
|
||||
void DateTimeTest::initTestCase()
|
||||
{
|
||||
//register all entities with Qt-MetaType mechanism
|
||||
REGISTER(SampleTable);
|
||||
REGISTER(DB);
|
||||
|
||||
db.setDriver(DRIVER);
|
||||
db.setHostName(HOST);
|
||||
db.setDatabaseName(DATABASE);
|
||||
db.setUserName(USERNAME);
|
||||
db.setPassword(PASSWORD);
|
||||
|
||||
QTEST_ASSERT(db.open());
|
||||
|
||||
db.sampleTables()->query()->remove();
|
||||
}
|
||||
|
||||
#define TEST_DATE(date, command, n) \
|
||||
do { \
|
||||
auto s = Nut::create<SampleTable>(); \
|
||||
s->setD(date); \
|
||||
db.sampleTables()->append(s); \
|
||||
db.saveChanges(); \
|
||||
auto count = db.sampleTables()->query() \
|
||||
->where(SampleTable::dField().command(n) == date.command(n)) \
|
||||
->count(); \
|
||||
QTEST_ASSERT(count); \
|
||||
} while (false)
|
||||
|
||||
#define TEST_TIME(time, command, n, num) \
|
||||
do { \
|
||||
auto s = Nut::create<SampleTable>(); \
|
||||
s->setT(time); \
|
||||
db.sampleTables()->append(s); \
|
||||
db.saveChanges(); \
|
||||
auto count = db.sampleTables()->query() \
|
||||
->where(SampleTable::tField().command(n) == time.addSecs(num)) \
|
||||
->count(); \
|
||||
QTEST_ASSERT(count); \
|
||||
} while (false)
|
||||
|
||||
#define TEST_DATE2(datetime, command, n) \
|
||||
do { \
|
||||
auto s = Nut::create<SampleTable>(); \
|
||||
s->setDT(datetime); \
|
||||
db.sampleTables()->append(s); \
|
||||
db.saveChanges(); \
|
||||
auto count = db.sampleTables()->query() \
|
||||
->where(SampleTable::dtField().command(n) == datetime.command(n)) \
|
||||
->count(); \
|
||||
QTEST_ASSERT(count); \
|
||||
} while (false)
|
||||
|
||||
#define TEST_TIME2(datetime, command, n, num) \
|
||||
do { \
|
||||
auto s = Nut::create<SampleTable>(); \
|
||||
s->setDT(datetime); \
|
||||
db.sampleTables()->append(s); \
|
||||
db.saveChanges(); \
|
||||
auto count = db.sampleTables()->query() \
|
||||
->where(SampleTable::dtField().command(n) == datetime.addSecs(num)) \
|
||||
->count(); \
|
||||
QTEST_ASSERT(count); \
|
||||
} while (false)
|
||||
|
||||
#define MINUTE(m) m * 60
|
||||
#define HOUR(h) MINUTE(h) * 60
|
||||
|
||||
void DateTimeTest::dateAdd()
|
||||
{
|
||||
QDate d = QDate::currentDate();
|
||||
|
||||
TEST_DATE(d, addYears, 10);
|
||||
TEST_DATE(d, addMonths, 10);
|
||||
TEST_DATE(d, addDays, 10);
|
||||
|
||||
TEST_DATE(d, addYears, -10);
|
||||
TEST_DATE(d, addMonths, -10);
|
||||
TEST_DATE(d, addDays, -10);
|
||||
}
|
||||
|
||||
void DateTimeTest::timeAdd()
|
||||
{
|
||||
QTime t = QTime::currentTime();
|
||||
|
||||
TEST_TIME(t, addHours, 10, HOUR(10));
|
||||
TEST_TIME(t, addMinutes, 10, MINUTE(10));
|
||||
TEST_TIME(t, addSeconds, 10, 10);
|
||||
|
||||
TEST_TIME(t, addHours, -10, HOUR(-10));
|
||||
TEST_TIME(t, addMinutes, -10, MINUTE(-10));
|
||||
TEST_TIME(t, addSeconds, -10, -10);
|
||||
}
|
||||
|
||||
void DateTimeTest::dateTimeAdd()
|
||||
{
|
||||
QDateTime dt = QDateTime::currentDateTime();
|
||||
|
||||
TEST_DATE2(dt, addYears, 10);
|
||||
TEST_DATE2(dt, addMonths, 10);
|
||||
TEST_DATE2(dt, addDays, 10);
|
||||
|
||||
TEST_DATE2(dt, addYears, -10);
|
||||
TEST_DATE2(dt, addMonths, -10);
|
||||
TEST_DATE2(dt, addDays, -10);
|
||||
|
||||
|
||||
TEST_TIME2(dt, addHours, 10, HOUR(10));
|
||||
TEST_TIME2(dt, addMinutes, 10, MINUTE(10));
|
||||
TEST_TIME2(dt, addSeconds, 10, 10);
|
||||
|
||||
TEST_TIME2(dt, addHours, -10, HOUR(-10));
|
||||
TEST_TIME2(dt, addMinutes, -10, MINUTE(-10));
|
||||
TEST_TIME2(dt, addSeconds, -10, -10);
|
||||
}
|
||||
|
||||
void DateTimeTest::datePart()
|
||||
{
|
||||
db.sampleTables()->query()->remove();
|
||||
|
||||
QDate d = QDate::currentDate();
|
||||
auto s = Nut::create<SampleTable>();
|
||||
s->setD(d);
|
||||
db.sampleTables()->append(s);
|
||||
db.saveChanges();
|
||||
|
||||
int count;
|
||||
|
||||
count = db.sampleTables()->query()->where(SampleTable::dField().year() == d.year())->count();
|
||||
QTEST_ASSERT(count);
|
||||
count = db.sampleTables()->query()->where(SampleTable::dField().month() == d.month())->count();
|
||||
QTEST_ASSERT(count);
|
||||
count = db.sampleTables()->query()->where(SampleTable::dField().day() == d.day())->count();
|
||||
QTEST_ASSERT(count);
|
||||
|
||||
}
|
||||
|
||||
void DateTimeTest::timePart()
|
||||
{
|
||||
db.sampleTables()->query()->remove();
|
||||
|
||||
QTime t = QTime::currentTime();
|
||||
auto s = Nut::create<SampleTable>();
|
||||
s->setT(t);
|
||||
db.sampleTables()->append(s);
|
||||
db.saveChanges();
|
||||
|
||||
int count;
|
||||
|
||||
count = db.sampleTables()->query()->where(SampleTable::tField().hour() == t.hour())->count();
|
||||
QTEST_ASSERT(count);
|
||||
count = db.sampleTables()->query()->where(SampleTable::tField().minute() == t.minute())->count();
|
||||
QTEST_ASSERT(count);
|
||||
count = db.sampleTables()->query()->where(SampleTable::tField().second() == t.second())->count();
|
||||
QTEST_ASSERT(count);
|
||||
}
|
||||
|
||||
void DateTimeTest::dateTimePart()
|
||||
{
|
||||
db.sampleTables()->query()->remove();
|
||||
|
||||
QDateTime dt = QDateTime::currentDateTime();
|
||||
auto s = Nut::create<SampleTable>();
|
||||
s->setDT(dt);
|
||||
db.sampleTables()->append(s);
|
||||
db.saveChanges();
|
||||
|
||||
int count;
|
||||
|
||||
count = db.sampleTables()->query()->where(SampleTable::dtField().year() == dt.date().year())->count();
|
||||
QTEST_ASSERT(count);
|
||||
count = db.sampleTables()->query()->where(SampleTable::dtField().month() == dt.date().month())->count();
|
||||
QTEST_ASSERT(count);
|
||||
count = db.sampleTables()->query()->where(SampleTable::dtField().day() == dt.date().day())->count();
|
||||
QTEST_ASSERT(count);
|
||||
|
||||
count = db.sampleTables()->query()->where(SampleTable::dtField().hour() == dt.time().hour())->count();
|
||||
QTEST_ASSERT(count);
|
||||
count = db.sampleTables()->query()->where(SampleTable::dtField().minute() == dt.time().minute())->count();
|
||||
QTEST_ASSERT(count);
|
||||
count = db.sampleTables()->query()->where(SampleTable::dtField().second() == dt.time().second())->count();
|
||||
QTEST_ASSERT(count);
|
||||
}
|
||||
|
||||
void DateTimeTest::cleanupTestCase()
|
||||
{
|
||||
db.sampleTables()->query()->remove();
|
||||
db.close();
|
||||
}
|
||||
|
||||
QTEST_MAIN(DateTimeTest)
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
#ifndef MAINTEST_H
|
||||
#define MAINTEST_H
|
||||
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/qglobal.h>
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#ifdef QT_GUI_LIB
|
||||
#include <QColor>
|
||||
#include <QPolygonF>
|
||||
#endif
|
||||
#include <QUrl>
|
||||
#include <QUuid>
|
||||
|
||||
#include "db.h"
|
||||
class DateTimeTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
DB db;
|
||||
|
||||
QDateTime _baseDateTime;
|
||||
|
||||
public:
|
||||
explicit DateTimeTest(QObject *parent = nullptr);
|
||||
|
||||
signals:
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
void dateAdd();
|
||||
void timeAdd();
|
||||
void dateTimeAdd();
|
||||
void datePart();
|
||||
void timePart();
|
||||
void dateTimePart();
|
||||
void cleanupTestCase();
|
||||
};
|
||||
|
||||
#endif // MAINTEST_H
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
QT += testlib sql gui
|
||||
|
||||
TARGET = tst_datetime
|
||||
TEMPLATE = app
|
||||
|
||||
CONFIG += warn_on c++11
|
||||
|
||||
include(../common/nut-lib.pri)
|
||||
|
||||
SOURCES += \
|
||||
db.cpp \
|
||||
sampletable.cpp \
|
||||
tst_datetime.cpp
|
||||
|
||||
HEADERS += \
|
||||
db.h \
|
||||
sampletable.h \
|
||||
tst_datetime.h
|
||||
|
||||
include($$PWD/../../ci-test-init.pri)
|
||||
|
|
@ -139,7 +139,12 @@ void GeneratorsTest::cleanupTestCase()
|
|||
.arg(i.key(), i.value().sqlite, i.value().mysql,
|
||||
i.value().psql, i.value().mssql));
|
||||
}
|
||||
qDebug() << p.toStdString().c_str();
|
||||
|
||||
QFile file(NUT_PATH "/doc/datatypes.md");
|
||||
if (file.open(QIODevice::WriteOnly)) {
|
||||
file.write(p.toUtf8());
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_MAIN(GeneratorsTest)
|
||||
|
|
|
|||
Loading…
Reference in New Issue