Author: lgiessmann
Date: Mon Apr 5 14:07:59 2010
New Revision: 258
Log:
new-datamodel: added the generics "add-reified-construct" and "delet-reified-construct" for "TopicC"; added "merge-constructs" for "TopicC"; changed the behaviour of merging "CharacteristicC"s
Modified:
branches/new-datamodel/src/model/datamodel.lisp
Modified: branches/new-datamodel/src/model/datamodel.lisp
==============================================================================
--- branches/new-datamodel/src/model/datamodel.lisp (original)
+++ branches/new-datamodel/src/model/datamodel.lisp Mon Apr 5 14:07:59 2010
@@ -155,6 +155,8 @@
(in-package :datamodel)
+;;TODO: mark-as-deleted should call mark as deleted for every owned
+;; versioned-construct of the called construct
;;TODO: check for duplicate identifiers after topic-creation/merge
;;TODO: add: add-to-version-history (parent) to all
;; "add-<construct>"/"delete-<construct>" generics
@@ -167,9 +169,7 @@
;; and a merge should be done
;;TODO: use some exceptions --> more than one type,
;; identifier, not-mergable merges, missing-init-args...
-;;TODO: implement merge-construct -> ReifiableConstructC -> ...
-;; the method should merge two constructs that are inherited from
-;; ReifiableConstructC
+
;;; globals ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -758,6 +758,11 @@
;;; generic definitions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defgeneric mark-as-deleted (construct &key source-locator revision)
+ (:documentation "Mark a construct as deleted if it comes from the source
+ indicated by source-locator"))
+
+
(defgeneric find-oldest-construct (construct-1 construct-2)
(:documentation "Returns the construct which owns the oldes version info.
If a construct is not a versioned construct the oldest
@@ -855,6 +860,17 @@
;;; VersionedConstructC
+(defgeneric does-not-exist-in-revision-history (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.")
+ (:method ((versioned-construct VersionedConstructC))
+ (or (not (versions versioned-construct))
+ (and (= (length (versions versioned-construct)) 1)
+ (= (start-revision (first (versions versioned-construct)))
+ (end-revision (first (versions versioned-construct))))))))
+
+
(defmethod find-oldest-construct ((construct-1 VersionedConstructC)
(construct-2 VersionedConstructC))
(let ((vi-1 (find-version-info (list construct-1)))
@@ -963,16 +979,14 @@
t)))
-(defgeneric mark-as-deleted (construct &key source-locator revision)
- (:documentation "Mark a construct as deleted if it comes from the source
- indicated by source-locator")
- (:method ((construct VersionedConstructC) &key source-locator revision)
- (declare (ignorable source-locator))
- (let
- ((last-version ;the last active version
- (find 0 (versions construct) :key #'end-revision)))
- (when last-version
- (setf (end-revision last-version) revision)))))
+(defmethod marks-as-deleted ((construct VersionedConstructC)
+ &key source-locator revision)
+ (declare (ignorable source-locator))
+ (let
+ ((last-version ;the last active version
+ (find 0 (versions construct) :key #'end-revision)))
+ (when last-version
+ (setf (end-revision last-version) revision))))
;;; TopicMapconstructC
@@ -1661,6 +1675,24 @@
(reifiable-construct (first assocs))))))
+(defgeneric add-reified-construct (construct reified-construct &key revision)
+ (:documentation "Sets the passed construct as reified-consturct of the given
+ topic.")
+ (:method ((construct TopicC) (reified-construct ReifiableConstructC)
+ &key (revision *TM-REVISION*))
+ (declare (integer revision))
+ (add-reifier reified-construct construct :revision revision)))
+
+
+(defgeneric delete-reified-construct (construct reified-construct &key revision)
+ (:documentation "Unsets the passed construct as reified-construct of the
+ given topic.")
+ (:method ((construct TopicC) (reified-construct ReifiableConstructC)
+ &key (revision *TM-REVISION*))
+ (declare (integer revision))
+ (delete-reifier reified-construct construct :revision revision)))
+
+
(defmethod in-topicmaps ((topic TopicC) &key (revision *TM-REVISION*))
(filter-slot-value-by-revision topic 'in-topicmaps :start-revision revision))
@@ -1931,7 +1963,7 @@
(parent-construct ReifiableConstructC)
&key (revision *TM-REVISION*))
(let ((already-set-parent (parent construct :revision revision))
- (same-parent-assoc ;should contain a object that was marked as deleted
+ (same-parent-assoc ;should contain an object that was marked as deleted
(loop for parent-assoc in (slot-p construct 'parent)
when (eql parent-construct (parent-construct parent-assoc))
return parent-assoc)))
@@ -2598,13 +2630,14 @@
(merge-constructs (reifier construct :revision revision)
reifier-topic)
reifier-topic)))
- (let ((all-constructs
- (let ((inner-construct (reified-construct merged-reifier-topic
- :revision revision)))
- (when inner-construct
- (list inner-construct)))))
+ (let ((all-constructs (map 'list #'reifiable-construct
+ (slot-p reifier-topic 'reified-construct))))
(let ((merged-construct construct))
- (cond ((find construct all-constructs)
+ (cond ((reified-construct merged-reifier-topic :revision revision)
+ (merge-constructs
+ (reified-construct merged-reifier-topic :revision revision)
+ construct))
+ ((find construct all-constructs)
(let ((reifier-assoc
(loop for reifier-assoc in
(slot-p merged-reifier-topic 'reified-construct)
@@ -2613,8 +2646,6 @@
return reifier-assoc)))
(add-to-version-history reifier-assoc
:start-revision revision)))
- (all-constructs
- (merge-constructs (first all-constructs) construct))
(t
(make-construct 'ReifierAssociationC
:reifiable-construct construct
@@ -2959,7 +2990,7 @@
(not start-revision))
(error "From make-association(): start-revision must be set"))
(let ((association
- (let ((existing-association
+ (let ((existing-associations
(remove-if
#'null
(map 'list #'(lambda(existing-association)
@@ -2970,9 +3001,12 @@
:instance-of instance-of)
existing-association))
(elephant:get-instances-by-class 'AssociationC)))))
- (if existing-association
- (first existing-association)
- (make-instance 'AssociationC)))))
+ (cond ((> (length existing-associations) 1)
+ (merge-all-constructs existing-associations))
+ (existing-associations
+ (first existing-associations))
+ (t
+ (make-instance 'AssociationC))))))
(dolist (role-plist roles)
(add-role association
(apply #'make-construct 'RoleC
@@ -2993,7 +3027,7 @@
(not start-revision))
(error "From make-role(): start-revision must be set"))
(let ((role
- (let ((existing-role
+ (let ((existing-roles
(when parent
(remove-if
#'null
@@ -3005,9 +3039,12 @@
:instance-of instance-of)
existing-role))
(map 'list #'role (slot-p parent 'roles)))))))
- (if existing-role
- (first existing-role)
- (make-instance 'RoleC)))))
+ (cond ((> (length existing-roles) 1)
+ (merge-all-constructs existing-roles))
+ (existing-roles
+ (first existing-roles))
+ (t
+ (make-instance 'RoleC))))))
(when player
(add-player role player :revision start-revision))
(when parent
@@ -3038,7 +3075,7 @@
:reifier reifier)
existing-tm))
(elephant:get-instances-by-class 'TopicMapC)))))
- (cond ((and existing-tms (> (length existing-tms) 1))
+ (cond ((> (length existing-tms) 1)
(merge-all-constructs existing-tms))
(existing-tms
(first existing-tms))
@@ -3077,7 +3114,7 @@
:topic-identifiers topic-identifiers)
existing-topic))
(elephant:get-instances-by-class 'TopicC)))))
- (cond ((and existing-topics (> (length existing-topics) 1))
+ (cond ((> (length existing-topics) 1)
(merge-all-constructs existing-topics))
(existing-topics
(first existing-topics))
@@ -3205,167 +3242,265 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+;;; merge-constructs ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defgeneric move-identifiers (source destination &key revision)
+ (:documentation "Sets all identifiers as mark as deleted in the given
+ version and adds the marked identifiers to the
+ destination construct."))
+(defmethod move-identifiers ((source ReifiableConstructC)
+ (destination ReifiableConstructC)
+ &key (revision *TM-REVISION*))
+ (declare (integer revision))
+ (let ((iis (item-identifiers source :revision revision)))
+ (dolist (ii iis)
+ (delete-item-identifier source ii :revision revision)
+ (add-item-identifier destination ii :revision revision))
+ iis))
-;;; start hacks ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-(defmethod merge-constructs ((construct-1 TopicMapConstructC) (construct-2 TopicMapconstructC)
+(defmethod move-identifiers ((source TopicC) (destination TopicC)
&key (revision *TM-REVISION*))
- (or revision)
- (if construct-1 construct-1 construct-2))
-;;; end hacks ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ (declare (integer revision))
+ (let ((iis (call-next-method))
+ (tids (topic-identifiers source :revision revision))
+ (psis (psis source :revision revision))
+ (sls (locators source :revision revision)))
+ (dolist (tid tids)
+ (delete-topic-identifier source tid :revision revision)
+ (add-topic-identifier destination tid :revision revision))
+ (dolist (psi psis)
+ (delete-psi source psi :revision revision)
+ (add-psi destination psi :revision revision))
+ (dolist (sl sls)
+ (delete-locator source sl :revision revision)
+ (add-locator destination sl :revision revision))
+ (append tids iis psis sls)))
+
+
+(defgeneric move-referenced-constructs (source destination &key revision)
+ (:documentation "Moves all referenced constructs in the given version from
+ the source TM-construct to the destination TM-construct."))
+
+
+(defmethod move-referenced-constructs ((source ReifiableConstructC)
+ (destination ReifiableConstructC)
+ &key (revision *TM-REVISION*))
+ (let ((source-reifier (reifier source :revision revision))
+ (destination-reifier (reifier destination :revision revision)))
+ (cond ((and source-reifier destination-reifier)
+ (delete-reifier (reified-construct source-reifier :revision revision)
+ source-reifier :revision revision)
+ (delete-reifier (reified-construct destination-reifier
+ :revision revision)
+ destination-reifier :revision revision)
+ (let ((merged-reifier
+ (merge-constructs source-reifier destination-reifier
+ :revision revision)))
+ (add-reifier destination merged-reifier :revision revision)))
+ (source-reifier
+ (delete-reifier (reified-construct source-reifier :revision revision)
+ source-reifier :revision revision)
+ (add-reifier destination source-reifier :revision revision)
+ source-reifier)
+ (destination-reifier
+ (add-reifier destination destination-reifier :revision revision)
+ destination-reifier))))
+
+
+(defmethod move-referenced-constructs ((source TopicC) (destination TopicC)
+ &key (revision *TM-REVISION*))
+ (let ((roles (player-in-roles source :revision revision))
+ (scopables (used-as-theme source :revision revision))
+ (typables (used-as-type source :revision revision)))
+ (dolist (role roles)
+ (delete-player role source :revision revision)
+ (add-player role destination :revision revision))
+ (dolist (scopable scopables)
+ (delete-theme scopable source :revision revision)
+ (add-theme scopable destination :revision revision))
+ (dolist (typable typables)
+ (delete-type typable source :revision revision)
+ (add-type typable destination :revision revision))
+ (append roles scopables typables)))
+
+
+(defgeneric move-reified-construct (source destination &key revision)
+ (:documentation "Moves the refied TM-construct from the source topic
+ to the given destination topic.")
+ (:method ((source TopicC) (destination TopicC) &key (revision *TM-REVISION*))
+ (declare (integer revision))
+ (let ((source-reified (reified-construct source :revision revision))
+ (destination-reified (reified-construct destination
+ :revision revision)))
+ (unless (eql (type-of source-reified) (type-of destination-reified))
+ (error "From move-reified-construct(): ~a and ~a can't be merged since the reified-constructs are not of the same type ~a ~a"
+ source destination source-reified destination-reified))
+ (cond ((and source-reified destination-reified)
+ (delete-reifier source-reified source :revision revision)
+ (delete-reifier destination-reified destination :revision revision)
+ (let ((merged-reified
+ (merge-constructs source-reified destination-reified
+ :revision revision)))
+ (add-reifier merged-reified destination :revision revision)
+ merged-reified))
+ (source-reified
+ (delete-reifier source source-reified :revision revision)
+ (add-reifier destination source-reified :revision revision)
+ source-reified)
+ (destination-reified
+ (add-reifier destination destination-reified :revision revision)
+ destination-reified)))))
+
+
+(defgeneric move-occurrences (source destination &key revision)
+ (:documentation "Moves all occurrences from the source topic to the
+ destination topic. If occurrences are TMDM equal
+ they are merged, i.e. one is marked-as-deleted.")
+ (:method ((source TopicC) (destination TopicC) &key (revision *TM-REVISION*))
+ (declare (integer revision))
+ (let ((occs-to-move (occurrences source :revision revision)))
+ (dolist (occ occs-to-move)
+ (delete-occurrence occ source :revision revision)
+ (let ((equivalent-occ
+ (find-if #'(lambda (destination-occ)
+ (when
+ (strictly-equivalent-constructs
+ occ destination-occ :revision revision)
+ destination-occ))
+ (occurrences destination :revision revision))))
+ (if equivalent-occ
+ (progn
+ (add-occurrence destination equivalent-occ :revision revision)
+ (move-identifiers occ equivalent-occ :revision revision)
+ (move-referenced-constructs occ equivalent-occ
+ :revision revision))
+ (add-occurrence destination occ :revision revision))))
+ occs-to-move)))
-(defun merge-characteristics (older-parent newer-parent
- &key (revision *TM-REVISION*)
- (characteristic-type 'OccurrenceC))
- "Deletes all characteristics of the given type from the newer-parent.
- Merges equivalent characteristics between the newer and the older parent.
- Adds all characteristics from the newer-parent to the older-parent or adds
- the merged characterisitcs to the older-parent."
- (declare (type (or TopicC NameC) older-parent newer-parent)
- (integer revision) (symbol characteristic-type))
- (let ((object-name
- (subseq (write-to-string characteristic-type) 0
- (- (length (write-to-string characteristic-type)) 1))))
- (let ((request-fun
- (symbol-function
- (find-symbol (concatenate 'string object-name "S"))))
- (delete-fun
- (symbol-function
- (find-symbol (concatenate 'string "DELETE-" object-name))))
- (add-fun
- (symbol-function
- (find-symbol (concatenate 'string "ADD-" object-name)))))
- (dolist (newer-char (funcall request-fun newer-parent :revision revision))
- (let ((older-char
- (find-if #'(lambda(char)
- (equivalent-constructs char newer-char
- :revision revision))
- (funcall request-fun older-parent :revision revision))))
- (funcall delete-fun newer-parent newer-char :revision revision)
- (if (and newer-char older-char)
+(defgeneric move-variants (source destination &key revision)
+ (:documentation "Moves all variants from the source name to the destination
+ name. If any variants are TMDM equal they are merged -->
+ i.e. one of the variants is marked-as-deleted.")
+ (:method ((source NameC) (destination NameC) &key (revision *TM-REVISION*))
+ (declare (integer revision))
+ (let ((vars-to-move (variants source :revision revision)))
+ (dolist (var vars-to-move)
+ (delete-variant source var :revision revision)
+ (let ((equivalent-var
+ (find-if #'(lambda (destination-var)
+ (when
+ (strictly-equivalent-constructs
+ var destination-var :revision revision)
+ destination-var))
+ (variants destination :revision revision))))
+ (if equivalent-var
(progn
- (funcall delete-fun older-parent older-char :revision revision)
- (funcall add-fun older-parent
- (merge-constructs newer-char older-char
- :revision revision)))
- (funcall add-fun older-parent newer-char)))))))
+ (add-variant destination equivalent-var :revision revision)
+ (move-identifiers var equivalent-var :revision revision)
+ (move-referenced-constructs var equivalent-var
+ :revision revision))
+ (add-variant destination var :revision revision))))
+ vars-to-move)))
-(defmethod merge-constructs ((construct-1 ReifiableConstructC)
- (construct-2 ReifiableConstructC)
- &key (revision *TM-REVISION*))
- (declare (integer revision))
- (if (eql construct-1 construct-2)
- construct-1
- (let ((older-construct (find-oldest-construct construct-1 construct-2)))
- (let ((newer-construct (if (eql older-construct construct-1)
- construct-2
- construct-1)))
- (dolist (ii (item-identifiers newer-construct :revision revision))
- (delete-item-identifier newer-construct ii :revision revision)
- (add-item-identifier older-construct ii :revision revision))
- (let ((reifier-1 (reifier newer-construct :revision revision))
- (reifier-2 (reifier older-construct :revision revision)))
- (when reifier-1
- (delete-reifier newer-construct reifier-1 :revision revision)
- (let ((merged-reifier
- (if reifier-2
- (progn
- (delete-reifier older-construct reifier-2
- :revision revision)
- (merge-constructs reifier-1 reifier-2
- :revision revision))
- reifier-1)))
- (add-reifier older-construct merged-reifier :revision revision))))
- (when (and (eql (type-of newer-construct) 'ReifiableConstructC)
- (eql (type-of newer-construct) 'ReifiableConstructC)
- (typep newer-construct 'VersionedConstructC)
- (typep older-construct 'VersionedConstructC))
- ;;If the older-construct is a "real" ReifiableConstructC and no sub
- ;;class the older-construct must be marked as deleted.
- ;;Sub classes are marked as deleted in the "next-method" calls.
- (mark-as-deleted newer-construct :revision revision)
- (add-to-version-history older-construct :start-revision revision))
- older-construct))))
-
+(defgeneric move-names (source destination &key revision)
+ (:documentation "Moves all names from the source topic to the destination
+ topic. If any names are equal they are merged, i.e.
+ one of the names is marked-as-deleted.")
+ (:method ((source TopicC) (destination TopicC) &key (revision *TM-REVISION*))
+ (declare (integer revision))
+ (let ((names-to-move (names source :revision revision)))
+ (dolist (name names-to-move)
+ (delete-name source name :revision revision)
+ (let ((equivalent-name
+ (find-if #'(lambda (destination-name)
+ (when
+ (strictly-equivalent-constructs
+ name destination-name :revision revision)
+ destination-name))
+ (names destination :revision revision))))
+ (if equivalent-name
+ (progn
+ (move-variants name equivalent-name :revision revision)
+ (add-name destination equivalent-name :revision revision)
+ (move-identifiers name equivalent-name :revision revision)
+ (move-referenced-constructs name equivalent-name
+ :revision revision))
+ (add-name destination name :revision revision))))
+ names-to-move)))
+
+
+(defun merge-changed-constructs (older-topic &key (revision *TM-REVISION*))
+ (declare (TopicC older-topic))
+ (dolist (construct (append (used-as-type older-topic :revision revision)
+ (used-as-theme older-topic :revision revision)
+ (player-in-roles older-topic :revision revision)))
+ (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))))))))
-(defmethod merge-constructs ((construct-1 CharacteristicC)
- (construct-2 CharacteristicC)
- &key (revision *TM-REVISION*))
- (declare (integer revision))
- (unless (equivalent-constructs construct-1 construct-2 :revision revision)
- (error "From merge-constructs(): ~a and ~a are not mergable"
- construct-1 construct-2))
- (if (eql construct-1 construct-2)
- construct-1
- (let ((older-construct (call-next-method)))
- (let ((newer-construct (if (eql older-construct construct-1)
- construct-2
- construct-1)))
- (when (and (typep construct-1 'NameC) (typep construct-2 'NameC))
- (merge-characteristics older-construct newer-construct
- :revision revision
- :characteristic-type 'VariantC)))
- older-construct)))
(defmethod merge-constructs ((construct-1 TopicC) (construct-2 TopicC)
&key (revision *TM-REVISION*))
- (declare (integer revision))
- (if (eql construct-1 construct-2)
- construct-1
- (let ((older-construct (call-next-method)))
- (let ((newer-construct (if (eql older-construct construct-1)
- construct-2
- construct-1)))
- (dolist (psi (psis newer-construct :revision revision))
- (delete-psi newer-construct psi :revision revision)
- (add-psi older-construct psi :revision revision))
- (dolist (locator (locators newer-construct :revision revision))
- (delete-locator newer-construct locator :revision revision)
- (add-locator older-construct locator :revision revision))
- (merge-characteristics older-construct newer-construct
- :revision revision
- :characteristic-type 'OccurrenceC)
- (merge-characteristics older-construct newer-construct
- :revision revision
- :characteristic-type 'NameC)
- ;;player-in-roles
- ;;used-as-type
- ;;used-as-scope
- ;;reified-construct
- ;;in-topicmaps
- ))))
+ (let ((older-topic (find-oldest-construct construct-1 construct-2)))
+ (let ((newer-topic (if (eql older-topic construct-1)
+ construct-2
+ construct-1)))
+ (move-identifiers newer-topic older-topic :revision revision)
+ (dolist (tm (in-topicmaps newer-topic :revision revision))
+ (add-to-tm tm older-topic))
+ (move-names newer-topic older-topic :revision revision)
+ (move-occurrences newer-topic older-topic :revision revision)
+ (move-referenced-constructs newer-topic older-topic :revision revision)
+ (move-reified-construct newer-topic older-topic :revision revision)
+ (merge-changed-constructs older-topic :revision revision)
+ (mark-as-deleted newer-topic :revision revision)
+ (when (does-not-exist-in-revision-history newer-topic)
+ (delete-construct newer-topic))
+ older-topic)))
+
+;TODO: merge-constructs: RoleC, AssociationC, TopicMapC,
+; OccurrenceC, NameC, VariantC --> call merge-constructs of the parent
+; and return the active construct on what merge-constructs was initialy
+; called
+;;; start hacks ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+(defmethod merge-constructs ((construct-1 TopicMapConstructC) (construct-2 TopicMapconstructC)
+ &key (revision *TM-REVISION*))
+ (or revision)
+ (if construct-1 construct-1 construct-2))
-
\ No newline at end of file
+;;; end hacks ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
\ No newline at end of file