Author: lgiessmann
Date: Fri Apr 23 14:47:37 2010
New Revision: 286
Log:
new-datamodel: fixed an elephant bug that appears in the current version --> "get-instances-by-class" is embraced within a function that filters all instances by typep and optional a given revision; fixed a potential versioning bug in "merge-all-constructs"; fixed a bug in "equivalent-construct" --> AssociationC; fixed a bug in "merge-changed-constructs"; fixed a bug in "merge-constructs" --> the returned association object is added to the union of all tms the given associations were present in; added some unit-tests
Modified:
branches/new-datamodel/src/model/datamodel.lisp
branches/new-datamodel/src/unit_tests/datamodel_test.lisp
Modified: branches/new-datamodel/src/model/datamodel.lisp
==============================================================================
--- branches/new-datamodel/src/model/datamodel.lisp (original)
+++ branches/new-datamodel/src/model/datamodel.lisp Fri Apr 23 14:47:37 2010
@@ -148,6 +148,9 @@
:check-for-duplicate-identifiers
:find-item-by-content
:rec-remf
+ :get-all-topics
+ :get-all-associations
+ :get-all-tms
;;globals
:*TM-REVISION*
@@ -156,10 +159,10 @@
(in-package :datamodel)
-
-;;TODO: mark-as-deleted should call mark-as-deleted for every owned ???
-;; versioned-construct of the called construct, same for add-xy ???
-;; and associations of player
+;;TODO: replace add-<xy> + add-parent in all merge-constructs where the
+;; characteristics are readded to make sure they are added to the current
+;; version --> collidates with merge-if-equivalent!!! in merge-constructs
+;;TODO: adapt changes-lisp
;;TODO: check merge-constructs in add-topic-identifier,
;; add-item-identifier/add-reifier (can merge the parent constructs
;; and the parent's parent construct + the reifier constructs),
@@ -701,6 +704,34 @@
;;; some helpers ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defun get-db-instances-by-class (class-symbol &key (revision *TM-REVISION*))
+ "Returns all instances of the given type and the given revision that are
+ stored in the db."
+ (declare (symbol class-symbol) (type (or null integer) revision))
+ (let ((db-instances (elephant:get-instances-by-class class-symbol)))
+ (let ((filtered-instances (remove-if-not #'(lambda(inst)
+ (typep inst class-symbol))
+ db-instances)))
+ (if revision
+ (remove-if #'null
+ (map 'list #'(lambda(inst)
+ (find-item-by-revision inst revision))
+ filtered-instances))
+ filtered-instances))))
+
+
+(defun get-all-topics (&optional (revision *TM-REVISION*))
+ (get-db-instances-by-class 'TopicC :revision revision))
+
+
+(defun get-all-associations (&optional (revision *TM-REVISION*))
+ (get-db-instances-by-class 'AssociationC :revision revision))
+
+
+(defun get-all-tms (&optional (revision *TM-REVISION*))
+ (get-db-instances-by-class 'TopicMapC :revision revision))
+
+
(defun find-version-info (versioned-constructs
&key (sort-function #'<) (sort-key 'start-revision))
"Returns all version-infos sorted by the function sort-function which is
@@ -811,14 +842,15 @@
(condition () nil)))
-(defun merge-all-constructs(constructs-to-be-merged)
+(defun merge-all-constructs(constructs-to-be-merged &key (revision *TM-REVISION*))
"Merges all constructs contained in the given list."
(declare (list constructs-to-be-merged))
(let ((constructs-to-be-merged (subseq constructs-to-be-merged 1))
(merged-construct (elt constructs-to-be-merged 0)))
(loop for construct-to-be-merged in constructs-to-be-merged
do (setf merged-construct
- (merge-constructs merged-construct construct-to-be-merged)))))
+ (merge-constructs merged-construct construct-to-be-merged
+ :revision revision)))))
(defgeneric internal-id (construct)
@@ -980,7 +1012,7 @@
;;; VersionedConstructC
-(defgeneric exist-in-revision-history-? (versioned-construct)
+(defgeneric exist-in-version-history-p (versioned-construct)
(:documentation "Returns t if the passed construct does not exist in any
revision, i.e. the construct has no version-infos or exactly
one whose start-revision is equal to its end-revision.")
@@ -1106,8 +1138,16 @@
(let
((last-version ;the last active version
(find 0 (versions construct) :key #'end-revision)))
- (when last-version
- (setf (end-revision last-version) revision))))
+ (if (and last-version
+ (= (start-revision last-version) revision))
+ (progn
+ (delete-construct last-version)
+ (let ((sorted-versions
+ (sort (versions construct) #'> :key #'end-revision)))
+ (when sorted-versions
+ (setf (end-revision (first sorted-versions)) revision))))
+ (when last-version
+ (setf (end-revision last-version) revision)))))
;;; TopicMapconstructC
@@ -2494,9 +2534,14 @@
(and (eql (instance-of construct-1 :revision revision)
(instance-of construct-2 :revision revision))
(not (set-exclusive-or (themes construct-1 :revision revision)
- (themes construct-1 :revision revision)))
- (not (set-exclusive-or (roles construct-1 :revision revision)
- (roles construct-2 :revision revision)))))
+ (themes construct-2 :revision revision)))
+
+ (not (set-exclusive-or
+ (roles construct-1 :revision revision)
+ (roles construct-2 :revision revision)
+ :test #'(lambda(role-1 role-2)
+ (strictly-equivalent-constructs role-1 role-2
+ :revision revision))))))
(defgeneric AssociationC-p (class-symbol)
@@ -2517,21 +2562,22 @@
(type (or null TopicC) instance-of))
;; item-identifiers and reifers are not checked because the equality have to
;; be variafied without them
- (let ((checked-roles
- (loop for assoc-role in (roles construct :revision start-revision)
- when (loop for plist in roles
- when (equivalent-construct
- assoc-role :player (getf plist :player)
- :start-revision (or (getf plist :start-revision)
- start-revision)
- :instance-of (getf plist :instance-of))
- return t)
- collect assoc-role)))
+ (let ((checked-roles nil))
+ (loop for plist in roles
+ do (let ((found-role
+ (find-if #'(lambda(assoc-role)
+ (equivalent-construct
+ assoc-role :player (getf plist :player)
+ :start-revision (or (getf plist :start-revision)
+ start-revision)
+ :instance-of (getf plist :instance-of)))
+ (roles construct :revision start-revision))))
+ (when found-role
+ (push found-role checked-roles))))
(and
(not (set-exclusive-or (roles construct :revision start-revision)
checked-roles))
- (= (length (roles construct :revision start-revision))
- (length roles))
+ (= (length checked-roles) (length roles))
(equivalent-typable-construct construct instance-of
:start-revision start-revision)
(equivalent-scopable-construct construct themes
@@ -3428,9 +3474,10 @@
:roles roles :themes themes
:instance-of instance-of)
existing-association))
- (elephant:get-instances-by-class 'AssociationC)))))
+ (get-all-associations nil)))))
(cond ((> (length existing-associations) 1)
- (merge-all-constructs existing-associations))
+ (merge-all-constructs existing-associations
+ :revision start-revision))
(existing-associations
(first existing-associations))
(t
@@ -3512,9 +3559,9 @@
:item-identifiers item-identifiers
:reifier reifier)
existing-tm))
- (elephant:get-instances-by-class 'TopicMapC)))))
+ (get-all-tms start-revision)))))
(cond ((> (length existing-tms) 1)
- (merge-all-constructs existing-tms))
+ (merge-all-constructs existing-tms :revision start-revision))
(existing-tms
(first existing-tms))
(t
@@ -3554,9 +3601,9 @@
:item-identifiers item-identifiers
:topic-identifiers topic-identifiers)
existing-topic))
- (elephant:get-instances-by-class 'TopicC)))))
+ (get-all-topics start-revision)))))
(cond ((> (length existing-topics) 1)
- (merge-all-constructs existing-topics))
+ (merge-all-constructs existing-topics :revision start-revision))
(existing-topics
(first existing-topics))
(t
@@ -3919,23 +3966,61 @@
(let ((parent (when (or (typep construct 'RoleC)
(typep construct 'CharacteristicC))
(parent construct :revision revision))))
- (let ((found-equivalent
- (find-if #'(lambda(other-construct)
- (strictly-equivalent-constructs
- other-construct construct :revision revision))
- (cond ((typep construct 'OccurrenceC)
- (occurrences parent :revision revision))
- ((typep construct 'NameC)
- (names parent :revision revision))
- ((typep construct 'VariantC)
- (variants parent :revision revision))
- ((typep construct 'RoleC)
- (roles parent :revision revision))
- ((typep construct 'AssociationC)
- (elephant:get-instances-by-class 'AssociationC))))))
- (when found-equivalent
- (merge-all-constructs (append found-equivalent (list construct))))))))
-
+ (let ((all-other (cond ((typep construct 'OccurrenceC)
+ (occurrences parent :revision revision))
+ ((typep construct 'NameC)
+ (names parent :revision revision))
+ ((typep construct 'VariantC)
+ (variants parent :revision revision))
+ ((typep construct 'RoleC)
+ (roles parent :revision revision)))))
+ (let ((all-equivalent
+ (remove-if
+ #'null
+ (map 'list #'(lambda(other)
+ (when (strictly-equivalent-constructs
+ construct other :revision revision)
+ other))
+ all-other))))
+ (when all-equivalent
+ (merge-all-constructs (append all-equivalent (list construct))
+ :revision revision))))))
+ (merge-changed-associations older-topic :revision revision))
+
+
+(defun merge-changed-associations (older-topic &key (revision *TM-REVISION*))
+ "Merges all associations that became TMDM-equal since two referenced topics
+ were merged, e.g. the association types."
+ (declare (TopicC older-topic))
+ (let ((all-assocs
+ (remove-duplicates
+ (append
+ (remove-if
+ #'null
+ (map 'list #'(lambda(role)
+ (parent role :revision revision))
+ (player-in-roles older-topic :revision revision)))
+ (remove-if
+ #'null
+ (map
+ 'list #'(lambda(constr)
+ (when (typep constr 'AssociationC)
+ constr))
+ (append (used-as-type older-topic :revision revision)
+ (used-as-theme older-topic :revision revision))))))))
+ (dolist (assoc all-assocs)
+ (let ((all-equivalent
+ (remove-if
+ #'null
+ (map 'list #'(lambda(db-assoc)
+ (when (strictly-equivalent-constructs
+ assoc db-assoc :revision revision)
+ db-assoc))
+ (get-all-associations nil)))))
+ (when all-equivalent
+ (merge-all-constructs (append all-equivalent (list assoc))
+ :revision revision))))))
+
(defmethod merge-constructs ((construct-1 TopicC) (construct-2 TopicC)
&key (revision *TM-REVISION*))
@@ -3953,7 +4038,7 @@
(move-reified-construct newer-topic older-topic :revision revision)
(merge-changed-constructs older-topic :revision revision)
(mark-as-deleted newer-topic :revision revision :source-locator nil)
- (when (exist-in-revision-history-? newer-topic)
+ (when (exist-in-version-history-p newer-topic)
(delete-construct newer-topic))
older-topic))))
@@ -3980,7 +4065,7 @@
(cond ((and parent-1 (eql parent-1 parent-2))
(move-referenced-constructs newer-char older-char
:revision revision)
- (delete-characteristic newer-char parent-2
+ (delete-characteristic parent-2 newer-char
:revision revision)
older-char)
((and parent-1 parent-2)
@@ -4032,7 +4117,7 @@
(add-to-tm top-or-assoc top-or-assoc))
(add-to-version-history older-tm :start-revision revision)
(mark-as-deleted newer-tm :revision revision)
- (when (exist-in-revision-history-? newer-tm)
+ (when (exist-in-version-history-p newer-tm)
(delete-construct newer-tm))
older-tm))))
@@ -4053,6 +4138,8 @@
construct-1 construct-2)
:construct-1 construct-1
:construct-2 construct-2)))
+ (dolist (tm (in-topicmaps newer-assoc :revision revision))
+ (add-to-tm tm older-assoc))
(move-referenced-constructs newer-assoc older-assoc)
(dolist (newer-role (roles newer-assoc :revision revision))
(let ((equivalent-role
@@ -4065,7 +4152,7 @@
(delete-role newer-assoc newer-role :revision revision)
(add-role older-assoc equivalent-role :revision revision)))
(mark-as-deleted newer-assoc :revision revision)
- (when (exist-in-revision-history-? newer-assoc)
+ (when (exist-in-version-history-p newer-assoc)
(delete-construct newer-assoc))
older-assoc))))
@@ -4091,8 +4178,14 @@
(cond ((and parent-1 (eql parent-1 parent-2))
(move-referenced-constructs newer-role older-role
:revision revision)
- (delete-role newer-role parent-2 :revision revision)
- (add-role older-role parent-1 :revision revision))
+ (delete-role parent-2 newer-role :revision revision)
+ (let ((r-assoc
+ (find-if
+ #'(lambda(r-assoc)
+ (and (eql (role r-assoc) older-role)
+ (eql (parent-construct r-assoc) parent-1)))
+ (slot-p parent-1 'roles))))
+ (add-to-version-history r-assoc :start-revision revision)))
((and parent-1 parent-2)
(let ((active-assoc (merge-constructs parent-1 parent-2
:revision revision)))
Modified: branches/new-datamodel/src/unit_tests/datamodel_test.lisp
==============================================================================
--- branches/new-datamodel/src/unit_tests/datamodel_test.lisp (original)
+++ branches/new-datamodel/src/unit_tests/datamodel_test.lisp Fri Apr 23 14:47:37 2010
@@ -81,7 +81,12 @@
:test-find-oldest-construct
:test-move-referenced-constructs-ReifiableConstructC
:test-move-referenced-constructs-NameC
- :test-merge-constructs-TopicC-1))
+ :test-merge-constructs-TopicC-1
+ :test-merge-constructs-TopicC-2
+ :test-merge-constructs-TopicC-3
+ :test-merge-constructs-TopicC-4
+ :test-merge-constructs-TopicC-5
+ :test-merge-constructs-TopicC-6))
;;TODO: test merge-constructs
@@ -1815,7 +1820,7 @@
:start-revision rev-1))
(role-2 (list :player player-2 :instance-of r-type-2
:start-revision rev-1))
- (role-3 (list :instance-of r-type-3 :player player-3
+ (role-3 (list :player player-3 :instance-of r-type-3
:start-revision rev-1))
(type-1 (make-instance 'd:TopicC))
(type-2 (make-instance 'd:TopicC))
@@ -1877,7 +1882,7 @@
(is-false (d::strictly-equivalent-constructs assoc-1 assoc-3))
(is-false (d::strictly-equivalent-constructs assoc-1 assoc-4))
(is-false (d::strictly-equivalent-constructs assoc-1 assoc-5))
- (is-false (d::strictly-equivalent-constructs assoc-1 assoc-6)))))))
+ (is-true (d::strictly-equivalent-constructs assoc-1 assoc-6)))))))
(test test-equivalent-TopicC ()
@@ -3046,6 +3051,414 @@
(is-true (d::marked-as-deleted-p occ-3))))))))))
+(test test-merge-constructs-TopicC-2 ()
+ "Tests the generic move-referenced-constructs corresponding to TopicC."
+ (with-fixture with-empty-db (*db-dir*)
+ (let ((rev-1 100)
+ (rev-2 200)
+ (rev-3 300))
+ (let ((ii-1 (make-construct 'ItemIdentifierC :uri "ii-1"))
+ (ii-2 (make-construct 'ItemIdentifierC :uri "ii-2"))
+ (ii-3 (make-construct 'ItemIdentifierC :uri "ii-3"))
+ (sl-1 (make-construct 'SubjectLocatorC :uri "sl-1"))
+ (sl-2 (make-construct 'SubjectLocatorC :uri "sl-2"))
+ (psi-1 (make-construct 'PersistentIdC :uri "psi-1"))
+ (psi-2 (make-construct 'PersistentIdC :uri "psi-2"))
+ (tid-1 (make-construct 'TopicIdentificationC :uri "tid-1"
+ :xtm-id "xtm-1"))
+ (tid-2 (make-construct 'TopicIdentificationC :uri "tid-2"
+ :xtm-id "xtm-2"))
+ (type-1 (make-construct 'TopicC :start-revision rev-1))
+ (type-2 (make-construct 'TopicC :start-revision rev-1))
+ (theme-1 (make-construct 'TopicC :start-revision rev-1))
+ (theme-2 (make-construct 'TopicC :start-revision rev-1)))
+ (let ((variant-1 (make-construct 'VariantC
+ :start-revision rev-1
+ :charvalue "var-1"
+ :themes (list theme-1)))
+ (variant-2 (make-construct 'VariantC
+ :start-revision rev-2
+ :charvalue "var-2"
+ :themes (list theme-2)))
+ (variant-3 (make-construct 'VariantC
+ :start-revision rev-1
+ :charvalue "var-1"
+ :themes (list theme-1)))
+ (occ-1 (make-construct 'OccurrenceC
+ :start-revision rev-1
+ :charvalue "occ-1"
+ :instance-of type-1
+ :themes (list theme-1)))
+ (occ-2 (make-construct 'OccurrenceC
+ :start-revision rev-1
+ :charvalue "occ-2"
+ :instance-of type-2))
+ (occ-3 (make-construct 'OccurrenceC
+ :start-revision rev-2
+ :item-identifiers (list ii-3)
+ :charvalue "occ-1"
+ :instance-of type-1
+ :themes (list theme-1))))
+ (let ((name-1 (make-construct 'NameC
+ :start-revision rev-1
+ :charvalue "name-1"
+ :instance-of type-1))
+ (name-2 (make-construct 'NameC
+ :start-revision rev-2
+ :charvalue "name-2"
+ :instance-of type-1
+ :variants (list variant-1 variant-2)))
+ (name-3 (make-construct 'NameC
+ :start-revision rev-1
+ :charvalue "name-1"
+ :instance-of type-1
+ :variants (list variant-3))))
+ (let ((top-1 (make-construct 'TopicC
+ :start-revision rev-1
+ :topic-identifiers (list tid-1)
+ :item-identifiers (list ii-1)
+ :locators (list sl-1)
+ :psis (list psi-1)
+ :names (list name-1 name-2)
+ :occurrences (list occ-1 occ-2)))
+ (top-2 (make-construct 'TopicC
+ :start-revision rev-3
+ :topic-identifiers (list tid-2)
+ :item-identifiers (list ii-2)
+ :locators (list sl-2)
+ :psis (list psi-2)
+ :names (list name-3)
+ :occurrences (list occ-3))))
+ (setf *TM-REVISION* rev-3)
+ (is (= (length (elephant:get-instances-by-class 'TopicC)) 6))
+ (is (= (length (elephant:get-instances-by-class 'NameC)) 3))
+ (is (= (length (elephant:get-instances-by-class 'OccurrenceC)) 3))
+ (is (= (length (elephant:get-instances-by-class 'VariantC)) 3))
+ (let ((top (d::merge-constructs top-1 top-2 :revision rev-3)))
+ (is (= (length (elephant:get-instances-by-class 'TopicC)) 5))
+ (is (= (length (elephant:get-instances-by-class 'NameC)) 2))
+ (is (= (length (elephant:get-instances-by-class 'OccurrenceC)) 2))
+ (is (= (length (elephant:get-instances-by-class 'VariantC)) 3))
+ (is (eql top top-1))
+ (is-false (append (psis top-2) (item-identifiers top-2)
+ (locators top-2) (topic-identifiers top-2)
+ (names top-2) (occurrences top-2)))
+ (is-false (set-exclusive-or (list ii-1 ii-2)
+ (item-identifiers top-1)))
+ (is-false (set-exclusive-or (list sl-1 sl-2) (locators top-1)))
+ (is-false (set-exclusive-or (list psi-1 psi-2) (psis top-1)))
+ (is-false (set-exclusive-or (list tid-1 tid-2)
+ (topic-identifiers top-1)))
+ (is-false (set-exclusive-or (list psi-1)
+ (psis top-1 :revision rev-2)))
+ (is-false (set-exclusive-or (list name-1 name-2)
+ (names top-1)))
+ (is-false (set-exclusive-or (variants name-1)
+ (list variant-3)))
+ (is-false (variants name-3))
+ (is-false (set-exclusive-or (occurrences top-1)
+ (list occ-1 occ-2)))
+ (is-false (set-exclusive-or (item-identifiers occ-1)
+ (list ii-3)))
+ (is-false (item-identifiers occ-3))
+ (is-true (d::marked-as-deleted-p name-3))
+ (is-true (d::marked-as-deleted-p occ-3))))))))))
+
+
+(test test-merge-constructs-TopicC-3 ()
+ "Tests the generic move-referenced-constructs corresponding to TopicC."
+ (with-fixture with-empty-db (*db-dir*)
+ (let ((rev-1 100)
+ (rev-3 300))
+ (let ((type-1 (make-construct 'TopicC :start-revision rev-1))
+ (type-2 (make-construct 'TopicC :start-revision rev-1))
+ (n-type (make-construct 'TopicC :start-revision rev-1))
+ (ii-1 (make-construct 'ItemIdentifierC :uri "ii-1"))
+ (ii-2 (make-construct 'ItemIdentifierC :uri "ii-2"))
+ (ii-3 (make-construct 'ItemIdentifierC :uri "ii-3"))
+ (ii-4 (make-construct 'ItemIdentifierC :uri "ii-4"))
+ (ii-5 (make-construct 'ItemIdentifierC :uri "ii-5"))
+ (ii-6 (make-construct 'ItemIdentifierC :uri "ii-6"))
+ (var-0-1
+ (make-construct 'VariantC
+ :start-revision rev-1
+ :themes (list
+ (make-construct 'TopicC
+ :start-revision rev-1))
+ :charvalue "var-0-1"))
+ (var-0-2
+ (make-construct 'VariantC
+ :start-revision rev-1
+ :themes (list
+ (make-construct 'TopicC
+ :start-revision rev-1))
+ :charvalue "var-0-1")))
+ (let ((occ-1 (make-construct 'OccurrenceC
+ :start-revision rev-1
+ :item-identifiers (list ii-1)
+ :charvalue "occ"
+ :instance-of type-1))
+ (occ-2 (make-construct 'OccurrenceC
+ :start-revision rev-1
+ :item-identifiers (list ii-2)
+ :charvalue "occ"
+ :instance-of type-2))
+ (name-1 (make-construct 'NameC
+ :start-revision rev-1
+ :item-identifiers (list ii-3)
+ :variants (list var-0-1)
+ :charvalue "name"
+ :instance-of type-1))
+ (name-2 (make-construct 'NameC
+ :start-revision rev-1
+ :item-identifiers (list ii-4)
+ :variants (list var-0-2)
+ :charvalue "name"
+ :instance-of type-2))
+ (var-1 (make-construct 'VariantC
+ :start-revision rev-1
+ :item-identifiers (list ii-5)
+ :charvalue "var"
+ :themes (list type-1)))
+ (var-2 (make-construct 'VariantC
+ :start-revision rev-1
+ :item-identifiers (list ii-6)
+ :charvalue "var"
+ :themes (list type-2))))
+ (let ((top-1 (make-construct 'TopicC
+ :start-revision rev-1
+ :occurrences (list occ-1 occ-2)
+ :names (list name-1 name-2)))
+ (name-3 (make-construct 'NameC
+ :start-revision rev-1
+ :charvalue "name-3"
+ :instance-of n-type
+ :variants (list var-1 var-2))))
+ (let ((top-2 (make-construct 'TopicC
+ :start-revision rev-1
+ :names (list name-3))))
+ (setf *TM-REVISION* rev-3)
+ (is (eql (d::merge-constructs type-1 type-2 :revision rev-3) type-1))
+ (is (= (length (occurrences top-1)) 1))
+ (is-false (set-exclusive-or
+ (list ii-1 ii-2)
+ (item-identifiers (first (occurrences top-1)))))
+ (is (= (length (slot-value top-1 'd::occurrences)) 2))
+ (is (= (length (names top-1)) 1))
+ (is-false (set-exclusive-or
+ (list ii-3 ii-4)
+ (item-identifiers (first (names top-1)))))
+ (is (= (length (slot-value top-1 'd::names)) 2))
+ (is-false (set-exclusive-or (list var-0-1 var-0-2)
+ (variants (first (names top-1)))))
+ (is-true (d::marked-as-deleted-p
+ (find-if-not #'(lambda(occ)
+ (eql occ (first (occurrences top-1))))
+ (slot-value top-1 'd::occurrences))))
+ (is-true (d::marked-as-deleted-p
+ (find-if-not #'(lambda(name)
+ (eql name (first (names top-1))))
+ (slot-value top-1 'd::names))))
+ (is (= (length (variants (first (names top-2)))) 1))
+ (is (= (length (slot-value (first (names top-2)) 'd::variants)) 2))
+ (is (eql (first (themes (first (variants (first (names top-2))))))
+ type-1)))))))))
+
+
+(test test-merge-constructs-TopicC-4 ()
+ "Tests the generic move-referenced-constructs corresponding to TopicC."
+ (with-fixture with-empty-db (*db-dir*)
+ (let ((rev-1 100)
+ (rev-3 300))
+ (let ((type-1 (make-construct 'TopicC :start-revision rev-1))
+ (type-2 (make-construct 'TopicC :start-revision rev-1))
+ (a-type (make-construct 'TopicC :start-revision rev-1))
+ (r-type (make-construct 'TopicC :start-revision rev-1))
+ (ii-1 (make-construct 'ItemIdentifierC :uri "ii-1"))
+ (ii-2 (make-construct 'ItemIdentifierC :uri "ii-2")))
+ (let ((assoc-1 (make-construct 'AssociationC
+ :start-revision rev-1
+ :instance-of a-type
+ :roles (list (list :player type-1
+ :instance-of r-type
+ :item-identifiers (list ii-1)
+ :start-revision rev-1)
+ (list :player type-2
+ :item-identifiers (list ii-2)
+ :instance-of r-type
+ :start-revision rev-1)))))
+ (setf *TM-REVISION* rev-3)
+ (is (eql (d::merge-constructs type-1 type-2 :revision rev-3) type-1))
+ (is (= (length (roles assoc-1)) 1))
+ (is (= (length (slot-value assoc-1 'd::roles)) 2))
+ (is (eql (instance-of (first (roles assoc-1))) r-type))
+ (is (eql (player (first (roles assoc-1))) type-1))
+ (is-false (set-exclusive-or (list ii-1 ii-2)
+ (item-identifiers (first (roles assoc-1)))))
+ (let ((active-role (first (roles assoc-1)))
+ (non-active-role
+ (let ((r-assoc (find-if-not #'(lambda(role)
+ (eql role (first (roles assoc-1))))
+ (slot-value assoc-1 'd::roles))))
+ (when r-assoc
+ (d::role r-assoc)))))
+ (is (= (length (d::versions
+ (first (slot-value active-role 'd::parent)))) 2))
+ (is (= (length (d::versions
+ (first (slot-value non-active-role 'd::parent)))) 1))
+ (is-true (find-if #'(lambda(vi)
+ (and (= rev-1 (d::start-revision vi))
+ (= rev-3 (d::end-revision vi))))
+ (d::versions (first (slot-value non-active-role
+ 'd::parent)))))
+ (is-true (find-if #'(lambda(vi)
+ (and (= rev-1 (d::start-revision vi))
+ (= rev-3 (d::end-revision vi))))
+ (d::versions (first (slot-value active-role
+ 'd::parent)))))
+ (is-true (find-if #'(lambda(vi)
+ (and (= rev-3 (d::start-revision vi))
+ (= 0 (d::end-revision vi))))
+ (d::versions (first (slot-value active-role
+ 'd::parent)))))))))))
+
+
+(test test-merge-constructs-TopicC-5 ()
+ "Tests the generic move-referenced-constructs corresponding to TopicC."
+ (with-fixture with-empty-db (*db-dir*)
+ (let ((rev-1 100)
+ (rev-3 300))
+ (let ((type-1 (make-construct 'TopicC :start-revision rev-1))
+ (type-2 (make-construct 'TopicC :start-revision rev-1))
+ (a-type (make-construct 'TopicC :start-revision rev-1))
+ (player-1 (make-construct 'TopicC :start-revision rev-1))
+ (ii-1 (make-construct 'ItemIdentifierC :uri "ii-1"))
+ (ii-2 (make-construct 'ItemIdentifierC :uri "ii-2")))
+ (let ((assoc-2 (make-construct 'AssociationC
+ :start-revision rev-1
+ :instance-of a-type
+ :roles (list (list :player player-1
+ :instance-of type-1
+ :item-identifiers (list ii-1)
+ :start-revision rev-1)
+ (list :player player-1
+ :item-identifiers (list ii-2)
+ :instance-of type-2
+ :start-revision rev-1)))))
+ (setf *TM-REVISION* rev-3)
+ (is (eql (d::merge-constructs type-1 type-2 :revision rev-3) type-1))
+ (is (= (length (roles assoc-2)) 1))
+ (is (= (length (slot-value assoc-2 'd::roles)) 2))
+ (is (eql (instance-of (first (roles assoc-2))) type-1))
+ (is (eql (player (first (roles assoc-2))) player-1))
+ (is-false (set-exclusive-or (list ii-1 ii-2)
+ (item-identifiers (first (roles assoc-2)))))
+ (let ((active-role (first (roles assoc-2)))
+ (non-active-role
+ (let ((r-assoc (find-if-not #'(lambda(role)
+ (eql role (first (roles assoc-2))))
+ (slot-value assoc-2 'd::roles))))
+ (when r-assoc
+ (d::role r-assoc)))))
+ (is (= (length (d::versions
+ (first (slot-value active-role 'd::parent)))) 2))
+ (is (= (length (d::versions
+ (first (slot-value non-active-role 'd::parent)))) 1))
+ (is-true (find-if #'(lambda(vi)
+ (and (= rev-1 (d::start-revision vi))
+ (= rev-3 (d::end-revision vi))))
+ (d::versions (first (slot-value non-active-role
+ 'd::parent)))))
+ (is-true (find-if #'(lambda(vi)
+ (and (= rev-1 (d::start-revision vi))
+ (= rev-3 (d::end-revision vi))))
+ (d::versions (first (slot-value active-role
+ 'd::parent)))))
+ (is-true (find-if #'(lambda(vi)
+ (and (= rev-3 (d::start-revision vi))
+ (= 0 (d::end-revision vi))))
+ (d::versions (first (slot-value active-role
+ 'd::parent)))))))))))
+
+
+(test test-merge-constructs-TopicC-6 ()
+ "Tests the generic move-referenced-constructs corresponding to TopicC."
+ (with-fixture with-empty-db (*db-dir*)
+ (let ((rev-1 100)
+ (rev-2 200)
+ (rev-3 300))
+ (let ((type-1 (make-construct 'TopicC :start-revision rev-1))
+ (type-2 (make-construct 'TopicC :start-revision rev-1))
+ (r-type-1 (make-construct 'TopicC :start-revision rev-1))
+ (r-type-2 (make-construct 'TopicC :start-revision rev-1))
+ (player-1 (make-construct 'TopicC :start-revision rev-1))
+ (player-2 (make-construct 'TopicC :start-revision rev-1))
+ (ii-1 (make-construct 'ItemIdentifierC :uri "ii-1"))
+ (ii-2 (make-construct 'ItemIdentifierC :uri "ii-2"))
+ (ii-3 (make-construct 'ItemIdentifierC :uri "ii-3"))
+ (ii-4 (make-construct 'ItemIdentifierC :uri "ii-4")))
+ (let ((assoc-3 (make-construct 'AssociationC
+ :start-revision rev-1
+ :instance-of type-1
+ :item-identifiers (list ii-3)
+ :roles (list (list :player player-1
+ :instance-of r-type-1
+ :item-identifiers (list ii-1)
+ :start-revision rev-1)
+ (list :player player-2
+ :instance-of r-type-2
+ :start-revision rev-1))))
+ (assoc-4 (make-construct 'AssociationC
+ :start-revision rev-2
+ :instance-of type-2
+ :item-identifiers (list ii-4)
+ :roles (list (list :player player-1
+ :instance-of r-type-1
+ :start-revision rev-2)
+ (list :player player-2
+ :item-identifiers (list ii-2)
+ :instance-of r-type-2
+ :start-revision rev-2)))))
+ (setf *TM-REVISION* rev-3)
+ (is (eql (d::merge-constructs type-1 type-2 :revision rev-3) type-1))
+ (is (= (length (d::versions assoc-3)) 2))
+ (is (= (length (d::versions assoc-4)) 1))
+ (is-true (find-if #'(lambda(vi)
+ (and (= (d::start-revision vi) rev-1)
+ (= (d::end-revision vi) rev-3)))
+ (d::versions assoc-3)))
+ (is-true (find-if #'(lambda(vi)
+ (and (= (d::start-revision vi) rev-3)
+ (= (d::end-revision vi) 0)))
+ (d::versions assoc-3)))
+ (is-true (find-if #'(lambda(vi)
+ (and (= (d::start-revision vi) rev-2)
+ (= (d::end-revision vi) rev-3)))
+ (d::versions assoc-4)))
+ (is (= (length (roles assoc-3)) 2))
+ (is (= (length (item-identifiers (first (roles assoc-3)))) 1))
+ (is (= (length (item-identifiers (second (roles assoc-3)))) 1))
+ (is (or (and (string= (uri (first (item-identifiers
+ (first (roles assoc-3)))))
+ "ii-1")
+ (string= (uri (first (item-identifiers
+ (second (roles assoc-3)))))
+ "ii-2"))
+ (and (string= (uri (first (item-identifiers
+ (first (roles assoc-3)))))
+ "ii-2")
+ (string= (uri (first (item-identifiers
+ (second (roles assoc-3)))))
+ "ii-1")))))))))
+
+
+
+
+
+
+;;TODO: merge topics/associations caused by a merge of their characteristics
+;;TODO: merge-topic when reifies a construct; merge 2 topics when occs are reified
+;; by the same reifier
@@ -3108,4 +3521,9 @@
(it.bese.fiveam:run! 'test-move-referenced-constructs-ReifiableConstructC)
(it.bese.fiveam:run! 'test-move-referenced-constructs-NameC)
(it.bese.fiveam:run! 'test-merge-constructs-TopicC-1)
+ (it.bese.fiveam:run! 'test-merge-constructs-TopicC-2)
+ (it.bese.fiveam:run! 'test-merge-constructs-TopicC-3)
+ (it.bese.fiveam:run! 'test-merge-constructs-TopicC-4)
+ (it.bese.fiveam:run! 'test-merge-constructs-TopicC-5)
+ (it.bese.fiveam:run! 'test-merge-constructs-TopicC-6)
)
\ No newline at end of file