mirror of
https://github.com/johndoe6345789/metabuilder.git
synced 2026-04-24 13:54:57 +00:00
code: qt6,frontends,qmldir (3 files)
This commit is contained in:
217
frontends/qt6/qmllib/dbal/DBALProvider.qml
Normal file
217
frontends/qt6/qmllib/dbal/DBALProvider.qml
Normal file
@@ -0,0 +1,217 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls.Material
|
||||
|
||||
/**
|
||||
* QML DBAL Client Component
|
||||
*
|
||||
* Provides database operations for QML UI components.
|
||||
* Wraps the C++ DBALClient for easy QML integration.
|
||||
*
|
||||
* Example:
|
||||
* ```qml
|
||||
* import "../qmllib/dbal"
|
||||
*
|
||||
* DBALProvider {
|
||||
* id: dbal
|
||||
* baseUrl: "http://localhost:3001/api/dbal"
|
||||
* tenantId: "default"
|
||||
*
|
||||
* onConnectedChanged: {
|
||||
* if (connected) {
|
||||
* loadUsers()
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* function loadUsers() {
|
||||
* dbal.list("User", { take: 20 }, function(result) {
|
||||
* userModel.clear()
|
||||
* for (var i = 0; i < result.items.length; i++) {
|
||||
* userModel.append(result.items[i])
|
||||
* }
|
||||
* })
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
Item {
|
||||
id: root
|
||||
|
||||
// Configuration
|
||||
property string baseUrl: "http://localhost:3001/api/dbal"
|
||||
property string tenantId: "default"
|
||||
property string authToken: ""
|
||||
|
||||
// State
|
||||
property bool connected: false
|
||||
property bool loading: false
|
||||
property string lastError: ""
|
||||
|
||||
// Signals
|
||||
signal errorOccurred(string message)
|
||||
signal operationCompleted(string operation, var result)
|
||||
|
||||
// Internal HTTP client (simplified - would use XMLHttpRequest in real impl)
|
||||
QtObject {
|
||||
id: internal
|
||||
|
||||
function request(method, endpoint, body, callback) {
|
||||
root.loading = true
|
||||
root.lastError = ""
|
||||
|
||||
var xhr = new XMLHttpRequest()
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === XMLHttpRequest.DONE) {
|
||||
root.loading = false
|
||||
|
||||
if (xhr.status >= 200 && xhr.status < 300) {
|
||||
try {
|
||||
var result = JSON.parse(xhr.responseText)
|
||||
if (callback) callback(result, null)
|
||||
root.operationCompleted(endpoint, result)
|
||||
} catch (e) {
|
||||
var err = "Failed to parse response: " + e.message
|
||||
root.lastError = err
|
||||
root.errorOccurred(err)
|
||||
if (callback) callback(null, err)
|
||||
}
|
||||
} else {
|
||||
var error = xhr.statusText || "Request failed"
|
||||
root.lastError = error
|
||||
root.errorOccurred(error)
|
||||
if (callback) callback(null, error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var url = root.baseUrl + endpoint
|
||||
xhr.open(method, url)
|
||||
xhr.setRequestHeader("Content-Type", "application/json")
|
||||
xhr.setRequestHeader("X-Tenant-ID", root.tenantId)
|
||||
|
||||
if (root.authToken) {
|
||||
xhr.setRequestHeader("Authorization", "Bearer " + root.authToken)
|
||||
}
|
||||
|
||||
if (body) {
|
||||
xhr.send(JSON.stringify(body))
|
||||
} else {
|
||||
xhr.send()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Public API
|
||||
|
||||
/**
|
||||
* Create a new record
|
||||
* @param {string} entity - Entity name (e.g., "User", "AuditLog")
|
||||
* @param {object} data - Record data
|
||||
* @param {function} callback - Callback(result, error)
|
||||
*/
|
||||
function create(entity, data, callback) {
|
||||
internal.request("POST", "/create", {
|
||||
entity: entity,
|
||||
data: data,
|
||||
tenantId: tenantId
|
||||
}, callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a single record by ID
|
||||
* @param {string} entity - Entity name
|
||||
* @param {string} id - Record ID
|
||||
* @param {function} callback - Callback(result, error)
|
||||
*/
|
||||
function read(entity, id, callback) {
|
||||
internal.request("GET", "/read/" + entity + "/" + id, null, callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing record
|
||||
* @param {string} entity - Entity name
|
||||
* @param {string} id - Record ID
|
||||
* @param {object} data - Updated fields
|
||||
* @param {function} callback - Callback(result, error)
|
||||
*/
|
||||
function update(entity, id, data, callback) {
|
||||
internal.request("PUT", "/update", {
|
||||
entity: entity,
|
||||
id: id,
|
||||
data: data
|
||||
}, callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a record
|
||||
* @param {string} entity - Entity name
|
||||
* @param {string} id - Record ID
|
||||
* @param {function} callback - Callback(success, error)
|
||||
*/
|
||||
function remove(entity, id, callback) {
|
||||
internal.request("DELETE", "/delete/" + entity + "/" + id, null, callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* List records with pagination and filtering
|
||||
* @param {string} entity - Entity name
|
||||
* @param {object} options - { take, skip, where, orderBy }
|
||||
* @param {function} callback - Callback({ items, total }, error)
|
||||
*/
|
||||
function list(entity, options, callback) {
|
||||
var body = {
|
||||
entity: entity,
|
||||
tenantId: tenantId
|
||||
}
|
||||
|
||||
if (options.take !== undefined) body.take = options.take
|
||||
if (options.skip !== undefined) body.skip = options.skip
|
||||
if (options.where !== undefined) body.where = options.where
|
||||
if (options.orderBy !== undefined) body.orderBy = options.orderBy
|
||||
|
||||
internal.request("POST", "/list", body, callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Find first record matching filter
|
||||
* @param {string} entity - Entity name
|
||||
* @param {object} filter - Filter criteria
|
||||
* @param {function} callback - Callback(result, error)
|
||||
*/
|
||||
function findFirst(entity, filter, callback) {
|
||||
internal.request("POST", "/findFirst", {
|
||||
entity: entity,
|
||||
tenantId: tenantId,
|
||||
filter: filter
|
||||
}, callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a named operation
|
||||
* @param {string} operation - Operation name
|
||||
* @param {object} params - Operation parameters
|
||||
* @param {function} callback - Callback(result, error)
|
||||
*/
|
||||
function execute(operation, params, callback) {
|
||||
internal.request("POST", "/execute", {
|
||||
operation: operation,
|
||||
params: params,
|
||||
tenantId: tenantId
|
||||
}, callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check connection to DBAL backend
|
||||
* @param {function} callback - Callback(success, error)
|
||||
*/
|
||||
function ping(callback) {
|
||||
internal.request("GET", "/ping", null, function(result, error) {
|
||||
root.connected = !error
|
||||
if (callback) callback(!error, error)
|
||||
})
|
||||
}
|
||||
|
||||
// Auto-ping on component ready
|
||||
Component.onCompleted: {
|
||||
ping()
|
||||
}
|
||||
}
|
||||
3
frontends/qt6/qmllib/dbal/qmldir
Normal file
3
frontends/qt6/qmllib/dbal/qmldir
Normal file
@@ -0,0 +1,3 @@
|
||||
module dbal
|
||||
|
||||
DBALProvider 1.0 DBALProvider.qml
|
||||
199
frontends/qt6/src/DBALClient.cpp
Normal file
199
frontends/qt6/src/DBALClient.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
#include "DBALClient.h"
|
||||
#include <QJsonDocument>
|
||||
#include <QNetworkRequest>
|
||||
#include <QUrl>
|
||||
#include <QUrlQuery>
|
||||
|
||||
DBALClient::DBALClient(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_networkManager(new QNetworkAccessManager(this))
|
||||
, m_baseUrl("http://localhost:3001/api/dbal")
|
||||
, m_tenantId("default")
|
||||
, m_connected(false)
|
||||
{
|
||||
connect(m_networkManager, &QNetworkAccessManager::finished,
|
||||
this, &DBALClient::handleNetworkReply);
|
||||
}
|
||||
|
||||
DBALClient::~DBALClient()
|
||||
{
|
||||
// Cleanup pending callbacks
|
||||
m_pendingCallbacks.clear();
|
||||
}
|
||||
|
||||
void DBALClient::setBaseUrl(const QString &url)
|
||||
{
|
||||
if (m_baseUrl != url) {
|
||||
m_baseUrl = url;
|
||||
emit baseUrlChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void DBALClient::setTenantId(const QString &id)
|
||||
{
|
||||
if (m_tenantId != id) {
|
||||
m_tenantId = id;
|
||||
emit tenantIdChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void DBALClient::setAuthToken(const QString &token)
|
||||
{
|
||||
if (m_authToken != token) {
|
||||
m_authToken = token;
|
||||
emit authTokenChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void DBALClient::setError(const QString &error)
|
||||
{
|
||||
m_lastError = error;
|
||||
emit errorOccurred(error);
|
||||
}
|
||||
|
||||
void DBALClient::sendRequest(const QString &method, const QString &endpoint,
|
||||
const QJsonObject &body, const QJSValue &callback)
|
||||
{
|
||||
QUrl url(m_baseUrl + endpoint);
|
||||
QNetworkRequest request(url);
|
||||
|
||||
// Set headers
|
||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
request.setRawHeader("X-Tenant-ID", m_tenantId.toUtf8());
|
||||
|
||||
if (!m_authToken.isEmpty()) {
|
||||
request.setRawHeader("Authorization", ("Bearer " + m_authToken).toUtf8());
|
||||
}
|
||||
|
||||
QNetworkReply *reply = nullptr;
|
||||
QByteArray jsonData = QJsonDocument(body).toJson(QJsonDocument::Compact);
|
||||
|
||||
if (method == "GET") {
|
||||
reply = m_networkManager->get(request);
|
||||
} else if (method == "POST") {
|
||||
reply = m_networkManager->post(request, jsonData);
|
||||
} else if (method == "PUT") {
|
||||
reply = m_networkManager->put(request, jsonData);
|
||||
} else if (method == "DELETE") {
|
||||
reply = m_networkManager->deleteResource(request);
|
||||
}
|
||||
|
||||
if (reply && callback.isCallable()) {
|
||||
m_pendingCallbacks[reply] = callback;
|
||||
}
|
||||
}
|
||||
|
||||
void DBALClient::handleNetworkReply(QNetworkReply *reply)
|
||||
{
|
||||
reply->deleteLater();
|
||||
|
||||
QJSValue callback = m_pendingCallbacks.take(reply);
|
||||
|
||||
if (reply->error() != QNetworkReply::NoError) {
|
||||
setError(reply->errorString());
|
||||
|
||||
if (callback.isCallable()) {
|
||||
QJSValueList args;
|
||||
args << QJSValue::NullValue;
|
||||
args << reply->errorString();
|
||||
callback.call(args);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray data = reply->readAll();
|
||||
QJsonDocument doc = QJsonDocument::fromJson(data);
|
||||
|
||||
if (callback.isCallable()) {
|
||||
QJSValueList args;
|
||||
// Convert QJsonObject to QJSValue through QVariant
|
||||
if (doc.isObject()) {
|
||||
args << callback.engine()->toScriptValue(doc.object().toVariantMap());
|
||||
} else if (doc.isArray()) {
|
||||
args << callback.engine()->toScriptValue(doc.array().toVariantList());
|
||||
} else {
|
||||
args << QJSValue::NullValue;
|
||||
}
|
||||
callback.call(args);
|
||||
}
|
||||
|
||||
// Update connected status
|
||||
if (!m_connected) {
|
||||
m_connected = true;
|
||||
emit connectedChanged();
|
||||
}
|
||||
}
|
||||
|
||||
// CRUD Operations
|
||||
|
||||
void DBALClient::create(const QString &entity, const QJsonObject &data, const QJSValue &callback)
|
||||
{
|
||||
QJsonObject body;
|
||||
body["entity"] = entity;
|
||||
body["data"] = data;
|
||||
body["tenantId"] = m_tenantId;
|
||||
|
||||
sendRequest("POST", "/create", body, callback);
|
||||
}
|
||||
|
||||
void DBALClient::read(const QString &entity, const QString &id, const QJSValue &callback)
|
||||
{
|
||||
QString endpoint = QString("/read/%1/%2").arg(entity, id);
|
||||
sendRequest("GET", endpoint, QJsonObject(), callback);
|
||||
}
|
||||
|
||||
void DBALClient::update(const QString &entity, const QString &id,
|
||||
const QJsonObject &data, const QJSValue &callback)
|
||||
{
|
||||
QJsonObject body;
|
||||
body["entity"] = entity;
|
||||
body["id"] = id;
|
||||
body["data"] = data;
|
||||
|
||||
sendRequest("PUT", "/update", body, callback);
|
||||
}
|
||||
|
||||
void DBALClient::remove(const QString &entity, const QString &id, const QJSValue &callback)
|
||||
{
|
||||
QString endpoint = QString("/delete/%1/%2").arg(entity, id);
|
||||
sendRequest("DELETE", endpoint, QJsonObject(), callback);
|
||||
}
|
||||
|
||||
void DBALClient::list(const QString &entity, const QJsonObject &options, const QJSValue &callback)
|
||||
{
|
||||
QJsonObject body;
|
||||
body["entity"] = entity;
|
||||
body["tenantId"] = m_tenantId;
|
||||
|
||||
if (options.contains("take")) body["take"] = options["take"];
|
||||
if (options.contains("skip")) body["skip"] = options["skip"];
|
||||
if (options.contains("where")) body["where"] = options["where"];
|
||||
if (options.contains("orderBy")) body["orderBy"] = options["orderBy"];
|
||||
|
||||
sendRequest("POST", "/list", body, callback);
|
||||
}
|
||||
|
||||
void DBALClient::findFirst(const QString &entity, const QJsonObject &filter, const QJSValue &callback)
|
||||
{
|
||||
QJsonObject body;
|
||||
body["entity"] = entity;
|
||||
body["tenantId"] = m_tenantId;
|
||||
body["filter"] = filter;
|
||||
|
||||
sendRequest("POST", "/findFirst", body, callback);
|
||||
}
|
||||
|
||||
void DBALClient::execute(const QString &operation, const QJsonObject ¶ms, const QJSValue &callback)
|
||||
{
|
||||
QJsonObject body;
|
||||
body["operation"] = operation;
|
||||
body["params"] = params;
|
||||
body["tenantId"] = m_tenantId;
|
||||
|
||||
sendRequest("POST", "/execute", body, callback);
|
||||
}
|
||||
|
||||
void DBALClient::ping()
|
||||
{
|
||||
sendRequest("GET", "/ping", QJsonObject(), QJSValue());
|
||||
}
|
||||
Reference in New Issue
Block a user