001 package de.deepamehta.core.impl; 002 003 import de.deepamehta.core.model.AssociationModel; 004 import de.deepamehta.core.model.IndexMode; 005 import de.deepamehta.core.model.RelatedAssociationModel; 006 import de.deepamehta.core.model.RelatedTopicModel; 007 import de.deepamehta.core.model.SimpleValue; 008 import de.deepamehta.core.model.TopicModel; 009 import de.deepamehta.core.service.ResultList; 010 import de.deepamehta.core.storage.spi.DeepaMehtaTransaction; 011 import de.deepamehta.core.storage.spi.DeepaMehtaStorage; 012 013 import static java.util.Arrays.asList; 014 import java.util.Iterator; 015 import java.util.List; 016 import java.util.logging.Logger; 017 018 019 020 public class StorageDecorator { 021 022 // ---------------------------------------------------------------------------------------------- Instance Variables 023 024 private DeepaMehtaStorage storage; 025 026 private final Logger logger = Logger.getLogger(getClass().getName()); 027 028 // ---------------------------------------------------------------------------------------------------- Constructors 029 030 public StorageDecorator(DeepaMehtaStorage storage) { 031 this.storage = storage; 032 } 033 034 // -------------------------------------------------------------------------------------------------- Public Methods 035 036 037 038 // === Topics === 039 040 /** 041 * @return The fetched topic. 042 * Note: its child topics are not fetched. 043 */ 044 TopicModel fetchTopic(long topicId) { 045 return storage.fetchTopic(topicId); 046 } 047 048 /** 049 * Looks up a single topic by exact property value. 050 * If no such topic exists <code>null</code> is returned. 051 * If more than one topic were found a runtime exception is thrown. 052 * <p> 053 * IMPORTANT: Looking up a topic this way requires the property to be indexed with indexing mode <code>KEY</code>. 054 * This is achieved by declaring the respective data field with <code>indexing_mode: "KEY"</code> 055 * (for statically declared data field, typically in <code>types.json</code>) or 056 * by calling DataField's {@link DataField#setIndexingMode} method with <code>"KEY"</code> as argument 057 * (for dynamically created data fields, typically in migration classes). 058 * 059 * @return The fetched topic. 060 * Note: its child topics are not fetched. 061 */ 062 TopicModel fetchTopic(String key, SimpleValue value) { 063 return storage.fetchTopic(key, value.value()); 064 } 065 066 List<TopicModel> fetchTopics(String key, SimpleValue value) { 067 return storage.fetchTopics(key, value.value()); 068 } 069 070 // --- 071 072 /** 073 * @return The fetched topics. 074 * Note: their child topics are not fetched. 075 */ 076 List<TopicModel> queryTopics(String searchTerm, String fieldUri) { 077 return storage.queryTopics(fieldUri, searchTerm); 078 } 079 080 // --- 081 082 Iterator<TopicModel> fetchAllTopics() { 083 return storage.fetchAllTopics(); 084 } 085 086 // --- 087 088 /** 089 * Creates a topic. 090 * <p> 091 * The topic's URI is stored and indexed. 092 * 093 * @return FIXDOC ### the created topic. Note: 094 * - the topic URI is initialzed and persisted. 095 * - the topic value is initialzed but not persisted. 096 * - the type URI is initialzed but not persisted. 097 */ 098 void storeTopic(TopicModel model) { 099 storage.storeTopic(model); 100 } 101 102 /** 103 * Stores and indexes the topic's URI. 104 */ 105 void storeTopicUri(long topicId, String uri) { 106 storage.storeTopicUri(topicId, uri); 107 } 108 109 void storeTopicTypeUri(long topicId, String topicTypeUri) { 110 storage.storeTopicTypeUri(topicId, topicTypeUri); 111 } 112 113 // --- 114 115 /** 116 * Convenience method (no indexing). 117 */ 118 void storeTopicValue(long topicId, SimpleValue value) { 119 storeTopicValue(topicId, value, asList(IndexMode.OFF), null, null); 120 } 121 122 /** 123 * Stores and indexes the topic's value. ### TODO: separate storing/indexing? 124 */ 125 void storeTopicValue(long topicId, SimpleValue value, List<IndexMode> indexModes, String indexKey, 126 SimpleValue indexValue) { 127 storage.storeTopicValue(topicId, value, indexModes, indexKey, indexValue); 128 } 129 130 void indexTopicValue(long topicId, IndexMode indexMode, String indexKey, SimpleValue indexValue) { 131 storage.indexTopicValue(topicId, indexMode, indexKey, indexValue); 132 } 133 134 // --- 135 136 /** 137 * Deletes the topic. 138 * <p> 139 * Prerequisite: the topic has no relations. 140 */ 141 void deleteTopic(long topicId) { 142 storage.deleteTopic(topicId); 143 } 144 145 146 147 // === Associations === 148 149 AssociationModel fetchAssociation(long assocId) { 150 return storage.fetchAssociation(assocId); 151 } 152 153 // --- 154 155 /** 156 * Convenience method (checks singularity). 157 * 158 * Returns the association between two topics, qualified by association type and both role types. 159 * If no such association exists <code>null</code> is returned. 160 * If more than one association exist, a runtime exception is thrown. 161 * 162 * @param assocTypeUri Association type filter. Pass <code>null</code> to switch filter off. 163 * ### FIXME: for methods with a singular return value all filters should be mandatory 164 */ 165 AssociationModel fetchAssociation(String assocTypeUri, long topicId1, long topicId2, String roleTypeUri1, 166 String roleTypeUri2) { 167 List<AssociationModel> assocs = fetchAssociations(assocTypeUri, topicId1, topicId2, roleTypeUri1, roleTypeUri2); 168 switch (assocs.size()) { 169 case 0: 170 return null; 171 case 1: 172 return assocs.get(0); 173 default: 174 throw new RuntimeException("Ambiguity: there are " + assocs.size() + " \"" + assocTypeUri + 175 "\" associations (topicId1=" + topicId1 + ", topicId2=" + topicId2 + ", " + 176 "roleTypeUri1=\"" + roleTypeUri1 + "\", roleTypeUri2=\"" + roleTypeUri2 + "\")"); 177 } 178 } 179 180 /** 181 * Returns the associations between two topics. If no such association exists an empty set is returned. 182 * 183 * @param assocTypeUri Association type filter. Pass <code>null</code> to switch filter off. 184 */ 185 List<AssociationModel> fetchAssociations(String assocTypeUri, long topicId1, long topicId2, 186 String roleTypeUri1, String roleTypeUri2) { 187 return storage.fetchAssociations(assocTypeUri, topicId1, topicId2, roleTypeUri1, roleTypeUri2); 188 } 189 190 // --- 191 192 /** 193 * Convenience method (checks singularity). 194 */ 195 AssociationModel fetchAssociationBetweenTopicAndAssociation(String assocTypeUri, long topicId, long assocId, 196 String topicRoleTypeUri, String assocRoleTypeUri) { 197 List<AssociationModel> assocs = fetchAssociationsBetweenTopicAndAssociation(assocTypeUri, topicId, assocId, 198 topicRoleTypeUri, assocRoleTypeUri); 199 switch (assocs.size()) { 200 case 0: 201 return null; 202 case 1: 203 return assocs.get(0); 204 default: 205 throw new RuntimeException("Ambiguity: there are " + assocs.size() + " \"" + assocTypeUri + 206 "\" associations (topicId=" + topicId + ", assocId=" + assocId + ", " + 207 "topicRoleTypeUri=\"" + topicRoleTypeUri + "\", assocRoleTypeUri=\"" + assocRoleTypeUri + "\")"); 208 } 209 } 210 211 List<AssociationModel> fetchAssociationsBetweenTopicAndAssociation(String assocTypeUri, long topicId, 212 long assocId, String topicRoleTypeUri, String assocRoleTypeUri) { 213 return storage.fetchAssociationsBetweenTopicAndAssociation(assocTypeUri, topicId, assocId, topicRoleTypeUri, 214 assocRoleTypeUri); 215 } 216 217 // --- 218 219 Iterator<AssociationModel> fetchAllAssociations() { 220 return storage.fetchAllAssociations(); 221 } 222 223 // --- 224 225 /** 226 * Stores and indexes the association's URI. 227 */ 228 void storeAssociationUri(long assocId, String uri) { 229 storage.storeAssociationUri(assocId, uri); 230 } 231 232 void storeAssociationTypeUri(long assocId, String assocTypeUri) { 233 storage.storeAssociationTypeUri(assocId, assocTypeUri); 234 } 235 236 void storeRoleTypeUri(long assocId, long playerId, String roleTypeUri) { 237 storage.storeRoleTypeUri(assocId, playerId, roleTypeUri); 238 } 239 240 // --- 241 242 /** 243 * Convenience method (no indexing). 244 */ 245 void storeAssociationValue(long assocId, SimpleValue value) { 246 storeAssociationValue(assocId, value, asList(IndexMode.OFF), null, null); 247 } 248 249 /** 250 * Stores and indexes the association's value. ### TODO: separate storing/indexing? 251 */ 252 void storeAssociationValue(long assocId, SimpleValue value, List<IndexMode> indexModes, String indexKey, 253 SimpleValue indexValue) { 254 storage.storeAssociationValue(assocId, value, indexModes, indexKey, indexValue); 255 } 256 257 void indexAssociationValue(long assocId, IndexMode indexMode, String indexKey, SimpleValue indexValue) { 258 storage.indexAssociationValue(assocId, indexMode, indexKey, indexValue); 259 } 260 261 // --- 262 263 void storeAssociation(AssociationModel model) { 264 storage.storeAssociation(model); 265 } 266 267 void deleteAssociation(long assocId) { 268 storage.deleteAssociation(assocId); 269 } 270 271 272 273 // === Traversal === 274 275 /** 276 * @return The fetched associations. 277 * Note: their child topics are not fetched. 278 */ 279 List<AssociationModel> fetchTopicAssociations(long topicId) { 280 return storage.fetchTopicAssociations(topicId); 281 } 282 283 List<AssociationModel> fetchAssociationAssociations(long assocId) { 284 return storage.fetchAssociationAssociations(assocId); 285 } 286 287 // --- 288 289 /** 290 * Convenience method (checks singularity). 291 * 292 * @param assocTypeUri may be null 293 * @param myRoleTypeUri may be null 294 * @param othersRoleTypeUri may be null 295 * @param othersTopicTypeUri may be null 296 * 297 * @return The fetched topic. 298 * Note: its child topics are not fetched. 299 */ 300 RelatedTopicModel fetchTopicRelatedTopic(long topicId, String assocTypeUri, String myRoleTypeUri, 301 String othersRoleTypeUri, String othersTopicTypeUri) { 302 ResultList<RelatedTopicModel> topics = fetchTopicRelatedTopics(topicId, assocTypeUri, myRoleTypeUri, 303 othersRoleTypeUri, othersTopicTypeUri, 0); 304 switch (topics.getSize()) { 305 case 0: 306 return null; 307 case 1: 308 return topics.iterator().next(); 309 default: 310 throw new RuntimeException("Ambiguity: there are " + topics.getSize() + " related topics (topicId=" + 311 topicId + ", assocTypeUri=\"" + assocTypeUri + "\", myRoleTypeUri=\"" + myRoleTypeUri + "\", " + 312 "othersRoleTypeUri=\"" + othersRoleTypeUri + "\", othersTopicTypeUri=\"" + othersTopicTypeUri + "\")"); 313 } 314 } 315 316 /** 317 * @param assocTypeUri may be null 318 * @param myRoleTypeUri may be null 319 * @param othersRoleTypeUri may be null 320 * @param othersTopicTypeUri may be null 321 * 322 * @return The fetched topics. 323 * Note: their child topics are not fetched. 324 */ 325 ResultList<RelatedTopicModel> fetchTopicRelatedTopics(long topicId, String assocTypeUri, 326 String myRoleTypeUri, String othersRoleTypeUri, 327 String othersTopicTypeUri, int maxResultSize) { 328 List<RelatedTopicModel> relTopics = storage.fetchTopicRelatedTopics(topicId, assocTypeUri, myRoleTypeUri, 329 othersRoleTypeUri, othersTopicTypeUri); 330 // ### TODO: respect maxResultSize 331 return new ResultList(relTopics.size(), relTopics); 332 } 333 334 /** 335 * Convenience method (receives *list* of association types). 336 * 337 * @param assocTypeUris may *not* be null 338 * @param myRoleTypeUri may be null 339 * @param othersRoleTypeUri may be null 340 * @param othersTopicTypeUri may be null 341 * 342 * @return The fetched topics. 343 * Note: their child topics are not fetched. 344 */ 345 ResultList<RelatedTopicModel> fetchTopicRelatedTopics(long topicId, List<String> assocTypeUris, 346 String myRoleTypeUri, String othersRoleTypeUri, 347 String othersTopicTypeUri, int maxResultSize) { 348 ResultList<RelatedTopicModel> result = new ResultList(); 349 for (String assocTypeUri : assocTypeUris) { 350 ResultList<RelatedTopicModel> res = fetchTopicRelatedTopics(topicId, assocTypeUri, myRoleTypeUri, 351 othersRoleTypeUri, othersTopicTypeUri, maxResultSize); 352 result.addAll(res); 353 } 354 return result; 355 } 356 357 // --- 358 359 /** 360 * Convenience method (checks singularity). 361 * 362 * @return The fetched association. 363 * Note: its child topics are not fetched. 364 */ 365 RelatedAssociationModel fetchTopicRelatedAssociation(long topicId, String assocTypeUri, String myRoleTypeUri, 366 String othersRoleTypeUri, String othersAssocTypeUri) { 367 ResultList<RelatedAssociationModel> assocs = fetchTopicRelatedAssociations(topicId, assocTypeUri, myRoleTypeUri, 368 othersRoleTypeUri, othersAssocTypeUri); 369 switch (assocs.getSize()) { 370 case 0: 371 return null; 372 case 1: 373 return assocs.iterator().next(); 374 default: 375 throw new RuntimeException("Ambiguity: there are " + assocs.getSize() + " related associations (topicId=" + 376 topicId + ", assocTypeUri=\"" + assocTypeUri + "\", myRoleTypeUri=\"" + myRoleTypeUri + "\", " + 377 "othersRoleTypeUri=\"" + othersRoleTypeUri + "\", othersAssocTypeUri=\"" + othersAssocTypeUri + "\")"); 378 } 379 } 380 381 /** 382 * @param assocTypeUri may be null 383 * @param myRoleTypeUri may be null 384 * @param othersRoleTypeUri may be null 385 * @param othersAssocTypeUri may be null 386 * 387 * @return The fetched associations. 388 * Note: their child topics are not fetched. 389 */ 390 ResultList<RelatedAssociationModel> fetchTopicRelatedAssociations(long topicId, String assocTypeUri, 391 String myRoleTypeUri, String othersRoleTypeUri, 392 String othersAssocTypeUri) { 393 List<RelatedAssociationModel> relAssocs = storage.fetchTopicRelatedAssociations(topicId, assocTypeUri, 394 myRoleTypeUri, othersRoleTypeUri, othersAssocTypeUri); 395 return new ResultList(relAssocs.size(), relAssocs); 396 } 397 398 // --- 399 400 /** 401 * Convenience method (checks singularity). 402 * 403 * @return The fetched topic. 404 * Note: its child topics are not fetched. 405 */ 406 RelatedTopicModel fetchAssociationRelatedTopic(long assocId, String assocTypeUri, String myRoleTypeUri, 407 String othersRoleTypeUri, String othersTopicTypeUri) { 408 ResultList<RelatedTopicModel> topics = fetchAssociationRelatedTopics(assocId, assocTypeUri, myRoleTypeUri, 409 othersRoleTypeUri, othersTopicTypeUri, 0); 410 switch (topics.getSize()) { 411 case 0: 412 return null; 413 case 1: 414 return topics.iterator().next(); 415 default: 416 throw new RuntimeException("Ambiguity: there are " + topics.getSize() + " related topics (assocId=" + 417 assocId + ", assocTypeUri=\"" + assocTypeUri + "\", myRoleTypeUri=\"" + myRoleTypeUri + "\", " + 418 "othersRoleTypeUri=\"" + othersRoleTypeUri + "\", othersTopicTypeUri=\"" + othersTopicTypeUri + "\")"); 419 } 420 } 421 422 /** 423 * @return The fetched topics. 424 * Note: their child topics are not fetched. 425 */ 426 ResultList<RelatedTopicModel> fetchAssociationRelatedTopics(long assocId, String assocTypeUri, 427 String myRoleTypeUri, String othersRoleTypeUri, 428 String othersTopicTypeUri, int maxResultSize) { 429 List<RelatedTopicModel> relTopics = storage.fetchAssociationRelatedTopics(assocId, assocTypeUri, myRoleTypeUri, 430 othersRoleTypeUri, othersTopicTypeUri); 431 // ### TODO: respect maxResultSize 432 return new ResultList(relTopics.size(), relTopics); 433 } 434 435 /** 436 * Convenience method (receives *list* of association types). 437 * 438 * @param assocTypeUris may be null 439 * @param myRoleTypeUri may be null 440 * @param othersRoleTypeUri may be null 441 * @param othersTopicTypeUri may be null 442 * 443 * @return The fetched topics. 444 * Note: their child topics are not fetched. 445 */ 446 ResultList<RelatedTopicModel> fetchAssociationRelatedTopics(long assocId, List<String> assocTypeUris, 447 String myRoleTypeUri, String othersRoleTypeUri, 448 String othersTopicTypeUri, int maxResultSize) { 449 ResultList<RelatedTopicModel> result = new ResultList(); 450 for (String assocTypeUri : assocTypeUris) { 451 ResultList<RelatedTopicModel> res = fetchAssociationRelatedTopics(assocId, assocTypeUri, myRoleTypeUri, 452 othersRoleTypeUri, othersTopicTypeUri, maxResultSize); 453 result.addAll(res); 454 } 455 return result; 456 } 457 458 // --- 459 460 /** 461 * Convenience method (checks singularity). 462 * 463 * @return The fetched association. 464 * Note: its child topics are not fetched. 465 */ 466 RelatedAssociationModel fetchAssociationRelatedAssociation(long assocId, String assocTypeUri, 467 String myRoleTypeUri, String othersRoleTypeUri, String othersAssocTypeUri) { 468 ResultList<RelatedAssociationModel> assocs = fetchAssociationRelatedAssociations(assocId, assocTypeUri, 469 myRoleTypeUri, othersRoleTypeUri, othersAssocTypeUri); 470 switch (assocs.getSize()) { 471 case 0: 472 return null; 473 case 1: 474 return assocs.iterator().next(); 475 default: 476 throw new RuntimeException("Ambiguity: there are " + assocs.getSize() + " related associations (assocId=" + 477 assocId + ", assocTypeUri=\"" + assocTypeUri + "\", myRoleTypeUri=\"" + myRoleTypeUri + "\", " + 478 "othersRoleTypeUri=\"" + othersRoleTypeUri + "\", othersAssocTypeUri=\"" + othersAssocTypeUri + 479 "\"),\nresult=" + assocs); 480 } 481 } 482 483 /** 484 * @param assocTypeUri may be null 485 * @param myRoleTypeUri may be null 486 * @param othersRoleTypeUri may be null 487 * @param othersAssocTypeUri may be null 488 * 489 * @return The fetched associations. 490 * Note: their child topics are not fetched. 491 */ 492 ResultList<RelatedAssociationModel> fetchAssociationRelatedAssociations(long assocId, String assocTypeUri, 493 String myRoleTypeUri, String othersRoleTypeUri, 494 String othersAssocTypeUri) { 495 List<RelatedAssociationModel> relAssocs = storage.fetchAssociationRelatedAssociations(assocId, assocTypeUri, 496 myRoleTypeUri, othersRoleTypeUri, othersAssocTypeUri); 497 return new ResultList(relAssocs.size(), relAssocs); 498 } 499 500 // --- 501 502 /** 503 * Convenience method (checks singularity). 504 * 505 * @param objectId id of a topic or an association 506 * @param assocTypeUri may be null 507 * @param myRoleTypeUri may be null 508 * @param othersRoleTypeUri may be null 509 * @param othersTopicTypeUri may be null 510 * 511 * @return The fetched topic. 512 * Note: its child topics are not fetched. 513 */ 514 RelatedTopicModel fetchRelatedTopic(long objectId, String assocTypeUri, String myRoleTypeUri, 515 String othersRoleTypeUri, String othersTopicTypeUri) { 516 ResultList<RelatedTopicModel> topics = fetchRelatedTopics(objectId, assocTypeUri, myRoleTypeUri, 517 othersRoleTypeUri, othersTopicTypeUri); 518 switch (topics.getSize()) { 519 case 0: 520 return null; 521 case 1: 522 return topics.iterator().next(); 523 default: 524 throw new RuntimeException("Ambiguity: there are " + topics.getSize() + " related topics (objectId=" + 525 objectId + ", assocTypeUri=\"" + assocTypeUri + "\", myRoleTypeUri=\"" + myRoleTypeUri + "\", " + 526 "othersRoleTypeUri=\"" + othersRoleTypeUri + "\", othersTopicTypeUri=\"" + othersTopicTypeUri + "\")"); 527 } 528 } 529 530 /** 531 * @param objectId id of a topic or an association 532 * @param assocTypeUri may be null 533 * @param myRoleTypeUri may be null 534 * @param othersRoleTypeUri may be null 535 * @param othersTopicTypeUri may be null 536 * 537 * @return The fetched topics. 538 * Note: their child topics are not fetched. 539 */ 540 ResultList<RelatedTopicModel> fetchRelatedTopics(long objectId, String assocTypeUri, String myRoleTypeUri, 541 String othersRoleTypeUri, String othersTopicTypeUri) { 542 List<RelatedTopicModel> relTopics = storage.fetchRelatedTopics(objectId, assocTypeUri, myRoleTypeUri, 543 othersRoleTypeUri, othersTopicTypeUri); 544 return new ResultList(relTopics.size(), relTopics); 545 } 546 547 // ### TODO: decorator for fetchRelatedAssociations() 548 549 550 551 // === Properties === 552 553 Object fetchTopicProperty(long topicId, String propUri) { 554 return storage.fetchTopicProperty(topicId, propUri); 555 } 556 557 Object fetchAssociationProperty(long assocId, String propUri) { 558 return storage.fetchAssociationProperty(assocId, propUri); 559 } 560 561 // --- 562 563 List<TopicModel> fetchTopicsByProperty(String propUri, Object propValue) { 564 return storage.fetchTopicsByProperty(propUri, propValue); 565 } 566 567 List<TopicModel> fetchTopicsByPropertyRange(String propUri, Number from, Number to) { 568 return storage.fetchTopicsByPropertyRange(propUri, from, to); 569 } 570 571 List<AssociationModel> fetchAssociationsByProperty(String propUri, Object propValue) { 572 return storage.fetchAssociationsByProperty(propUri, propValue); 573 } 574 575 List<AssociationModel> fetchAssociationsByPropertyRange(String propUri, Number from, Number to) { 576 return storage.fetchAssociationsByPropertyRange(propUri, from, to); 577 } 578 579 // --- 580 581 void storeTopicProperty(long topicId, String propUri, Object propValue, boolean addToIndex) { 582 storage.storeTopicProperty(topicId, propUri, propValue, addToIndex); 583 } 584 585 void storeAssociationProperty(long assocId, String propUri, Object propValue, boolean addToIndex) { 586 storage.storeAssociationProperty(assocId, propUri, propValue, addToIndex); 587 } 588 589 // --- 590 591 boolean hasTopicProperty(long topicId, String propUri) { 592 return storage.hasTopicProperty(topicId, propUri); 593 } 594 595 boolean hasAssociationProperty(long assocId, String propUri) { 596 return storage.hasAssociationProperty(assocId, propUri); 597 } 598 599 // --- 600 601 void removeTopicProperty(long topicId, String propUri) { 602 storage.deleteTopicProperty(topicId, propUri); 603 } 604 605 void removeAssociationProperty(long assocId, String propUri) { 606 storage.deleteAssociationProperty(assocId, propUri); 607 } 608 609 610 611 // === DB === 612 613 DeepaMehtaTransaction beginTx() { 614 return storage.beginTx(); 615 } 616 617 /** 618 * Initializes the database. 619 * Prerequisite: there is an open transaction. 620 * 621 * @return <code>true</code> if a clean install is detected, <code>false</code> otherwise. 622 */ 623 boolean init() { 624 boolean isCleanInstall = storage.setupRootNode(); 625 if (isCleanInstall) { 626 logger.info("Starting with a fresh DB -- Setting migration number to 0"); 627 storeMigrationNr(0); 628 } 629 return isCleanInstall; 630 } 631 632 void shutdown() { 633 storage.shutdown(); 634 } 635 636 // --- 637 638 int fetchMigrationNr() { 639 return (Integer) storage.fetchTopicProperty(0, "core_migration_nr"); 640 } 641 642 void storeMigrationNr(int migrationNr) { 643 storage.storeTopicProperty(0, "core_migration_nr", migrationNr, false); // addToIndex=false 644 } 645 646 // --- 647 648 Object getDatabaseVendorObject() { 649 return storage.getDatabaseVendorObject(); 650 } 651 652 Object getDatabaseVendorObject(long objectId) { 653 return storage.getDatabaseVendorObject(objectId); 654 } 655 }