option to create new buckets / sub-buckets
This commit is contained in:
parent
4394c8a50a
commit
98b78ab1e6
89
main.go
89
main.go
@ -78,6 +78,79 @@ func withBrowse_ReadOnly(b_ref ObjectReference, browse []string, fn func(db *bol
|
||||
})
|
||||
}
|
||||
|
||||
func err2triple(err error) (int64, *C.char, int) {
|
||||
if err != nil {
|
||||
msg := err.Error()
|
||||
return ERROR_AND_STOP_CALLING, C.CString(msg), len(msg)
|
||||
}
|
||||
|
||||
return FINISHED_OK, nil, 0
|
||||
}
|
||||
|
||||
//export Bolt_CreateBucket
|
||||
func Bolt_CreateBucket(b_ref ObjectReference, browse []string, newBucket string) (int64, *C.char, int) {
|
||||
err := withBoltDBReference(b_ref, func(db *bolt.DB) error {
|
||||
return db.Update(func(tx *bolt.Tx) error {
|
||||
|
||||
if len(browse) == 0 {
|
||||
// Top-level bucket
|
||||
_, err := tx.CreateBucket([]byte(newBucket))
|
||||
return err
|
||||
|
||||
} else {
|
||||
// Deeper bucket
|
||||
bucket := tx.Bucket([]byte(browse[0]))
|
||||
if bucket == nil {
|
||||
return errors.New("Unknown bucket")
|
||||
}
|
||||
for i := 1; i < len(browse); i += 1 {
|
||||
bucket = bucket.Bucket([]byte(browse[i]))
|
||||
if bucket == nil {
|
||||
return errors.New("Unknown bucket")
|
||||
}
|
||||
}
|
||||
|
||||
// Walked the bucket chain, now create the new bucket
|
||||
_, err := bucket.CreateBucket([]byte(newBucket))
|
||||
return err
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return err2triple(err)
|
||||
}
|
||||
|
||||
//export Bolt_DeleteBucket
|
||||
func Bolt_DeleteBucket(b_ref ObjectReference, browse []string, delBucket string) (int64, *C.char, int) {
|
||||
err := withBoltDBReference(b_ref, func(db *bolt.DB) error {
|
||||
return db.Update(func(tx *bolt.Tx) error {
|
||||
|
||||
if len(browse) == 0 {
|
||||
// Top-level bucket
|
||||
return tx.DeleteBucket([]byte(delBucket))
|
||||
|
||||
} else {
|
||||
// Deeper bucket
|
||||
bucket := tx.Bucket([]byte(browse[0]))
|
||||
if bucket == nil {
|
||||
return errors.New("Unknown bucket")
|
||||
}
|
||||
for i := 1; i < len(browse); i += 1 {
|
||||
bucket = bucket.Bucket([]byte(browse[i]))
|
||||
if bucket == nil {
|
||||
return errors.New("Unknown bucket")
|
||||
}
|
||||
}
|
||||
|
||||
// Walked the bucket chain, now delete the selected bucket
|
||||
return bucket.DeleteBucket([]byte(delBucket))
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return err2triple(err)
|
||||
}
|
||||
|
||||
type CallResponse struct {
|
||||
s string
|
||||
e error
|
||||
@ -94,7 +167,7 @@ func Bolt_DBStats(b ObjectReference) (int64, *C.char, int) {
|
||||
|
||||
jBytes, err := json.Marshal(stats)
|
||||
if err != nil {
|
||||
return ERROR_AND_STOP_CALLING, C.CString(err.Error()), len(err.Error())
|
||||
return err2triple(err)
|
||||
}
|
||||
|
||||
return REAL_MESSAGE, C.CString(string(jBytes)), len(jBytes)
|
||||
@ -110,12 +183,12 @@ func Bolt_BucketStats(b ObjectReference, browse []string) (int64, *C.char, int)
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return ERROR_AND_STOP_CALLING, C.CString(err.Error()), len(err.Error())
|
||||
return err2triple(err)
|
||||
}
|
||||
|
||||
jBytes, err := json.Marshal(stats)
|
||||
if err != nil {
|
||||
return ERROR_AND_STOP_CALLING, C.CString(err.Error()), len(err.Error())
|
||||
return err2triple(err)
|
||||
}
|
||||
|
||||
return REAL_MESSAGE, C.CString(string(jBytes)), len(jBytes)
|
||||
@ -224,7 +297,7 @@ func Bolt_GetItem(b ObjectReference, browse []string, key string) (int64, *C.cha
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return ERROR_AND_STOP_CALLING, C.CString(err.Error()), len(err.Error())
|
||||
return err2triple(err)
|
||||
}
|
||||
|
||||
return REAL_MESSAGE, ret, ret_len
|
||||
@ -234,20 +307,18 @@ func Bolt_GetItem(b ObjectReference, browse []string, key string) (int64, *C.cha
|
||||
func GetNext(oRef ObjectReference) (int64, *C.char, int) {
|
||||
pNC_Iface, ok := gms.Get(oRef)
|
||||
if !ok {
|
||||
msg := NullObjectReference.Error()
|
||||
return ERROR_AND_STOP_CALLING, C.CString(msg), len(msg)
|
||||
return err2triple(NullObjectReference)
|
||||
}
|
||||
|
||||
pNC, ok := pNC_Iface.(*NextCall)
|
||||
if !ok {
|
||||
msg := NullObjectReference.Error()
|
||||
return ERROR_AND_STOP_CALLING, C.CString(msg), len(msg)
|
||||
return err2triple(NullObjectReference)
|
||||
}
|
||||
|
||||
cr, ok := <-pNC.content
|
||||
if !ok {
|
||||
gms.Delete(oRef)
|
||||
return FINISHED_OK, nil, 0
|
||||
return err2triple(nil)
|
||||
}
|
||||
|
||||
if cr.e != nil {
|
||||
|
@ -29,6 +29,33 @@ static const int ERROR_AND_KEEP_CALLING = 101;
|
||||
static const int FINISHED_OK = 102;
|
||||
static const int REAL_MESSAGE = 103;
|
||||
|
||||
bool BoltDB::addBucket(QStringList bucketPath, QByteArray bucketName, QString& errorOut)
|
||||
{
|
||||
GoSliceManagedWrapper browse(&bucketPath);
|
||||
GoString bucketNameGS = Interop::toGoString_WeakRef(&bucketName);
|
||||
auto resp = ::Bolt_CreateBucket(this->gmsDbRef, browse.slice, bucketNameGS);
|
||||
|
||||
if (resp.r0 == ERROR_AND_STOP_CALLING) {
|
||||
errorOut = QString::fromUtf8(resp.r1, resp.r2);
|
||||
free(resp.r1);
|
||||
return false;
|
||||
|
||||
} else if (resp.r0 == FINISHED_OK) {
|
||||
return true;
|
||||
|
||||
} else {
|
||||
// ?? unreachable
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool BoltDB::deleteBucket(QStringList bucketPath, QByteArray bucketName, QString& errorOut)
|
||||
{
|
||||
errorOut = "Not implemented";
|
||||
return false; // not implemented
|
||||
}
|
||||
|
||||
bool BoltDB::listBucketsAtRoot(QString& errorOut, NameReciever cb)
|
||||
{
|
||||
auto listJob = ::Bolt_ListBucketsAtRoot(this->gmsDbRef);
|
||||
|
@ -20,6 +20,10 @@ public:
|
||||
|
||||
bool listBuckets(QStringList bucketPath, QString& errorOut, NameReciever cb);
|
||||
|
||||
bool addBucket(QStringList bucketPath, QByteArray bucketName, QString& errorOut);
|
||||
|
||||
bool deleteBucket(QStringList bucketPath, QByteArray bucketName, QString& errorOut);
|
||||
|
||||
bool listKeys(QStringList bucketPath, QString& errorOut, std::function<void(QByteArray, int64_t)> cb);
|
||||
|
||||
bool getData(QStringList bucketPath, QByteArray key, std::function<void(QByteArray)> onSuccess, std::function<void(QString)> onError);
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QJsonDocument>
|
||||
#include <QInputDialog>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
@ -17,10 +18,14 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
|
||||
databaseContext = new QMenu();
|
||||
databaseContext->addAction(ui->actionRefresh_buckets);
|
||||
databaseContext->addAction(ui->actionAdd_bucket);
|
||||
databaseContext->addSeparator();
|
||||
databaseContext->addAction(ui->actionDisconnect);
|
||||
|
||||
bucketContext = new QMenu();
|
||||
bucketContext->addAction(ui->actionRefresh_buckets);
|
||||
bucketContext->addAction(ui->actionAdd_bucket);
|
||||
bucketContext->addSeparator();
|
||||
bucketContext->addAction(ui->actionDelete_bucket);
|
||||
}
|
||||
|
||||
@ -302,3 +307,69 @@ void MainWindow::on_bucketData_doubleClicked(const QModelIndex &index)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
void MainWindow::on_actionAdd_bucket_triggered()
|
||||
{
|
||||
QTreeWidgetItem* itm = lastContextSelection;
|
||||
if (itm == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
QTreeWidgetItem* top = itm;
|
||||
QStringList browse;
|
||||
while(top->parent() != nullptr) {
|
||||
browse.push_front(top->text(0));
|
||||
top = top->parent();
|
||||
}
|
||||
|
||||
// Get BDB
|
||||
|
||||
auto *bdb = GET_BDB(top);
|
||||
|
||||
// Prompt for bucket name
|
||||
|
||||
QString name = QInputDialog::getText(this, tr("New bucket"), tr("Enter a key for the new bucket:"));
|
||||
if (name.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create
|
||||
QString err;
|
||||
if (! bdb->addBucket(browse, name.toUtf8(), err)) {
|
||||
QMessageBox qmb;
|
||||
qmb.setText(tr("Error creating bucket: %1").arg(err));
|
||||
qmb.exec();
|
||||
return;
|
||||
}
|
||||
|
||||
// Refresh bucket list
|
||||
refreshBucketTree(itm); // sub-tree only
|
||||
ui->bucketTree->expandItem(itm);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionDelete_bucket_triggered()
|
||||
{
|
||||
QTreeWidgetItem* itm = lastContextSelection;
|
||||
if (itm == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
QTreeWidgetItem* top = itm;
|
||||
QStringList browse;
|
||||
while(top->parent() != nullptr) {
|
||||
browse.push_front(top->text(0));
|
||||
top = top->parent();
|
||||
}
|
||||
|
||||
// Get BDB
|
||||
|
||||
auto *bdb = GET_BDB(top);
|
||||
|
||||
// Prompt for confirmation
|
||||
|
||||
if (QMessageBox::question(this, tr("Delete bucket"), tr("Are you sure you want to remove the bucket '%s'?").arg(itm->text(0)), QMessageBox::Yes, QMessageBox::Cancel) != QMessageBox::Yes) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -40,6 +40,10 @@ private slots:
|
||||
|
||||
void on_actionNew_database_triggered();
|
||||
|
||||
void on_actionAdd_bucket_triggered();
|
||||
|
||||
void on_actionDelete_bucket_triggered();
|
||||
|
||||
protected:
|
||||
void openDatabase(QString file);
|
||||
void refreshBucketTree(QTreeWidgetItem* top);
|
||||
|
@ -297,8 +297,9 @@
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDelete_bucket">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/rsrc/table_delete.png</normaloff>:/rsrc/table_delete.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete bucket</string>
|
||||
@ -320,7 +321,16 @@
|
||||
<normaloff>:/rsrc/database_add.png</normaloff>:/rsrc/database_add.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>New database...</string>
|
||||
<string>&New database...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAdd_bucket">
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/rsrc/table_add.png</normaloff>:/rsrc/table_add.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Add bucket...</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
|
@ -5,5 +5,7 @@
|
||||
<file>rsrc/information.png</file>
|
||||
<file>rsrc/database_lightning.png</file>
|
||||
<file>rsrc/database.png</file>
|
||||
<file>rsrc/table_add.png</file>
|
||||
<file>rsrc/table_delete.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
Loading…
Reference in New Issue
Block a user