Kstars

catalogsdb.h
1/*
2 SPDX-FileCopyrightText: 2021 Valentin Boettcher <hiro at protagon.space; @hiro98:tchncs.de>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5*/
6
7#pragma once
8
9#include <QSqlDatabase>
10#include <QSqlError>
11#include <exception>
12#include <list>
13#include <QString>
14#include <QList>
15#include <catalogsdb_debug.h>
16#include <QSqlQuery>
17#include <QMutex>
18#include <QObject>
19#include <QThread>
20
21#include "polyfills/qstring_hash.h"
22#include <unordered_map>
23#include <queue>
24
25#include <unordered_set>
26#include <utility>
27#include "catalogobject.h"
28#include "nan.h"
29#include "typedef.h"
30
31namespace CatalogsDB
32{
33/**
34 * A simple struct to hold information about catalogs.
35 */
36struct Catalog
37{
38 /**
39 * The catalog id.
40 */
41 int id = -1;
42
43 /**
44 * The catalog mame.
45 */
46 QString name = "Unknown";
47
48 /**
49 * The precedence level of a catalog.
50 *
51 * If doublicate objects exist in the database, the one from the
52 * catalog with the highest precedence winns.
53 */
54 double precedence = 0;
55
56 /**
57 * The author of the catalog.
58 */
60
61 /**
62 * The catalog source.
63 */
65
66 /**
67 * A (short) description for the catalog.
68 * QT html is allowed.
69 */
71
72 /**
73 * Wether the catalog is mutable.
74 */
75 bool mut = false;
76
77 /**
78 * Wether the catalog is enabled.
79 */
80 bool enabled = false;
81
82 /**
83 * The catalog version.
84 */
85 int version = -1;
86
87 /**
88 * The catalog color in the form `[default color];[scheme file
89 * name];[color]...`.
90 */
92
93 /**
94 * The catalog license.
95 */
97
98 /**
99 * The catalog maintainer.
100 */
102
103 /**
104 * Build time of the catalog. Usually only catalogs with the same
105 * timestamp can be considered dedublicated.
106 *
107 * A `null` timestamp indicates that the catalog has not been
108 * built by the catalog repository.
109 */
111};
112
113const Catalog cat_defaults{};
114
115/**
116 * Holds statistical information about the objects in a catalog.
117 */
119{
120 std::map<SkyObject::TYPE, int> object_counts;
121 int total_count = 0;
122};
123
124const QString db_file_extension = "kscat";
125constexpr int application_id = 0x4d515158;
126constexpr int custom_cat_min_id = 1000;
127constexpr int user_catalog_id = 0;
128constexpr float default_maglim = 99;
129const QString flux_unit = "mag";
130const QString flux_frequency = "400 nm";
131using CatalogColorMap = std::map<QString, QColor>;
132using ColorMap = std::map<int, CatalogColorMap>;
133using CatalogObjectList = std::list<CatalogObject>;
134using CatalogObjectVector = std::vector<CatalogObject>;
135
136/**
137 * \returns A hash table of the form `color scheme: color` by
138 * parsing a string of the form `[default color];[scheme file
139 * name];[color]...`.
140 */
141CatalogColorMap parse_color_string(const QString &str);
142
143/**
144 * \returns A color string of the form`[default color];[scheme file
145 * name];[color]...`.
146 *
147 * The inverse of `CatalogsDB::parse_color_string`.
148 */
149QString to_color_string(CatalogColorMap colors);
150
151/**
152 * Manages the catalog database and provides an interface to provide an
153 * interface to query and modify the database. For more information on
154 * how the catalog database system works see the KStars Handbook.
155 *
156 * The class manages a database connection which is assumed to be
157 * working (invariant). If the database can't be accessed a
158 * DatabaseError is thrown upon construction. The manager is designed
159 * to hold as little state as possible because the database should be
160 * the single source of truth. Prepared statements are made class
161 * members, only if they are performance critical.
162 *
163 * Most methods in this class are thread safe.
164 *
165 * The intention is that you access a/the catalogs database directly
166 * locally in the code where objects from the database are required and
167 * not through layers of references and pointers.
168 *
169 * The main DSO database can be accessed as follows:
170 * ```cpp
171 * CatalogsDB::DBManager manager{ CatalogsDB::dso_db_path() };
172 * for(auto& o : manager.get_objects(10)) {
173 * // do something
174 * }
175 * ```
176 *
177 * To query the database, first check if the required query is already
178 * hardcoded into the `DBManager`. If this is not the case you can either
179 * add it (if it is performance critical and executed frequently) or use
180 * `DBManager::general_master_query` to construct a custom `SQL` query.
181 */
183{
184 public:
185 /**
186 * Constructs a database manager from the \p filename which is
187 * resolved to a path in the kstars data directory.
188 *
189 * The constructor resolves the path to the database, opens it
190 * (throws if that does not work), checks the database version
191 * (throws if that does not match), initializes the database,
192 * registers the user catalog and updates the all_catalog_view.
193 */
194 DBManager(const QString &filename);
195 DBManager(const DBManager &other);
196
197 DBManager &operator=(DBManager other)
198 {
199 using std::swap;
200 DBManager tmp{ other };
201
202 m_db_file = other.m_db_file;
203 swap(m_db, other.m_db);
204 swap(m_q_cat_by_id, other.m_q_cat_by_id);
205 swap(m_q_obj_by_trixel, other.m_q_obj_by_trixel);
206 swap(m_q_obj_by_trixel_no_nulls, other.m_q_obj_by_trixel_no_nulls);
207 swap(m_q_obj_by_trixel_null_mag, other.m_q_obj_by_trixel_null_mag);
208 swap(m_q_obj_by_name, other.m_q_obj_by_name);
209 swap(m_q_obj_by_name_exact, other.m_q_obj_by_name_exact);
210 swap(m_q_obj_by_lim, other.m_q_obj_by_lim);
211 swap(m_q_obj_by_maglim, other.m_q_obj_by_maglim);
212 swap(m_q_obj_by_maglim_and_type, other.m_q_obj_by_maglim_and_type);
213 swap(m_q_obj_by_oid, other.m_q_obj_by_oid);
214
215 return *this;
216 };
217
218 ~DBManager()
219 {
220 m_db.commit();
221 m_db.close();
222 }
223
224 /**
225 * @return the filename of the database
226 */
227 const QString &db_file_name() const { return m_db_file; };
228
229 /**
230 * @return wether the catalog with the \p id has been found and
231 * the catalog.
232 *
233 * @todo use std::optional when transitioning to c++17
234 */
235 const std::pair<bool, Catalog> get_catalog(const int id);
236
237 /**
238 * \return a vector with all catalogs from the database. If \p
239 * include_disabled is `true`, disabled catalogs will be included.
240 */
241 const std::vector<Catalog> get_catalogs(bool include_disabled = false);
242
243 /**
244 * @return true if the catalog with \p id exists
245 *
246 * @todo use std::optional when transitioning to c++17
247 */
248 bool catalog_exists(const int id);
249
250 /**
251 * @return return a vector of objects in the trixel with \p id.
252 */
253 inline CatalogObjectVector get_objects_in_trixel(const int trixel) {
254 return _get_objects_in_trixel_generic(m_q_obj_by_trixel, trixel);
255 }
256
257 /**
258 * @return return a vector of objects of known mag in the trixel with \p id.
259 */
260 inline CatalogObjectVector get_objects_in_trixel_no_nulls(const int trixel) {
261 return _get_objects_in_trixel_generic(m_q_obj_by_trixel_no_nulls, trixel);
262 }
263
264 /**
265 * @return return a vector of objects of unknown mag in the trixel with \p id.
266 */
267 inline CatalogObjectVector get_objects_in_trixel_null_mag(const int trixel) {
268 return _get_objects_in_trixel_generic(m_q_obj_by_trixel_null_mag, trixel);
269 }
270
271 /**
272 * \brief Find an objects by name.
273 *
274 * This will search the `name`, `long_name` and `catalog_identifier`
275 * fields in all enabled catalogs for \p `name` and then return a new
276 * instance of `CatalogObject` sourced from the master catalog.
277 *
278 * \param limit Upper limit to the quanitity of results. `-1` means "no
279 * limit"
280 * \param exactMatchOnly If true, the supplied name must match exactly
281 *
282 * \return a list of matching objects
283 */
284 CatalogObjectList find_objects_by_name(const QString &name, const int limit = -1,
285 const bool exactMatchOnly = false);
286
287 /**
288 * \brief Find an objects by name in the catalog with \p `catalog_id`.
289 *
290 * \return a list of matching objects
291 */
292 CatalogObjectList find_objects_by_name(const int catalog_id, const QString &name,
293 const int limit = -1);
294
295 /**
296 * \brief Find an objects by searching the name four wildcard. See
297 * the LIKE sqlite statement.
298 *
299 * \return a list of matching objects
300 */
301 CatalogObjectList find_objects_by_wildcard(const QString &wildcard,
302 const int limit = -1);
303 /**
304 * \brief Find an objects by searching the master catlog with a
305 * query like `SELECT ... FROM master WHERE \p where ORDER BY \p
306 * order_by ...`.
307 *
308 * To be used if performance does not matter (much).
309 * \p order_by can be ommitted.
310 *
311 * \return wether the query was successful, an error message if
312 * any and a list of matching objects
313 */
314 std::tuple<bool, const QString, CatalogObjectList>
315 general_master_query(const QString &where, const QString &order_by = "",
316 const int limit = -1);
317
318 /**
319 * \brief Get an object by \p `oid`. Optinally a \p `catalog_id` can be speicfied.
320 *
321 * \returns if the object was found and the object itself
322 */
323 std::pair<bool, CatalogObject> get_object(const CatalogObject::oid &oid);
324 std::pair<bool, CatalogObject> get_object(const CatalogObject::oid &oid,
325 const int catalog_id);
326
327 /**
328 * Get \p limit objects with magnitude smaller than \p maglim (smaller =
329 * brighter) from the database.
330 */
331 CatalogObjectList get_objects(float maglim = default_maglim, int limit = -1);
332
333 /**
334 * Get all objects from the database.
335 */
336 CatalogObjectList get_objects_all();
337
338 /**
339 * Get \p limit objects of \p type with magnitude smaller than \p
340 * maglim (smaller = brighter) from the database. Optionally one
341 * can filter by \p `catalog_id`.
342 */
343 CatalogObjectList get_objects(SkyObject::TYPE type, float maglim = default_maglim,
344 int limit = -1);
345 /**
346 * Get \p limit objects from the catalog with \p `catalog_id` of
347 * \p type with magnitude smaller than \p maglim (smaller =
348 * brighter) from the database. Optionally one can filter by \p
349 * `catalog_id`.
350 */
351 CatalogObjectList get_objects_in_catalog(SkyObject::TYPE type, const int catalog_id,
352 float maglim = default_maglim,
353 int limit = -1);
354
355 /**
356 * @return return the htmesh level used by the catalog db
357 */
358 int htmesh_level() const { return m_htmesh_level; };
359
360 /**
361 * \brief Enable or disable a catalog.
362 * \return `true` in case of succes, `false` and an error message in case
363 * of an error
364 *
365 * This will recreate the master table.
366 */
367 std::pair<bool, QString> set_catalog_enabled(const int id, const bool enabled);
368
369 /**
370 * \brief remove a catalog
371 * \return `true` in case of succes, `false` and an error message
372 * in case of an error
373 *
374 * This will recreate the master table.
375 */
376 std::pair<bool, QString> remove_catalog(const int id);
377
378 /**
379 * Add a `CatalogObject` to a table with \p `catalog_id`. For the rest of
380 * the arguments see `CatalogObject::CatalogObject`.
381 *
382 * \returns wether the operation was successful and if not, an error
383 * message
384 */
385 std::pair<bool, QString> add_object(const int catalog_id, const SkyObject::TYPE t,
386 const CachingDms &r, const CachingDms &d,
387 const QString &n, const float m = NaN::f,
388 const QString &lname = QString(),
389 const QString &catalog_identifier = QString(),
390 const float a = 0.0, const float b = 0.0,
391 const double pa = 0.0, const float flux = 0);
392
393 /**
394 * Add the \p `object` to a table with \p `catalog_id`. For the
395 * rest of the arguments see `CatalogObject::CatalogObject`.
396 *
397 * \returns wether the operation was successful and if not, an
398 * error message
399 */
400 std::pair<bool, QString> add_object(const int catalog_id, const CatalogObject &obj);
401
402 /**
403 * Add the \p `objects` to a table with \p `catalog_id`. For the
404 * rest of the arguments see `CatalogObject::CatalogObject`.
405 *
406 * \returns wether the operation was successful and if not, an
407 * error message
408 */
409 std::pair<bool, QString> add_objects(const int catalog_id,
410 const CatalogObjectVector &objects);
411
412 /**
413 * Remove the catalog object with the \p `oid` from the catalog with the
414 * \p `catalog_id`.
415 *
416 * Refreshes the master catalog.
417 *
418 * \returns wether the operation was successful and if not, an
419 * error message
420 */
421 std::pair<bool, QString> remove_object(const int catalog_id,
422 const CatalogObject::oid &id);
423
424 /**
425 * Dumps the catalog with \p `id` into the file under the path \p
426 * `file_path`. This file can then be imported with
427 * `import_catalog`. If the file already exists, it will be
428 * overwritten.
429 *
430 * The `user_version` and `application_id` pragmas are set to special
431 * values, but otherwise the dump format is equal to the internal
432 * database format.
433 *
434 * \returns wether the operation was successful and if not, an error
435 * message
436 */
437 std::pair<bool, QString> dump_catalog(int catalog_id, QString file_path);
438
439 /**
440 * Loads a dumped catalog from path \p `file_path`. Will overwrite
441 * an existing catalog if \p `overwrite` is set to true. Immutable
442 * catalogs are overwritten by default.
443 *
444 * Checks if the pragma `application_id` matches
445 * `CatalogsDB::application_id` and the pragma `user_version` to match
446 * the database format version.
447 *
448 * \returns wether the operation was successful and if not, an error
449 * message
450 */
451 std::pair<bool, QString> import_catalog(const QString &file_path,
452 const bool overwrite = false);
453 /**
454 * Registers a new catalog in the database.
455 *
456 * For the parameters \sa Catalog. The catalog gets inserted into
457 * `m_catalogs`. The `all_catalog_view` is updated.
458 *
459 * \return true in case of success, false in case of an error
460 * (along with the error)
461 */
462 std::pair<bool, QString>
463 register_catalog(const int id, const QString &name, const bool mut,
464 const bool enabled, const double precedence,
465 const QString &author = cat_defaults.author,
466 const QString &source = cat_defaults.source,
467 const QString &description = cat_defaults.description,
468 const int version = cat_defaults.version,
469 const QString &color = cat_defaults.color,
470 const QString &license = cat_defaults.license,
471 const QString &maintainer = cat_defaults.maintainer,
472 const QDateTime &timestamp = cat_defaults.timestamp);
473
474 std::pair<bool, QString> register_catalog(const Catalog &cat);
475
476 /**
477 * Update the metatadata \p `catalog`.
478 *
479 * The updated fields are: title, author, source, description.
480 *
481 * \return true in case of success, false in case of an error
482 * (along with the error).
483 */
484 std::pair<bool, QString> update_catalog_meta(const Catalog &cat);
485
486 /**
487 * Clone objects from the catalog with \p `id_1` to another with `id_2`. Useful to create a
488 * custom catalog from an immutable one.
489 */
490 std::pair<bool, QString> copy_objects(const int id_1, const int id_2);
491
492 /**
493 * Finds the smallest free id for a catalog.
494 */
496
497 /**
498 * \returns statistics about the master catalog.
499 */
500 const std::pair<bool, CatalogStatistics> get_master_statistics();
501
502 /**
503 * \returns statistics about the catalog with \p `catalog_id`.
504 */
505 const std::pair<bool, CatalogStatistics> get_catalog_statistics(const int catalog_id);
506
507 /**
508 * Compiles the master catalog by merging the individual catalogs based
509 * on `oid` and precedence and creates an index by (trixel, magnitude) on
510 * the master table. **Caution** you may want to call
511 * `update_catalog_views` beforhand.
512 *
513 * @return true in case of success, false in case of an error
514 */
516
517 /**
518 * Updates the all_catalog_view so that it includes all known
519 * catalogs.
520 *
521 * @return true in case of success, false in case of an error
522 */
524
525 /** \returns the catalog colors as a hash table of the form `catalog id:
526 * scheme: color`.
527 *
528 * The colors are loaded from the `Catalog::color` field and the
529 * `SqlStatements::color_table` in that order.
530 */
531 ColorMap get_catalog_colors();
532
533 /** \returns the catalog colors as a hash table of for the catalog
534 * with \p id in the form `scheme: color`.
535 *
536 * The colors are loaded from the `Catalog::color` field and the
537 * `SqlStatements::color_table` in that order.
538 */
539 CatalogColorMap get_catalog_colors(const int id);
540
541 /** Saves the configures colors of the catalog with id \p id in \p
542 * colors into the database. \returns wether the insertion was
543 * possible and an error message if not.
544 */
545 std::pair<bool, QString> insert_catalog_colors(const int id,
546 const CatalogColorMap &colors);
547
548 private:
549 /**
550 * The backing catalog database.
551 */
552 QSqlDatabase m_db;
553
554 /**
555 * The filename of the database.
556 *
557 * Will be a reference to a member of `m_db_paths`.
558 */
559 QString m_db_file;
560
561 //@{
562 /**
563 * Some performance criticall sql queries are prepared stored as memebers.
564 * When using those queries `m_mutex` should be locked!
565 *
566 * \sa prepare_queries
567 */
568
569 QSqlQuery m_q_cat_by_id;
570 QSqlQuery m_q_obj_by_trixel;
571 QSqlQuery m_q_obj_by_trixel_null_mag;
572 QSqlQuery m_q_obj_by_trixel_no_nulls;
573 QSqlQuery m_q_obj_by_name;
574 QSqlQuery m_q_obj_by_name_exact;
575 QSqlQuery m_q_obj_by_lim;
576 QSqlQuery m_q_obj_by_maglim;
577 QSqlQuery m_q_obj_by_maglim_and_type;
578 QSqlQuery m_q_obj_by_oid;
579 //@}
580
581 /**
582 * The level of the htmesh used to index the catalog entries.
583 *
584 * If the htmesh level of a catalog is different, the catalog will
585 * be reindexed upon importing it.
586 *
587 * A value of -1 means that the htmesh-level has not been
588 * deterined yet.
589 */
590 int m_htmesh_level = -1;
591
592 /**
593 * The version of the database.
594 *
595 * A value of -1 means that the htmesh-level has not been
596 * deterined yet.
597 */
598 int m_db_version = -1;
599
600 /**
601 * A simple mutex to be locked when using prepared statements,
602 * that are stored in the class.
603 */
604 QMutex m_mutex;
605
606 //@{
607 /**
608 * Helpers
609 */
610
611 /**
612 * Initializes the database with the minimum viable tables.
613 *
614 * The catalog registry is created and the database version is set
615 * to SqlStatements::current_db_version and the htmesh-level is
616 * set to SqlStatements::default_htmesh_level if they don't exist.
617 *
618 * @return true in case of success, false in case of an error
619 */
620 bool initialize_db();
621
622 /**
623 * Reads the database version and the htmesh level from the
624 * database. If the meta table does not exist, the default vaulues
625 * SqlStatements::current_db_version and
626 * SqlStatements::default_htmesh_level.
627 *
628 * @return [version, htmesh-level, is-init?]
629 */
630 std::tuple<int, int, bool> get_db_meta();
631
632 /**
633 * Gets a vector of catalog ids of catalogs. If \p include_disabled is
634 * `true`, disabled catalogs will be included.
635 */
636 std::vector<int> get_catalog_ids(bool include_enabled = false);
637
638 /**
639 * Prepares performance critical sql queries.
640 *
641 * @return [success, error]
642 */
643 std::pair<bool, QSqlError> prepare_queries();
644
645 /**
646 * Read a `CatalogObject` from the tip of the \p query.
647 */
648 CatalogObject read_catalogobject(const QSqlQuery &query) const;
649
650 /**
651 * Read the first `CatalogObject` from the tip of the \p `query`
652 * that hasn't been exec'd yet.
653 */
654 std::pair<bool, CatalogObject> read_first_object(QSqlQuery &query) const;
655
656 /**
657 * Read all `CatalogObject`s from the \p query.
658 */
659 CatalogObjectList fetch_objects(QSqlQuery &query) const;
660
661 /**
662 * Internal implementation to forcably remove a catalog (even the
663 * user catalog, use with caution!)
664 */
665 std::pair<bool, QString> remove_catalog_force(const int id);
666
667 /**
668 *
669 */
670 CatalogObjectVector _get_objects_in_trixel_generic(QSqlQuery &query, const int trixel);
671
672 //@}
673};
674
675/**
676 * Database related error, thrown when database access fails or an
677 * action does not succeed.
678 *
679 * QSqlError is not used here to encapsulate the database further.
680 */
681class DatabaseError : std::exception
682{
683 public:
684 enum class ErrorType
685 {
686 OPEN,
687 VERSION,
688 INIT,
689 CREATE_CATALOG,
690 CREATE_MASTER,
691 NOT_FOUND,
692 PREPARE,
693 UNKNOWN
694 };
695
696 DatabaseError(QString message, ErrorType type = ErrorType::UNKNOWN,
697 const QSqlError &error = QSqlError())
698 : m_message{ std::move(message) }, m_type{ type }, m_error{ error }, m_report{
699 m_message.toStdString() +
700 (error.text().length() > 0 ? "\nSQL ERROR: " + error.text().toStdString() :
701 std::string(""))
702 } {};
703
704 const char *what() const noexcept override { return m_report.c_str(); }
705 const QString &message() const noexcept { return m_message; }
706 ErrorType type() const noexcept { return m_type; }
707
708 private:
709 const QString m_message;
710 const ErrorType m_type;
711 const QSqlError m_error;
712 const std::string m_report;
713};
714
715/** \returns the path to the dso database */
716QString dso_db_path();
717
718/** \returns true and a catalog if the catalog metadata (name, author,
719 ...) can be read */
720std::pair<bool, Catalog> read_catalog_meta_from_file(const QString &path);
721
722
723
724
725/**
726 * A concurrent wrapper around \sa CatalogsDB::DBManager
727 *
728 * This wrapper can be instantiated from the main thread. It spawns
729 * its own thread and moves itself to the thread, allowing the main
730 * thread to call DB operations without blocking the user
731 * interface. It provides a generic wrapper interface, \sa
732 * AsyncDBManager::execute(), to call the methods of DBManager.
733 *
734 * Since it is hard to use signal-slot communication with a generic
735 * wrapper like \sa AsyncDBManager::execute(), a wrapper is provided
736 * for the two most likely overloads of \sa
737 * DBManager::find_objects_by_name, which are time-consuming and
738 * frequently used, and these can be directly invoked from
739 * QMetaObject::invokeMethod or an appropriate signal
740 *
741 * The void override of \sa AsyncDBManager::init() does the most
742 * commonly done thing, which is to open the DSO database
743 *
744 */
745class AsyncDBManager : public QObject {
746 // Note: Follows the active object pattern described here
747 // https://youtu.be/SncJ3D-fO7g?list=PL6CJYn40gN6jgr-Rpl3J4XDQYhmUnxb-g&t=272
749
750private:
751 std::shared_ptr<DBManager> m_manager;
752 std::queue<std::unique_ptr<CatalogObjectList>> m_result;
753 std::shared_ptr<QThread> m_thread;
754 QMutex m_resultMutex;
755
756public:
757 template <typename... Args>
758 using DBManagerMethod = CatalogObjectList (DBManager::*)(Args...);
759
760 /**
761 * Constructor, does nothing. Call init() to do the actual setup after the QThread stars
762 */
763 template <typename... Args>
764 AsyncDBManager(Args... args)
765 : QObject(nullptr)
766 , m_manager(nullptr)
767 , m_thread(nullptr)
768 {
769 m_thread.reset(new QThread);
770 moveToThread(m_thread.get());
771 connect(m_thread.get(), &QThread::started, [&]() {
772 init(args...);
773 });
774 m_thread->start();
775
776 /*
777 * This is an attempt to fix a bug introduced in 5a2ba9f8e8b275f44b7593a50ca66f09cb2f985d
778 * where KStars Crashes on MacOS when launched by double clicking (NOT by Terminal or QT Creator)
779 * and then the find dialog is accessed. For some reason, this fixes it?
780 */
781 #ifdef Q_OS_MACOS
782 QThread::msleep(100);
783 #endif
784 }
785
787 {
788 QMetaObject::invokeMethod(this, "cleanup");
789 m_thread->wait();
790 }
791
792 /**
793 * Return a pointer to the DBManager, for non-DB functionalities
794 */
795 inline std::shared_ptr<DBManager> manager() { return m_manager; }
796
797 /**
798 * Return a pointer to the QThread object
799 */
800 inline std::shared_ptr<QThread> thread() { return m_thread; }
801
802 /**
803 * Construct the DBManager object
804 *
805 * Should be done in the thread corresponding to this object
806 */
807 template <typename... Args> void init(Args&&... args)
808 {
809 m_manager = std::make_shared<DBManager>(std::forward<Args>(args)...);
810 }
811
812 /**
813 * A generic wrapper to call any method on DBManager that returns a CatalogObjectList
814 *
815 * For practical use examples, see \sa
816 * AsyncDBManager::find_objects_by_name below which uses this
817 * wrapper
818 */
819 template <typename... Args>
820 void execute(DBManagerMethod<Args...> dbManagerMethod, Args... args)
821 {
822 // c.f. https://stackoverflow.com/questions/25392935/wrap-a-function-pointer-in-c-with-variadic-template
823
824 // N.B. The perfect forwarding idiom is not used because we
825 // also want to be able to bind to lvalue references, whereas
826 // the types deduced for the arguments has to match the type
827 // deduced to identify the function overload to be used.
828 QMutexLocker _{&m_resultMutex};
829 m_result.emplace(
830 std::make_unique<CatalogObjectList>((m_manager.get()->*dbManagerMethod)(args...))
831 );
832 emit resultReady();
833 }
834
835 /**
836 * execute(), but specialized to find_objects_by_name
837 *
838 * @fixme Code duplication needed to support older compilers
839 */
840 void _find_objects_by_name(const QString& name, const int limit, const bool exactMatchOnly)
841 {
842 // FIXME: Remove this and use execute() once C++1x compilers
843 // support variadic template type deduction properly
844 QMutexLocker _{&m_resultMutex};
845 m_result.emplace(
846 std::make_unique<CatalogObjectList>((m_manager.get()->find_objects_by_name)(name, limit, exactMatchOnly))
847 );
848 emit resultReady();
849 }
850
851signals:
852 void resultReady(void);
853 void threadReady(void);
854
855
856public slots:
857
858 void init()
859 {
860 m_manager = std::make_shared<DBManager>(dso_db_path());
861 }
862
863 /**
864 * Calls the given DBManager method, storing the result for later retrieval
865 *
866 * \p dbManagerMethod method to execute (must return a CatalogObjectList)
867 * \p args arguments to supply to the method
868 */
869
870 void find_objects_by_name(const QString& name, const int limit = -1)
871 {
872 // N.B. One cannot have a function pointer to a function with
873 // default arguments, so all arguments must be supplied here
874
875 // FIXME: Uncomment to use generic wrapper execute() once
876 // compilers gain proper type-deduction support
877 // execute<const QString&, const int, const bool>(
878 // &DBManager::find_objects_by_name,
879 // name, limit, false);
880
881 _find_objects_by_name(name, limit, false);
882 }
883
884 void find_objects_by_name_exact(const QString &name)
885 {
886 // FIXME: Uncomment to use generic wrapper execute() once
887 // compilers gain proper type-deduction support
888 // execute<const QString&, const int, const bool>(
889 // &DBManager::find_objects_by_name,
890 // name, 1, true);
891
892 _find_objects_by_name(name, 1, true);
893 }
894
895 /**
896 * Returns the result of the previous call, or a nullptr if none exists
897 */
898 std::unique_ptr<CatalogObjectList> result()
899 {
900 QMutexLocker _{&m_resultMutex};
901 if (m_result.empty())
902 {
903 return std::unique_ptr<CatalogObjectList>();
904 }
905 std::unique_ptr<CatalogObjectList> result = std::move(m_result.front());
906 m_result.pop();
907 return result;
908 }
909
910private slots:
911
912 void cleanup()
913 {
914 Q_ASSERT(m_manager.use_count() == 1);
915 m_manager.reset();
916 m_thread->quit();
917 }
918
919 void emitReady()
920 {
921 emit threadReady();
922 }
923
924};
925
926} // namespace CatalogsDB
a dms subclass that caches its sine and cosine values every time the angle is changed.
Definition cachingdms.h:19
A simple container object to hold the minimum information for a Deep Sky Object to be drawn on the sk...
A concurrent wrapper around.
Definition catalogsdb.h:745
AsyncDBManager(Args... args)
Constructor, does nothing.
Definition catalogsdb.h:764
void find_objects_by_name(const QString &name, const int limit=-1)
Calls the given DBManager method, storing the result for later retrieval.
Definition catalogsdb.h:870
void init(Args &&... args)
Construct the DBManager object.
Definition catalogsdb.h:807
std::shared_ptr< QThread > thread()
Return a pointer to the QThread object.
Definition catalogsdb.h:800
void execute(DBManagerMethod< Args... > dbManagerMethod, Args... args)
A generic wrapper to call any method on DBManager that returns a CatalogObjectList.
Definition catalogsdb.h:820
std::shared_ptr< DBManager > manager()
Return a pointer to the DBManager, for non-DB functionalities.
Definition catalogsdb.h:795
std::unique_ptr< CatalogObjectList > result()
Returns the result of the previous call, or a nullptr if none exists.
Definition catalogsdb.h:898
void _find_objects_by_name(const QString &name, const int limit, const bool exactMatchOnly)
execute(), but specialized to find_objects_by_name
Definition catalogsdb.h:840
Manages the catalog database and provides an interface to provide an interface to query and modify th...
Definition catalogsdb.h:183
CatalogObjectList get_objects_all()
Get all objects from the database.
std::pair< bool, QString > add_object(const int catalog_id, const SkyObject::TYPE t, const CachingDms &r, const CachingDms &d, const QString &n, const float m=NaN::f, const QString &lname=QString(), const QString &catalog_identifier=QString(), const float a=0.0, const float b=0.0, const double pa=0.0, const float flux=0)
Add a CatalogObject to a table with `catalog_id`.
int find_suitable_catalog_id()
Finds the smallest free id for a catalog.
bool compile_master_catalog()
Compiles the master catalog by merging the individual catalogs based on oid and precedence and create...
bool update_catalog_views()
Updates the all_catalog_view so that it includes all known catalogs.
CatalogObjectVector get_objects_in_trixel_null_mag(const int trixel)
Definition catalogsdb.h:267
const QString & db_file_name() const
Definition catalogsdb.h:227
CatalogObjectList find_objects_by_name(const QString &name, const int limit=-1, const bool exactMatchOnly=false)
Find an objects by name.
std::pair< bool, QString > set_catalog_enabled(const int id, const bool enabled)
Enable or disable a catalog.
ColorMap get_catalog_colors()
const std::pair< bool, CatalogStatistics > get_catalog_statistics(const int catalog_id)
CatalogObjectList find_objects_by_wildcard(const QString &wildcard, const int limit=-1)
Find an objects by searching the name four wildcard.
std::tuple< bool, const QString, CatalogObjectList > general_master_query(const QString &where, const QString &order_by="", const int limit=-1)
Find an objects by searching the master catlog with a query like SELECT ... FROM master WHERE \p wher...
std::pair< bool, QString > update_catalog_meta(const Catalog &cat)
Update the metatadata `catalog`.
std::pair< bool, QString > remove_catalog(const int id)
remove a catalog
const std::pair< bool, Catalog > get_catalog(const int id)
std::pair< bool, QString > remove_object(const int catalog_id, const CatalogObject::oid &id)
Remove the catalog object with the `oid` from the catalog with the `catalog_id`.
CatalogObjectList get_objects_in_catalog(SkyObject::TYPE type, const int catalog_id, float maglim=default_maglim, int limit=-1)
Get limit objects from the catalog with `catalog_id` of type with magnitude smaller than maglim (smal...
int htmesh_level() const
Definition catalogsdb.h:358
DBManager(const QString &filename)
Constructs a database manager from the filename which is resolved to a path in the kstars data direct...
CatalogObjectVector get_objects_in_trixel_no_nulls(const int trixel)
Definition catalogsdb.h:260
std::pair< bool, QString > register_catalog(const int id, const QString &name, const bool mut, const bool enabled, const double precedence, const QString &author=cat_defaults.author, const QString &source=cat_defaults.source, const QString &description=cat_defaults.description, const int version=cat_defaults.version, const QString &color=cat_defaults.color, const QString &license=cat_defaults.license, const QString &maintainer=cat_defaults.maintainer, const QDateTime &timestamp=cat_defaults.timestamp)
Registers a new catalog in the database.
std::pair< bool, QString > import_catalog(const QString &file_path, const bool overwrite=false)
Loads a dumped catalog from path `file_path`.
std::pair< bool, QString > add_objects(const int catalog_id, const CatalogObjectVector &objects)
Add the `objects` to a table with `catalog_id`.
const std::vector< Catalog > get_catalogs(bool include_disabled=false)
CatalogObjectList get_objects(float maglim=default_maglim, int limit=-1)
Get limit objects with magnitude smaller than maglim (smaller = brighter) from the database.
bool catalog_exists(const int id)
std::pair< bool, QString > insert_catalog_colors(const int id, const CatalogColorMap &colors)
Saves the configures colors of the catalog with id id in colors into the database.
const std::pair< bool, CatalogStatistics > get_master_statistics()
std::pair< bool, QString > dump_catalog(int catalog_id, QString file_path)
Dumps the catalog with `id` into the file under the path file_path.
std::pair< bool, CatalogObject > get_object(const CatalogObject::oid &oid)
Get an object by `oid`.
CatalogObjectVector get_objects_in_trixel(const int trixel)
Definition catalogsdb.h:253
std::pair< bool, QString > copy_objects(const int id_1, const int id_2)
Clone objects from the catalog with `id_1` to another with id_2.
Database related error, thrown when database access fails or an action does not succeed.
Definition catalogsdb.h:682
TYPE
The type classification of the SkyObject.
Definition skyobject.h:112
bool invokeMethod(QObject *context, Functor &&function, FunctorReturnType *ret)
Q_OBJECTQ_OBJECT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void moveToThread(QThread *targetThread)
std::string toStdString() const const
void msleep(unsigned long msecs)
void started()
Holds statistical information about the objects in a catalog.
Definition catalogsdb.h:119
A simple struct to hold information about catalogs.
Definition catalogsdb.h:37
QString color
The catalog color in the form [default color];[scheme file name];[color]....
Definition catalogsdb.h:91
QString maintainer
The catalog maintainer.
Definition catalogsdb.h:101
int version
The catalog version.
Definition catalogsdb.h:85
double precedence
The precedence level of a catalog.
Definition catalogsdb.h:54
QString name
The catalog mame.
Definition catalogsdb.h:46
bool enabled
Wether the catalog is enabled.
Definition catalogsdb.h:80
QString license
The catalog license.
Definition catalogsdb.h:96
QString description
A (short) description for the catalog.
Definition catalogsdb.h:70
QString author
The author of the catalog.
Definition catalogsdb.h:59
QString source
The catalog source.
Definition catalogsdb.h:64
bool mut
Wether the catalog is mutable.
Definition catalogsdb.h:75
QDateTime timestamp
Build time of the catalog.
Definition catalogsdb.h:110
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Mon Nov 4 2024 16:38:42 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.