Co-authored-by: Hamed Masafi <hamed.masfi@gmail.com>
This commit is contained in:
Hamed Masafi 2022-04-28 16:23:42 +04:30 committed by GitHub
parent 8fa6a3b6d7
commit ad6eab9de1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
137 changed files with 3396 additions and 936 deletions

1
.cmake.conf Normal file
View File

@ -0,0 +1 @@
set(QT_REPO_MODULE_VERSION "0.7.0")

View File

@ -1,90 +1,158 @@
name: CI build name: CI Build
on: [push] on:
push:
branches-ignore:
- "releases/**"
paths-ignore:
- "**.md"
pull_request:
paths-ignore:
- "**.md"
jobs: jobs:
build: build:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
version: qt_version: [5.12.11, 5.15.2, 6.2.0]
- 5.15.0 platform: [ubuntu-20.04, windows-latest, macos-latest]
platform:
- gcc_64
- android
- msvc2019
- msvc2019_64
- winrt_x64_msvc2019
- winrt_x86_msvc2019
- winrt_armv7_msvc2019
- mingw81_64
- mingw81_32
- clang_64
- ios
include: include:
- platform: gcc_64 - qt_version: 6.2.0
os: ubuntu-latest additional_arguments: -D QT_DEFAULT_MAJOR_VERSION=6
- platform: android build_cmake: true
os: ubuntu-latest - platform: ubuntu-20.04
- platform: msvc2019_64 make: make
os: windows-latest #CXXFLAGS: -Wall -Wextra
- platform: msvc2019 MAKEFLAGS: -j2
os: windows-latest - platform: macos-latest
- platform: winrt_x64_msvc2019 make: make
os: windows-latest #CXXFLAGS: -Wall -Wextra
- platform: winrt_x86_msvc2019 MAKEFLAGS: -j3
os: windows-latest - platform: windows-latest
- platform: winrt_armv7_msvc2019 make: nmake
os: windows-latest QMAKE_MSC_VER: 16.11.31911.196
- platform: mingw81_64 cmake_params: -D CMAKE_CXX_FLAGS_DEBUG="/g"
os: windows-latest - platform: ubuntu-20.04
- platform: mingw81_32 tests: [sqlite, posgtresql]
os: windows-latest - platform: ubuntu-20.04
- platform: clang_64 qt_version: system
os: macos-latest tests: [sqlite, posgtresql, mysql]
make: make
runs-on: ${{matrix.os}} name: ubuntu-20.04, system
- platform: windows-latest
qt_version: 5.15.2
tests: [mssql]
runs-on: ${{ matrix.platform }}
name: ${{ matrix.platform }} - Qt ${{ matrix.qt_version }}
env:
CXXFLAGS: ${{ matrix.CXXFLAGS }}
MAKEFLAGS: ${{ matrix.MAKEFLAGS }}
QMAKE_MSC_VER: ${{ matrix.QMAKE_MSC_VER }}
CMAKE_PREFIX_PATH: $Qt6_DIR/lib/cmake
CMAKE_CXX_FLAGS_DEBUG: ${{ matrix.CMAKE_CXX_FLAGS_DEBUG }}
steps: steps:
- uses: actions/checkout@v1 - name: Clone repo
uses: actions/checkout@v2.3.4
with: with:
submodules: recursive submodules: recursive
- uses: actions/setup-python@v1
- uses: Skycoder42/action-setup-qt@master - name: Install Qt
id: qt if: matrix.qt_version != 'system'
uses: jurplel/install-qt-action@v2.14.0
with: with:
version: ${{matrix.version}} version: ${{ matrix.qt_version }}
platform: ${{matrix.platform}}
packages: qt.tools.ifw.32 - name: Install Qt from package manager
- name: qmake if: matrix.qt_version == 'system'
run: | run: |
qmake CONFIG+=install_ok QT_PLATFORM=${{matrix.platform}} "QT_TOOL_PATH=${{steps.qt.outputs.qtdir}}/Tools" nut.pro sudo apt install qt5-default qt5-qmake qt5-qmake-bin libqt5core5a libqt5gui5 libqt5sql5 libqt5sql5-psql libqt5sql5-mysql libqt5sql5-sqlite
${{steps.qt.outputs.make}} qmake_all
- name: make module - name: Setup MSVC environment for QMake
run: | uses: ilammy/msvc-dev-cmd@v1
${{steps.qt.outputs.make}}
${{steps.qt.outputs.make}} INSTALL_ROOT="${{steps.qt.outputs.installdir}}" install
- name: make tests
if: steps.qt.outputs.tests == 'true'
run: |
${{steps.qt.outputs.make}} all
${{steps.qt.outputs.make}} ${{steps.qt.outputs.testflags}} run-tests
- name: upload module to releases
uses: Skycoder42/action-upload-release@master
if: startsWith(github.ref, 'refs/tags/')
with: with:
repo_token: ${{secrets.GITHUB_TOKEN}} uwp: false
directory: ${{steps.qt.outputs.outdir}}
platform: ${{matrix.platform}} - name: Build with QMake
asset_name: nut-${{matrix.platform}}-${{matrix.version}} run: |
tag: ${{github.ref}} mkdir build-qmake
overwrite: true cd build-qmake
qmake ../nut.pro
${{ matrix.make }} qmake_all
${{ matrix.make }}
- name: Build with CMake
if: startsWith(matrix.qt_version, '6.')
run: |
mkdir build-cmake
cd build-cmake
cmake .. ${{ matrix.additional_arguments }} ${{ matrix.cmake_params }}
cmake --build .
- name: Seutp postgres
if: contains(matrix.tests, 'posgtresql')
uses: ikalnytskyi/action-setup-postgres@v1
- name: Setup sql server
if: contains(matrix.tests, 'mssql')
uses: potatoqualitee/mssqlsuite@v1
with:
install: sqlengine
sa-password: NUT_sa_PASS_1_???
show-log: true
- name: Check sql server
if: contains(matrix.tests, 'mssql')
run: sqlcmd -S localhost -U sa -P NUT_sa_PASS_1_??? -d tempdb -Q "SELECT @@version;"
- name: Run tests with sqlite
if: contains(matrix.tests, 'sqlite')
continue-on-error: true
run: |
rm tests/auto/common/test_params.h
cp tests/auto/common/test_params_sqlite.h tests/auto/common/test_params.h
cd build-qmake
${{ matrix.make }} all
${{ matrix.make }} run-tests
- name: Run tests with posgtresql
if: contains(matrix.tests, 'posgtresql')
#continue-on-error: true
run: |
rm tests/auto/common/test_params.h
cp tests/auto/common/test_params_postgresql.h tests/auto/common/test_params.h
cd build-qmake
${{ matrix.make }} all
${{ matrix.make }} run-tests
- name: Run tests with mysql
if: contains(matrix.tests, 'mysql')
#continue-on-error: true
run: |
sudo systemctl start mysql.service
rm tests/auto/common/test_params.h
cp tests/auto/common/test_params_mysql.h tests/auto/common/test_params.h
cd build-qmake
${{ matrix.make }} all
${{ matrix.make }} run-tests
- name: Run tests with sql server
if: contains(matrix.tests, 'mssql')
continue-on-error: true
run: |
rm tests/auto/common/test_params.h
cp tests/auto/common/test_params_mssql.h tests/auto/common/test_params.h
cd build-qmake
${{ matrix.make }} all
${{ matrix.make }} run-tests
deploy: deploy:
if: startsWith(github.ref, 'refs/tags/') if: startsWith(github.ref, 'refs/tags/')
needs: build needs: build
runs-on: ubuntu-latest runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
with: with:
@ -94,7 +162,7 @@ jobs:
- uses: Skycoder42/action-deploy-qt@master - uses: Skycoder42/action-deploy-qt@master
with: with:
token: ${{secrets.GITHUB_TOKEN}} token: ${{secrets.GITHUB_TOKEN}}
version: 5.15.0 version: 5.15.2
host: ${{secrets.SSHFS_HOST}} host: ${{secrets.SSHFS_HOST}}
key: ${{secrets.SSHFS_KEY}} key: ${{secrets.SSHFS_KEY}}
port: ${{secrets.SSHFS_PORT}} port: ${{secrets.SSHFS_PORT}}

1
.gitignore vendored
View File

@ -54,3 +54,4 @@ test/tst_quuid/tst_uuid*
test/tst_upgrades/tst_upgrades* test/tst_upgrades/tst_upgrades*
.idea .idea
CMakeLists.txt.user

3
.gitmodules vendored
View File

@ -1,3 +0,0 @@
[submodule "src/nut/3rdparty/serializer"]
path = src/nut/3rdparty/serializer
url = https://github.com/HamedMasafi/Serializer.git

21
CMakeLists.txt Normal file
View File

@ -0,0 +1,21 @@
# Generated from nut.pro.
cmake_minimum_required(VERSION 3.16)
set(CMAKE_AUTOMOC ON)
include(.cmake.conf)
project(Nut
VERSION "0.7.0"
DESCRIPTION "Nut"
HOMEPAGE_URL "https://github.com/HamedMasafi/Nut"
LANGUAGES CXX C
)
set(PROJECT_VERSION_MAJOR, 0)
set(PROJECT_VERSION_MINOR, 7)
set(PROJECT_VERSION_PATCH, 0)
find_package(Qt6 CONFIG REQUIRED COMPONENTS BuildInternals Core Gui Sql)
qt_build_repo()

View File

@ -1,4 +1,4 @@
Database class must inherits from Nut::Database class. Database class must inherit from Nut::Database class.
Database class can have NUT_DB_VERSION for declaring version number, version will be stored in database if upgrade needed. Database class can have NUT_DB_VERSION for declaring version number, version will be stored in database if upgrade needed.
```cpp ```cpp
NUT_DB_VERSION(major, minor) NUT_DB_VERSION(major, minor)

View File

@ -30,7 +30,7 @@ auto posts = db.posts().query()
->orderBy(Post::idField()) ->orderBy(Post::idField())
->toList(); ->toList();
``` ```
Also you can sort descending by adding **!** to field name Also, you can sort descending by adding **!** to field name
```cpp ```cpp
auto posts = db.posts().query() auto posts = db.posts().query()
->where(Post::idField() == 1) ->where(Post::idField() == 1)

View File

@ -1,22 +0,0 @@
QMAKE_CXX.QT_COMPILER_STDCXX = 201402L
QMAKE_CXX.QMAKE_GCC_MAJOR_VERSION = 10
QMAKE_CXX.QMAKE_GCC_MINOR_VERSION = 2
QMAKE_CXX.QMAKE_GCC_PATCH_VERSION = 1
QMAKE_CXX.COMPILER_MACROS = \
QT_COMPILER_STDCXX \
QMAKE_GCC_MAJOR_VERSION \
QMAKE_GCC_MINOR_VERSION \
QMAKE_GCC_PATCH_VERSION
QMAKE_CXX.INCDIRS = \
/usr/include/c++/10 \
/usr/include/c++/10/x86_64-redhat-linux \
/usr/include/c++/10/backward \
/usr/lib/gcc/x86_64-redhat-linux/10/include \
/usr/local/include \
/usr/include
QMAKE_CXX.LIBDIRS = \
/usr/lib/gcc/x86_64-redhat-linux/10 \
/usr/lib64 \
/lib64 \
/usr/lib \
/lib

3
src/CMakeLists.txt Normal file
View File

@ -0,0 +1,3 @@
# Generated from src.pro.
add_subdirectory(nut)

@ -1 +0,0 @@
Subproject commit 535778e15d30ef51b53e80d47630bef4ca20f4c7

65
src/nut/CMakeLists.txt Normal file
View File

@ -0,0 +1,65 @@
# Generated from nut.pro.
#####################################################################
## Nut Module:
#####################################################################
qt_internal_add_module(Nut
SOURCES
config/nut_config.h
config/nut_consts.h
config/nut_global.h
config/nut_macros.h
config/nut_namespace.h
core/abstracttableset.cpp core/abstracttableset.h
core/abstracttablesetdata.h
core/bulkinserter.cpp core/bulkinserter.h core/bulkinserter_p.h
core/changelogtable.cpp core/changelogtable.h
core/database.cpp core/database.h core/database_p.h
core/foreigncontainer.cpp core/foreigncontainer.h
core/propertysignalmapper.cpp core/propertysignalmapper.h
core/query.cpp core/query.h
core/table.cpp core/table.h core/table_p.h
core/tableset.cpp core/tableset.h
core/sqlserializer.cpp core/sqlserializer.h
generators/abstractsqlgenerator.cpp generators/abstractsqlgenerator.h
generators/mysqlgenerator.cpp generators/mysqlgenerator.h
generators/postgresqlgenerator.cpp generators/postgresqlgenerator.h
generators/sqlitegenerator.cpp generators/sqlitegenerator.h
generators/sqlservergenerator.cpp generators/sqlservergenerator.h
models/databasemodel.cpp models/databasemodel.h
models/sqlmodel.cpp models/sqlmodel.h models/sqlmodel_p.h
models/tablemodel.cpp models/tablemodel.h
phrase.cpp phrase.h
phrases/abstractfieldphrase.cpp phrases/abstractfieldphrase.h
phrases/assignmentphrase.cpp phrases/assignmentphrase.h
phrases/assignmentphraselist.cpp phrases/assignmentphraselist.h
phrases/conditionalphrase.cpp phrases/conditionalphrase.h
phrases/fieldphrase.cpp phrases/fieldphrase.h
phrases/fieldphrase_bool.cpp phrases/fieldphrase_bool.h
phrases/fieldphrase_date.cpp phrases/fieldphrase_date.h
phrases/fieldphrase_qstring.cpp phrases/fieldphrase_qstring.h
phrases/phrasedata.cpp phrases/phrasedata.h
phrases/phrasedatalist.cpp phrases/phrasedatalist.h
phrases/phraselist.cpp phrases/phraselist.h
types/dbgeography.cpp types/dbgeography.h
DEFINES
NUT_BUILD_LIB
NUT_SHARED
NUT_SHARED_POINTER
QT_DEPRECATED_WARNINGS
INCLUDE_DIRECTORIES
config
core
generators
models
phrases
types
PUBLIC_LIBRARIES
Qt::Core
Qt::Gui
Qt::Sql
)
#### Keys ignored in scope 1:.:.:nut.pro:<TRUE>:
# MODULE = "nut"

View File

@ -1,6 +1,10 @@
#ifndef NUT_CONFIG_H #ifndef NUT_CONFIG_H
#define NUT_CONFIG_H #define NUT_CONFIG_H
#include <QtGlobal>
QT_BEGIN_NAMESPACE
#if defined(NUT_SHARED) || !defined(NUT_STATIC) #if defined(NUT_SHARED) || !defined(NUT_STATIC)
# ifdef NUT_STATIC # ifdef NUT_STATIC
# error "Both NUT_SHARED and NUT_STATIC defined, please make up your mind" # error "Both NUT_SHARED and NUT_STATIC defined, please make up your mind"
@ -17,4 +21,6 @@
# define NUT_EXPORT # define NUT_EXPORT
#endif #endif
QT_END_NAMESPACE
#endif // NUT_CONFIG_H #endif // NUT_CONFIG_H

View File

@ -21,6 +21,10 @@
#ifndef NUT_CONSTS_H #ifndef NUT_CONSTS_H
#define NUT_CONSTS_H #define NUT_CONSTS_H
#include <QtGlobal>
QT_BEGIN_NAMESPACE
#define __NAME "name" #define __NAME "name"
#define __TYPE "type" #define __TYPE "type"
#define __FIELDS "fields" #define __FIELDS "fields"
@ -46,6 +50,7 @@
#define __nut_REMOVE "remove" #define __nut_REMOVE "remove"
#define __nut_CHANGE "change" #define __nut_CHANGE "change"
#define NUT_NAMESPACE Nut
#ifdef NUT_NAMESPACE #ifdef NUT_NAMESPACE
# define NUT_BEGIN_NAMESPACE namespace NUT_NAMESPACE{ # define NUT_BEGIN_NAMESPACE namespace NUT_NAMESPACE{
# define NUT_END_NAMESPACE } # define NUT_END_NAMESPACE }
@ -56,4 +61,6 @@
# define NUT_WRAP_NAMESPACE(x) x # define NUT_WRAP_NAMESPACE(x) x
#endif #endif
QT_END_NAMESPACE
#endif // NUT_CONSTS_H #endif // NUT_CONSTS_H

View File

@ -1,7 +1,9 @@
#ifndef NUT_GLOBAL_H #ifndef NUT_GLOBAL_H
#define NUT_GLOBAL_H #define NUT_GLOBAL_H
#define NUT_NAMESPACE Nut #include <QtGlobal>
QT_BEGIN_NAMESPACE
#include <QtNut/nut_config.h> #include <QtNut/nut_config.h>
#include <QtNut/nut_consts.h> #include <QtNut/nut_consts.h>
@ -9,4 +11,6 @@
#include <QtNut/nut_macros.h> #include <QtNut/nut_macros.h>
#include <QtNut/nut_namespace.h> #include <QtNut/nut_namespace.h>
QT_END_NAMESPACE
#endif // NUT_GLOBAL_H #endif // NUT_GLOBAL_H

View File

@ -1,6 +1,9 @@
#ifndef NUT_MACROS_H #ifndef NUT_MACROS_H
#define NUT_MACROS_H #define NUT_MACROS_H
#include <QtGlobal>
QT_BEGIN_NAMESPACE
#define NUT_INFO(type, name, value) \ #define NUT_INFO(type, name, value) \
Q_CLASSINFO(__nut_NAME_PERFIX type #name #value, \ Q_CLASSINFO(__nut_NAME_PERFIX type #name #value, \
@ -17,127 +20,128 @@
#define NUT_DB_VERSION(version) \ #define NUT_DB_VERSION(version) \
NUT_INFO(__nut_DB_VERSION, version, 0) NUT_INFO(__nut_DB_VERSION, version, 0)
#define NUT_DECLARE_TABLE(type, name) \ #define NUT_DECLARE_TABLE(type, name) \
NUT_INFO(__nut_TABLE, type, name) \ NUT_INFO(__nut_TABLE, type, name) \
Q_PROPERTY(NUT_WRAP_NAMESPACE(TableSet<type>) name READ name) \ Q_PROPERTY(NUT_WRAP_NAMESPACE(TableSet<type>) name READ name) \
NUT_WRAP_NAMESPACE(TableSet<type>) *m_##name; \ NUT_WRAP_NAMESPACE(TableSet<type>) * m_##name; \
public: \ \
static const type *_##name; \ public: \
NUT_WRAP_NAMESPACE(TableSet<type>) *name() const \ static const type *_##name; \
{ return m_##name; } \ NUT_WRAP_NAMESPACE(TableSet<type>) * name() const { return m_##name; } \
private: \
private:
//Table //Table
#define NUT_FIELD(type, name) \ #define NUT_FIELD(type, name) \
private: \ private: \
NUT_INFO(__nut_FIELD, name, 0) \ NUT_INFO(__nut_FIELD, name, 0) \
public: \ public: \
static NUT_WRAP_NAMESPACE(FieldPhrase<type>)& name ## Field(){ \ static NUT_WRAP_NAMESPACE(FieldPhrase<type>) & name##Field() \
static NUT_WRAP_NAMESPACE(FieldPhrase<type>) f = \ { \
NUT_WRAP_NAMESPACE(FieldPhrase<type>) \ static NUT_WRAP_NAMESPACE(FieldPhrase<type>) f = NUT_WRAP_NAMESPACE( \
(staticMetaObject.className(), #name); \ FieldPhrase<type>)(staticMetaObject.className(), #name); \
return f; \ return f; \
} }
#define NUT_DECLARE_FIELD(type, name, read, write) \ #define NUT_DECLARE_FIELD(type, name, read, write) \
Q_PROPERTY(type name READ read WRITE write) \ Q_PROPERTY(type name READ read WRITE write) \
NUT_INFO(__nut_FIELD, name, 0) \ NUT_INFO(__nut_FIELD, name, 0) \
type m_##name; \ type m_##name; \
public: \ \
static NUT_WRAP_NAMESPACE(FieldPhrase<type>)& name ## Field(){ \ public: \
static NUT_WRAP_NAMESPACE(FieldPhrase<type>) f = \ static NUT_WRAP_NAMESPACE(FieldPhrase<type>) & name##Field() \
NUT_WRAP_NAMESPACE(FieldPhrase<type>) \ { \
(staticMetaObject.className(), #name); \ static NUT_WRAP_NAMESPACE(FieldPhrase<type>) f = NUT_WRAP_NAMESPACE( \
return f; \ FieldPhrase<type>)(staticMetaObject.className(), #name); \
} \ return f; \
type read() const{ \ } \
return m_##name; \ type read() const { return m_##name; } \
} \ void write(type name) \
void write(type name){ \ { \
m_##name = name; \ m_##name = name; \
propertyChanged(QString::fromUtf8(#name)); \ propertyChanged(QString::fromUtf8(#name)); \
} }
#define NUT_FOREIGN_KEY(type, keytype, name, read, write) \ #define NUT_FOREIGN_KEY(type, keytype, name, read, write) \
Q_PROPERTY(Nut::Row<type> name READ read WRITE write) \ Q_PROPERTY(NUT_WRAP_NAMESPACE(Row<type>) name READ read WRITE write) \
NUT_DECLARE_FIELD(keytype, name##Id, read##Id, write##Id) \ NUT_DECLARE_FIELD(keytype, name##Id, read##Id, write##Id) \
NUT_INFO(__nut_FOREIGN_KEY, name, type) \ NUT_INFO(__nut_FOREIGN_KEY, name, type) \
Nut::Row<type> m_##name; \ NUT_WRAP_NAMESPACE(Row<type>) m_##name; \
public Q_SLOTS: \ public Q_SLOTS: \
Nut::Row<type> read() const { return m_##name ; } \ NUT_WRAP_NAMESPACE(Row<type>) read() const { return m_##name; } \
Q_INVOKABLE void write(Nut::Row<type> name){ \ Q_INVOKABLE void write(NUT_WRAP_NAMESPACE(Row<type>) name) { m_##name = name; }
m_##name = name; \
}
#define NUT_FOREIGN_KEY_DECLARE(type, keytype, name, read, write) \ #define NUT_FOREIGN_KEY_DECLARE(type, keytype, name, read, write) \
NUT_INFO(__nut_FIELD, name##Id, 0) \ NUT_INFO(__nut_FIELD, name##Id, 0) \
NUT_INFO(__nut_FOREIGN_KEY, name, type) \ NUT_INFO(__nut_FOREIGN_KEY, name, type) \
Nut::Row<type> m_##name; \ NUT_WRAP_NAMESPACE(Row<type>) m_##name; \
keytype m_##name##Id; \ keytype m_##name##Id; \
Q_PROPERTY(Nut::Row<type> name READ read WRITE write) \ Q_PROPERTY(NUT_WRAP_NAMESPACE(Row<type>) name READ read WRITE write) \
Q_PROPERTY(keytype name##Id READ read##Id WRITE write##Id) \ Q_PROPERTY(keytype name##Id READ read##Id WRITE write##Id) \
public: \ public: \
Nut::Row<type> read() const; \ NUT_WRAP_NAMESPACE(Row<type>) read() const; \
keytype read##Id() const; \ keytype read##Id() const; \
static NUT_WRAP_NAMESPACE(FieldPhrase<keytype>)& name##Id ## Field(){ \ static NUT_WRAP_NAMESPACE(FieldPhrase<keytype>) & name##Id##Field() \
static NUT_WRAP_NAMESPACE(FieldPhrase<keytype>) f = \ { \
NUT_WRAP_NAMESPACE(FieldPhrase<keytype>) \ static NUT_WRAP_NAMESPACE(FieldPhrase<keytype>) f = NUT_WRAP_NAMESPACE( \
(staticMetaObject.className(), #name "Id"); \ FieldPhrase<keytype>)(staticMetaObject.className(), #name "Id"); \
return f; \ return f; \
} \ } \
public : \ \
Q_INVOKABLE void write(Nut::Row<type> name); \ public: \
Q_INVOKABLE void write(Nut::Row<Nut::Table> name); \ Q_INVOKABLE void write(NUT_WRAP_NAMESPACE(Row<type>) name); \
Q_INVOKABLE void write(NUT_WRAP_NAMESPACE(Row<NUT_WRAP_NAMESPACE(Table)>) name); \
void write##Id(keytype name##Id); void write##Id(keytype name##Id);
#define NUT_FOREIGN_KEY_IMPLEMENT(class, type, keytype, name, read, write) \ #define NUT_FOREIGN_KEY_IMPLEMENT(class, type, keytype, name, read, write) \
Nut::Row<type> class::read() const { return m_##name ; } \ NUT_WRAP_NAMESPACE(Row<type>) class ::read() const { return m_##name; } \
void class::write(Nut::Row<type> name){ \ void class ::write(NUT_WRAP_NAMESPACE(Row<type>) name) \
propertyChanged(QStringLiteral(QT_STRINGIFY2(name##Id))); \ { \
m_##name = name; \ propertyChanged(QStringLiteral(QT_STRINGIFY2(name##Id))); \
m_##name##Id = name->primaryValue().value<keytype>(); \ m_##name = name; \
} \ m_##name##Id = name->primaryValue().value<keytype>(); \
void class::write(Nut::Row<Nut::Table> name){ \ } \
write(qSharedPointerDynamicCast<type>(name)); \ void class ::write(NUT_WRAP_NAMESPACE(Row<NUT_WRAP_NAMESPACE(Table)>) name) \
} keytype class::read##Id() const{ \ { \
if (m_##name) \ write(qSharedPointerDynamicCast<type>(name)); \
return m_##name->primaryValue().value<keytype>(); \ } \
return m_##name##Id; \ keytype class ::read##Id() const \
} \ { \
void class::write##Id(keytype name##Id){ \ if (m_##name) \
m_##name##Id = name##Id; \ return m_##name->primaryValue().value<keytype>(); \
m_##name = nullptr; \ return m_##name##Id; \
propertyChanged(QStringLiteral(QT_STRINGIFY2(name##Id))); \ } \
void class ::write##Id(keytype name##Id) \
{ \
m_##name##Id = name##Id; \
m_##name = nullptr; \
propertyChanged(QStringLiteral(QT_STRINGIFY2(name##Id))); \
} }
#define NUT_DECLARE_CHILD_TABLE(type, n) \
private: \
NUT_WRAP_NAMESPACE(TableSet)<type> *m_##n; \
\
public: \
static type *n##Table(); \
NUT_WRAP_NAMESPACE(TableSet)<type> *n();
#define NUT_DECLARE_CHILD_TABLE(type, n) \ #define NUT_IMPLEMENT_CHILD_TABLE(class, type, n) \
private: \ type *class ::n##Table() \
NUT_WRAP_NAMESPACE(TableSet)<type> *m_##n; \ { \
public: \ static auto f = new type(); \
static type *n##Table(); \ return f; \
NUT_WRAP_NAMESPACE(TableSet)<type> *n(); } \
NUT_WRAP_NAMESPACE(TableSet)<type> *class ::n() { return m_##n; }
#define NUT_IMPLEMENT_CHILD_TABLE(class, type, n) \
type *class::n##Table(){ \
static auto f = new type(); \
return f; \
} \
NUT_WRAP_NAMESPACE(TableSet)<type> *class::n(){ \
return m_##n; \
}
//#define NUT_FIELD(name) NUT_INFO(__nut_FIELD, name, 0) //#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) \
public: \ NUT_INFO(__nut_PRIMARY_KEY, x, 0) \
QVariant primaryValue() const override { \ public: \
return property(#x); \ QVariant primaryValue() const override { return property(#x); } \
} \ void setPrimaryValue(const QVariant &value) override { setProperty(#x, value); } \
void setPrimaryValue(const QVariant &value) override { \ \
setProperty(#x, value); \ private:
} \
private:
#define NUT_AUTO_INCREMENT(x) NUT_INFO(__nut_AUTO_INCREMENT, x, 0) #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)\
@ -149,4 +153,6 @@ public : \
#define NUT_NOT_NULL(x) NUT_INFO(__nut_NOT_NULL, x, 1) #define NUT_NOT_NULL(x) NUT_INFO(__nut_NOT_NULL, x, 1)
#define NUT_INDEX(name, field, order) #define NUT_INDEX(name, field, order)
QT_END_NAMESPACE
#endif // NUT_MACROS_H #endif // NUT_MACROS_H

View File

@ -1,10 +1,6 @@
#ifndef NUT_NAMESPACE_H #ifndef NUT_NAMESPACE_H
#define NUT_NAMESPACE_H #define NUT_NAMESPACE_H
#ifndef NUT_GLOBAL_H
# error "Do not include nut_namespace.h header directly!"
#endif
//avoid ide warnings //avoid ide warnings
#include <QtNut/nut_global.h> #include <QtNut/nut_global.h>
@ -13,6 +9,8 @@
#include <QtCore/QVariant> #include <QtCore/QVariant>
#include <QtCore/QMetaClassInfo> #include <QtCore/QMetaClassInfo>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
inline bool nutClassInfo(const QMetaClassInfo &classInfo, inline bool nutClassInfo(const QMetaClassInfo &classInfo,
@ -84,59 +82,77 @@ inline bool nutClassInfoInt(const QMetaClassInfo &classInfo,
} }
#ifdef NUT_RAW_POINTER #ifdef NUT_RAW_POINTER
template <typename T> template<typename T>
using RowList = QList<T*>; using RowList = QList<T *>;
template <typename T>
using RowSet = QSet<T*>;
template <typename T>
using Row = T*;
template<class T> template<class T>
inline Row<T> create() { using WeakRowList = QList<T *>;
template<typename T>
using RowSet = QSet<T *>;
template<typename T>
using Row = T *;
template<class T>
inline Row<T> create()
{
return new T; return new T;
} }
template<class T> template<class T>
inline T *get(const Row<T> row) { inline T *get(const Row<T> row)
{
return row; return row;
} }
template<class T> template<class T>
inline T *get(const QSharedPointer<T> row) { inline T *get(const QSharedPointer<T> row)
{
return row.data(); return row.data();
} }
#else #else
template <class T> template<class T>
using RowList = QList<QSharedPointer<T>>; using RowList = QList<QSharedPointer<T>>;
template <class T> template<class T>
using RowSet = QSet<QSharedPointer<T>>; using WeakRowList = QList<QWeakPointer<T>>;
template <typename T>
using Row = QSharedPointer<T>;
template<class T> template<class T>
inline Row<T> create() { using RowSet = QSet<QSharedPointer<T>>;
template<typename T>
using Row = QSharedPointer<T>;
template<typename T>
using WeakRow = QWeakPointer<T>;
template<class T>
inline Row<T> create()
{
return QSharedPointer<T>(new T); return QSharedPointer<T>(new T);
} }
template<class T> template<class T>
inline Row<T> create(QObject *parent) { inline Row<T> create(QObject *parent)
{
return QSharedPointer<T>(new T(parent)); return QSharedPointer<T>(new T(parent));
} }
template<class T> template<class T>
inline Row<T> createFrom(T *row) { inline Row<T> createFrom(T *row)
{
return QSharedPointer<T>(row); return QSharedPointer<T>(row);
} }
template<class T> template<class T>
inline Row<T> createFrom(const QSharedPointer<T> row) { inline Row<T> createFrom(const QSharedPointer<T> row)
{
return row; return row;
} }
#endif #endif
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // NUT_NAMESPACE_H #endif // NUT_NAMESPACE_H

View File

@ -18,12 +18,16 @@
** **
**************************************************************************/ **************************************************************************/
#include <QWeakPointer>
#include "table.h" #include "table.h"
#include "database.h" #include "database.h"
#include "abstracttableset.h" #include "abstracttableset.h"
#include "databasemodel.h" #include "databasemodel.h"
#include "abstracttablesetdata.h" #include "abstracttablesetdata.h"
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
AbstractTableSet::AbstractTableSet(Database *parent) : QObject(parent), AbstractTableSet::AbstractTableSet(Database *parent) : QObject(parent),
@ -40,7 +44,7 @@ AbstractTableSet::AbstractTableSet(Table *parent) : QObject(parent),
AbstractTableSet::~AbstractTableSet() AbstractTableSet::~AbstractTableSet()
{ {
Q_FOREACH (Row<Table> t, data->childs) for (auto &t: data->children)
if (t) if (t)
t->setParentTableSet(nullptr); t->setParentTableSet(nullptr);
} }
@ -52,14 +56,14 @@ int AbstractTableSet::save(Database *db, bool cleanUp)
if (data->table) if (data->table)
masterModel = db->model().tableByClassName(QString::fromUtf8(data->table->metaObject()->className())); masterModel = db->model().tableByClassName(QString::fromUtf8(data->table->metaObject()->className()));
Q_FOREACH (Row<Table> t, data->childs) { for (auto &t : data->children) {
if (data->table) if (data->table)
t->setParentTable(data->table, t->setParentTable(data->table,
masterModel, masterModel,
db->model().tableByClassName(QString::fromUtf8(t->metaObject()->className()))); db->model().tableByClassName(
QString::fromUtf8(t->metaObject()->className())));
if (t->status() == Table::Added if (t->status() == Table::Added || t->status() == Table::Modified
|| t->status() == Table::Modified
|| t->status() == Table::Deleted) { || t->status() == Table::Deleted) {
rowsAffected += t->save(db); rowsAffected += t->save(db);
if (cleanUp) if (cleanUp)
@ -71,32 +75,67 @@ int AbstractTableSet::save(Database *db, bool cleanUp)
} }
} }
if (cleanUp) for (auto &row : data->weakChildren) {
data->childs.clear(); auto t = row.lock();
if (data->table)
t->setParentTable(data->table,
masterModel,
db->model().tableByClassName(
QString::fromUtf8(t->metaObject()->className())));
if (t->status() == Table::Added || t->status() == Table::Modified
|| t->status() == Table::Deleted) {
rowsAffected += t->save(db);
if (cleanUp)
#ifdef NUT_RAW_POINTER
t->deleteLater();
#else
remove(row);
#endif
}
}
if (cleanUp) {
data->children.clear();
data->weakChildren.clear();
}
return rowsAffected; return rowsAffected;
} }
void AbstractTableSet::clearChilds() void AbstractTableSet::clearChildren()
{ {
#ifdef NUT_RAW_POINTER #ifdef NUT_RAW_POINTER
Q_FOREACH (Table *t, data->childs) for (auto &t: data->children)
t->deleteLater(); t->deleteLater();
#endif #endif
data->childs.clear(); data->children.clear();
} }
void AbstractTableSet::add(Row<Table> t) void AbstractTableSet::add(Row<Table> t)
{ {
data.detach(); data.detach();
data->childs.append(t); data->children.append(t);
t->setParentTableSet(this); t->setParentTableSet(this);
} }
void AbstractTableSet::add(WeakRow<Table> t)
{
data.detach();
data->weakChildren.append(t);
t.toStrongRef()->setParentTableSet(this);
}
void AbstractTableSet::remove(Row<Table> t) void AbstractTableSet::remove(Row<Table> t)
{ {
data.detach(); data.detach();
data->childs.removeAll(t); data->children.removeAll(t);
}
void AbstractTableSet::remove(WeakRow<Table> t)
{
data.detach();
data->weakChildren.removeAll(t);
} }
QString AbstractTableSet::childClassName() const QString AbstractTableSet::childClassName() const
@ -117,7 +156,9 @@ void AbstractTableSet::setDatabase(Database *database)
int AbstractTableSet::size() const int AbstractTableSet::size() const
{ {
return data->childs.size(); return data->children.size();
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -28,11 +28,14 @@
#include <QtNut/nut_global.h> #include <QtNut/nut_global.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class Table; class Table;
class Database; class Database;
class AbstractTableSetData; class AbstractTableSetData;
class TableModel;
class NUT_EXPORT AbstractTableSet : public QObject class NUT_EXPORT AbstractTableSet : public QObject
{ {
@ -42,7 +45,7 @@ public:
virtual ~AbstractTableSet(); virtual ~AbstractTableSet();
virtual int save(Database *db, bool cleanUp = false); virtual int save(Database *db, bool cleanUp = false);
void clearChilds(); void clearChildren();
QString childClassName() const; QString childClassName() const;
Database *database() const; Database *database() const;
@ -58,12 +61,17 @@ public://TODO: change this to private
// void remove(Table *t); // void remove(Table *t);
void add(Row<Table> t); void add(Row<Table> t);
void add(WeakRow<Table> t);
void remove(Row<Table> t); void remove(Row<Table> t);
void remove(WeakRow<Table> t);
friend class Table; friend class Table;
friend class QueryBase; friend class QueryBase;
private:
void saveChangedOnRow(Nut::Table *t, Nut::TableModel *masterModel);
}; };
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // NUT_ABSTRACTTABLESET_H #endif // NUT_ABSTRACTTABLESET_H

View File

@ -25,6 +25,8 @@
#include <QtNut/nut_global.h> #include <QtNut/nut_global.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class Table; class Table;
@ -42,13 +44,17 @@ public:
// QSet<Table*> tables; // QSet<Table*> tables;
// QList<Table*> childRows; // QList<Table*> childRows;
RowList<Table> childs; RowList<Table> children;
WeakRowList<Table> weakChildren;
Database *database; Database *database;
Table *table; Table *table;
QString childClassName; QString childClassName;
}; };
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // NUT_ABSTRACTTABLESETDATA_H #endif // NUT_ABSTRACTTABLESETDATA_H

View File

@ -1,3 +1,23 @@
/**************************************************************************
**
** This file is part of Nut project.
** https://github.com/HamedMasafi/Nut
**
** Nut is free software: you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Nut is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
**
**************************************************************************/
#include "bulkinserter.h" #include "bulkinserter.h"
#include "bulkinserter_p.h" #include "bulkinserter_p.h"
@ -8,6 +28,8 @@
#include <QtCore/QDebug> #include <QtCore/QDebug>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
BulkInserterPrivate::BulkInserterPrivate(Database *db) BulkInserterPrivate::BulkInserterPrivate(Database *db)
@ -21,7 +43,7 @@ BulkInserter::BulkInserter(Database *db, QString &className)
{ {
Q_D(BulkInserter); Q_D(BulkInserter);
Q_FOREACH (TableModel *m, db->model()) for (auto &m: db->model())
if (m->className() == className) if (m->className() == className)
d->className = m->name(); d->className = m->name();
} }
@ -71,3 +93,5 @@ int BulkInserter::apply()
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -1,3 +1,23 @@
/**************************************************************************
**
** This file is part of Nut project.
** https://github.com/HamedMasafi/Nut
**
** Nut is free software: you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Nut is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
**
**************************************************************************/
#ifndef BULKINSERTER_H #ifndef BULKINSERTER_H
#define BULKINSERTER_H #define BULKINSERTER_H
@ -8,6 +28,8 @@
#include <QtNut/nut_global.h> #include <QtNut/nut_global.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class PhraseList; class PhraseList;
@ -15,7 +37,7 @@ class Database;
class BulkInserterPrivate; class BulkInserterPrivate;
class NUT_EXPORT BulkInserter class NUT_EXPORT BulkInserter
{ {
Q_DECLARE_PRIVATE(BulkInserter); Q_DECLARE_PRIVATE(BulkInserter)
public: public:
BulkInserter(Database *db, QString &className); BulkInserter(Database *db, QString &className);
@ -37,4 +59,6 @@ private:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // BULKINSERTER_H #endif // BULKINSERTER_H

View File

@ -1,8 +1,40 @@
/**************************************************************************
**
** This file is part of Nut project.
** https://github.com/HamedMasafi/Nut
**
** Nut is free software: you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Nut is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
**
**************************************************************************/
//
// W A R N I N G
// -------------
//
// This file is not part of the Nut API. This header
// file may change from version to version without notice, or even be removed.
//
// We mean it.
//
#ifndef BULKINSERTER_P_H #ifndef BULKINSERTER_P_H
#define BULKINSERTER_P_H #define BULKINSERTER_P_H
#include <QtNut/phraselist.h> #include <QtNut/phraselist.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class Database; class Database;
@ -20,4 +52,6 @@ public:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // BULKINSERTER_P_H #endif // BULKINSERTER_P_H

View File

@ -20,6 +20,8 @@
#include "changelogtable.h" #include "changelogtable.h"
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
ChangeLogTable::ChangeLogTable(QObject *tableSet) : Table(tableSet) ChangeLogTable::ChangeLogTable(QObject *tableSet) : Table(tableSet)
@ -29,3 +31,5 @@ ChangeLogTable::ChangeLogTable(QObject *tableSet) : Table(tableSet)
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -24,6 +24,8 @@
#include <QtCore/qglobal.h> #include <QtCore/qglobal.h>
#include <QtNut/table.h> #include <QtNut/table.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class NUT_EXPORT ChangeLogTable : public Table class NUT_EXPORT ChangeLogTable : public Table
@ -43,6 +45,8 @@ public:
NUT_END_NAMESPACE NUT_END_NAMESPACE
Q_DECLARE_METATYPE(Nut::ChangeLogTable*) QT_END_NAMESPACE
Q_DECLARE_METATYPE(NUT_WRAP_NAMESPACE(ChangeLogTable*))
#endif // CHANGELOGTABLE_H #endif // CHANGELOGTABLE_H

View File

@ -11,6 +11,7 @@ HEADERS += \
$$PWD/foreigncontainer.h \ $$PWD/foreigncontainer.h \
$$PWD/propertysignalmapper.h \ $$PWD/propertysignalmapper.h \
$$PWD/query.h \ $$PWD/query.h \
$$PWD/sqlserializer.h \
$$PWD/table.h \ $$PWD/table.h \
$$PWD/table_p.h \ $$PWD/table_p.h \
$$PWD/tableset.h $$PWD/tableset.h
@ -23,6 +24,7 @@ SOURCES += \
$$PWD/foreigncontainer.cpp \ $$PWD/foreigncontainer.cpp \
$$PWD/propertysignalmapper.cpp \ $$PWD/propertysignalmapper.cpp \
$$PWD/query.cpp \ $$PWD/query.cpp \
$$PWD/sqlserializer.cpp \
$$PWD/table.cpp \ $$PWD/table.cpp \
$$PWD/tableset.cpp $$PWD/tableset.cpp

View File

@ -49,8 +49,11 @@
# define __CHANGE_LOG_TABLE_NAME "__change_logs" # define __CHANGE_LOG_TABLE_NAME "__change_logs"
#endif #endif
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
QStringList DatabasePrivate::updatedDatabases;
qulonglong DatabasePrivate::lastId = 0; qulonglong DatabasePrivate::lastId = 0;
QMap<QString, DatabaseModel> DatabasePrivate::allTableMaps; QMap<QString, DatabaseModel> DatabasePrivate::allTableMaps;
@ -131,7 +134,12 @@ bool DatabasePrivate::updateDatabase()
{ {
Q_Q(Database); Q_Q(Database);
if (!getCurrectSchema()) QString databaseHistoryName = driver + "\t" + databaseName + "\t" + hostName;
if (updatedDatabases.contains(databaseHistoryName))
return true;
if (!getCurrentSchema())
return true; return true;
DatabaseModel last = isDatabaseNew ? DatabaseModel() : getLastSchema(); DatabaseModel last = isDatabaseNew ? DatabaseModel() : getLastSchema();
@ -140,12 +148,12 @@ bool DatabasePrivate::updateDatabase()
if (last == current) { if (last == current) {
qDebug("Database is up-to-date"); qDebug("Database is up-to-date");
//TODO: crash without this and I don't know why! //TODO: crash without this and I don't know why!
changeLogs->clearChilds(); changeLogs->clearChildren();
return true; return true;
} }
Q_FOREACH (TableModel *tm, current) { for (auto &tm: current) {
Q_FOREACH (FieldModel *fm, tm->fields()) { for (auto &fm: tm->fields()) {
if (sqlGenerator->fieldType(fm).isEmpty()) { if (sqlGenerator->fieldType(fm).isEmpty()) {
qWarning("The type (%s) is not supported for field %s::%s", qWarning("The type (%s) is not supported for field %s::%s",
QMetaType::typeName(fm->type), QMetaType::typeName(fm->type),
@ -160,10 +168,10 @@ bool DatabasePrivate::updateDatabase()
else else
qDebug("Database is changed"); qDebug("Database is changed");
QStringList sql = sqlGenerator->diff(last, current); QStringList sql = sqlGenerator->diffDatabase(last, current);
db.transaction(); db.transaction();
Q_FOREACH (QString s, sql) { for (auto &s: sql) {
db.exec(s); db.exec(s);
if (db.lastError().type() != QSqlError::NoError) { if (db.lastError().type() != QSqlError::NoError) {
@ -182,6 +190,7 @@ bool DatabasePrivate::updateDatabase()
if (!last.count()) if (!last.count())
q->databaseCreated(); q->databaseCreated();
updatedDatabases.append(databaseHistoryName);
} else { } else {
qWarning("Unable update database, error = %s", qWarning("Unable update database, error = %s",
db.lastError().text().toLatin1().data()); db.lastError().text().toLatin1().data());
@ -190,14 +199,14 @@ bool DatabasePrivate::updateDatabase()
return ok; return ok;
} }
bool DatabasePrivate::getCurrectSchema() bool DatabasePrivate::getCurrentSchema()
{ {
Q_Q(Database); Q_Q(Database);
//is not first instanicate of this class //is not first instanicate of this class
if (allTableMaps.contains(QString::fromUtf8(q->metaObject()->className()))) { if (allTableMaps.contains(QString::fromUtf8(q->metaObject()->className()))) {
currentModel = allTableMaps[QString::fromUtf8(q->metaObject()->className())]; currentModel = allTableMaps[QString::fromUtf8(q->metaObject()->className())];
return false; // return false;
} }
QMap<QString, QString> tables; QMap<QString, QString> tables;
@ -252,15 +261,28 @@ bool DatabasePrivate::getCurrectSchema()
QMetaProperty tableProperty = q->metaObject()->property(i); QMetaProperty tableProperty = q->metaObject()->property(i);
int typeId = QMetaType::type(tableProperty.typeName()); int typeId = QMetaType::type(tableProperty.typeName());
if (tables.values().contains(QString::fromUtf8(tableProperty.name())) if ((unsigned) typeId >= QVariant::UserType) {
bool contains{false};
auto tableName = QString::fromUtf8(tableProperty.name());
for (auto i = tables.begin(); i != tables.end(); ++i)
if (i.value() == tableName)
contains = true;
if (contains) {
TableModel *sch = new TableModel(typeId, tableName);
currentModel.append(sch);
}
}
/*if (tables.values().contains(QString::fromUtf8(tableProperty.name()))
&& (unsigned)typeId >= QVariant::UserType) { && (unsigned)typeId >= QVariant::UserType) {
TableModel *sch = new TableModel(typeId, QString::fromUtf8(tableProperty.name())); TableModel *sch = new TableModel(typeId, QString::fromUtf8(tableProperty.name()));
currentModel.append(sch); currentModel.append(sch);
} }*/
} }
Q_FOREACH (TableModel *table, currentModel) { for (auto &table: currentModel) {
Q_FOREACH (FieldModel *f, table->fields()) { for (auto &f: table->fields()) {
if (f->isPrimaryKey && ! sqlGenerator->supportPrimaryKey(f->type)) if (f->isPrimaryKey && ! sqlGenerator->supportPrimaryKey(f->type))
qFatal("The field of type %s does not support as primary key", qFatal("The field of type %s does not support as primary key",
qPrintable(f->typeName)); qPrintable(f->typeName));
@ -270,7 +292,7 @@ bool DatabasePrivate::getCurrectSchema()
qPrintable(f->typeName)); qPrintable(f->typeName));
} }
Q_FOREACH (RelationModel *fk, table->foreignKeys()) for (auto &fk: table->foreignKeys())
fk->masterTable = currentModel.tableByClassName(fk->masterClassName); fk->masterTable = currentModel.tableByClassName(fk->masterClassName);
} }
@ -295,28 +317,8 @@ DatabaseModel DatabasePrivate::getLastSchema()
DatabaseModel ret = json; DatabaseModel ret = json;
return ret; return ret;
/*
Q_FOREACH (QString key, json.keys()) {
TableModel *sch = new TableModel(json.value(key).toObject(), key);
ret.append(sch);
}*/
} }
return DatabaseModel(); return DatabaseModel();
// QSqlQuery query = q->exec("select * from __change_logs order by id
// desc limit 1");
// DatabaseModel ret;
// if(query.next()){
// QJsonObject json =
// QJsonDocument::fromJson(query.value("data").toByteArray()).object();
// Q_FOREACH (QString key, json.keys()) {
// TableModel *sch = new TableModel(json.value(key).toObject(),
// key);
// ret.append(sch);
// }
// }
// return ret;
} }
bool DatabasePrivate::putModelToDatabase() bool DatabasePrivate::putModelToDatabase()
@ -333,26 +335,16 @@ bool DatabasePrivate::putModelToDatabase()
changeLog->deleteLater(); changeLog->deleteLater();
return true; return true;
// QSqlQuery query(db);
// query.prepare("insert into __change_logs (data) values (:data)");
// query.bindValue(":data",
// QString(QJsonDocument(currentModel.toJson()).toJson()));
// bool ret = query.exec();
// if(query.lastError().type() != QSqlError::NoError)
// qWarning(QString("storeSchemaInDB" +
// query.lastError().text()).toLatin1().data());
// return ret;
} }
void DatabasePrivate::createChangeLogs() void DatabasePrivate::createChangeLogs()
{ {
// currentModel.model("change_log") // currentModel.model("change_log")
QStringList diff = sqlGenerator->diff(nullptr, QStringList diff = sqlGenerator->diffTable(nullptr,
currentModel.tableByName( currentModel.tableByName(
QStringLiteral("__change_log"))); QStringLiteral("__change_log")));
Q_FOREACH (QString s, diff) for (auto &s: diff)
db.exec(s); db.exec(s);
} }
@ -564,12 +556,12 @@ bool Database::open(bool updateDatabase)
else if (d->driver == QStringLiteral("QODBC") || d->driver == QStringLiteral("QODBC3")) { else if (d->driver == QStringLiteral("QODBC") || d->driver == QStringLiteral("QODBC3")) {
QString driverName = QString(); QString driverName = QString();
QStringList parts = d->databaseName.toLower().split(';'); QStringList parts = d->databaseName.toLower().split(';');
Q_FOREACH (QString p, parts) for (auto &p: parts)
if (p.trimmed().startsWith(QStringLiteral("driver="))) if (p.trimmed().startsWith(QStringLiteral("driver=")))
driverName = p.split('=').at(1).toLower().trimmed(); driverName = p.split('=').at(1).toLower().trimmed();
// if (driverName == "{sql server}") // if (driverName == "{sql server}")
d->sqlGenerator = new SqlServerGenerator(this); d->sqlGenerator = new SqlServerGenerator(this);
// TODO: add ODBC driver for mysql, postgres, ... // TODO: add ODBC driver for mysql, postgres, ...
} }
@ -615,7 +607,7 @@ int Database::saveChanges(bool cleanUp)
} }
int rowsAffected = 0; int rowsAffected = 0;
Q_FOREACH (AbstractTableSet *ts, d->tableSets) for (const auto &ts: qAsConst(d->tableSets))
rowsAffected += ts->save(this, cleanUp); rowsAffected += ts->save(this, cleanUp);
return rowsAffected; return rowsAffected;
@ -624,8 +616,10 @@ int Database::saveChanges(bool cleanUp)
void Database::cleanUp() void Database::cleanUp()
{ {
Q_D(Database); Q_D(Database);
Q_FOREACH (AbstractTableSet *ts, d->tableSets) for (const auto &ts: qAsConst(d->tableSets))
ts->clearChilds(); ts->clearChildren();
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -29,6 +29,8 @@
#include <QtNut/nut_global.h> #include <QtNut/nut_global.h>
#include <QtNut/tableset.h> #include <QtNut/tableset.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class DatabaseModel; class DatabaseModel;
@ -57,7 +59,7 @@ public:
QSqlQuery exec(const QString& sql); QSqlQuery exec(const QString& sql);
int saveChanges(bool cleanUp = false); int saveChanges(bool cleanUp = true);
void cleanUp(); void cleanUp();
QString databaseName() const; QString databaseName() const;
@ -75,7 +77,6 @@ public:
QSqlDatabase database(); QSqlDatabase database();
protected: protected:
//remove minor version
virtual void databaseCreated(); virtual void databaseCreated();
virtual void databaseUpdated(int oldVersion, int newVersion); virtual void databaseUpdated(int oldVersion, int newVersion);
@ -96,4 +97,6 @@ private:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // NUTDATABASE_H #endif // NUTDATABASE_H

View File

@ -18,6 +18,16 @@
** **
**************************************************************************/ **************************************************************************/
//
// W A R N I N G
// -------------
//
// This file is not part of the Nut API. This header
// file may change from version to version without notice, or even be removed.
//
// We mean it.
//
#ifndef DATABASE_P_H #ifndef DATABASE_P_H
#define DATABASE_P_H #define DATABASE_P_H
@ -27,6 +37,8 @@
#include <QtNut/database.h> #include <QtNut/database.h>
#include <QtNut/databasemodel.h> #include <QtNut/databasemodel.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class ChangeLogTable; class ChangeLogTable;
@ -44,7 +56,7 @@ public:
void createChangeLogs(); void createChangeLogs();
bool putModelToDatabase(); bool putModelToDatabase();
DatabaseModel getLastSchema(); DatabaseModel getLastSchema();
bool getCurrectSchema(); bool getCurrentSchema();
QSqlDatabase db; QSqlDatabase db;
@ -63,6 +75,7 @@ public:
static QMap<QString, DatabaseModel> allTableMaps; static QMap<QString, DatabaseModel> allTableMaps;
static qulonglong lastId; static qulonglong lastId;
static QStringList updatedDatabases;
QSet<AbstractTableSet *> tableSets; QSet<AbstractTableSet *> tableSets;
@ -73,4 +86,6 @@ public:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // DATABASE_P_H #endif // DATABASE_P_H

View File

@ -1,6 +1,33 @@
/**************************************************************************
**
** This file is part of Nut project.
** https://github.com/HamedMasafi/Nut
**
** Nut is free software: you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Nut is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
**
**************************************************************************/
#ifndef FOREIGNCONTAINER_H #ifndef FOREIGNCONTAINER_H
#define FOREIGNCONTAINER_H #define FOREIGNCONTAINER_H
#include <QtGlobal>
#include <QtNut/NutGlobal>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE
template<class _OBJECT, typename _KEY> template<class _OBJECT, typename _KEY>
class ForeignContainer class ForeignContainer
{ {
@ -55,4 +82,8 @@ public:
} }
}; };
NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // FOREIGNCONTAINER_H #endif // FOREIGNCONTAINER_H

View File

@ -20,6 +20,9 @@
#include "propertysignalmapper.h" #include "propertysignalmapper.h"
#include "table.h" #include "table.h"
#include "nut_global.h"
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
@ -71,3 +74,5 @@ QString PropertySignalMapper::changedProperty(QObject *obj, int senderSignalInde
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -26,6 +26,8 @@
#include <QMetaMethod> #include <QMetaMethod>
#include <QMetaProperty> #include <QMetaProperty>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class Table; class Table;
@ -46,4 +48,6 @@ public:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // PROPERTYSIGNALMAPPER_H #endif // PROPERTYSIGNALMAPPER_H

View File

@ -20,6 +20,8 @@
#include "query.h" #include "query.h"
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
/*! /*!
@ -80,3 +82,5 @@ NUT_BEGIN_NAMESPACE
*/ */
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -44,9 +44,18 @@
#include <QtNut/tablemodel.h> #include <QtNut/tablemodel.h>
#include <QtNut/sqlmodel.h> #include <QtNut/sqlmodel.h>
#ifdef NUT_PRINT_DEBUG_INFO
# define printSql(sql) qDebug().noquote() << "[Nut][" << __FUNCTION__ << "] sql=" << sql;
#else
# define printSql(sql)
#endif
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
struct NUT_EXPORT QueryData { struct NUT_EXPORT QueryData {
bool hasCustomCommand{false};
QString sql; QString sql;
QString className; QString className;
QString tableName; QString tableName;
@ -146,24 +155,28 @@ public:
//debug purpose //debug purpose
QString sqlCommand() const; QString sqlCommand() const;
Query<T> &setSqlCommand(const QString &command);
}; };
template<typename T> template<typename T>
template<typename O> template<typename O>
Q_OUTOFLINE_TEMPLATE QList<O> Query<T>::select(const std::function<O (const QSqlQuery &)> allocator) Q_OUTOFLINE_TEMPLATE QList<O> Query<T>::select(const std::function<O (const QSqlQuery &)> allocator)
{ {
//Q_D(AbstractQuery);
QList<O> ret; QList<O> ret;
d->joins.prepend(d->tableName); if (!d->hasCustomCommand) {
d->sql = d->database->sqlGenerator()->selectCommand(d->tableName, d->joins.prepend(d->tableName);
AbstractSqlGenerator::SingleField, d->sql = d->database->sqlGenerator()->selectCommand(d->tableName,
QStringLiteral("*"), AbstractSqlGenerator::SingleField,
d->wherePhrase, QStringLiteral("*"),
d->relations, d->wherePhrase,
d->skip, d->relations,
d->take); d->skip,
d->take);
printSql(d->sql);
}
QSqlQuery q = d->database->exec(d->sql); QSqlQuery q = d->database->exec(d->sql);
while (q.next()) { while (q.next()) {
@ -184,8 +197,6 @@ template <class T>
Q_OUTOFLINE_TEMPLATE Query<T>::Query(Database *database, AbstractTableSet *tableSet) Q_OUTOFLINE_TEMPLATE Query<T>::Query(Database *database, AbstractTableSet *tableSet)
: d(new QueryData(database)) : d(new QueryData(database))
{ {
//Q_D(AbstractQuery);
d->database = database; d->database = database;
d->tableSet = tableSet; d->tableSet = tableSet;
d->className = QString::fromUtf8(T::staticMetaObject.className()); d->className = QString::fromUtf8(T::staticMetaObject.className());
@ -209,7 +220,6 @@ Q_OUTOFLINE_TEMPLATE Query<T>::Query(Query<T> &&other) {
template <class T> template <class T>
Q_OUTOFLINE_TEMPLATE Query<T>::~Query() Q_OUTOFLINE_TEMPLATE Query<T>::~Query()
{ {
//Q_D(AbstractQuery);
delete d; delete d;
} }
@ -228,14 +238,19 @@ Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::operator=(const Query<T> &q)
template <class T> template <class T>
Q_OUTOFLINE_TEMPLATE RowList<T> Query<T>::toList(int count) Q_OUTOFLINE_TEMPLATE RowList<T> Query<T>::toList(int count)
{ {
//Q_D(AbstractQuery);
RowList<T> returnList; RowList<T> returnList;
d->select = QStringLiteral("*"); d->select = QStringLiteral("*");
d->sql = d->database->sqlGenerator()->selectCommand( if (!d->hasCustomCommand)
d->tableName, d->fieldPhrase, d->wherePhrase, d->orderPhrase, d->sql = d->database->sqlGenerator()->selectCommand(d->tableName,
d->relations, d->skip, count); d->fieldPhrase,
d->wherePhrase,
d->orderPhrase,
d->relations,
d->skip,
count);
printSql(d->sql);
QSqlQuery q = d->database->exec(d->sql); QSqlQuery q = d->database->exec(d->sql);
if (q.lastError().isValid()) { if (q.lastError().isValid()) {
qDebug() << q.lastError().text(); qDebug() << q.lastError().text();
@ -244,7 +259,7 @@ Q_OUTOFLINE_TEMPLATE RowList<T> Query<T>::toList(int count)
QSet<TableModel*> relatedTables; QSet<TableModel*> relatedTables;
relatedTables << d->database->model().tableByName(d->tableName); relatedTables << d->database->model().tableByName(d->tableName);
Q_FOREACH (RelationModel *rel, d->relations) for (auto &rel: d->relations)
relatedTables << rel->slaveTable << rel->masterTable; relatedTables << rel->slaveTable << rel->masterTable;
struct LevelData{ struct LevelData{
@ -271,7 +286,7 @@ Q_OUTOFLINE_TEMPLATE RowList<T> Query<T>::toList(int count)
data.lastKeyValue = QVariant(); data.lastKeyValue = QVariant();
QHash<QString, QString> masters; QHash<QString, QString> masters;
Q_FOREACH (RelationModel *rel, d->relations) for (auto &rel: d->relations)
if (rel->slaveTable->name() == table->name()) if (rel->slaveTable->name() == table->name())
masters.insert(rel->masterTable->name(), rel->localProperty); masters.insert(rel->masterTable->name(), rel->localProperty);
@ -337,7 +352,7 @@ Q_OUTOFLINE_TEMPLATE RowList<T> Query<T>::toList(int count)
} }
// check if master if current table has processed // check if master if current table has processed
Q_FOREACH (int m, data.masters) for (auto &m: data.masters)
if (!checked[m]) { if (!checked[m]) {
// qDebug() << "row is checked"; // qDebug() << "row is checked";
continue; continue;
@ -350,7 +365,7 @@ Q_OUTOFLINE_TEMPLATE RowList<T> Query<T>::toList(int count)
//create table row //create table row
Row<Table> row; Row<Table> row;
if (data.table->className() == d->className) { if (data.table->className() == d->className) {
Row<T> tmpRow = Nut::create<T>(); Row<T> tmpRow = create<T>();
row = tmpRow.template objectCast<Table>(); row = tmpRow.template objectCast<Table>();
row->init(); row->init();
@ -363,8 +378,13 @@ Q_OUTOFLINE_TEMPLATE RowList<T> Query<T>::toList(int count)
} else { } else {
Table *table; Table *table;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
auto childMetaObject = QMetaType(data.table->typeId()).metaObject();
#else
const QMetaObject *childMetaObject const QMetaObject *childMetaObject
= QMetaType::metaObjectForType(data.table->typeId()); = QMetaType::metaObjectForType(data.table->typeId());
#endif
table = qobject_cast<Table *>(childMetaObject->newInstance()); table = qobject_cast<Table *>(childMetaObject->newInstance());
// table = dynamic_cast<Table *>(QMetaType::create(data.table->typeId())); // table = dynamic_cast<Table *>(QMetaType::create(data.table->typeId()));
if (!table) if (!table)
@ -374,7 +394,7 @@ Q_OUTOFLINE_TEMPLATE RowList<T> Query<T>::toList(int count)
} }
QList<FieldModel*> childFields = data.table->fields(); QList<FieldModel*> childFields = data.table->fields();
Q_FOREACH (FieldModel *field, childFields) for (auto &field: childFields)
row->setProperty(field->name.toLatin1().data(), row->setProperty(field->name.toLatin1().data(),
d->database->sqlGenerator()->unescapeValue( d->database->sqlGenerator()->unescapeValue(
field->type, field->type,
@ -399,6 +419,8 @@ Q_OUTOFLINE_TEMPLATE RowList<T> Query<T>::toList(int count)
Q_ARG(Nut::Row<Nut::Table>, Q_ARG(Nut::Row<Nut::Table>,
levels[master].lastRow)); levels[master].lastRow));
if (Q_UNLIKELY(!ok))
qWarning("Unable to invoke method %s on object", qPrintable(setterName));
} }
} }
@ -419,17 +441,20 @@ template <typename T>
template <typename F> template <typename F>
Q_OUTOFLINE_TEMPLATE QList<F> Query<T>::select(const FieldPhrase<F> f) Q_OUTOFLINE_TEMPLATE QList<F> Query<T>::select(const FieldPhrase<F> f)
{ {
//Q_D(AbstractQuery);
QList<F> ret; QList<F> ret;
d->joins.prepend(d->tableName); if (!d->hasCustomCommand) {
d->sql = d->database->sqlGenerator()->selectCommand( d->joins.prepend(d->tableName);
d->tableName, d->sql = d->database->sqlGenerator()->selectCommand(d->tableName,
AbstractSqlGenerator::SingleField, f.data->toString(), AbstractSqlGenerator::SingleField,
d->wherePhrase, f.data->toString(),
d->relations, d->wherePhrase,
d->skip, d->take); d->relations,
d->skip,
d->take);
printSql(d->sql);
}
QSqlQuery q = d->database->exec(d->sql); QSqlQuery q = d->database->exec(d->sql);
while (q.next()) { while (q.next()) {
@ -455,16 +480,16 @@ Q_OUTOFLINE_TEMPLATE Row<T> Query<T>::first()
template <class T> template <class T>
Q_OUTOFLINE_TEMPLATE int Query<T>::count() Q_OUTOFLINE_TEMPLATE int Query<T>::count()
{ {
//Q_D(AbstractQuery); if (!d->hasCustomCommand) {
d->joins.prepend(d->tableName);
d->joins.prepend(d->tableName); d->select = QStringLiteral("COUNT(*)");
d->select = QStringLiteral("COUNT(*)"); d->sql = d->database->sqlGenerator()->selectCommand(d->tableName,
d->sql = d->database->sqlGenerator()->selectCommand( AbstractSqlGenerator::Count,
d->tableName, QStringLiteral("*"),
AbstractSqlGenerator::Count, d->wherePhrase,
QStringLiteral("*"), d->relations);
d->wherePhrase, printSql(d->sql);
d->relations); }
QSqlQuery q = d->database->exec(d->sql); QSqlQuery q = d->database->exec(d->sql);
if (q.next()) if (q.next())
@ -475,14 +500,15 @@ Q_OUTOFLINE_TEMPLATE int Query<T>::count()
template <class T> template <class T>
Q_OUTOFLINE_TEMPLATE QVariant Query<T>::max(const FieldPhrase<int> &f) Q_OUTOFLINE_TEMPLATE QVariant Query<T>::max(const FieldPhrase<int> &f)
{ {
//Q_D(AbstractQuery); if (!d->hasCustomCommand) {
d->joins.prepend(d->tableName);
d->joins.prepend(d->tableName); d->sql = d->database->sqlGenerator()->selectCommand(d->tableName,
d->sql = d->database->sqlGenerator()->selectCommand( AbstractSqlGenerator::Max,
d->tableName, f.data->toString(),
AbstractSqlGenerator::Max, f.data->toString(), d->wherePhrase,
d->wherePhrase, d->relations);
d->relations); printSql(d->sql);
}
QSqlQuery q = d->database->exec(d->sql); QSqlQuery q = d->database->exec(d->sql);
if (q.next()) if (q.next())
@ -493,14 +519,15 @@ Q_OUTOFLINE_TEMPLATE QVariant Query<T>::max(const FieldPhrase<int> &f)
template <class T> template <class T>
Q_OUTOFLINE_TEMPLATE QVariant Query<T>::min(const FieldPhrase<int> &f) Q_OUTOFLINE_TEMPLATE QVariant Query<T>::min(const FieldPhrase<int> &f)
{ {
//Q_D(AbstractQuery); if (!d->hasCustomCommand) {
d->joins.prepend(d->tableName);
d->joins.prepend(d->tableName); d->sql = d->database->sqlGenerator()->selectCommand(d->tableName,
d->sql = d->database->sqlGenerator()->selectCommand( AbstractSqlGenerator::Min,
d->tableName, f.data->toString(),
AbstractSqlGenerator::Min, f.data->toString(), d->wherePhrase,
d->wherePhrase, d->relations);
d->relations); printSql(d->sql);
}
QSqlQuery q = d->database->exec(d->sql); QSqlQuery q = d->database->exec(d->sql);
if (q.next()) if (q.next())
@ -511,14 +538,15 @@ Q_OUTOFLINE_TEMPLATE QVariant Query<T>::min(const FieldPhrase<int> &f)
template <class T> template <class T>
Q_OUTOFLINE_TEMPLATE QVariant Query<T>::sum(const FieldPhrase<int> &f) Q_OUTOFLINE_TEMPLATE QVariant Query<T>::sum(const FieldPhrase<int> &f)
{ {
//Q_D(AbstractQuery); if (!d->hasCustomCommand) {
d->joins.prepend(d->tableName);
d->joins.prepend(d->tableName); d->sql = d->database->sqlGenerator()->selectCommand(d->tableName,
d->sql = d->database->sqlGenerator()->selectCommand( AbstractSqlGenerator::Sum,
d->tableName, f.data->toString(),
AbstractSqlGenerator::Sum, f.data->toString(), d->wherePhrase,
d->wherePhrase, d->relations);
d->relations); printSql(d->sql);
}
QSqlQuery q = d->database->exec(d->sql); QSqlQuery q = d->database->exec(d->sql);
if (q.next()) if (q.next())
@ -529,14 +557,15 @@ Q_OUTOFLINE_TEMPLATE QVariant Query<T>::sum(const FieldPhrase<int> &f)
template <class T> template <class T>
Q_OUTOFLINE_TEMPLATE QVariant Query<T>::average(const FieldPhrase<int> &f) Q_OUTOFLINE_TEMPLATE QVariant Query<T>::average(const FieldPhrase<int> &f)
{ {
//Q_D(AbstractQuery); if (!d->hasCustomCommand) {
d->joins.prepend(d->tableName);
d->joins.prepend(d->tableName); d->sql = d->database->sqlGenerator()->selectCommand(d->tableName,
d->sql = d->database->sqlGenerator()->selectCommand( AbstractSqlGenerator::Average,
d->tableName, f.data->toString(),
AbstractSqlGenerator::Average, f.data->toString(), d->wherePhrase,
d->wherePhrase, d->relations);
d->relations); printSql(d->sql);
}
QSqlQuery q = d->database->exec(d->sql); QSqlQuery q = d->database->exec(d->sql);
if (q.next()) if (q.next())
@ -547,9 +576,10 @@ Q_OUTOFLINE_TEMPLATE QVariant Query<T>::average(const FieldPhrase<int> &f)
template<class T> template<class T>
Q_OUTOFLINE_TEMPLATE QVariant Query<T>::insert(const AssignmentPhraseList &p) Q_OUTOFLINE_TEMPLATE QVariant Query<T>::insert(const AssignmentPhraseList &p)
{ {
//Q_D(AbstractQuery); if (!d->hasCustomCommand) {
d->sql = d->database->sqlGenerator() d->sql = d->database->sqlGenerator()->insertCommand(d->tableName, p);
->insertCommand(d->tableName, p); printSql(d->sql);
}
QSqlQuery q = d->database->exec(d->sql); QSqlQuery q = d->database->exec(d->sql);
return q.lastInsertId(); return q.lastInsertId();
@ -558,8 +588,6 @@ Q_OUTOFLINE_TEMPLATE QVariant Query<T>::insert(const AssignmentPhraseList &p)
template <class T> template <class T>
Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::join(const QString &className) Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::join(const QString &className)
{ {
//Q_D(AbstractQuery);
RelationModel *rel = d->database->model() RelationModel *rel = d->database->model()
.relationByClassNames(d->className, className); .relationByClassNames(d->className, className);
if (!rel) if (!rel)
@ -587,7 +615,6 @@ Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::join(Table *c)
template <class T> template <class T>
Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::where(const ConditionalPhrase &ph) Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::where(const ConditionalPhrase &ph)
{ {
//Q_D(AbstractQuery);
if (d->wherePhrase.data) if (d->wherePhrase.data)
d->wherePhrase = d->wherePhrase && ph; d->wherePhrase = d->wherePhrase && ph;
else else
@ -598,7 +625,6 @@ Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::where(const ConditionalPhrase &ph)
template <class T> template <class T>
Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::setWhere(const ConditionalPhrase &ph) Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::setWhere(const ConditionalPhrase &ph)
{ {
//Q_D(AbstractQuery);
d->wherePhrase = ph; d->wherePhrase = ph;
return *this; return *this;
} }
@ -606,7 +632,6 @@ Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::setWhere(const ConditionalPhrase &ph)
template<class T> template<class T>
Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::skip(int n) Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::skip(int n)
{ {
//Q_D(AbstractQuery);
d->skip = n; d->skip = n;
return *this; return *this;
} }
@ -614,7 +639,6 @@ Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::skip(int n)
template<class T> template<class T>
Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::take(int n) Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::take(int n)
{ {
//Q_D(AbstractQuery);
d->take = n; d->take = n;
return *this; return *this;
} }
@ -622,24 +646,13 @@ Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::take(int n)
template<class T> template<class T>
Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::fields(const PhraseList &ph) Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::fields(const PhraseList &ph)
{ {
//Q_D(AbstractQuery);
d->fieldPhrase = ph; d->fieldPhrase = ph;
return *this; return *this;
} }
//template <class T>
//Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::orderBy(QString fieldName,
// QString type)
//{
// //Q_D(AbstractQuery);
// d->orderPhrases.append(fieldName, type);
// return *this;
//}
template <class T> template <class T>
Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::orderBy(const PhraseList &ph) Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::orderBy(const PhraseList &ph)
{ {
//Q_D(AbstractQuery);
d->orderPhrase = ph; d->orderPhrase = ph;
return *this; return *this;
} }
@ -647,13 +660,10 @@ Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::orderBy(const PhraseList &ph)
template <class T> template <class T>
Q_OUTOFLINE_TEMPLATE int Query<T>::update(const AssignmentPhraseList &ph) Q_OUTOFLINE_TEMPLATE int Query<T>::update(const AssignmentPhraseList &ph)
{ {
//Q_D(AbstractQuery); if (!d->hasCustomCommand) {
d->sql = d->database->sqlGenerator()->updateCommand(d->tableName, ph, d->wherePhrase);
d->sql = d->database->sqlGenerator()->updateCommand( printSql(d->sql);
d->tableName, }
ph,
d->wherePhrase);
QSqlQuery q = d->database->exec(d->sql); QSqlQuery q = d->database->exec(d->sql);
return q.numRowsAffected(); return q.numRowsAffected();
@ -662,10 +672,10 @@ Q_OUTOFLINE_TEMPLATE int Query<T>::update(const AssignmentPhraseList &ph)
template <class T> template <class T>
Q_OUTOFLINE_TEMPLATE int Query<T>::remove() Q_OUTOFLINE_TEMPLATE int Query<T>::remove()
{ {
//Q_D(AbstractQuery); if (!d->hasCustomCommand) {
d->sql = d->database->sqlGenerator()->deleteCommand(d->tableName, d->wherePhrase);
d->sql = d->database->sqlGenerator()->deleteCommand( printSql(d->sql);
d->tableName, d->wherePhrase); }
QSqlQuery q = d->database->exec(d->sql); QSqlQuery q = d->database->exec(d->sql);
return q.numRowsAffected(); return q.numRowsAffected();
@ -682,36 +692,33 @@ Q_OUTOFLINE_TEMPLATE QSqlQueryModel *Query<T>::toModel()
template <class T> template <class T>
Q_OUTOFLINE_TEMPLATE void Query<T>::toModel(QSqlQueryModel *model) Q_OUTOFLINE_TEMPLATE void Query<T>::toModel(QSqlQueryModel *model)
{ {
//Q_D(AbstractQuery); if (!d->hasCustomCommand) {
d->sql = d->database->sqlGenerator()->selectCommand(d->tableName,
d->sql = d->database->sqlGenerator()->selectCommand( d->fieldPhrase,
d->tableName, d->wherePhrase,
d->fieldPhrase, d->orderPhrase,
d->wherePhrase, d->orderPhrase, d->relations, d->relations,
d->skip, d->take); d->skip,
d->take);
printSql(d->sql);
}
DatabaseModel dbModel = d->database->model(); DatabaseModel dbModel = d->database->model();
model->setQuery(d->sql, d->database->database()); model->setQuery(d->sql, d->database->database());
int fieldIndex = 0; int fieldIndex = 0;
if (d->fieldPhrase.data.count()) { if (d->fieldPhrase.data.count()) {
Q_FOREACH (const PhraseData *pd, d->fieldPhrase.data) { for (const auto &pd : qAsConst(d->fieldPhrase.data)) {
QString displayName = dbModel QString displayName = dbModel.tableByClassName(QString::fromUtf8(pd->className))
.tableByClassName(QString::fromUtf8(pd->className))
->field(QString::fromUtf8(pd->fieldName)) ->field(QString::fromUtf8(pd->fieldName))
->displayName; ->displayName;
model->setHeaderData(fieldIndex++, model->setHeaderData(fieldIndex++, Qt::Horizontal, displayName);
Qt::Horizontal,
displayName);
} }
} else { } else {
TableModel *tbl = d->database->model().tableByName(d->tableName); TableModel *tbl = d->database->model().tableByName(d->tableName);
Q_FOREACH (FieldModel *f, tbl->fields()) { for (auto &f : tbl->fields()) {
model->setHeaderData(fieldIndex++, model->setHeaderData(fieldIndex++, Qt::Horizontal, f->displayName);
Qt::Horizontal,
f->displayName);
} }
} }
} }
@ -719,38 +726,15 @@ Q_OUTOFLINE_TEMPLATE void Query<T>::toModel(QSqlQueryModel *model)
template<class T> template<class T>
Q_OUTOFLINE_TEMPLATE void Query<T>::toModel(SqlModel *model) Q_OUTOFLINE_TEMPLATE void Query<T>::toModel(SqlModel *model)
{ {
//Q_D(AbstractQuery);
d->sql = d->database->sqlGenerator()->selectCommand( d->sql = d->database->sqlGenerator()->selectCommand(
d->tableName, d->tableName,
d->fieldPhrase, d->fieldPhrase,
d->wherePhrase, d->orderPhrase, d->relations, d->wherePhrase, d->orderPhrase, d->relations,
d->skip, d->take); d->skip, d->take);
printSql(d->sql);
model->setTable(toList()); model->setTable(toList());
/*
DatabaseModel dbModel = d->database->model();
model->setQuery(d->sql, d->database->database());
int fieldIndex = 0;
if (d->fieldPhrase.data.count()) {
Q_FOREACH (const PhraseData *pd, d->fieldPhrase.data) {
QString displayName = dbModel.tableByClassName(pd->className)
->field(pd->fieldName)->displayName;
model->setHeaderData(fieldIndex++,
Qt::Horizontal,
displayName);
}
} else {
TableModel *tbl = d->database->model().tableByName(d->tableName);
Q_FOREACH (FieldModel *f, tbl->fields()) {
model->setHeaderData(fieldIndex++,
Qt::Horizontal,
f->displayName);
}
}*/
} }
template <class T> template <class T>
@ -760,15 +744,15 @@ Q_OUTOFLINE_TEMPLATE QString Query<T>::sqlCommand() const
return d->sql; return d->sql;
} }
//TODO: complete this class later template<class T>
//class RawQuery : public Query<void> Q_OUTOFLINE_TEMPLATE Query<T> &Query<T>::setSqlCommand(const QString &command)
//{ {
//public: d->hasCustomCommand = true;
// void setRawCommand(const QString &sql) { d->sql = command;
}
// }
//};
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // NUT_QUERY_H #endif // NUT_QUERY_H

View File

@ -0,0 +1,694 @@
/**************************************************************************
**
** This file is part of Nut project.
** https://github.com/HamedMasafi/Nut
**
** Nut is free software: you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Nut is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
**
**************************************************************************/
#include "sqlserializer.h"
#include <QtCore/QUuid>
#include <QtCore/QPoint>
#include <QtCore/QPointF>
#include <QtCore/QSizeF>
#include <QtCore/QSize>
#include <QtCore/QRect>
#include <QtCore/QRectF>
#include <QtCore/QDate>
#include <QtCore/QTime>
#include <QtCore/QDateTime>
#include <QtCore/QDebug>
#include <QtCore/QUrl>
#include <QtCore/QLineF>
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonArray>
#include <QtCore/QJsonObject>
#include <QtCore/QBitArray>
#include <QtCore/QBuffer>
#include "nut_p.h"
#include "nut_global.h"
#ifdef QT_GUI_LIB
#include <QtGui/QFont>
#include <QtGui/QPolygon>
#include <QtGui/QPolygonF>
#include <QtGui/QColor>
#include <QtGui/QImage>
#include <QtGui/QVector2D>
#include <QtGui/QVector3D>
#include <QtGui/QVector4D>
#endif
#define DATE_FORMAT QStringLiteral("yyyy-MM-dd")
#define TIME_FORMAT QStringLiteral("HH:mm:ss.zzz")
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE
SqlSerializer::SqlSerializer()
{
}
SqlSerializer::~SqlSerializer()
{
}
QVariant SqlSerializer::fromString(const QString &value, const QMetaType::Type &type) const
{
switch (type) {
case QMetaType::Bool: return !value.compare(QStringLiteral("true"), Qt::CaseInsensitive) || value == QStringLiteral("1");
case QMetaType::Char:
case QMetaType::SChar:
case QMetaType::Int: return value.toInt();
case QMetaType::UChar:
case QMetaType::UInt: return value.toUInt();
case QMetaType::Short: return value.toShort();
case QMetaType::UShort: return value.toUShort();
case QMetaType::Long: return QVariant::fromValue(value.toLong());
case QMetaType::ULong: return QVariant::fromValue(value.toULong());
case QMetaType::LongLong: return value.toLongLong();
case QMetaType::ULongLong: return QVariant::fromValue(value.toULongLong());
case QMetaType::Float: return value.toFloat();
case QMetaType::Double: return value.toDouble();
case QMetaType::QString: return unescapeString(value);
case QMetaType::QDate: return QDate::fromString(value, DATE_FORMAT);
case QMetaType::QTime: return QTime::fromString(value, TIME_FORMAT);
case QMetaType::QDateTime: return QDateTime::fromString(value, DATE_FORMAT + QStringLiteral(" ") + TIME_FORMAT);
case QMetaType::QUrl: return QUrl(value);
case QMetaType::QChar: return value.at(0);
case QMetaType::QStringList: {
QStringList ret;
QString copy(value);
QString out;
while (readString(copy, out) )
ret.append(out);
return ret;
}
case QMetaType::QPoint: {
QList<int> parts = toListInt(value);
if (parts.size() != 2)
return QPoint();
return QPoint(parts.at(0), parts.at(1));
}
case QMetaType::QSize: {
QList<int> parts = toListInt(value);
if (parts.size() != 2)
return QSize();
return QSize(parts.at(0), parts.at(1));
}
case QMetaType::QRect: {
QList<int> parts = toListInt(value);
if (parts.size() != 4)
return QRect();
return QRect(parts.at(0), parts.at(1), parts.at(2), parts.at(3));
}
case QMetaType::QLine: {
QList<int> parts = toListInt(value);
if (parts.size() != 4)
return QLine();
return QLine(parts.at(0), parts.at(1), parts.at(2), parts.at(3));
}
case QMetaType::QPointF: {
QList<qreal> parts = toListReal(value);
if (parts.size() != 2)
return QPointF();
return QPointF(parts.at(0), parts.at(1));
}
case QMetaType::QSizeF: {
QList<qreal> parts = toListReal(value);
if (parts.size() != 2)
return QSizeF();
return QSizeF(parts.at(0), parts.at(1));
}
case QMetaType::QRectF: {
QList<qreal> parts = toListReal(value);
if (parts.size() != 4)
return QRectF();
return QRectF(parts.at(0), parts.at(1), parts.at(2), parts.at(3));
}
case QMetaType::QLineF: {
QList<qreal> parts = toListReal(value);
if (parts.size() != 4)
return QLineF();
return QLineF(parts.at(0), parts.at(1), parts.at(2), parts.at(3));
}
case QMetaType::QUuid:
return QUuid(value);
case QMetaType::QByteArray:
return value.toUtf8();
case QMetaType::QJsonDocument:
return QJsonDocument::fromJson(value.toUtf8());
case QMetaType::QJsonObject:
return QJsonDocument::fromJson(value.toUtf8()).object();
case QMetaType::QJsonArray:
return QJsonDocument::fromJson(value.toUtf8()).array();
case QMetaType::QJsonValue: {
if (value == QStringLiteral("true"))
return QJsonValue(true);
else if (value == QStringLiteral("false"))
return QJsonValue(false);
bool ok;
int n = value.toInt(&ok);
if (ok)
return QJsonValue(n);
double d = value.toDouble(&ok);
if (ok)
return QJsonValue(d);
return QJsonValue(value);
}
case QMetaType::QBitArray: {
QBitArray bita(value.size());
for (int i = 0; i < value.size(); ++i) {
if (value.at(i) == QStringLiteral("0"))
bita.setBit(i, false);
else
bita.setBit(i, true);
}
return bita;
}
case QMetaType::QVariantMap: {
QVariantMap ret;
QStringList parts = value.split(QStringLiteral("\n"));
for (auto &p: parts) {
if (p.isEmpty())
continue;
QString name;
QString value;
if (readString(p, name) && readString(p, value))
ret.insert(name, value);
}
return ret;
}
case QMetaType::QVariantList: {
QVariantMap ret;
QStringList parts = value.split(QStringLiteral("\n"));
for (auto &p: parts) {
if (p.isEmpty())
continue;
QString name;
QString value;
if (readString(p, name) && readString(p, value))
ret.insert(name, value);
}
return ret;
}
#ifdef QT_GUI_LIB
case QMetaType::QVector2D: {
QList<float> parts = toListFloat(value);
if (parts.size() != 2)
return QVector2D();
return QVector2D(parts.at(0), parts.at(1));
}
case QMetaType::QVector3D: {
QList<float> parts = toListFloat(value);
if (parts.size() != 3)
return QVector3D();
return QVector3D(parts.at(0), parts.at(1), parts.at(2));
}
case QMetaType::QVector4D: {
QList<float> parts = toListFloat(value);
if (parts.size() != 4)
return QVector4D();
return QVector4D(parts.at(0), parts.at(1), parts.at(2), parts.at(3));
}
case QMetaType::QImage: {
QImage image;
image.loadFromData(QByteArray::fromBase64(value.toLocal8Bit()));
return image;
}
case QMetaType::QColor:
return QColor(value);
case QMetaType::QPolygon: {
QStringList parts = value.split(QStringLiteral(" "));
QPolygon pol;
for (int i = 0; i < parts.count(); i++)
pol.append(fromString(parts.at(i), QMetaType::QPoint).toPoint());
return pol;
}
case QMetaType::QPolygonF: {
QStringList parts = value.split(QStringLiteral(" "));
QPolygonF pol;
for (int i = 0; i < parts.count(); i++)
pol.append(fromString(parts.at(i), QMetaType::QPointF).toPointF());
return pol;
}
case QMetaType::QFont: {
QFont f;
f.fromString(value);
return f;
}
#endif
default:
return QVariant();
}
}
QString SqlSerializer::toString(const QVariant &value) const
{
auto type = METATYPE_ID(value);
switch (type) {
case QMetaType::Bool:
case QMetaType::Char:
case QMetaType::Short:
case QMetaType::UShort:
case QMetaType::Int:
case QMetaType::UInt:
case QMetaType::Long:
case QMetaType::ULong:
case QMetaType::LongLong:
case QMetaType::ULongLong:
case QMetaType::Double:
case QMetaType::Float:
case QMetaType::QChar:
case QMetaType::QUrl:
return value.toString();
case QMetaType::UChar:
case QMetaType::SChar:
return QString::number(value.toInt());
case QMetaType::QString:
return value.toString();
case QMetaType::QStringList: {
QString ret;
QStringList sl = value.toStringList();
for (auto &s: sl) {
if (!ret.isEmpty())
ret.append(QStringLiteral(" "));
ret.append(QStringLiteral("\"") + escapeString(s) + QStringLiteral("\""));
}
return ret;
}
case QMetaType::QUuid:
return value.toUuid().toString();
case QMetaType::QByteArray:
return QString::fromUtf8(value.toByteArray());
case QMetaType::QDate: return value.toDate().toString(DATE_FORMAT);
case QMetaType::QTime: return value.toTime().toString(TIME_FORMAT);
case QMetaType::QDateTime: return value.toDateTime().toString(DATE_FORMAT + QStringLiteral(" ") + TIME_FORMAT);
case QMetaType::QPoint: {
QPoint pt = value.toPoint();
return fromVariantList({pt.x(), pt.y()});
}
case QMetaType::QPointF: {
QPointF pt = value.toPointF();
return fromVariantList({pt.x(), pt.y()});
}
case QMetaType::QSize: {
QSize pt = value.toSize();
return fromVariantList({pt.width(), pt.height()});
}
case QMetaType::QSizeF: {
QSizeF pt = value.toSizeF();
return fromVariantList({pt.width(), pt.height()});
}
case QMetaType::QRect: {
QRect rc = value.toRect();
return fromVariantList({rc.x(), rc.y(), rc.width(), rc.height()});
}
case QMetaType::QRectF: {
QRectF rc = value.toRectF();
return fromVariantList({rc.x(), rc.y(), rc.width(), rc.height()});
}
case QMetaType::QLine: {
QLine rc = value.toLine();
return fromVariantList({rc.x1(), rc.y1(), rc.x2(), rc.y2()});
}
case QMetaType::QLineF: {
QLineF rc = value.toLineF();
return fromVariantList({rc.x1(), rc.y1(), rc.x2(), rc.y2()});
}
case QMetaType::QJsonDocument:
return QString::fromUtf8(value.toJsonDocument().toJson(QJsonDocument::Compact));
case QMetaType::QJsonObject: {
QJsonDocument doc;
doc.setObject(value.toJsonObject());
return QString::fromUtf8(doc.toJson(QJsonDocument::Compact));
}
case QMetaType::QJsonArray: {
QJsonDocument doc;
doc.setArray(value.toJsonArray());
return QString::fromUtf8(doc.toJson(QJsonDocument::Compact));
}
case QMetaType::QJsonValue:
return value.toJsonValue().toVariant().toString();
case QMetaType::QBitArray: {
QString ret;
QBitArray bita = value.toBitArray();
for (int i = 0; i < bita.size(); ++i)
ret.append(bita.at(i) ? QStringLiteral("1") : QStringLiteral("0"));
return ret;
}
case QMetaType::QVariantMap: {
QString ret;
QVariantMap map = value.toMap();
for (auto i = map.begin(); i != map.end(); ++i) {
if (!ret.isEmpty())
ret.append(QStringLiteral("\n"));
QVariant v = map.value(i.key());
QString str = toString(v);
ret.append(QStringLiteral("\"%1\" \"%2\"")
.arg(escapeString(i.key()), escapeString(str)));
}
return ret;
}
#ifdef QT_GUI_LIB
case QMetaType::QVector2D: {
QVector2D vec = value.value<QVector2D>();
return fromList(QList<float>() << vec.x() << vec.y());
}
case QMetaType::QVector3D: {
QVector3D vec = value.value<QVector3D>();
return fromList(QList<float>() << vec.x() << vec.y() << vec.z());
}
case QMetaType::QVector4D: {
QVector4D vec = value.value<QVector4D>();
return fromList(QList<float>() << vec.x() << vec.y() << vec.z() << vec.w());
}
case QMetaType::QImage: {
QImage image = value.value<QImage>();
QByteArray byteArray;
QBuffer buffer(&byteArray);
image.save(&buffer, "PNG");
QString base64 = QString::fromLatin1(byteArray.toBase64().data());
return base64;
}
case QMetaType::QColor:
return value.value<QColor>().name();
case QMetaType::QPolygon: {
QStringList list;
QPolygon pol = value.value<QPolygon>();
QPoint pt;
for (int i = 0; i < pol.size(); ++i) {
pt = pol.at(i);
list.append(toString(pt));
}
return list.join(QStringLiteral(" "));
}
case QMetaType::QPolygonF: {
QStringList list;
QPolygonF pol = value.value<QPolygonF>();
QPointF pt;
for (int i = 0; i < pol.size(); ++i) {
pt = pol.at(i);
list.append(toString(pt));
}
return list.join(QStringLiteral(" "));
}
case QMetaType::QFont:
return value.value<QFont>().toString();
#endif
case QMetaType::QVariantList: {
auto l = value.toList();
QString ret;
for (auto &v: l) {
if (!ret.isEmpty())
ret.append(QStringLiteral(", "));
ret.append(toString(v));
}
return QStringLiteral("(") + ret + QStringLiteral(")");
break;
}
default:
qWarning("The type (%s) does not supported",
METATYPE_TO_NAME(type));
return QString();
}
}
QList<int> SqlSerializer::toListInt(const QString &s) const
{
return toListInt(s, QStringLiteral(","));
}
QList<int> SqlSerializer::toListInt(const QString &s, const QString &sep) const
{
auto parts = s.split(sep);
QList<int> ret;
for (auto &p: parts) {
bool ok;
ret.append(p.toInt(&ok));
if (!ok)
return ret;
}
return ret;
}
QList<qreal> SqlSerializer::toListReal(const QString &s) const
{
return toListReal(s, QStringLiteral(","));
}
QString SqlSerializer::fromList(const QList<int> &list) const
{
QString ret;
for (auto &n: list) {
if (!ret.isEmpty())
ret.append(QStringLiteral(","));
ret.append(QString::number(n));
}
return ret;
}
QList<qreal> SqlSerializer::toListReal(const QString &s, const QString &sep) const
{
auto parts = s.split(sep);
QList<qreal> ret;
for (auto &p: parts) {
bool ok;
ret.append(p.toDouble(&ok));
if (!ok)
return ret;
}
return ret;
}
QList<float> SqlSerializer::toListFloat(const QString &s) const
{
auto parts = s.split(QStringLiteral(","));
QList<float> ret;
for (auto &p: parts) {
bool ok;
ret.append(p.toFloat(&ok));
if (!ok)
return ret;
}
return ret;
}
QString SqlSerializer::fromList(const QList<qreal> &list) const
{
QString ret;
for (auto &n: list) {
if (!ret.isEmpty())
ret.append(QStringLiteral(","));
ret.append(QString::number(n, 'f', -1));
}
return ret;
}
QString SqlSerializer::fromList(const QList<float> &list) const
{
QString ret;
for (auto &n: list) {
if (!ret.isEmpty())
ret.append(QStringLiteral(","));
ret.append(QString::number(static_cast<double>(n)));
}
return ret;
}
QString SqlSerializer::fromVariantList(const QVariantList &list) const
{
QString ret;
for (auto &n: list) {
if (!ret.isEmpty())
ret.append(QStringLiteral(","));
ret.append(n.toString());
}
return ret;
}
#define CASE_W(o, r) \
case o: \
ret.append(QStringLiteral(r)); \
break;
QString SqlSerializer::escapeString(const QString &str) const
{
// QString ret;
// for (int i = 0; i < str.length(); ++i) {
// switch (str.at(i).cell()) {
// CASE_W('\\', "\\\\")
// CASE_W('\r', "\\r")
// CASE_W('\n', "\\n")
// CASE_W('\a', "\\a")
// CASE_W('\b', "\\b")
// CASE_W('\f', "\\f")
// // CASE_W('\'', "\\'")
// CASE_W('\t', "\\t")
// CASE_W('\v', "\\v")
// CASE_W('\"', "\\\"")
// default:
// ret.append(str.at(i));
// }
// }
// return ret;
QString ret(str);
return ret.replace(QStringLiteral("'"), QStringLiteral("''"));
}
QString SqlSerializer::unescapeString(const QString &str) const
{
// QString ret;
// for (int i = 0; i < str.length(); ++i) {
// if (str.at(i) == '\\' && str.length() > i) {
// switch (str.at(++i).cell()) {
// case '\\':
// ret.append(QStringLiteral("\\"));
// break;
// case 'r':
// ret.append(QStringLiteral("\r"));
// break;
// case 'n':
// ret.append(QStringLiteral("\n"));
// break;
// case 'a':
// ret.append(QStringLiteral("\a"));
// break;
// case 'b':
// ret.append(QStringLiteral("b"));
// break;
// case 'f':
// ret.append(QStringLiteral("\f"));
// break;
// // case '\'':
// // ret.append(QStringLiteral("\\'"));
// // break;
// case 't':
// ret.append(QStringLiteral("\t"));
// break;
// case 'v':
// ret.append(QStringLiteral("\v"));
// break;
// case '"':
// ret.append(QStringLiteral("\\\""));
// break;
// default:
// ret.append(str.at(i));
// }
// } else {
// ret.append(str.at(i));
// }
// }
// return ret;
QString ret(str);
return ret.replace(QStringLiteral("''"), QStringLiteral("'"));
}
bool SqlSerializer::readString(QString &text, QString &out) const
{
int start = -1;
int end = -1;
for (int i = 0; i < text.length(); ++i) {
if (text.at(i) == QLatin1Char('"') && (i == 0 || text.at(i - 1) != QStringLiteral("\\"))) {
if (start == -1)
start = i;
else
end = i;
}
if (end != -1){
out = text.mid(start + 1, end - start - 1);
text = text.mid(end + 1);
return true;
}
}
return false;
}
QVariant SqlSerializer::deserialize(const QString &value, const QMetaType::Type &type) const
{
return fromString(unescapeString(value), type);
}
QString SqlSerializer::serialize(const QVariant &value) const
{
return escapeString(toString(value));
}
NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -0,0 +1,63 @@
/**************************************************************************
**
** This file is part of Nut project.
** https://github.com/HamedMasafi/Nut
**
** Nut is free software: you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Nut is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
**
**************************************************************************/
#ifndef SQLSERIALIZER_H
#define SQLSERIALIZER_H
#include <QVariant>
#include <QtNut/NutGlobal>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE
class SqlSerializer
{
public:
SqlSerializer();
virtual ~SqlSerializer();
bool readString(QString &text, QString &out) const;
QVariant fromString(const QString &value, const QMetaType::Type &type) const;
QString toString(const QVariant &value) const;
QList<int> toListInt(const QString &s) const;
QList<int> toListInt(const QString &s, const QString &sep) const;
QList<qreal> toListReal(const QString &s) const;
QList<qreal> toListReal(const QString &s, const QString &sep) const;
QList<float> toListFloat(const QString &s) const;
QString fromList(const QList<int> &list) const;
QString fromList(const QList<qreal> &list) const;
QString fromList(const QList<float> &list) const;
QString fromVariantList(const QVariantList &list) const;
QVariant deserialize(const QString &value, const QMetaType::Type &type) const;
QString serialize(const QVariant &value) const;
private:
QString escapeString(const QString &str) const;
QString unescapeString(const QString &str) const;
};
NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // SQLSERIALIZER_H

View File

@ -30,6 +30,8 @@
#include "abstracttableset.h" #include "abstracttableset.h"
#include "propertysignalmapper.h" #include "propertysignalmapper.h"
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
/* /*
@ -89,17 +91,6 @@ void Table::add(AbstractTableSet *t)
void Table::propertyChanged(const QString &propName) void Table::propertyChanged(const QString &propName)
{ {
//Q_D(Table);
// if (!d->model)
// d->model = TableModel::findByClassName(metaObject()->className());
// if (!d->model)
// qFatal ("model for class '%s' not found", qPrintable(metaObject()->className()));
// Q_FOREACH (FieldModel *f, d->model->fields())
// if(f->isPrimaryKey && propName == f->name && f->isAutoIncrement)
// return;
d.detach(); d.detach();
d->changedProperties.insert(propName); d->changedProperties.insert(propName);
if (d->status == FetchedFromDB) if (d->status == FetchedFromDB)
@ -121,7 +112,7 @@ void Table::clear()
d->changedProperties.clear(); d->changedProperties.clear();
} }
QSet<QString> Table::changedProperties() const const QSet<QString> &Table::changedProperties() const
{ {
//Q_D(const Table); //Q_D(const Table);
return d->changedProperties; return d->changedProperties;
@ -138,7 +129,7 @@ bool Table::setParentTable(Table *master, TableModel *masterModel, TableModel *m
// if (!d->model) // if (!d->model)
// d->model = TableModel::findByClassName(metaObject()->className()); // d->model = TableModel::findByClassName(metaObject()->className());
Q_FOREACH (RelationModel *r, model->foreignKeys()) for (auto &r: model->foreignKeys())
if(r->masterClassName == masterClassName) if(r->masterClassName == masterClassName)
{ {
setProperty(QString(r->localColumn).toLatin1().data(), setProperty(QString(r->localColumn).toLatin1().data(),
@ -179,7 +170,7 @@ void Table::setParentTableSet(AbstractTableSet *parent)
AbstractTableSet *Table::childTableSet(const QString &name) const AbstractTableSet *Table::childTableSet(const QString &name) const
{ {
//Q_D(const Table); //Q_D(const Table);
Q_FOREACH (AbstractTableSet *t, d->childTableSets) for (auto &t: qAsConst(d->childTableSets))
if (t->childClassName() == name) if (t->childClassName() == name)
return t; return t;
return Q_NULLPTR; return Q_NULLPTR;
@ -230,3 +221,5 @@ void TablePrivate::refreshModel()
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -29,6 +29,8 @@
#include <QtNut/tablemodel.h> #include <QtNut/tablemodel.h>
#include <QtNut/phrase.h> #include <QtNut/phrase.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class Database; class Database;
@ -66,7 +68,7 @@ public:
AbstractTableSet *childTableSet(const QString &name) const; AbstractTableSet *childTableSet(const QString &name) const;
QSet<QString> changedProperties() const; const QSet<QString> &changedProperties() const;
bool setParentTable(Table *master, TableModel *masterModel, TableModel *model); bool setParentTable(Table *master, TableModel *masterModel, TableModel *model);
Q_SIGNALS: Q_SIGNALS:
@ -103,4 +105,9 @@ private:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
Q_DECLARE_METATYPE(NUT_WRAP_NAMESPACE(Table)*)
Q_DECLARE_METATYPE(NUT_WRAP_NAMESPACE(Row<NUT_WRAP_NAMESPACE(Table)>))
#endif // TABLE_H #endif // TABLE_H

View File

@ -1,3 +1,33 @@
/**************************************************************************
**
** This file is part of Nut project.
** https://github.com/HamedMasafi/Nut
**
** Nut is free software: you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Nut is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
**
**************************************************************************/
//
// W A R N I N G
// -------------
//
// This file is not part of the Nut API. This header
// file may change from version to version without notice, or even be removed.
//
// We mean it.
//
#ifndef TABLEPRIVATE_H #ifndef TABLEPRIVATE_H
#define TABLEPRIVATE_H #define TABLEPRIVATE_H
@ -7,6 +37,8 @@
#include <QtNut/nut_global.h> #include <QtNut/nut_global.h>
#include <QtNut/table.h> #include <QtNut/table.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class TableModel; class TableModel;
@ -31,4 +63,6 @@ public:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // TABLEPRIVATE_H #endif // TABLEPRIVATE_H

View File

@ -35,6 +35,8 @@
#include <QtNut/databasemodel.h> #include <QtNut/databasemodel.h>
#include <QtNut/abstracttablesetdata.h> #include <QtNut/abstracttablesetdata.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
template<class T> template<class T>
@ -98,16 +100,16 @@ Q_OUTOFLINE_TEMPLATE BulkInserter TableSet<T>::bulkInserter()
template<class T> template<class T>
Q_OUTOFLINE_TEMPLATE int TableSet<T>::length() const Q_OUTOFLINE_TEMPLATE int TableSet<T>::length() const
{ {
return data->childs.count(); return data->children.count();
} }
template<class T> template<class T>
Q_OUTOFLINE_TEMPLATE Row<T> TableSet<T>::at(int i) const Q_OUTOFLINE_TEMPLATE Row<T> TableSet<T>::at(int i) const
{ {
#ifdef NUT_RAW_POINTER #ifdef NUT_RAW_POINTER
return reinterpret_cast<T*>(data->childs.at(i)); return reinterpret_cast<T*>(data->children.at(i));
#else #else
return data->childs.at(i).template objectCast<T>(); return data->children.at(i).template objectCast<T>();
#endif #endif
} }
@ -136,7 +138,7 @@ template<class T>
Q_OUTOFLINE_TEMPLATE void TableSet<T>::append(Row<T> t) Q_OUTOFLINE_TEMPLATE void TableSet<T>::append(Row<T> t)
{ {
data.detach(); data.detach();
data->childs.append(t); data->children.append(t);
// data->tables.insert(t.data()); // data->tables.insert(t.data());
// data->childRows.append(t.data()); // data->childRows.append(t.data());
@ -151,7 +153,7 @@ Q_OUTOFLINE_TEMPLATE void TableSet<T>::append(Row<T> t)
template<class T> template<class T>
Q_OUTOFLINE_TEMPLATE void TableSet<T>::append(RowList<T> t) Q_OUTOFLINE_TEMPLATE void TableSet<T>::append(RowList<T> t)
{ {
Q_FOREACH (Row<T> i, t) for (auto &i: t)
append(i); append(i);
} }
@ -159,19 +161,21 @@ template<class T>
Q_OUTOFLINE_TEMPLATE void TableSet<T>::remove(Row<T> t) Q_OUTOFLINE_TEMPLATE void TableSet<T>::remove(Row<T> t)
{ {
data.detach(); data.detach();
// data->childs.removeOne(t.data()); // data->children.removeOne(t.data());
// data->tables.remove(t.data()); // data->tables.remove(t.data());
data->childs.removeOne(t); data->children.removeOne(t);
t->setStatus(Table::Deleted); t->setStatus(Table::Deleted);
} }
template<class T> template<class T>
Q_OUTOFLINE_TEMPLATE void TableSet<T>::remove(RowList<T> t) Q_OUTOFLINE_TEMPLATE void TableSet<T>::remove(RowList<T> t)
{ {
Q_FOREACH (Row<T> i, t) for (auto &i: t)
remove(i); remove(i);
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // TABLESET_H #endif // TABLESET_H

View File

@ -31,6 +31,9 @@
#include "databasemodel.h" #include "databasemodel.h"
#include "tablemodel.h" #include "tablemodel.h"
#include "sqlserializer.h" #include "sqlserializer.h"
#include "nut_p.h"
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
@ -114,7 +117,7 @@ QString AbstractSqlGenerator::recordsPhrase(TableModel *table)
return QString(); return QString();
QString ret = QString(); QString ret = QString();
Q_FOREACH (FieldModel *f, table->fields()) { for (auto &f: table->fields()) {
if (!ret.isEmpty()) if (!ret.isEmpty())
ret.append(QLatin1String(", ")); ret.append(QLatin1String(", "));
ret.append(QStringLiteral("%1.%2 AS \"%1.%2\"").arg(table->name(), f->name)); ret.append(QStringLiteral("%1.%2 AS \"%1.%2\"").arg(table->name(), f->name));
@ -125,9 +128,9 @@ QString AbstractSqlGenerator::recordsPhrase(TableModel *table)
QString AbstractSqlGenerator::insertBulk(const QString &tableName, const PhraseList &ph, const QList<QVariantList> &vars) QString AbstractSqlGenerator::insertBulk(const QString &tableName, const PhraseList &ph, const QList<QVariantList> &vars)
{ {
QString sql; QString sql;
Q_FOREACH (QVariantList list, vars) { for (auto &list: vars) {
QStringList values; QStringList values;
Q_FOREACH (QVariant v, list) for (auto &v: list)
values.append(escapeValue(v)); values.append(escapeValue(v));
if (!sql.isEmpty()) if (!sql.isEmpty())
@ -147,7 +150,7 @@ QString AbstractSqlGenerator::fieldDeclare(FieldModel *field)
if (type.isEmpty()) if (type.isEmpty())
return type; return type;
QString ret = escaleFieldName(field->name) + QStringLiteral(" ") + type; QString ret = escapeFieldName(field->name) + QStringLiteral(" ") + type;
if (field->notNull) if (field->notNull)
ret.append(QStringLiteral(" NOT NULL")); ret.append(QStringLiteral(" NOT NULL"));
@ -157,7 +160,7 @@ QString AbstractSqlGenerator::fieldDeclare(FieldModel *field)
return ret; return ret;
} }
QString AbstractSqlGenerator::escaleFieldName(const QString &fieldName) const QString AbstractSqlGenerator::escapeFieldName(const QString &fieldName) const
{ {
return fieldName; return fieldName;
} }
@ -174,7 +177,7 @@ QString AbstractSqlGenerator::relationDeclare(const RelationModel *relation)
.arg(relation->localColumn, relation->slaveTable->name()); .arg(relation->localColumn, relation->slaveTable->name());
} }
QStringList AbstractSqlGenerator::diff(const DatabaseModel &lastModel, QStringList AbstractSqlGenerator::diffDatabase(const DatabaseModel &lastModel,
const DatabaseModel &newModel) const DatabaseModel &newModel)
{ {
QStringList ret; QStringList ret;
@ -185,7 +188,7 @@ QStringList AbstractSqlGenerator::diff(const DatabaseModel &lastModel,
for (i = unionModel.begin(); i != unionModel.end(); ++i) { for (i = unionModel.begin(); i != unionModel.end(); ++i) {
TableModel *oldTable = lastModel.tableByName((*i)->name()); TableModel *oldTable = lastModel.tableByName((*i)->name());
TableModel *newTable = newModel.tableByName((*i)->name()); TableModel *newTable = newModel.tableByName((*i)->name());
QStringList sql = diff(oldTable, newTable); QStringList sql = diffTable(oldTable, newTable);
if (!sql.isEmpty()) if (!sql.isEmpty())
ret << sql; ret << sql;
@ -197,13 +200,16 @@ QStringList AbstractSqlGenerator::diff(const DatabaseModel &lastModel,
return ret; return ret;
} }
QString AbstractSqlGenerator::diff(FieldModel *oldField, FieldModel *newField) QString AbstractSqlGenerator::diffField(FieldModel *oldField, FieldModel *newField)
{ {
QString sql = QString(); if (!oldField && !newField)
return QString();
if (oldField && newField) if (oldField && newField)
if (*oldField == *newField) if (*oldField == *newField)
return sql; return QString();
QString sql = QString();
if (!newField) { if (!newField) {
sql = QStringLiteral("DROP COLUMN ") + oldField->name; sql = QStringLiteral("DROP COLUMN ") + oldField->name;
} else { } else {
@ -216,7 +222,7 @@ QString AbstractSqlGenerator::diff(FieldModel *oldField, FieldModel *newField)
return sql; return sql;
} }
QStringList AbstractSqlGenerator::diff(TableModel *oldTable, TableModel *newTable) QStringList AbstractSqlGenerator::diffTable(TableModel *oldTable, TableModel *newTable)
{ {
if (!newTable && !oldTable) if (!newTable && !oldTable)
return QStringList(); return QStringList();
@ -232,28 +238,28 @@ QStringList AbstractSqlGenerator::diff(TableModel *oldTable, TableModel *newTabl
QList<QString> relations; QList<QString> relations;
if (oldTable) { if (oldTable) {
Q_FOREACH (FieldModel *f, oldTable->fields()) for (auto &f: oldTable->fields())
if (!fieldNames.contains(f->name)) if (!fieldNames.contains(f->name))
fieldNames.append(f->name); fieldNames.append(f->name);
Q_FOREACH (RelationModel *r, oldTable->foreignKeys()) for (auto &r: oldTable->foreignKeys())
if (!relations.contains(r->localColumn)) if (!relations.contains(r->localColumn))
relations.append(r->localColumn); relations.append(r->localColumn);
} }
Q_FOREACH (FieldModel *f, newTable->fields()) for (auto &f: newTable->fields())
if (!fieldNames.contains(f->name)) if (!fieldNames.contains(f->name))
fieldNames.append(f->name); fieldNames.append(f->name);
Q_FOREACH (RelationModel *r, newTable->foreignKeys()) for (auto &r: newTable->foreignKeys())
if (!relations.contains(r->localColumn)) if (!relations.contains(r->localColumn))
relations.append(r->localColumn); relations.append(r->localColumn);
QStringList columnSql; QStringList columnSql;
Q_FOREACH (QString fieldName, fieldNames) { for (auto &fieldName: fieldNames) {
FieldModel *newField = newTable->field(fieldName); FieldModel *newField = newTable->field(fieldName);
if (oldTable) { if (oldTable) {
FieldModel *oldField = oldTable->field(fieldName); FieldModel *oldField = oldTable->field(fieldName);
QString buffer = diff(oldField, newField); QString buffer = diffField(oldField, newField);
if (!buffer.isEmpty()) if (!buffer.isEmpty())
columnSql << buffer; columnSql << buffer;
} else { } else {
@ -303,23 +309,23 @@ QStringList AbstractSqlGenerator::diffRelation(TableModel *oldTable, TableModel
QList<QString> relations; QList<QString> relations;
if (oldTable) { if (oldTable) {
Q_FOREACH (RelationModel *r, oldTable->foreignKeys()) for (auto &r: oldTable->foreignKeys())
if (!relations.contains(r->localColumn)) if (!relations.contains(r->localColumn))
relations.append(r->localColumn); relations.append(r->localColumn);
} }
Q_FOREACH (RelationModel *r, newTable->foreignKeys()) for (auto &r: newTable->foreignKeys())
if (!relations.contains(r->localColumn)) if (!relations.contains(r->localColumn))
relations.append(r->localColumn); relations.append(r->localColumn);
QStringList columnSql; QStringList columnSql;
Q_FOREACH (QString fieldName, relations) { for (auto &fieldName: relations) {
RelationModel *newRelation = newTable->foreignKeyByField(fieldName); RelationModel *newRelation = newTable->foreignKeyByField(fieldName);
RelationModel *oldRelation = nullptr; RelationModel *oldRelation = nullptr;
if (oldTable) if (oldTable)
oldRelation = oldTable->foreignKeyByField(fieldName); oldRelation = oldTable->foreignKeyByField(fieldName);
QStringList buffer = diff(oldRelation, newRelation); QStringList buffer = diffRelation2(oldRelation, newRelation);
if (!buffer.isEmpty()) if (!buffer.isEmpty())
columnSql << buffer.at(0); columnSql << buffer.at(0);
} }
@ -332,7 +338,7 @@ QStringList AbstractSqlGenerator::diffRelation(TableModel *oldTable, TableModel
return ret; return ret;
} }
QStringList AbstractSqlGenerator::diff(RelationModel *oldRel, RelationModel *newRel) QStringList AbstractSqlGenerator::diffRelation2(RelationModel *oldRel, RelationModel *newRel)
{ {
QStringList ret; QStringList ret;
/* /*
@ -478,7 +484,7 @@ QString AbstractSqlGenerator::insertRecord(Table *t, QString tableName)
if (changedPropertiesText != QLatin1String("")) if (changedPropertiesText != QLatin1String(""))
changedPropertiesText.append(QStringLiteral(", ")); changedPropertiesText.append(QStringLiteral(", "));
changedPropertiesText.append(escaleFieldName(f)); changedPropertiesText.append(escapeFieldName(f));
} }
sql = QStringLiteral("INSERT INTO %1 (%2) VALUES (%3)") sql = QStringLiteral("INSERT INTO %1 (%2) VALUES (%3)")
.arg(tableName, changedPropertiesText, values.join(QStringLiteral(", "))); .arg(tableName, changedPropertiesText, values.join(QStringLiteral(", ")));
@ -495,9 +501,9 @@ QString AbstractSqlGenerator::updateRecord(Table *t, QString tableName)
QString key = model->primaryKey(); QString key = model->primaryKey();
QStringList values; QStringList values;
for (auto &f : t->changedProperties()) for (const auto &f : t->changedProperties())
if (f != key) if (f != key)
values.append(f + QStringLiteral("=") values.append(escapeFieldName(f) + QStringLiteral("=")
+ escapeValue(t->property(f.toLatin1().data()))); + escapeValue(t->property(f.toLatin1().data())));
sql = QStringLiteral("UPDATE %1 SET %2 WHERE %3=%4") sql = QStringLiteral("UPDATE %1 SET %2 WHERE %3=%4")
@ -600,11 +606,11 @@ QString AbstractSqlGenerator::selectCommand(const QString &tableName,
if (fields.data.count() == 0) { if (fields.data.count() == 0) {
QSet<TableModel*> tables; QSet<TableModel*> tables;
tables.insert(_database->model().tableByName(tableName)); tables.insert(_database->model().tableByName(tableName));
Q_FOREACH (RelationModel *rel, joins) for (auto &rel: joins)
tables << rel->masterTable << rel->slaveTable; tables << rel->masterTable << rel->slaveTable;
selectText = QString(); selectText = QString();
Q_FOREACH (TableModel *t, tables) { for (auto &t: qAsConst(tables)) {
if (!selectText.isEmpty()) if (!selectText.isEmpty())
selectText.append(QStringLiteral(", ")); selectText.append(QStringLiteral(", "));
selectText.append(recordsPhrase(t)); selectText.append(recordsPhrase(t));
@ -689,8 +695,8 @@ QString AbstractSqlGenerator::updateCommand(const QString &tableName,
const ConditionalPhrase &where) const ConditionalPhrase &where)
{ {
QString assigmentTexts = QString(); QString assigmentTexts = QString();
Q_FOREACH (PhraseData *d, assigments.data) { for (auto &d: assigments.data) {
if (assigmentTexts != QStringLiteral("")) if (assigmentTexts != QLatin1String())
assigmentTexts.append(QStringLiteral(", ")); assigmentTexts.append(QStringLiteral(", "));
assigmentTexts.append(createConditionalPhrase(d)); assigmentTexts.append(createConditionalPhrase(d));
@ -717,92 +723,23 @@ QString AbstractSqlGenerator::insertCommand(const QString &tableName, const Assi
QString fieldNames; QString fieldNames;
QString values; QString values;
Q_FOREACH (PhraseData *d, assigments.data) { for (auto &d: assigments.data) {
if (!fieldNames.isEmpty()) if (!fieldNames.isEmpty())
fieldNames.append(QStringLiteral(", ")); fieldNames.append(QStringLiteral(", "));
if (!values.isEmpty()) if (!values.isEmpty())
values.append(QStringLiteral(", ")); values.append(QStringLiteral(", "));
fieldNames.append(escaleFieldName(QString::fromUtf8(d->left->fieldName))); fieldNames.append(escapeFieldName(QString::fromUtf8(d->left->fieldName)));
values.append(escapeValue(d->operand)); values.append(escapeValue(d->operand));
} }
return QStringLiteral("INSERT INTO %1 (%2) VALUES (%3);") return QStringLiteral("INSERT INTO %1 (%2) VALUES (%3);")
.arg(tableName, fieldNames, values); .arg(tableName, fieldNames, values);
} }
//QString SqlGeneratorBase::selectCommand(SqlGeneratorBase::AgregateType t,
// QString agregateArg,
// QString tableName,
// QList<WherePhrase> &wheres,
// QList<WherePhrase> &orders,
// QList<RelationModel*> joins,
// int skip, int take)
//{
// Q_UNUSED(take)
// Q_UNUSED(skip)
// QStringList joinedOrders;
// QString select = agregateText(t, agregateArg);
// //TODO: temporatory disabled
// if (t == SelectAll) {
// QSet<TableModel*> tables;
// tables.insert(_database->model().tableByName(tableName));
// Q_FOREACH (RelationModel *rel, joins)
// tables << rel->masterTable << rel->slaveTable;
// select = "";
// Q_FOREACH (TableModel *t, tables) {
// if (!select.isEmpty())
// select.append(", ");
// select.append(recordsPhrase(t));
// }
// }
// QString from = join(tableName, joins, &joinedOrders);
// QString where = createWhere(wheres);
// QString orderText = joinedOrders.join(", ");
// Q_FOREACH (WherePhrase p, orders) {
// if (orderText != "")
// orderText.append(", ");
// orderText.append(phraseOrder(p.data()));
// }
// QString sql = "SELECT " + select + " FROM " + from;
// if (where != "")
// sql.append(" WHERE " + where);
// if (orderText != "")
// sql.append(" ORDER BY " + orderText);
// for (int i = 0; i < _database->model().count(); i++)
// sql = sql.replace(_database->model().at(i)->className() + ".",
// _database->model().at(i)->name() + ".");
// replaceTableNames(sql);
// return sql + " ";
//}
//QString SqlGeneratorBase::createWhere(QList<WherePhrase> &wheres)
//{
// QString whereText = "";
// Q_FOREACH (WherePhrase w, wheres) {
// if (whereText != "")
// whereText.append(" AND ");
// whereText.append(phrase(w.data()));
// }
// return whereText;
//}
void AbstractSqlGenerator::replaceTableNames(QString &command) void AbstractSqlGenerator::replaceTableNames(QString &command)
{ {
Q_FOREACH (TableModel *m, _database->model()) for (auto &m: _database->model())
command = command command = command
.replace(QStringLiteral("[") + m->className() .replace(QStringLiteral("[") + m->className()
+ QStringLiteral("]"), m->name()); + QStringLiteral("]"), m->name());
@ -810,10 +747,10 @@ void AbstractSqlGenerator::replaceTableNames(QString &command)
void AbstractSqlGenerator::removeTableNames(QString &command) void AbstractSqlGenerator::removeTableNames(QString &command)
{ {
Q_FOREACH (TableModel *m, _database->model()) for (auto &m: _database->model())
command = command.replace(QStringLiteral("[") command = command.replace(QStringLiteral("[")
+ m->className() + m->className()
+ QStringLiteral("]."), QStringLiteral("")); + QStringLiteral("]."), QLatin1String());
} }
QString AbstractSqlGenerator::dateTimePartName(const PhraseData::Condition &op) const QString AbstractSqlGenerator::dateTimePartName(const PhraseData::Condition &op) const
@ -891,13 +828,13 @@ QString AbstractSqlGenerator::dateTimePartName(const PhraseData::Condition &op)
QString AbstractSqlGenerator::escapeValue(const QVariant &v) const QString AbstractSqlGenerator::escapeValue(const QVariant &v) const
{ {
if (v.type() == QVariant::String && v.toString().isEmpty()) if (VARIANT_TYPE_COMPARE(v, String) && v.toString().isEmpty())
return QStringLiteral("''"); return QStringLiteral("''");
if (v.type() == QVariant::List) { if (VARIANT_TYPE_COMPARE_X(v, QVariant::List, QMetaType::QVariantList)) {
auto list = v.toList(); auto list = v.toList();
QStringList ret; QStringList ret;
Q_FOREACH (QVariant vi, list) { for (auto &vi: list) {
ret.append(QStringLiteral("'") ret.append(QStringLiteral("'")
+ _serializer->serialize(vi) + _serializer->serialize(vi)
+ QStringLiteral("'")); + QStringLiteral("'"));
@ -1121,7 +1058,7 @@ QString AbstractSqlGenerator::createConditionalPhrase(const PhraseData *d) const
QString AbstractSqlGenerator::createOrderPhrase(const PhraseList &ph) QString AbstractSqlGenerator::createOrderPhrase(const PhraseList &ph)
{ {
QString ret = QString(); QString ret = QString();
Q_FOREACH (const PhraseData *d, ph.data) { for (const auto &d: ph.data) {
if (!ret.isEmpty()) if (!ret.isEmpty())
ret.append(QStringLiteral(", ")); ret.append(QStringLiteral(", "));
ret.append(d->toString()); ret.append(d->toString());
@ -1135,10 +1072,10 @@ QString AbstractSqlGenerator::createOrderPhrase(const PhraseList &ph)
QString AbstractSqlGenerator::createFieldPhrase(const PhraseList &ph) QString AbstractSqlGenerator::createFieldPhrase(const PhraseList &ph)
{ {
QString ret = QString(); QString ret = QString();
Q_FOREACH (const PhraseData *d, ph.data) { for (const auto &d: ph.data) {
if (!ret.isEmpty()) if (!ret.isEmpty())
ret.append(QStringLiteral(", ")); ret.append(QStringLiteral(", "));
ret.append(d->toString()); ret.append("`" + d->toString() + "`");
if (d->isNot) if (d->isNot)
qDebug() << "Operator ! is ignored in fields phrase"; qDebug() << "Operator ! is ignored in fields phrase";
} }
@ -1147,7 +1084,7 @@ QString AbstractSqlGenerator::createFieldPhrase(const PhraseList &ph)
void AbstractSqlGenerator::createInsertPhrase(const AssignmentPhraseList &ph, QString &fields, QString &values) void AbstractSqlGenerator::createInsertPhrase(const AssignmentPhraseList &ph, QString &fields, QString &values)
{ {
Q_FOREACH (PhraseData *d, ph.data) { for (auto &d: ph.data) {
if (!fields.isEmpty()) if (!fields.isEmpty())
fields.append(QStringLiteral(", ")); fields.append(QStringLiteral(", "));
@ -1175,3 +1112,5 @@ void AbstractSqlGenerator::createInsertPhrase(const AssignmentPhraseList &ph, QS
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -27,7 +27,8 @@
#include <QtNut/phrase.h> #include <QtNut/phrase.h>
class SqlSerializer;
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
@ -37,6 +38,7 @@ class DatabaseModel;
class TableModel; class TableModel;
class Database; class Database;
struct RelationModel; struct RelationModel;
class SqlSerializer;
class NUT_EXPORT AbstractSqlGenerator : public QObject class NUT_EXPORT AbstractSqlGenerator : public QObject
{ {
// Q_OBJECT // Q_OBJECT
@ -80,7 +82,7 @@ public:
//fields //fields
virtual QString fieldType(FieldModel *field) = 0; virtual QString fieldType(FieldModel *field) = 0;
virtual QString fieldDeclare(FieldModel *field); virtual QString fieldDeclare(FieldModel *field);
virtual QString escaleFieldName(const QString &fieldName) const; virtual QString escapeFieldName(const QString &fieldName) const;
virtual QStringList constraints(TableModel *table); virtual QStringList constraints(TableModel *table);
virtual QString escapeValue(const QVariant &v) const; virtual QString escapeValue(const QVariant &v) const;
virtual QVariant unescapeValue(const QMetaType::Type &type, const QVariant &dbValue); virtual QVariant unescapeValue(const QMetaType::Type &type, const QVariant &dbValue);
@ -91,11 +93,11 @@ public:
virtual QString relationDeclare(const RelationModel *relation); virtual QString relationDeclare(const RelationModel *relation);
virtual QStringList diff(const DatabaseModel &lastModel, const DatabaseModel &newModel); virtual QStringList diffDatabase(const DatabaseModel &lastModel, const DatabaseModel &newModel);
virtual QString diff(FieldModel *oldField, FieldModel *newField); virtual QString diffField(FieldModel *oldField, FieldModel *newField);
virtual QStringList diff(TableModel *oldTable, TableModel *newTable); virtual QStringList diffTable(TableModel *oldTable, TableModel *newTable);
virtual QStringList diffRelation(TableModel *oldTable, TableModel *newTable); virtual QStringList diffRelation(TableModel *oldTable, TableModel *newTable);
virtual QStringList diff(RelationModel *oldRel, RelationModel *newRel); virtual QStringList diffRelation2(RelationModel *oldRel, RelationModel *newRel);
virtual QString join(const QString &mainTable, virtual QString join(const QString &mainTable,
const QList<RelationModel*> &list, const QList<RelationModel*> &list,
@ -169,4 +171,6 @@ protected:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // NUT_ABSTRACTSQLGENERATOR_H #endif // NUT_ABSTRACTSQLGENERATOR_H

View File

@ -26,12 +26,17 @@
#include <QtCore/QTime> #include <QtCore/QTime>
#include <QtCore/QDate> #include <QtCore/QDate>
#include <QtCore/QDateTime> #include <QtCore/QDateTime>
#include <QtCore/QUuid>
#ifdef QT_GUI_LIB #ifdef QT_GUI_LIB
# include <QtGui/QPolygon> # include <QtGui/QPolygon>
# include <QtGui/QPolygonF> # include <QtGui/QPolygonF>
#endif #endif
#include "sqlserializer.h" #include "sqlserializer.h"
#include "nut_p.h"
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
@ -83,15 +88,15 @@ QString MySqlGenerator::fieldType(FieldModel *field)
dbType = QStringLiteral("TEXT"); dbType = QStringLiteral("TEXT");
break; break;
case QMetaType::QUuid:
dbType = QStringLiteral("VARCHAR(38)");
break;
case QMetaType::QPolygon: case QMetaType::QPolygon:
case QMetaType::QPolygonF: case QMetaType::QPolygonF:
// dbType = "POLYGON"; // dbType = "POLYGON";
// break; // break;
case QMetaType::QUuid:
// dbType = "VARCHAR(64)";
// break;
case QMetaType::QPoint: case QMetaType::QPoint:
case QMetaType::QPointF: case QMetaType::QPointF:
@ -114,7 +119,7 @@ QString MySqlGenerator::fieldType(FieldModel *field)
default: default:
qWarning("Type %s::%s(%d) is not supported", qWarning("Type %s::%s(%d) is not supported",
qPrintable(field->name), qPrintable(field->name),
QMetaType::typeName(field->type), METATYPE_TO_NAME(field->type),
field->type); field->type);
dbType = QString(); dbType = QString();
} }
@ -127,18 +132,21 @@ QString MySqlGenerator::fieldType(FieldModel *field)
QString MySqlGenerator::escapeValue(const QVariant &v) const QString MySqlGenerator::escapeValue(const QVariant &v) const
{ {
if (v.type() == QVariant::Bool) if (VARIANT_TYPE_COMPARE_X(v, Bool, Bool))
return v.toBool() ? QStringLiteral("1") : QStringLiteral("0"); return v.toBool() ? QStringLiteral("1") : QStringLiteral("0");
if (v.type() == QVariant::Time) if (VARIANT_TYPE_COMPARE(v, Time))
return v.toTime().toString(QStringLiteral("''HH:mm:ss''")); return v.toTime().toString(QStringLiteral("''HH:mm:ss''"));
if (v.type() == QVariant::Date) if (VARIANT_TYPE_COMPARE(v, Date))
return v.toDate().toString(QStringLiteral("''yyyy-MM-dd''")); return v.toDate().toString(QStringLiteral("''yyyy-MM-dd''"));
if (v.type() == QVariant::DateTime) if (VARIANT_TYPE_COMPARE(v, DateTime))
return v.toDateTime().toString(QStringLiteral("''yyyy-MM-dd HH:mm:ss''")); return v.toDateTime().toString(QStringLiteral("''yyyy-MM-dd HH:mm:ss''"));
if (VARIANT_TYPE_COMPARE(v, Uuid))
return QStringLiteral("'") + v.toUuid().toString() + QStringLiteral("'");
//#ifdef QT_GUI_LIB //#ifdef QT_GUI_LIB
// if (v.type() == QVariant::Polygon) { // if (v.type() == QVariant::Polygon) {
// QString ret; // QString ret;
@ -194,7 +202,7 @@ QVariant MySqlGenerator::unescapeValue(const QMetaType::Type &type, const QVaria
// if (!readInsideParentese(ref, p)) // if (!readInsideParentese(ref, p))
// return pol; // return pol;
// QStringList parts = p.split(","); // QStringList parts = p.split(",");
// Q_FOREACH (QString v, parts) { // for (auto &v: parts) {
// QList<int> l = _serializer->toListInt(p.trimmed(), " "); // QList<int> l = _serializer->toListInt(p.trimmed(), " ");
// if (l.count() != 2) // if (l.count() != 2)
// return QPolygon(); // return QPolygon();
@ -210,7 +218,7 @@ QVariant MySqlGenerator::unescapeValue(const QMetaType::Type &type, const QVaria
// return pol; // return pol;
// QStringList parts = p.split(","); // QStringList parts = p.split(",");
// Q_FOREACH (QString v, parts) { // for (auto &v: parts) {
// QList<qreal> l = _serializer->toListReal(p.trimmed(), " "); // QList<qreal> l = _serializer->toListReal(p.trimmed(), " ");
// if (l.count() != 2) // if (l.count() != 2)
// return QPolygonF(); // return QPolygonF();
@ -229,6 +237,9 @@ QVariant MySqlGenerator::unescapeValue(const QMetaType::Type &type, const QVaria
if (type == QMetaType::QDate) if (type == QMetaType::QDate)
return dbValue.toDate(); return dbValue.toDate();
if (type == QMetaType::QUuid)
return QUuid::fromString(dbValue.toString());
return AbstractSqlGenerator::unescapeValue(type, dbValue); return AbstractSqlGenerator::unescapeValue(type, dbValue);
} }
@ -240,12 +251,12 @@ bool MySqlGenerator::readInsideParentese(QString &text, QString &out)
for (int i = 0; i < text.length(); ++i) { for (int i = 0; i < text.length(); ++i) {
QChar ch = text.at(i); QChar ch = text.at(i);
if (ch == '(') { if (ch == QLatin1Char('(')) {
if (start == -1) if (start == -1)
start = i; start = i;
pc++; pc++;
} }
if (ch == ')') { if (ch == QLatin1Char(')')) {
pc--; pc--;
if (!pc && end == -1) if (!pc && end == -1)
@ -315,11 +326,20 @@ QString MySqlGenerator::createConditionalPhrase(const PhraseData *d) const
case PhraseData::AddMinutes: case PhraseData::AddMinutes:
case PhraseData::AddMinutesDateTime: case PhraseData::AddMinutesDateTime:
case PhraseData::AddSeconds: case PhraseData::AddSeconds:
case PhraseData::AddSecondsDateTime: case PhraseData::AddSecondsDateTime: {
return QStringLiteral("DATE_ADD(%1, INTERVAL %2 %3)") auto interval = d->operand.toInt();
.arg(createConditionalPhrase(d->left),
d->operand.toString(), if (interval < 0)
AbstractSqlGenerator::dateTimePartName(op)); return QStringLiteral("DATE_SUB(%1, INTERVAL %2 %3)")
.arg(createConditionalPhrase(d->left))
.arg(-interval)
.arg(AbstractSqlGenerator::dateTimePartName(op));
else
return QStringLiteral("DATE_ADD(%1, INTERVAL %2 %3)")
.arg(createConditionalPhrase(d->left))
.arg(interval)
.arg(AbstractSqlGenerator::dateTimePartName(op));
}
default: default:
break; break;
@ -362,8 +382,11 @@ QString MySqlGenerator::primaryKeyConstraint(const TableModel *table) const
.arg(table->primaryKey()); .arg(table->primaryKey());
} }
QString MySqlGenerator::escaleFieldName(const QString &fieldName) const QString MySqlGenerator::escapeFieldName(const QString &fieldName) const
{ {
return "`" + fieldName + "`"; return "`" + fieldName + "`";
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -25,6 +25,8 @@
#include <QtNut/abstractsqlgenerator.h> #include <QtNut/abstractsqlgenerator.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class NUT_EXPORT MySqlGenerator : public AbstractSqlGenerator class NUT_EXPORT MySqlGenerator : public AbstractSqlGenerator
@ -40,7 +42,7 @@ public:
QString createConditionalPhrase(const PhraseData *d) const override; QString createConditionalPhrase(const PhraseData *d) const override;
void appendSkipTake(QString &sql, int skip, int take) override; void appendSkipTake(QString &sql, int skip, int take) override;
QString primaryKeyConstraint(const TableModel *table) const override; QString primaryKeyConstraint(const TableModel *table) const override;
QString escaleFieldName(const QString &fieldName) const override; QString escapeFieldName(const QString &fieldName) const override;
private: private:
bool readInsideParentese(QString &text, QString &out); bool readInsideParentese(QString &text, QString &out);
@ -48,4 +50,6 @@ private:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // MYSQLGENERATOR_H #endif // MYSQLGENERATOR_H

View File

@ -32,6 +32,9 @@
#include "table.h" #include "table.h"
#include "tablemodel.h" #include "tablemodel.h"
#include "sqlserializer.h" #include "sqlserializer.h"
#include "nut_p.h"
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
@ -43,12 +46,12 @@ bool PostgreSqlGenerator::readInsideParentese(QString &text, QString &out)
for (int i = 0; i < text.length(); ++i) { for (int i = 0; i < text.length(); ++i) {
QChar ch = text.at(i); QChar ch = text.at(i);
if (ch == '(') { if (ch == QLatin1Char('(')) {
if (start == -1) if (start == -1)
start = i; start = i;
pc++; pc++;
} }
if (ch == ')') { if (ch == QLatin1Char(')')) {
pc--; pc--;
if (!pc && end == -1) if (!pc && end == -1)
@ -63,14 +66,14 @@ bool PostgreSqlGenerator::readInsideParentese(QString &text, QString &out)
return false; return false;
} }
bool PostgreSqlGenerator::isPostGisType(const QVariant::Type &t) const bool PostgreSqlGenerator::isPostGisType(const QMetaType::Type &t) const
{ {
return t == QVariant::Point return t == QMetaType::QPoint
|| t == QVariant::PointF || t == QMetaType::QPointF
|| t == QVariant::Rect || t == QMetaType::QRect
|| t == QVariant::RectF || t == QMetaType::QRectF
|| t == QVariant::Polygon || t == QMetaType::QPolygon
|| t == QVariant::PolygonF; || t == QMetaType::QPolygonF;
} }
PostgreSqlGenerator::PostgreSqlGenerator(Database *parent) : AbstractSqlGenerator (parent) PostgreSqlGenerator::PostgreSqlGenerator(Database *parent) : AbstractSqlGenerator (parent)
@ -189,13 +192,16 @@ QString PostgreSqlGenerator::fieldType(FieldModel *field)
return dbType; return dbType;
} }
QString PostgreSqlGenerator::diff(FieldModel *oldField, FieldModel *newField) QString PostgreSqlGenerator::diffField(FieldModel *oldField, FieldModel *newField)
{ {
QString sql = QString(); if(!oldField && !newField)
return QString();
if(oldField && newField) if(oldField && newField)
if(*oldField == *newField) if(*oldField == *newField)
return QString(); return QString();
QString sql = QString();
if(!newField){ if(!newField){
sql = QStringLiteral("DROP COLUMN ") + oldField->name; sql = QStringLiteral("DROP COLUMN ") + oldField->name;
}else{ }else{
@ -212,25 +218,25 @@ QString PostgreSqlGenerator::diff(FieldModel *oldField, FieldModel *newField)
QString PostgreSqlGenerator::escapeValue(const QVariant &v) const QString PostgreSqlGenerator::escapeValue(const QVariant &v) const
{ {
if (v.type() == QVariant::Time) if (VARIANT_TYPE_COMPARE(v, Time))
return v.toTime().toString(QStringLiteral("''HH:mm:ss''")); return v.toTime().toString(QStringLiteral("''HH:mm:ss''"));
if (v.type() == QVariant::Date) if (VARIANT_TYPE_COMPARE(v, Date))
return v.toDate().toString(QStringLiteral("''yyyy-MM-dd''")); return v.toDate().toString(QStringLiteral("''yyyy-MM-dd''"));
if (v.type() == QVariant::DateTime) if (VARIANT_TYPE_COMPARE(v, DateTime))
return v.toDateTime().toString(QStringLiteral("''yyyy-MM-dd HH:mm:ss''")); return v.toDateTime().toString(QStringLiteral("''yyyy-MM-dd HH:mm:ss''"));
if (v.type() == QVariant::StringList) if (VARIANT_TYPE_COMPARE(v, StringList))
return QStringLiteral("'{") return QStringLiteral("'{")
+ v.toStringList().join(QStringLiteral(",")) + v.toStringList().join(QStringLiteral(","))
+ QStringLiteral("}'"); + QStringLiteral("}'");
if (v.type() == QVariant::Point) { if (VARIANT_TYPE_COMPARE(v, Point)) {
QPoint pt = v.toPoint(); QPoint pt = v.toPoint();
return QStringLiteral("point(%1, %2)").arg(pt.x()).arg(pt.y()); return QStringLiteral("point(%1, %2)").arg(pt.x()).arg(pt.y());
} }
if (v.type() == QVariant::PointF) { if (VARIANT_TYPE_COMPARE(v, PointF)) {
QPointF pt = v.toPointF(); QPointF pt = v.toPointF();
return QStringLiteral("point(%1, %2)").arg(pt.x()).arg(pt.y()); return QStringLiteral("point(%1, %2)").arg(pt.x()).arg(pt.y());
} }
@ -241,7 +247,7 @@ QString PostgreSqlGenerator::escapeValue(const QVariant &v) const
} }
#ifdef QT_GUI_LIB #ifdef QT_GUI_LIB
if (v.type() == QVariant::Polygon) { if (VARIANT_TYPE_COMPARE(v, Polygon)) {
QString ret; QString ret;
QPoint pt; QPoint pt;
QPolygon pol = v.value<QPolygon>(); QPolygon pol = v.value<QPolygon>();
@ -254,7 +260,7 @@ QString PostgreSqlGenerator::escapeValue(const QVariant &v) const
} }
return QStringLiteral("'((") + ret + QStringLiteral("))'"); return QStringLiteral("'((") + ret + QStringLiteral("))'");
} }
if (v.type() == QVariant::PolygonF) { if (VARIANT_TYPE_COMPARE(v, PolygonF)) {
QString ret; QString ret;
QPointF pt; QPointF pt;
QPolygonF pol = v.value<QPolygonF>(); QPolygonF pol = v.value<QPolygonF>();
@ -287,20 +293,20 @@ QVariant PostgreSqlGenerator::unescapeValue(const QMetaType::Type &type, const Q
return AbstractSqlGenerator::unescapeValue(QMetaType::QPoint, return AbstractSqlGenerator::unescapeValue(QMetaType::QPoint,
dbValue.toString() dbValue.toString()
.replace(QStringLiteral("("), .replace(QStringLiteral("("),
QStringLiteral("")) QLatin1String())
.replace(QStringLiteral(")"), .replace(QStringLiteral(")"),
QStringLiteral(""))); QLatin1String()));
if (type == QMetaType::QPointF) if (type == QMetaType::QPointF)
return AbstractSqlGenerator::unescapeValue(QMetaType::QPointF, return AbstractSqlGenerator::unescapeValue(QMetaType::QPointF,
dbValue.toString() dbValue.toString()
.replace(QStringLiteral("("), .replace(QStringLiteral("("),
QStringLiteral("")) QLatin1String())
.replace(QStringLiteral(")"), .replace(QStringLiteral(")"),
QStringLiteral(""))); QLatin1String()));
if (type == QMetaType::QStringList) if (type == QMetaType::QStringList)
return dbValue.toString() return dbValue.toString()
.replace(QStringLiteral("{"), QStringLiteral("")) .replace(QStringLiteral("{"), QLatin1String())
.replace(QStringLiteral("}"), QStringLiteral("")) .replace(QStringLiteral("}"), QLatin1String())
.split(QStringLiteral(",")); .split(QStringLiteral(","));
#ifdef QT_GUI_LIB #ifdef QT_GUI_LIB
@ -340,6 +346,17 @@ QVariant PostgreSqlGenerator::unescapeValue(const QMetaType::Type &type, const Q
return AbstractSqlGenerator::unescapeValue(type, dbValue); return AbstractSqlGenerator::unescapeValue(type, dbValue);
} }
void PostgreSqlGenerator::appendSkipTake(QString &sql, int skip, int take)
{
if (take > 0 && skip > 0) {
sql.append(QStringLiteral(" LIMIT %1 OFFSET %2")
.arg(take)
.arg(skip));
} else if (take > 0) {
sql.append(QStringLiteral(" LIMIT %1").arg(take));
}
}
QString PostgreSqlGenerator::createConditionalPhrase(const PhraseData *d) const QString PostgreSqlGenerator::createConditionalPhrase(const PhraseData *d) const
{ {
if (!d) if (!d)
@ -353,7 +370,7 @@ QString PostgreSqlGenerator::createConditionalPhrase(const PhraseData *d) const
} }
if (d->type == PhraseData::WithVariant) { if (d->type == PhraseData::WithVariant) {
if (isPostGisType(d->operand.type()) && d->operatorCond == PhraseData::Equal) { if (isPostGisType(METATYPE_ID(d->operand)) && d->operatorCond == PhraseData::Equal) {
return QStringLiteral("%1 ~= %2") return QStringLiteral("%1 ~= %2")
.arg(AbstractSqlGenerator::createConditionalPhrase(d->left), .arg(AbstractSqlGenerator::createConditionalPhrase(d->left),
escapeValue(d->operand)); escapeValue(d->operand));
@ -402,3 +419,5 @@ QString PostgreSqlGenerator::createConditionalPhrase(const PhraseData *d) const
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -25,30 +25,33 @@
#include <QtNut/abstractsqlgenerator.h> #include <QtNut/abstractsqlgenerator.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class NUT_EXPORT PostgreSqlGenerator : public AbstractSqlGenerator class NUT_EXPORT PostgreSqlGenerator : public AbstractSqlGenerator
{ {
private: private:
bool readInsideParentese(QString &text, QString &out); bool readInsideParentese(QString &text, QString &out);
bool isPostGisType(const QVariant::Type &t) const; bool isPostGisType(const QMetaType::Type &t) const;
public: public:
explicit PostgreSqlGenerator(Database *parent = nullptr); explicit PostgreSqlGenerator(Database *parent = nullptr);
QString fieldType(FieldModel *field) override; QString fieldType(FieldModel *field) override;
QString diff(FieldModel *oldField, FieldModel *newField) override; QString diffField(FieldModel *oldField, FieldModel *newField) override;
// SqlGeneratorBase interface
public:
QString escapeValue(const QVariant &v) const override; QString escapeValue(const QVariant &v) const override;
QVariant unescapeValue(const QMetaType::Type &type, const QVariant &dbValue) override; QVariant unescapeValue(const QMetaType::Type &type, const QVariant &dbValue) override;
void appendSkipTake(QString &sql, int skip = -1, int take = -1) override;
// SqlGeneratorBase interface
protected: protected:
QString createConditionalPhrase(const PhraseData *d) const override; QString createConditionalPhrase(const PhraseData *d) const override;
}; };
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // POSTGRESQLGENERATOR_H #endif // POSTGRESQLGENERATOR_H

View File

@ -21,6 +21,9 @@
#include "sqlitegenerator.h" #include "sqlitegenerator.h"
#include "table.h" #include "table.h"
#include "tablemodel.h" #include "tablemodel.h"
#include "nut_p.h"
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
@ -116,15 +119,18 @@ bool SqliteGenerator::supportAutoIncrement(const QMetaType::Type &type)
} }
QStringList SqliteGenerator::diff(TableModel *oldTable, TableModel *newTable) QStringList SqliteGenerator::diffTable(TableModel *oldTable, TableModel *newTable)
{ {
QStringList ret; QStringList ret;
if (!oldTable && !newTable)
return ret;
if (oldTable && newTable) if (oldTable && newTable)
if (*oldTable == *newTable) if (*oldTable == *newTable)
return ret; return ret;
QStringList newTableSql = AbstractSqlGenerator::diff(nullptr, newTable); QStringList newTableSql = AbstractSqlGenerator::diffTable(nullptr, newTable);
if (!newTable) if (!newTable)
return QStringList() << QStringLiteral("DROP TABLE ") + oldTable->name(); return QStringList() << QStringLiteral("DROP TABLE ") + oldTable->name();
@ -135,22 +141,22 @@ QStringList SqliteGenerator::diff(TableModel *oldTable, TableModel *newTable)
QList<QString> fieldNames; QList<QString> fieldNames;
QList<QString> relations; QList<QString> relations;
Q_FOREACH (FieldModel *f, oldTable->fields()) for (auto &f: oldTable->fields())
if (!fieldNames.contains(f->name)) if (!fieldNames.contains(f->name))
fieldNames.append(f->name); fieldNames.append(f->name);
Q_FOREACH (RelationModel *r, oldTable->foreignKeys()) for (auto &r: oldTable->foreignKeys())
if (!relations.contains(r->localColumn)) if (!relations.contains(r->localColumn))
relations.append(r->localColumn); relations.append(r->localColumn);
Q_FOREACH (FieldModel *f, newTable->fields()) for (auto &f: newTable->fields())
if (!fieldNames.contains(f->name)) if (!fieldNames.contains(f->name))
fieldNames.append(f->name); fieldNames.append(f->name);
Q_FOREACH (RelationModel *r, newTable->foreignKeys()) for (auto &r: newTable->foreignKeys())
if (!relations.contains(r->localColumn)) if (!relations.contains(r->localColumn))
relations.append(r->localColumn); relations.append(r->localColumn);
QString columns; QString columns;
Q_FOREACH (FieldModel *f, oldTable->fields()) { for (auto &f: oldTable->fields()) {
if (!newTable->field(f->name)) if (!newTable->field(f->name))
continue; continue;
@ -238,9 +244,8 @@ QString SqliteGenerator::createConditionalPhrase(const PhraseData *d) const
int i = d->operand.toInt(); int i = d->operand.toInt();
return QStringLiteral("DATE(%1,'%2 %3')") return QStringLiteral("DATE(%1,'%2 %3')")
.arg(createConditionalPhrase(d->left), .arg(createConditionalPhrase(d->left),
(i < 0 ? QStringLiteral("") : QStringLiteral("+")) + QString::number(i), (i < 0 ? QLatin1String() : QStringLiteral("+")) + QString::number(i),
dateTimePartName(op)); dateTimePartName(op));
break;
} }
case PhraseData::AddHours: case PhraseData::AddHours:
case PhraseData::AddMinutes: case PhraseData::AddMinutes:
@ -248,9 +253,8 @@ QString SqliteGenerator::createConditionalPhrase(const PhraseData *d) const
int i = d->operand.toInt(); int i = d->operand.toInt();
return QStringLiteral("TIME(%1,'%2 %3')") return QStringLiteral("TIME(%1,'%2 %3')")
.arg(createConditionalPhrase(d->left), .arg(createConditionalPhrase(d->left),
(i < 0 ? QStringLiteral("") : QStringLiteral("+")) + QString::number(i), (i < 0 ? QLatin1String() : QStringLiteral("+")) + QString::number(i),
dateTimePartName(op)); dateTimePartName(op));
break;
} }
case PhraseData::AddYearsDateTime: case PhraseData::AddYearsDateTime:
case PhraseData::AddMonthsDateTime: case PhraseData::AddMonthsDateTime:
@ -261,7 +265,7 @@ QString SqliteGenerator::createConditionalPhrase(const PhraseData *d) const
int i = d->operand.toInt(); int i = d->operand.toInt();
return QStringLiteral("DATETIME(%1,'%2 %3')") return QStringLiteral("DATETIME(%1,'%2 %3')")
.arg(createConditionalPhrase(d->left), .arg(createConditionalPhrase(d->left),
(i < 0 ? QStringLiteral("") : QStringLiteral("+")) + QString::number(i), (i < 0 ? QLatin1String() : QStringLiteral("+")) + QString::number(i),
dateTimePartName(op)); dateTimePartName(op));
break; break;
} }
@ -308,13 +312,13 @@ QString SqliteGenerator::createConditionalPhrase(const PhraseData *d) const
QString SqliteGenerator::escapeValue(const QVariant &v) const QString SqliteGenerator::escapeValue(const QVariant &v) const
{ {
if (v.type() == QVariant::Time) if (VARIANT_TYPE_COMPARE(v, Time))
return v.toTime().toString(QStringLiteral("''HH:mm:ss''")); return v.toTime().toString(QStringLiteral("''HH:mm:ss''"));
if (v.type() == QVariant::Date) if (VARIANT_TYPE_COMPARE(v, Date))
return v.toDate().toString(QStringLiteral("''yyyy-MM-dd''")); return v.toDate().toString(QStringLiteral("''yyyy-MM-dd''"));
if (v.type() == QVariant::DateTime) if (VARIANT_TYPE_COMPARE(v, DateTime))
return v.toDateTime().toString(QStringLiteral("''yyyy-MM-dd HH:mm:ss''")); return v.toDateTime().toString(QStringLiteral("''yyyy-MM-dd HH:mm:ss''"));
return AbstractSqlGenerator::escapeValue(v); return AbstractSqlGenerator::escapeValue(v);
@ -335,3 +339,5 @@ QVariant SqliteGenerator::unescapeValue(const QMetaType::Type &type, const QVari
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -25,6 +25,8 @@
#include <QtNut/abstractsqlgenerator.h> #include <QtNut/abstractsqlgenerator.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class NUT_EXPORT SqliteGenerator : public AbstractSqlGenerator class NUT_EXPORT SqliteGenerator : public AbstractSqlGenerator
@ -40,7 +42,7 @@ public:
void appendSkipTake(QString &sql, int skip, int take) override; void appendSkipTake(QString &sql, int skip, int take) override;
QString primaryKeyConstraint(const TableModel *table) const override; QString primaryKeyConstraint(const TableModel *table) const override;
QStringList diff(TableModel *oldTable, TableModel *newTable) override; QStringList diffTable(TableModel *oldTable, TableModel *newTable) override;
QString createConditionalPhrase(const PhraseData *d) const override; QString createConditionalPhrase(const PhraseData *d) const override;
@ -50,4 +52,6 @@ public:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // SQLITEGENERATOR_H #endif // SQLITEGENERATOR_H

View File

@ -21,10 +21,13 @@
#include "sqlservergenerator.h" #include "sqlservergenerator.h"
#include "table.h" #include "table.h"
#include "tablemodel.h" #include "tablemodel.h"
#include "nut_p.h"
#include <QtCore/QPoint> #include <QtCore/QPoint>
#include <QtCore/QRegularExpression> #include <QtCore/QRegularExpression>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
SqlServerGenerator::SqlServerGenerator(Database *parent) SqlServerGenerator::SqlServerGenerator(Database *parent)
@ -37,7 +40,7 @@ QString SqlServerGenerator::masterDatabaseName(QString databaseName)
return databaseName.replace( return databaseName.replace(
QRegularExpression(QStringLiteral("DATABASE\\=(\\w+)"), QRegularExpression(QStringLiteral("DATABASE\\=(\\w+)"),
QRegularExpression::CaseInsensitiveOption), QRegularExpression::CaseInsensitiveOption),
QStringLiteral("DATABASE=")); QStringLiteral("DATABASE=master"));
} }
QString SqlServerGenerator::fieldType(FieldModel *field) QString SqlServerGenerator::fieldType(FieldModel *field)
@ -130,13 +133,16 @@ QString SqlServerGenerator::fieldType(FieldModel *field)
} }
} }
QString SqlServerGenerator::diff(FieldModel *oldField, FieldModel *newField) QString SqlServerGenerator::diffField(FieldModel *oldField, FieldModel *newField)
{ {
QString sql = QString(); if (!oldField && !newField)
return QString();
if (oldField && newField) if (oldField && newField)
if (*oldField == *newField) if (*oldField == *newField)
return sql; return QString();
QString sql = QString();
if (!newField) { if (!newField) {
sql = QStringLiteral("DROP COLUMN ") + oldField->name; sql = QStringLiteral("DROP COLUMN ") + oldField->name;
} else { } else {
@ -152,44 +158,44 @@ QString SqlServerGenerator::diff(FieldModel *oldField, FieldModel *newField)
QString SqlServerGenerator::escapeValue(const QVariant &v) const QString SqlServerGenerator::escapeValue(const QVariant &v) const
{ {
switch (v.type()) { switch (METATYPE_ID(v)) {
case QVariant::String: case QMetaType::QString:
case QVariant::Char: case QMetaType::QChar:
case QVariant::Polygon: case QMetaType::QPolygon:
case QVariant::PolygonF: case QMetaType::QPolygonF:
case QVariant::Size: case QMetaType::QSize:
case QVariant::SizeF: case QMetaType::QSizeF:
case QVariant::Rect: case QMetaType::QRect:
case QVariant::RectF: case QMetaType::QRectF:
case QVariant::Line: case QMetaType::QLine:
case QVariant::LineF: case QMetaType::QLineF:
case QVariant::Color: case QMetaType::QColor:
case QVariant::StringList: case QMetaType::QStringList:
// case QVariant::JsonArray: // case QMetaType::QJsonArray:
// case QVariant::JsonValue: // case QMetaType::QJsonValue:
// case QVariant::JsonObject: // case QMetaType::QJsonObject:
// case QVariant::JsonDocument: // case QMetaType::QJsonDocument:
case QVariant::Url: case QMetaType::QUrl:
return QStringLiteral("N") + AbstractSqlGenerator::escapeValue(v); return QStringLiteral("N") + AbstractSqlGenerator::escapeValue(v);
// case QVariant::Point: { // case QMetaType::QPoint: {
// QPoint pt = v.toPoint(); // QPoint pt = v.toPoint();
// return QString("geography::POINT(%1, %2, 4326)").arg(pt.x()).arg( // return QString("geography::POINT(%1, %2, 4326)").arg(pt.x()).arg(
// pt.y()); // pt.y());
// } // }
// case QVariant::PointF: { // case QMetaType::QPointF: {
// QPointF pt = v.toPointF(); // QPointF pt = v.toPointF();
// return QString("geography::POINT(%1, %2, 4326)").arg(pt.x()).arg( // return QString("geography::POINT(%1, %2, 4326)").arg(pt.x()).arg(
// pt.y()); // pt.y());
// } // }
case QVariant::Time: case QMetaType::QTime:
return v.toTime().toString(QStringLiteral("''HH:mm:ss''")); return v.toTime().toString(QStringLiteral("''HH:mm:ss''"));
case QVariant::Date: case QMetaType::QDate:
return v.toDate().toString(QStringLiteral("''yyyy-MM-dd''")); return v.toDate().toString(QStringLiteral("''yyyy-MM-dd''"));
case QVariant::DateTime: case QMetaType::QDateTime:
return v.toDateTime().toString(QStringLiteral("''yyyy-MM-dd HH:mm:ss''")); return v.toDateTime().toString(QStringLiteral("''yyyy-MM-dd HH:mm:ss''"));
default: default:
@ -279,3 +285,5 @@ QString SqlServerGenerator::createConditionalPhrase(const PhraseData *d) const
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -25,6 +25,8 @@
#include <QtNut/abstractsqlgenerator.h> #include <QtNut/abstractsqlgenerator.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class NUT_EXPORT SqlServerGenerator : public AbstractSqlGenerator class NUT_EXPORT SqlServerGenerator : public AbstractSqlGenerator
@ -35,7 +37,7 @@ public:
QString masterDatabaseName(QString databaseName) override; QString masterDatabaseName(QString databaseName) override;
QString fieldType(FieldModel *field) override; QString fieldType(FieldModel *field) override;
QString diff(FieldModel *oldField, FieldModel *newField) override; QString diffField(FieldModel *oldField, FieldModel *newField) override;
QString escapeValue(const QVariant &v) const override; QString escapeValue(const QVariant &v) const override;
QVariant unescapeValue(const QMetaType::Type &type, const QVariant &dbValue) override; QVariant unescapeValue(const QMetaType::Type &type, const QVariant &dbValue) override;
@ -48,4 +50,6 @@ protected:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // SQLSERVERGENERATOR_H #endif // SQLSERVERGENERATOR_H

View File

@ -24,6 +24,8 @@
#include <QtCore/QJsonArray> #include <QtCore/QJsonArray>
#include <QtCore/QJsonObject> #include <QtCore/QJsonObject>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
QMap<QString, DatabaseModel*> DatabaseModel::_models; QMap<QString, DatabaseModel*> DatabaseModel::_models;
@ -48,7 +50,7 @@ DatabaseModel::DatabaseModel(const QJsonObject &json) :
setVersion(json.value(NODE_VERSION).toInt()); setVersion(json.value(NODE_VERSION).toInt());
QJsonObject tables = json.value(NODE_TABLES).toObject(); QJsonObject tables = json.value(NODE_TABLES).toObject();
Q_FOREACH (QString key, tables.keys()) { for (auto &key: tables.keys()) {
if(!tables.value(key).isObject()) if(!tables.value(key).isObject())
continue; continue;
@ -146,7 +148,7 @@ RelationModel *DatabaseModel::relationByClassNames(const QString &masterClassNam
if(!childTable) if(!childTable)
return nullptr; return nullptr;
Q_FOREACH (RelationModel *rel, childTable->foreignKeys()) for (auto &rel: childTable->foreignKeys())
if(rel->masterClassName == masterClassName) if(rel->masterClassName == masterClassName)
return rel; return rel;
@ -160,7 +162,7 @@ RelationModel *DatabaseModel::relationByTableNames(const QString &masterTableNam
if(!childTable) if(!childTable)
return nullptr; return nullptr;
Q_FOREACH (RelationModel *rel, childTable->foreignKeys()) for (auto &rel: childTable->foreignKeys())
if(rel->masterTable->name() == masterTableName) if(rel->masterTable->name() == masterTableName)
return rel; return rel;
@ -174,7 +176,7 @@ DatabaseModel DatabaseModel::fromJson(QJsonObject &json)
model.setVersion(json.value(NODE_VERSION).toInt()); model.setVersion(json.value(NODE_VERSION).toInt());
QJsonObject tables = json.value(NODE_TABLES).toObject(); QJsonObject tables = json.value(NODE_TABLES).toObject();
Q_FOREACH (QString key, tables.keys()) { for (auto &key: tables.keys()) {
if(!json.value(key).isObject()) if(!json.value(key).isObject())
continue; continue;
@ -209,8 +211,8 @@ bool DatabaseModel::remove(const QString &tableName)
void DatabaseModel::fixRelations() void DatabaseModel::fixRelations()
{ {
/*TODO: fixme /*TODO: fixme
Q_FOREACH (TableModel *table, currentModel) for (auto &table: currentModel)
Q_FOREACH (RelationModel *fk, table->foreignKeys()) for (auto &fk: table->foreignKeys())
fk->masterTable = currentModel.tableByClassName(fk->masterClassName); fk->masterTable = currentModel.tableByClassName(fk->masterClassName);
*/ */
} }
@ -238,12 +240,11 @@ void DatabaseModel::deleteAllModels()
DatabaseModel operator +(const DatabaseModel &l, const DatabaseModel &r) DatabaseModel operator +(const DatabaseModel &l, const DatabaseModel &r)
{ {
DatabaseModel model; DatabaseModel model;
DatabaseModel::const_iterator i;
for (i = r.constBegin(); i != r.constEnd(); ++i) for (auto i = r.constBegin(); i != r.constEnd(); ++i)
model.append(*i); model.append(*i);
for (i = l.constBegin(); i != l.constEnd(); ++i) for (auto i = l.constBegin(); i != l.constEnd(); ++i)
model.append(*i); model.append(*i);
return model; return model;
@ -252,17 +253,16 @@ DatabaseModel operator +(const DatabaseModel &l, const DatabaseModel &r)
DatabaseModel operator |(const DatabaseModel &l, const DatabaseModel &r) DatabaseModel operator |(const DatabaseModel &l, const DatabaseModel &r)
{ {
DatabaseModel ret; DatabaseModel ret;
DatabaseModel::const_iterator i;
QSet<QString> tables; QSet<QString> tables;
for (i = r.constBegin(); i != r.constEnd(); ++i) { for (auto i = r.constBegin(); i != r.constEnd(); ++i) {
if (tables.contains((*i)->name())) if (tables.contains((*i)->name()))
continue; continue;
ret.append(*i); ret.append(*i);
tables.insert((*i)->name()); tables.insert((*i)->name());
} }
for (i = l.constBegin(); i != l.constEnd(); ++i) { for (auto i = l.constBegin(); i != l.constEnd(); ++i) {
if (tables.contains((*i)->name())) if (tables.contains((*i)->name()))
continue; continue;
ret.append(*i); ret.append(*i);
@ -273,3 +273,5 @@ DatabaseModel operator |(const DatabaseModel &l, const DatabaseModel &r)
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -18,8 +18,8 @@
** **
**************************************************************************/ **************************************************************************/
#ifndef DATABASEMODEL_H #ifndef DATABASE_MODEL_H
#define DATABASEMODEL_H #define DATABASE_MODEL_H
#include <QtCore/QList> #include <QtCore/QList>
#include <QtCore/QMap> #include <QtCore/QMap>
@ -29,6 +29,8 @@
class QJsonObject; class QJsonObject;
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class TableModel; class TableModel;
@ -66,7 +68,7 @@ public:
bool remove(const QString &tableName); bool remove(const QString &tableName);
//TODO: may be private (called from DatabasePrivate::getCurrectSchema only) //TODO: may be private (called from DatabasePrivate::getCurrentSchema only)
void fixRelations(); void fixRelations();
static DatabaseModel *modelByName(const QString &name); static DatabaseModel *modelByName(const QString &name);
@ -78,4 +80,6 @@ DatabaseModel operator |(const DatabaseModel &l, const DatabaseModel &r);
NUT_END_NAMESPACE NUT_END_NAMESPACE
#endif // DATABASEMODEL_H QT_END_NAMESPACE
#endif // DATABASE_MODEL_H

View File

@ -27,6 +27,8 @@
#include "sqlmodel.h" #include "sqlmodel.h"
#include "query.h" #include "query.h"
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
SqlModelPrivate::SqlModelPrivate(SqlModel *parent) : q_ptr(parent) SqlModelPrivate::SqlModelPrivate(SqlModel *parent) : q_ptr(parent)
@ -124,3 +126,5 @@ Row<Table> SqlModel::at(const int &i) const
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -27,6 +27,8 @@
#include <QtNut/nut_global.h> #include <QtNut/nut_global.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class Database; class Database;
@ -44,9 +46,10 @@ public:
// explicit SqlModel(Query *q); // explicit SqlModel(Query *q);
explicit SqlModel(Database *database, AbstractTableSet *tableSet, QObject *parent = Q_NULLPTR); explicit SqlModel(Database *database, AbstractTableSet *tableSet, QObject *parent = Q_NULLPTR);
int rowCount(const QModelIndex &parent) const; int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const; int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const; QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
template<class T> template<class T>
void setTable(RowList<T> rows); void setTable(RowList<T> rows);
@ -54,7 +57,6 @@ public:
void setRows(RowList<Table> rows); void setRows(RowList<Table> rows);
void append(Row<Table> table); void append(Row<Table> table);
// void append(Table *table); // void append(Table *table);
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
Row<Table> at(const int &i) const; Row<Table> at(const int &i) const;
void setRenderer(const std::function<QVariant (int, QVariant)> &renderer); void setRenderer(const std::function<QVariant (int, QVariant)> &renderer);
@ -67,12 +69,13 @@ template<class T>
Q_OUTOFLINE_TEMPLATE void SqlModel::setTable(RowList<T> rows) Q_OUTOFLINE_TEMPLATE void SqlModel::setTable(RowList<T> rows)
{ {
RowList<Table> tab; RowList<Table> tab;
Q_FOREACH (auto t, rows) for (auto t: rows)
tab.append(t); tab.append(t);
setRows(tab); setRows(tab);
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // SQLMODEL_H #endif // SQLMODEL_H

View File

@ -1,3 +1,33 @@
/**************************************************************************
**
** This file is part of Nut project.
** https://github.com/HamedMasafi/Nut
**
** Nut is free software: you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Nut is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
**
**************************************************************************/
//
// W A R N I N G
// -------------
//
// This file is not part of the Nut API. This header
// file may change from version to version without notice, or even be removed.
//
// We mean it.
//
#ifndef SQLMODEL_P_H #ifndef SQLMODEL_P_H
#define SQLMODEL_P_H #define SQLMODEL_P_H
@ -8,6 +38,8 @@
#include <QtNut/nut_global.h> #include <QtNut/nut_global.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class SqlModel; class SqlModel;
@ -29,4 +61,6 @@ public:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // SQLMODEL_P_H #endif // SQLMODEL_P_H

View File

@ -26,6 +26,9 @@
#include "tablemodel.h" #include "tablemodel.h"
#include "nut_global.h" #include "nut_global.h"
#include "nut_p.h"
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
@ -74,7 +77,7 @@ FieldModel *TableModel::field(int n) const
FieldModel *TableModel::field(const QString &name) const FieldModel *TableModel::field(const QString &name) const
{ {
Q_FOREACH (FieldModel *f, _fields) for (auto &f: _fields)
if(f->name == name) if(f->name == name)
return f; return f;
@ -94,7 +97,7 @@ QList<RelationModel *> TableModel::foreignKeys() const
QStringList TableModel::fieldsNames() const QStringList TableModel::fieldsNames() const
{ {
QStringList ret; QStringList ret;
Q_FOREACH (FieldModel *f, _fields) for (auto &f: _fields)
ret.append(f->name); ret.append(f->name);
return ret; return ret;
} }
@ -106,7 +109,7 @@ bool TableModel::operator ==(const TableModel &t) const{
if(fields().count() != t.fields().count()) if(fields().count() != t.fields().count())
return false; return false;
Q_FOREACH (FieldModel *f, _fields) { for (auto &f: _fields) {
FieldModel *tf = t.field(f->name); FieldModel *tf = t.field(f->name);
if(!tf) if(!tf)
return false; return false;
@ -129,7 +132,7 @@ TableModel::TableModel(int typeId, const QString &tableName)
// if (findByTypeId(typeId)) // if (findByTypeId(typeId))
// return; // return;
const QMetaObject *tableMetaObject = QMetaType::metaObjectForType(typeId); const QMetaObject *tableMetaObject = QMetaType(typeId).metaObject();
_typeId = typeId; _typeId = typeId;
_name = tableName; _name = tableName;
@ -162,12 +165,16 @@ TableModel::TableModel(int typeId, const QString &tableName)
QMetaProperty fieldProperty = tableMetaObject->property(j); QMetaProperty fieldProperty = tableMetaObject->property(j);
auto name = QString::fromUtf8(fieldProperty.name()); auto name = QString::fromUtf8(fieldProperty.name());
FieldModel *fieldObj = field(name); FieldModel *fieldObj = field(name);
Q_FOREACH (FieldModel *f, _fields) for (auto &f: _fields)
if(f->name == name) if(f->name == name)
f = fieldObj; fieldObj = f;
if(!fieldObj) if(!fieldObj)
continue; continue;
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
fieldObj->type = static_cast<QMetaType::Type>(fieldProperty.metaType().id());
#else
fieldObj->type = static_cast<QMetaType::Type>(fieldProperty.type()); fieldObj->type = static_cast<QMetaType::Type>(fieldProperty.type());
#endif
fieldObj->typeName = QString::fromUtf8(fieldProperty.typeName()); fieldObj->typeName = QString::fromUtf8(fieldProperty.typeName());
} }
@ -244,13 +251,17 @@ TableModel::TableModel(const QJsonObject &json, const QString &tableName) : _typ
QJsonObject fields = json.value(QStringLiteral(__FIELDS)).toObject(); QJsonObject fields = json.value(QStringLiteral(__FIELDS)).toObject();
QJsonObject relations = json.value(QStringLiteral(__FOREIGN_KEYS)).toObject(); QJsonObject relations = json.value(QStringLiteral(__FOREIGN_KEYS)).toObject();
Q_FOREACH (QString key, fields.keys()) { for (auto &key: fields.keys()) {
QJsonObject fieldObject = fields.value(key).toObject(); QJsonObject fieldObject = fields.value(key).toObject();
//TODO: use FieldModel(QJsonObject) ctor //TODO: use FieldModel(QJsonObject) ctor
auto *f = new FieldModel; auto *f = new FieldModel;
f->name = fieldObject.value(QStringLiteral(__NAME)).toString(); f->name = fieldObject.value(QStringLiteral(__NAME)).toString();
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
f->type = static_cast<QMetaType::Type>(QMetaType::fromName(fieldObject.value(QStringLiteral(__TYPE)).toString().toLatin1()).id());
#else
f->type = static_cast<QMetaType::Type>(QMetaType::type(fieldObject.value(QStringLiteral(__TYPE)).toString().toLatin1().data())); f->type = static_cast<QMetaType::Type>(QMetaType::type(fieldObject.value(QStringLiteral(__TYPE)).toString().toLatin1().data()));
f->typeName = QString::fromUtf8(QMetaType::typeName(f->type)); #endif
f->typeName = QString::fromUtf8(METATYPE_TO_NAME(f->type));
if(fieldObject.contains(QStringLiteral(__nut_NOT_NULL))) if(fieldObject.contains(QStringLiteral(__nut_NOT_NULL)))
f->notNull = fieldObject.value(QStringLiteral(__nut_NOT_NULL)).toBool(); f->notNull = fieldObject.value(QStringLiteral(__nut_NOT_NULL)).toBool();
@ -266,7 +277,7 @@ TableModel::TableModel(const QJsonObject &json, const QString &tableName) : _typ
_fields.append(f); _fields.append(f);
} }
Q_FOREACH (QString key, relations.keys()) { for (auto &key: relations.keys()) {
QJsonObject relObject = fields.value(key).toObject(); QJsonObject relObject = fields.value(key).toObject();
_foreignKeys.append(new RelationModel(relObject)); _foreignKeys.append(new RelationModel(relObject));
} }
@ -284,10 +295,10 @@ QJsonObject TableModel::toJson() const
QJsonObject fieldsObj; QJsonObject fieldsObj;
QJsonObject foreignKeysObj; QJsonObject foreignKeysObj;
Q_FOREACH (FieldModel *f, _fields) { for (auto &f: _fields) {
QJsonObject fieldObj; QJsonObject fieldObj;
fieldObj.insert(QStringLiteral(__NAME), f->name); fieldObj.insert(QStringLiteral(__NAME), f->name);
fieldObj.insert(QStringLiteral(__TYPE), QString::fromUtf8(QVariant::typeToName(f->type))); fieldObj.insert(QStringLiteral(__TYPE), QString::fromUtf8(METATYPE_TO_NAME(f->type)));
if(f->length) if(f->length)
fieldObj.insert(QStringLiteral(__nut_LEN), f->length); fieldObj.insert(QStringLiteral(__nut_LEN), f->length);
@ -309,7 +320,7 @@ QJsonObject TableModel::toJson() const
fieldsObj.insert(f->name, fieldObj); fieldsObj.insert(f->name, fieldObj);
} }
Q_FOREACH (RelationModel *rel, _foreignKeys) for (auto &rel: _foreignKeys)
foreignKeysObj.insert(rel->localColumn, rel->toJson()); foreignKeysObj.insert(rel->localColumn, rel->toJson());
obj.insert(QStringLiteral(__FIELDS), fieldsObj); obj.insert(QStringLiteral(__FIELDS), fieldsObj);
@ -320,7 +331,7 @@ QJsonObject TableModel::toJson() const
RelationModel *TableModel::foreignKey(const QString &otherTable) const RelationModel *TableModel::foreignKey(const QString &otherTable) const
{ {
Q_FOREACH (RelationModel *fk, _foreignKeys) for (auto &fk: _foreignKeys)
if(fk->masterClassName == otherTable) if(fk->masterClassName == otherTable)
return fk; return fk;
@ -329,7 +340,7 @@ RelationModel *TableModel::foreignKey(const QString &otherTable) const
RelationModel *TableModel::foreignKeyByField(const QString &fieldName) const RelationModel *TableModel::foreignKeyByField(const QString &fieldName) const
{ {
Q_FOREACH (RelationModel *fk, _foreignKeys) for (auto &fk: _foreignKeys)
if(fk->localColumn == fieldName) if(fk->localColumn == fieldName)
return fk; return fk;
@ -339,9 +350,9 @@ RelationModel *TableModel::foreignKeyByField(const QString &fieldName) const
QString TableModel::toString() const QString TableModel::toString() const
{ {
QStringList sl; QStringList sl;
Q_FOREACH (FieldModel *f, _fields) for (auto &f: _fields)
sl.append(f->name + QStringLiteral(" ") sl.append(f->name + QStringLiteral(" ")
+ QString::fromUtf8(QVariant::typeToName(f->type))); + QString::fromUtf8(METATYPE_TO_NAME(f->type)));
QString ret = QStringLiteral("%1 (%2)") QString ret = QStringLiteral("%1 (%2)")
.arg(_name, sl.join(QStringLiteral(", "))); .arg(_name, sl.join(QStringLiteral(", ")));
@ -350,7 +361,7 @@ QString TableModel::toString() const
QString TableModel::primaryKey() const QString TableModel::primaryKey() const
{ {
Q_FOREACH (FieldModel *f, _fields) for (auto &f: _fields)
if(f->isPrimaryKey) if(f->isPrimaryKey)
return f->name; return f->name;
return QString(); return QString();
@ -381,7 +392,7 @@ QJsonObject FieldModel::toJson() const
{ {
QJsonObject fieldObj; QJsonObject fieldObj;
fieldObj.insert(QStringLiteral(__NAME), name); fieldObj.insert(QStringLiteral(__NAME), name);
fieldObj.insert(QStringLiteral(__TYPE), QString::fromUtf8(QVariant::typeToName(type))); fieldObj.insert(QStringLiteral(__TYPE), QString::fromUtf8(METATYPE_TO_NAME(type)));
fieldObj.insert(QStringLiteral(__nut_LEN), length); fieldObj.insert(QStringLiteral(__nut_LEN), length);
fieldObj.insert(QStringLiteral(__nut_NOT_NULL), notNull); fieldObj.insert(QStringLiteral(__nut_NOT_NULL), notNull);
fieldObj.insert(QStringLiteral(__nut_UNIQUE), isUnique); fieldObj.insert(QStringLiteral(__nut_UNIQUE), isUnique);
@ -424,3 +435,5 @@ bool operator !=(const RelationModel &l, const RelationModel &r)
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -28,6 +28,8 @@
class QJsonObject; class QJsonObject;
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class TableModel; class TableModel;
@ -135,4 +137,6 @@ private:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // TABLEMODEL_H #endif // TABLEMODEL_H

View File

@ -16,4 +16,3 @@ HEADERS += \
SOURCES += \ SOURCES += \
$$PWD/phrase.cpp $$PWD/phrase.cpp
include($$PWD/3rdparty/serializer/src/src.pri)

View File

@ -17,11 +17,11 @@ include(phrases/phrases.pri)
include(models/models.pri) include(models/models.pri)
HEADERS += \ HEADERS += \
$$PWD/phrase.h $$PWD/phrase.h \
$$PWD/nut_p.h
SOURCES += \ SOURCES += \
$$PWD/phrase.cpp $$PWD/phrase.cpp
load(qt_module) load(qt_module)
include($$PWD/3rdparty/serializer/src/src.pri)

48
src/nut/nut_p.h Normal file
View File

@ -0,0 +1,48 @@
/**************************************************************************
**
** This file is part of Nut project.
** https://github.com/HamedMasafi/Nut
**
** Nut is free software: you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** Nut is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public License
** along with Nut. If not, see <http://www.gnu.org/licenses/>.
**
**************************************************************************/
//
// W A R N I N G
// -------------
//
// This file is not part of the Nut API. This header
// file may change from version to version without notice, or even be removed.
//
// We mean it.
//
#ifndef NUT_P_H
#define NUT_P_H
#include <QtGlobal>
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
# define VARIANT_TYPE_COMPARE(v, t) v.typeId() == QMetaType::Q##t
# define VARIANT_TYPE_COMPARE_X(v, vt, mt) v.typeId() == QMetaType::mt
# define METATYPE_TO_NAME(type) QMetaType(type).name()
# define METATYPE_ID(v) static_cast<QMetaType::Type>(v.typeId())
#else
# define VARIANT_TYPE_COMPARE(v, t) v.type() == QVariant::t
# define VARIANT_TYPE_COMPARE_X(v, vt, mt) v.type() == QVariant::vt
# define METATYPE_TO_NAME(type) QMetaType::typeName(type)
# define METATYPE_ID(v) static_cast<QMetaType::Type>(v.type())
#endif
#endif

View File

@ -19,3 +19,6 @@
**************************************************************************/ **************************************************************************/
#include "phrase.h" #include "phrase.h"
QT_BEGIN_NAMESPACE
QT_END_NAMESPACE

View File

@ -21,6 +21,9 @@
#ifndef PHRASE_H #ifndef PHRASE_H
#define PHRASE_H #define PHRASE_H
#include <QtGlobal>
#include <QtNut/nut_global.h> #include <QtNut/nut_global.h>
#include <QtNut/conditionalphrase.h> #include <QtNut/conditionalphrase.h>
#include <QtNut/abstractfieldphrase.h> #include <QtNut/abstractfieldphrase.h>
@ -35,4 +38,7 @@
#include <QtNut/fieldphrase_qstring.h> #include <QtNut/fieldphrase_qstring.h>
#include <QtNut/fieldphrase_bool.h> #include <QtNut/fieldphrase_bool.h>
QT_BEGIN_NAMESPACE
QT_END_NAMESPACE
#endif // PHRASE_H #endif // PHRASE_H

View File

@ -21,6 +21,8 @@
#include "abstractfieldphrase.h" #include "abstractfieldphrase.h"
#include <QDebug> #include <QDebug>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
AbstractFieldPhrase::AbstractFieldPhrase(PhraseData *d) : data(d) AbstractFieldPhrase::AbstractFieldPhrase(PhraseData *d) : data(d)
@ -137,3 +139,5 @@ AbstractFieldPhrase AbstractFieldPhrase::operator !()
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -26,6 +26,8 @@
#include <QtNut/conditionalphrase.h> #include <QtNut/conditionalphrase.h>
#include <QtNut/phraselist.h> #include <QtNut/phraselist.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class PhraseData; class PhraseData;
@ -46,7 +48,7 @@ public:
ConditionalPhrase in(QList<T> list) ConditionalPhrase in(QList<T> list)
{ {
QVariantList vlist; QVariantList vlist;
Q_FOREACH (T t, list) for (auto &t: list)
vlist.append(QVariant::fromValue(t)); vlist.append(QVariant::fromValue(t));
return ConditionalPhrase(this, PhraseData::In, vlist); return ConditionalPhrase(this, PhraseData::In, vlist);
@ -87,4 +89,6 @@ protected:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // ABSTRACTFIELDPHRASE_H #endif // ABSTRACTFIELDPHRASE_H

View File

@ -22,6 +22,8 @@
#include "assignmentphrase.h" #include "assignmentphrase.h"
#include "phrasedata.h" #include "phrasedata.h"
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
AssignmentPhrase::AssignmentPhrase(PhraseData *d) : data(d) AssignmentPhrase::AssignmentPhrase(PhraseData *d) : data(d)
@ -61,3 +63,5 @@ AssignmentPhrase::~AssignmentPhrase()
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -23,6 +23,9 @@
#include <QtNut/nut_global.h> #include <QtNut/nut_global.h>
#include <QtNut/assignmentphraselist.h> #include <QtNut/assignmentphraselist.h>
#include <QtNut/NutGlobal>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
@ -45,5 +48,6 @@ public:
}; };
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // ASSIGNMENTPHRASE_H #endif // ASSIGNMENTPHRASE_H

View File

@ -22,8 +22,9 @@
#include "phrasedata.h" #include "phrasedata.h"
#include "assignmentphrase.h" #include "assignmentphrase.h"
NUT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE
AssignmentPhraseList AssignmentPhrase::operator &(const AssignmentPhrase &other) AssignmentPhraseList AssignmentPhrase::operator &(const AssignmentPhrase &other)
{ {
@ -68,18 +69,14 @@ AssignmentPhraseList AssignmentPhraseList::operator &(const AssignmentPhrase
AssignmentPhraseList::~AssignmentPhraseList() AssignmentPhraseList::~AssignmentPhraseList()
{ {
// Q_FOREACH (PhraseData *d, data)
// if (!d->ref.deref())
// delete d;
// qDeleteAll(data);
// data.clear();
} }
void AssignmentPhraseList::incAllDataParents() void AssignmentPhraseList::incAllDataParents()
{ {
Q_FOREACH (PhraseData *d, data) for (auto &d: data)
d->ref.ref(); d->ref.ref();
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -23,6 +23,8 @@
#include <QtNut/nut_global.h> #include <QtNut/nut_global.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class PhraseData; class PhraseData;
@ -47,4 +49,6 @@ private:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // ASSIGNMENTPHRASELIST_H #endif // ASSIGNMENTPHRASELIST_H

View File

@ -24,6 +24,8 @@
#include "conditionalphrase.h" #include "conditionalphrase.h"
#include "phrasedata.h" #include "phrasedata.h"
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
ConditionalPhrase::ConditionalPhrase() : data(nullptr) ConditionalPhrase::ConditionalPhrase() : data(nullptr)
@ -232,3 +234,5 @@ ConditionalPhrase operator >=(ConditionalPhrase &&l, ConditionalPhrase &&r)
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -23,6 +23,8 @@
#include <QtNut/phrasedata.h> #include <QtNut/phrasedata.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class PhraseData; class PhraseData;
@ -89,7 +91,8 @@ ConditionalPhrase NUT_EXPORT operator <=(ConditionalPhrase &&l, ConditionalPhras
ConditionalPhrase NUT_EXPORT operator >(ConditionalPhrase &&l, ConditionalPhrase &&r); ConditionalPhrase NUT_EXPORT operator >(ConditionalPhrase &&l, ConditionalPhrase &&r);
ConditionalPhrase NUT_EXPORT operator >=(ConditionalPhrase &&l, ConditionalPhrase &&r); ConditionalPhrase NUT_EXPORT operator >=(ConditionalPhrase &&l, ConditionalPhrase &&r);
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // CONDITIONALPHRASE_H #endif // CONDITIONALPHRASE_H

View File

@ -24,6 +24,8 @@
#include <QtNut/nut_global.h> #include <QtNut/nut_global.h>
#include <QtNut/abstractfieldphrase.h> #include <QtNut/abstractfieldphrase.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
template<typename T> template<typename T>
@ -60,4 +62,6 @@ Q_OUTOFLINE_TEMPLATE ConditionalPhrase FieldPhrase<T>::operator ==(const QVarian
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // FIELDPHRASE_H #endif // FIELDPHRASE_H

View File

@ -1,6 +1,6 @@
#include "fieldphrase_bool.h" #include "fieldphrase_bool.h"
NUT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
NUT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -5,6 +5,8 @@
#include <QtNut/fieldphrase.h> #include <QtNut/fieldphrase.h>
#include <QtNut/fieldphrase.h> #include <QtNut/fieldphrase.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
template<> template<>
@ -35,4 +37,6 @@ public:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // NUT_FIELDPHRASE_BOOL_H #endif // NUT_FIELDPHRASE_BOOL_H

View File

@ -20,6 +20,8 @@
#include "fieldphrase_date.h" #include "fieldphrase_date.h"
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
FieldPhrase<QDate>::FieldPhrase(const char *className, const char *s) : FieldPhrase<QDate>::FieldPhrase(const char *className, const char *s) :
@ -145,3 +147,5 @@ COMMON_OPERATORS_IMPL(QTime)
COMMON_OPERATORS_IMPL(QDateTime) COMMON_OPERATORS_IMPL(QDateTime)
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -26,6 +26,8 @@
#include <QtNut/fieldphrase.h> #include <QtNut/fieldphrase.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
#define COMMON_OPERATORS_DECL(T) \ #define COMMON_OPERATORS_DECL(T) \
@ -121,4 +123,6 @@ public:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // DATEPHRASE_H #endif // DATEPHRASE_H

View File

@ -5,6 +5,8 @@
#include <QtNut/abstractfieldphrase.h> #include <QtNut/abstractfieldphrase.h>
#include <QtNut/fieldphrase.h> #include <QtNut/fieldphrase.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
template<> template<>
@ -36,4 +38,6 @@ public:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // NUT_FIELDPHRASE_QSTRING_H #endif // NUT_FIELDPHRASE_QSTRING_H

View File

@ -5,6 +5,8 @@
#include <QtNut/fieldphrase.h> #include <QtNut/fieldphrase.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
#define SPECIALIZATION_NUMERIC_MEMBER(type, op, cond) \ #define SPECIALIZATION_NUMERIC_MEMBER(type, op, cond) \
@ -85,4 +87,6 @@ SPECIALIZATION_NUMERIC_TYPE(float)
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // NUMERICPHRASE_H #endif // NUMERICPHRASE_H

View File

@ -20,18 +20,20 @@
#include "phrasedata.h" #include "phrasedata.h"
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
PhraseData::PhraseData() PhraseData::PhraseData()
: className(""), fieldName(""), type(Field), operatorCond(NotAssign), : className(""), fieldName(""), type(Field), operatorCond(NotAssign),
left(nullptr), right(nullptr), operand(QVariant::Invalid), isNot(false), left(nullptr), right(nullptr), operand(), isNot(false),
ref(1) ref(1)
{ } { }
PhraseData::PhraseData(const char *className, const char *fieldName) PhraseData::PhraseData(const char *className, const char *fieldName)
: className(className), fieldName(fieldName), type(Field), : className(className), fieldName(fieldName), type(Field),
operatorCond(NotAssign), left(nullptr), right(nullptr), operatorCond(NotAssign), left(nullptr), right(nullptr),
operand(QVariant::Invalid), isNot(false), ref(1) operand(), isNot(false), ref(1)
{ } { }
PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o) PhraseData::PhraseData(PhraseData *l, PhraseData::Condition o)
@ -115,3 +117,5 @@ void PhraseData::cleanUp(PhraseData *d)
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -23,6 +23,8 @@
#include <QtNut/nut_global.h> #include <QtNut/nut_global.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class NUT_EXPORT PhraseData class NUT_EXPORT PhraseData
@ -122,4 +124,6 @@ private:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // PHRASEDATA_H #endif // PHRASEDATA_H

View File

@ -20,6 +20,8 @@
#include "phrasedatalist.h" #include "phrasedatalist.h"
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
PhraseDataList::PhraseDataList() : QList<PhraseData*>() PhraseDataList::PhraseDataList() : QList<PhraseData*>()
@ -43,7 +45,7 @@ void PhraseDataList::append(PhraseData *d)
void PhraseDataList::append(QList<PhraseData *> &dl) void PhraseDataList::append(QList<PhraseData *> &dl)
{ {
Q_FOREACH (PhraseData *d, dl) for (auto &d: dl)
d->ref.ref(); d->ref.ref();
QList<PhraseData*>::append(dl); QList<PhraseData*>::append(dl);
} }
@ -59,3 +61,5 @@ PhraseDataList::~PhraseDataList()
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -23,6 +23,8 @@
#include <QtNut/phrasedata.h> #include <QtNut/phrasedata.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class NUT_EXPORT PhraseDataList : public QList<PhraseData*> class NUT_EXPORT PhraseDataList : public QList<PhraseData*>
@ -37,4 +39,6 @@ public:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // PHRASEDATALIST_H #endif // PHRASEDATALIST_H

View File

@ -21,6 +21,8 @@
#include "abstractfieldphrase.h" #include "abstractfieldphrase.h"
#include "phraselist.h" #include "phraselist.h"
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
PhraseList::PhraseList() : isValid(false) PhraseList::PhraseList() : isValid(false)
@ -83,7 +85,7 @@ PhraseList PhraseList::operator |(const AbstractFieldPhrase &other) {
void PhraseList::incAllDataParents() void PhraseList::incAllDataParents()
{ {
// Q_FOREACH (PhraseData *d, data) // for (auto &d: data)
// d->parents++; // d->parents++;
} }
@ -92,3 +94,5 @@ PhraseList PhraseList::operator |(PhraseList &other) {
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -24,6 +24,8 @@
#include <QtNut/nut_global.h> #include <QtNut/nut_global.h>
#include <QtNut/phrasedatalist.h> #include <QtNut/phrasedatalist.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class AbstractFieldPhrase; class AbstractFieldPhrase;
@ -51,4 +53,6 @@ private:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
#endif // PHRASELIST_H #endif // PHRASELIST_H

View File

@ -20,6 +20,8 @@
#include "dbgeography.h" #include "dbgeography.h"
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
DbGeography::DbGeography() : m_longitude(0), m_latitude(0) DbGeography::DbGeography() : m_longitude(0), m_latitude(0)
@ -79,3 +81,5 @@ DbGeography::operator QVariant()
} }
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE

View File

@ -27,6 +27,8 @@
#include <QtNut/nut_global.h> #include <QtNut/nut_global.h>
QT_BEGIN_NAMESPACE
NUT_BEGIN_NAMESPACE NUT_BEGIN_NAMESPACE
class NUT_EXPORT DbGeography class NUT_EXPORT DbGeography
@ -50,6 +52,8 @@ public:
NUT_END_NAMESPACE NUT_END_NAMESPACE
QT_END_NAMESPACE
Q_DECLARE_METATYPE(NUT_WRAP_NAMESPACE(DbGeography)) Q_DECLARE_METATYPE(NUT_WRAP_NAMESPACE(DbGeography))
#endif // DBGEOGRAPHY_H #endif // DBGEOGRAPHY_H

7
tests/CMakeLists.txt Normal file
View File

@ -0,0 +1,7 @@
# Generated from tests.pro.
if(QT_BUILD_STANDALONE_TESTS)
# Add qt_find_package calls for extra dependencies that need to be found when building
# the standalone tests here.
endif()
qt_build_tests()

13
tests/auto/CMakeLists.txt Normal file
View File

@ -0,0 +1,13 @@
# Generated from auto.pro.
add_subdirectory(tst_basic)
add_subdirectory(tst_benckmark)
add_subdirectory(tst_datatypes)
add_subdirectory(tst_phrases)
add_subdirectory(tst_properties)
add_subdirectory(tst_qttypes)
add_subdirectory(tst_quuid)
add_subdirectory(tst_generators)
add_subdirectory(tst_upgrades)
add_subdirectory(tst_json)
add_subdirectory(tst_datetime)

View File

@ -4,13 +4,19 @@
#include <QtCore/qglobal.h> #include <QtCore/qglobal.h>
#include <QtCore/QDateTime> #include <QtCore/QDateTime>
#include <QtNut/table.h> #include <QtNut/table.h>
#include <QSharedPointer>
#ifdef NUT_NAMESPACE #ifdef NUT_NAMESPACE
using namespace NUT_NAMESPACE; using namespace NUT_NAMESPACE;
#endif #endif
class Post; #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
Q_MOC_INCLUDE("user.h")
Q_MOC_INCLUDE("post.h")
#endif
class User; class User;
class Post;
class Comment : public Table class Comment : public Table
{ {
Q_OBJECT Q_OBJECT

View File

@ -13,18 +13,17 @@
.arg(QString::fromUtf8(__func__)) .arg(QString::fromUtf8(__func__))
/*#define DRIVER QStringLiteral("QSQLITE") #define DATABASE QStringLiteral("nut_test_%1_db") \
#define HOST QString() .arg(QString::fromUtf8(metaObject()->className())).toLower()
#define USERNAME QString() #include "test_params.h"
#define PASSWORD QString()
*/ /*
#define DRIVER QStringLiteral("QMYSQL") #define DRIVER QStringLiteral("QMYSQL")
#define HOST QStringLiteral("192.168.10.2") #define HOST QStringLiteral("192.168.10.2")
#define USERNAME QStringLiteral("root") #define USERNAME QStringLiteral("root")
#define PASSWORD QStringLiteral("lDexDJGvQwx20sfgtsetDSupmn9") #define PASSWORD QStringLiteral("lDexDJGvQwx20sfgtsetDSupmn9")
*/
#define DATABASE QStringLiteral("nut_test_%1_db") \
.arg(QString::fromUtf8(metaObject()->className())).toLower()
#ifdef Q_OS_LINUX #ifdef Q_OS_LINUX
# define OS "Linux" # define OS "Linux"

View File

@ -1,54 +1,54 @@
contains(debug_and_release, CONFIG): message(debug_and_release) contains(debug_and_release, CONFIG): message(debug_and_release)
debug_and_release:!ReleaseBuild:!DebugBuild { debug_and_release:!ReleaseBuild:!DebugBuild {
runtarget.target = run-tests runtarget.target = run-tests
runtarget.CONFIG = recursive runtarget.CONFIG = recursive
runtarget.recurse_target = run-tests runtarget.recurse_target = run-tests
QMAKE_EXTRA_TARGETS += runtarget QMAKE_EXTRA_TARGETS += runtarget
} else { } else {
oneshell.target = .ONESHELL oneshell.target = .ONESHELL
QMAKE_EXTRA_TARGETS += oneshell QMAKE_EXTRA_TARGETS += oneshell
win32:!win32-g++ { win32:!win32-g++ {
CONFIG(debug, debug|release): outdir_helper = debug CONFIG(debug, debug|release): outdir_helper = debug
CONFIG(release, debug|release): outdir_helper = release CONFIG(release, debug|release): outdir_helper = release
runtarget.target = run-tests runtarget.target = run-tests
!compat_test: runtarget.depends += $(DESTDIR_TARGET) !compat_test: runtarget.depends += $(DESTDIR_TARGET)
runtarget.commands += set PATH=$$shell_path($$shadowed($$dirname(_QMAKE_CONF_))/bin);$$shell_path($$[QT_INSTALL_BINS]);$(PATH) runtarget.commands += set PATH=$$shell_path($$shadowed($$dirname(_QMAKE_CONF_))/bin);$$shell_path($$[QT_INSTALL_BINS]);$(PATH)
runtarget.commands += $$escape_expand(\\n\\t)set QT_PLUGIN_PATH=$$shadowed($$dirname(_QMAKE_CONF_))/plugins;$$[QT_INSTALL_PLUGINS];$(QT_PLUGIN_PATH) runtarget.commands += $$escape_expand(\\n\\t)set QT_PLUGIN_PATH=$$shadowed($$dirname(_QMAKE_CONF_))/plugins;$$[QT_INSTALL_PLUGINS];$(QT_PLUGIN_PATH)
runtarget.commands += $$escape_expand(\\n\\t)set QML2_IMPORT_PATH=$$shadowed($$dirname(_QMAKE_CONF_))/qml;$$[QT_INSTALL_QML];$(QML2_IMPORT_PATH) runtarget.commands += $$escape_expand(\\n\\t)set QML2_IMPORT_PATH=$$shadowed($$dirname(_QMAKE_CONF_))/qml;$$[QT_INSTALL_QML];$(QML2_IMPORT_PATH)
!isEmpty(LOGGING_RULES): runtarget.commands += $$escape_expand(\\n\\t)set \"QT_LOGGING_RULES=$$LOGGING_RULES\" !isEmpty(LOGGING_RULES): runtarget.commands += $$escape_expand(\\n\\t)set \"QT_LOGGING_RULES=$$LOGGING_RULES\"
runtarget.commands += $$escape_expand(\\n\\t)if exist $${outdir_helper}\\fail del $${outdir_helper}\\fail runtarget.commands += $$escape_expand(\\n\\t)if exist $${outdir_helper}\\fail del $${outdir_helper}\\fail
runtarget.commands += $$escape_expand(\\n\\t)start /w call $(DESTDIR_TARGET) ^> $${outdir_helper}\\test.log ^|^| echo FAIL ^> $${outdir_helper}\\fail ^& exit 0 runtarget.commands += $$escape_expand(\\n\\t)start /w call $(DESTDIR_TARGET) ^> $${outdir_helper}\\test.log ^|^| echo FAIL ^> $${outdir_helper}\\fail ^& exit 0
runtarget.commands += $$escape_expand(\\n\\t)type $${outdir_helper}\\test.log runtarget.commands += $$escape_expand(\\n\\t)type $${outdir_helper}\\test.log
runtarget.commands += $$escape_expand(\\n\\t)if exist $${outdir_helper}\\fail exit 42 runtarget.commands += $$escape_expand(\\n\\t)if exist $${outdir_helper}\\fail exit 42
QMAKE_EXTRA_TARGETS += runtarget QMAKE_EXTRA_TARGETS += runtarget
} else { } else {
win32-g++: QMAKE_DIRLIST_SEP = ";" win32-g++: QMAKE_DIRLIST_SEP = ";"
runtarget.commands += export PATH=\"$$shell_path($$shadowed($$dirname(_QMAKE_CONF_))/bin):$$shell_path($$[QT_INSTALL_BINS]):$${LITERAL_DOLLAR}$${LITERAL_DOLLAR}PATH\" runtarget.commands += export PATH=\"$$shell_path($$shadowed($$dirname(_QMAKE_CONF_))/bin):$$shell_path($$[QT_INSTALL_BINS]):$${LITERAL_DOLLAR}$${LITERAL_DOLLAR}PATH\"
runtarget.commands += $$escape_expand(\\n\\t)export QT_PLUGIN_PATH=\"$$shadowed($$dirname(_QMAKE_CONF_))/plugins$${QMAKE_DIRLIST_SEP}$$[QT_INSTALL_PLUGINS]$${QMAKE_DIRLIST_SEP}$(QT_PLUGIN_PATH)\" runtarget.commands += $$escape_expand(\\n\\t)export QT_PLUGIN_PATH=\"$$shadowed($$dirname(_QMAKE_CONF_))/plugins$${QMAKE_DIRLIST_SEP}$$[QT_INSTALL_PLUGINS]$${QMAKE_DIRLIST_SEP}$(QT_PLUGIN_PATH)\"
runtarget.commands += $$escape_expand(\\n\\t)export QML2_IMPORT_PATH=\"$$shadowed($$dirname(_QMAKE_CONF_))/qml$${QMAKE_DIRLIST_SEP}$$[QT_INSTALL_QML]$${QMAKE_DIRLIST_SEP}$(QML2_IMPORT_PATH)\" runtarget.commands += $$escape_expand(\\n\\t)export QML2_IMPORT_PATH=\"$$shadowed($$dirname(_QMAKE_CONF_))/qml$${QMAKE_DIRLIST_SEP}$$[QT_INSTALL_QML]$${QMAKE_DIRLIST_SEP}$(QML2_IMPORT_PATH)\"
!isEmpty(LOGGING_RULES): runtarget.commands += $$escape_expand(\\n\\t)export QT_LOGGING_RULES=\"$$LOGGING_RULES\" !isEmpty(LOGGING_RULES): runtarget.commands += $$escape_expand(\\n\\t)export QT_LOGGING_RULES=\"$$LOGGING_RULES\"
win32-g++: QMAKE_DIRLIST_SEP = ":" win32-g++: QMAKE_DIRLIST_SEP = ":"
linux|win32-g++ { linux|win32-g++ {
runtarget.commands += $$escape_expand(\\n\\t)export LD_LIBRARY_PATH=\"$$shadowed($$dirname(_QMAKE_CONF_))/lib$${QMAKE_DIRLIST_SEP}$$[QT_INSTALL_LIBS]$${QMAKE_DIRLIST_SEP}$(LD_LIBRARY_PATH)\" runtarget.commands += $$escape_expand(\\n\\t)export LD_LIBRARY_PATH=\"$$shadowed($$dirname(_QMAKE_CONF_))/lib$${QMAKE_DIRLIST_SEP}$$[QT_INSTALL_LIBS]$${QMAKE_DIRLIST_SEP}$(LD_LIBRARY_PATH)\"
runtarget.commands += $$escape_expand(\\n\\t)export QT_QPA_PLATFORM=minimal runtarget.commands += $$escape_expand(\\n\\t)export QT_QPA_PLATFORM=minimal
} else:mac { } else:mac {
runtarget.commands += $$escape_expand(\\n\\t)export DYLD_LIBRARY_PATH=\"$$shadowed($$dirname(_QMAKE_CONF_))/lib:$$[QT_INSTALL_LIBS]:$(DYLD_LIBRARY_PATH)\" runtarget.commands += $$escape_expand(\\n\\t)export DYLD_LIBRARY_PATH=\"$$shadowed($$dirname(_QMAKE_CONF_))/lib:$$[QT_INSTALL_LIBS]:$(DYLD_LIBRARY_PATH)\"
runtarget.commands += $$escape_expand(\\n\\t)export DYLD_FRAMEWORK_PATH=\"$$shadowed($$dirname(_QMAKE_CONF_))/lib:$$[QT_INSTALL_LIBS]:$(DYLD_FRAMEWORK_PATH)\" runtarget.commands += $$escape_expand(\\n\\t)export DYLD_FRAMEWORK_PATH=\"$$shadowed($$dirname(_QMAKE_CONF_))/lib:$$[QT_INSTALL_LIBS]:$(DYLD_FRAMEWORK_PATH)\"
}
runtarget.target = run-tests
win32-g++ {
!compat_test: runtarget.depends += $(DESTDIR_TARGET)
runtarget.commands += $$escape_expand(\\n\\t)./$(DESTDIR_TARGET)
} else {
!compat_test: runtarget.depends += $(TARGET)
runtarget.commands += $$escape_expand(\\n\\t)./$(TARGET)
}
QMAKE_EXTRA_TARGETS += runtarget
} }
runtarget.target = run-tests
win32-g++ {
!compat_test: runtarget.depends += $(DESTDIR_TARGET)
runtarget.commands += $$escape_expand(\\n\\t)./$(DESTDIR_TARGET)
} else {
!compat_test: runtarget.depends += $(TARGET)
runtarget.commands += $$escape_expand(\\n\\t)./$(TARGET)
}
QMAKE_EXTRA_TARGETS += runtarget
}
} }
INCLUDEPATH += $$PWD/../common INCLUDEPATH += $$PWD/../common
@ -57,6 +57,7 @@ QT += nut
CONFIG += testcase CONFIG += testcase
DEFINES += NUT_PATH=\\\"$$PWD/../../\\\" DEFINES += NUT_PATH=\\\"$$PWD/../../\\\"
DEFINES += NUT_PRINT_DEBUG_INFO
runtarget.target = run-tests runtarget.target = run-tests
runtarget.CONFIG = recursive runtarget.CONFIG = recursive

View File

@ -6,11 +6,17 @@
#include <QtNut/table.h> #include <QtNut/table.h>
#include <QtNut/database.h> #include <QtNut/database.h>
#include <QtNut/databasemodel.h> #include <QtNut/databasemodel.h>
#include <QSharedPointer>
#ifdef NUT_NAMESPACE #ifdef NUT_NAMESPACE
using namespace NUT_NAMESPACE; using namespace NUT_NAMESPACE;
#endif #endif
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
Q_MOC_INCLUDE("comment.h")
Q_MOC_INCLUDE("score.h")
#endif
class Comment; class Comment;
class Score; class Score;
class Post : public Table class Post : public Table

View File

@ -2,7 +2,7 @@
#include "user.h" #include "user.h"
#include "post.h" #include "post.h"
Score::Score(QObject *parent) : Nut::Table(parent) Score::Score(QObject *parent) : NUT_WRAP_NAMESPACE(Table)(parent)
{ {
} }

View File

@ -3,10 +3,17 @@
#include <QUuid> #include <QUuid>
#include <QtNut/table.h> #include <QtNut/table.h>
#include <QSharedPointer>
#include <QMetaType>
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
Q_MOC_INCLUDE("user.h")
Q_MOC_INCLUDE("post.h")
#endif
class User; class User;
class Post; class Post;
class Score : public Nut::Table class Score : public NUT_WRAP_NAMESPACE(Table)
{ {
Q_OBJECT Q_OBJECT
@ -15,6 +22,8 @@ class Score : public Nut::Table
NUT_DECLARE_FIELD(int, score, score, setScore) NUT_DECLARE_FIELD(int, score, score, setScore)
NUT_DECLARE_FIELD(int, condition, condition, setCondition)
NUT_FOREIGN_KEY_DECLARE(Post, int, post, post, setPost) NUT_FOREIGN_KEY_DECLARE(Post, int, post, post, setPost)
NUT_FOREIGN_KEY_DECLARE(User, QUuid, author, author, setAuthor) NUT_FOREIGN_KEY_DECLARE(User, QUuid, author, author, setAuthor)

View File

@ -0,0 +1,4 @@
#define DRIVER QStringLiteral("QSQLITE")
#define HOST QString()
#define USERNAME QString()
#define PASSWORD QString()

View File

@ -0,0 +1,14 @@
#include <QtGlobal>
#ifdef DATABASE
#undef DATABASE
#endif
#define DATABASE \
QStringLiteral("DRIVER={SQL Server Native Client 11.0};Server=localhost;DATABASE=nut_test_%1_db;UID=sa;PWD=NUT_sa_PASS_1_???;") \
.arg(QString::fromUtf8(metaObject()->className()).toLower())
#define DRIVER QStringLiteral("QODBC")
#define HOST QLatin1String("")
#define USERNAME QLatin1String("")
#define PASSWORD QLatin1String("")

View File

@ -0,0 +1,4 @@
#define DRIVER QStringLiteral("QMYSQL")
#define HOST QStringLiteral("localhost")
#define USERNAME QStringLiteral("root")
#define PASSWORD QStringLiteral("root")

View File

@ -0,0 +1,4 @@
#define DRIVER QStringLiteral("QPSQL")
#define HOST QStringLiteral("localhost")
#define USERNAME QStringLiteral("postgres")
#define PASSWORD QStringLiteral("postgres")

View File

@ -0,0 +1,4 @@
#define DRIVER QStringLiteral("QSQLITE")
#define HOST QString()
#define USERNAME QString()
#define PASSWORD QString()

View File

@ -3,9 +3,9 @@
#include "user.h" #include "user.h"
User::User(QObject *tableSet) : Table(tableSet), User::User(QObject *tableSet) : Nut::Table(tableSet),
m_comments(new TableSet<Comment>(this)), m_comments(new Nut::TableSet<Comment>(this)),
m_scores(new TableSet<Score>(this)) m_scores(new Nut::TableSet<Score>(this))
{ {
init(); init();
} }

View File

@ -6,14 +6,20 @@
#include <QtCore/QUuid> #include <QtCore/QUuid>
#include <QtCore/QString> #include <QtCore/QString>
#include <QSharedPointer>
#ifdef NUT_NAMESPACE #ifdef NUT_NAMESPACE
using namespace NUT_NAMESPACE; using namespace NUT_NAMESPACE;
#endif #endif
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
Q_MOC_INCLUDE("comment.h")
Q_MOC_INCLUDE("score.h")
#endif
class Comment; class Comment;
class Score; class Score;
class User : public Nut::Table class User : public NUT_WRAP_NAMESPACE(Table)
{ {
Q_OBJECT Q_OBJECT

View File

@ -7,6 +7,13 @@
using namespace NUT_NAMESPACE; using namespace NUT_NAMESPACE;
#endif #endif
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
Q_MOC_INCLUDE("user.h")
Q_MOC_INCLUDE("post.h")
Q_MOC_INCLUDE("score.h")
Q_MOC_INCLUDE("comment.h")
#endif
class Post; class Post;
class Comment; class Comment;
class User; class User;

Some files were not shown because too many files have changed in this diff Show More