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

KDE's Doxygen guidelines are available online.