@@ 612,20 612,14 @@ func (db *DB) ContentRefererList(contentID string) (ret []ContentRefSet, err err
return db.contentRefererList(contentID, defaultDepth)
}
-func (db *DB) ContentUpdate(space space.Space, ct contenttype.ContentType, content content.Content, newParams []ContentNewParam, updateParams []ContentUpdateParam) (content.Content, error) {
+func (db *DB) contentUpdate(t *sql.Tx, space space.Space, ct contenttype.ContentType, content content.Content, newParams []ContentNewParam, updateParams []ContentUpdateParam) error {
depth := defaultDepth
- t, err := db.Begin()
- if err != nil {
- return nil, err
- }
- defer t.Rollback()
-
// TODO: Do we have to do this w/ types? Can you not find a better way?
// I'm beginning to think we're over using interfaces and it's hurting.
c, ok := content.(*Content)
if !ok {
- return nil, fmt.Errorf("failed to type cast value type before attempting to update content")
+ return fmt.Errorf("failed to type cast value type before attempting to update content")
}
for _, item := range updateParams {
@@ 637,7 631,7 @@ func (db *DB) ContentUpdate(space space.Space, ct contenttype.ContentType, conte
}
if err := db.valueReferenceListUpdate(space, ct, c, t, item.ID, strings.Split(item.Value, "-"), depth); err != nil {
- return nil, err
+ return err
}
continue
}
@@ 649,12 643,12 @@ func (db *DB) ContentUpdate(space space.Space, ct contenttype.ContentType, conte
_, _, queryValueUpdate, err := db.valueQuerySetByType(item.Type)
if err != nil {
- return nil, err
+ return err
}
if _, err := t.Exec(queryValueUpdate, item.Value, item.ID); err != nil {
db.log.Println(err)
- return nil, fmt.Errorf("failed to create update content value '%s'", item.Value)
+ return fmt.Errorf("failed to create update content value '%s'", item.Value)
}
}
@@ 667,7 661,7 @@ func (db *DB) ContentUpdate(space space.Space, ct contenttype.ContentType, conte
}
if err := db.valueReferenceListNew(space, ct, c, t, item.Name, strings.Split(item.Value, "-"), depth); err != nil {
- return nil, err
+ return err
}
continue
}
@@ 679,41 673,55 @@ func (db *DB) ContentUpdate(space space.Space, ct contenttype.ContentType, conte
queryValueNewType, queryValueGetTypeByID, _, err := db.valueQuerySetByType(item.Type)
if err != nil {
- return nil, err
+ return err
}
res, err := t.Exec(queryValueNewType, item.Value)
if err != nil {
- return nil, fmt.Errorf("failed to attach field value of content")
+ return fmt.Errorf("failed to attach field value of content")
}
valueID, err := res.LastInsertId()
if err != nil {
- return nil, fmt.Errorf("failed to read new field value of content")
+ return fmt.Errorf("failed to read new field value of content")
}
res, err = t.Exec(queryValueNew, content.ID(), ct.ID(), item.Name, valueID)
if err != nil {
- return nil, fmt.Errorf("failed to attach field value of content")
+ return fmt.Errorf("failed to attach field value of content")
}
valueID, err = res.LastInsertId()
if err != nil {
- return nil, fmt.Errorf("failed to read new field value of content")
+ return fmt.Errorf("failed to read new field value of content")
}
var value ContentValue
if err := t.QueryRow(queryValueGetTypeByID, valueID).Scan(&value.FieldID, &value.FieldType, &value.FieldName, &value.FieldValue); err != nil {
- return nil, fmt.Errorf("failed to find value created")
+ return fmt.Errorf("failed to find value created")
}
if err := db.contentValueAttachRef(t, &value, depth); err != nil {
- return nil, err
+ return err
}
c.ContentValues = append(c.ContentValues, value)
}
+ return nil
+}
+
+func (db *DB) ContentUpdate(space space.Space, ct contenttype.ContentType, content content.Content, newParams []ContentNewParam, updateParams []ContentUpdateParam) (content.Content, error) {
+ t, err := db.Begin()
+ if err != nil {
+ return nil, err
+ }
+ defer t.Rollback()
+
+ if err := db.contentUpdate(t, space, ct, content, newParams, updateParams); err != nil {
+ return nil, err
+ }
+
if err := t.Commit(); err != nil {
return nil, err
}
@@ 169,11 169,13 @@ func (db *DB) spaceCopyContentTypes(t *sql.Tx, next, prevS space.Space) error {
c content.Content
}
+ // We've made a change to the content copy impl. We skip first pass of ref
+ // types then update contents. This fixes loop references.
+
// todo are contents that could not be processes yet, due to Reference and
// ReferenceList dependencies. They will be taken care of in later iterations
// (up to a depth of three).
var todo []cct
- var todoN []cct // Used for later for loop.
// refmap is used for todo to pull information from.
// old content ID -> new content
@@ 223,26 225,17 @@ func (db *DB) spaceCopyContentTypes(t *sql.Tx, next, prevS space.Space) error {
}
if !ok {
+ // If we're not OK that means we need to update the content to account for ref types.
todo = append(todo, cct{ct, prevC})
}
}
}
- // NOTE: Going over defaultDepth should be an impossible case, as we stop
- // user from creating depths of >3 elsewhere. It's a hard limit.
- for i := 0; len(todo) > 0 && i < defaultDepth; i++ {
- todoN = append(todo[:0:0], todo...) // Copy todo to todoN.
- todo = nil
-
- for _, set := range todoN {
- ok, err := db.spaceCopyContent(t, next, set.ct, set.c, refmap)
- if err != nil {
- return err
- }
-
- if !ok {
- todo = append(todo, set)
- }
+ // Update reference types that were skipped because content was not createt.
+ for _, set := range todo {
+ err := db.spaceUpdateContent(t, next, set.ct, set.c, refmap)
+ if err != nil {
+ return fmt.Errorf("failed to copy for references %s: %w", set.c.MustValueByName("name").Value(), err)
}
}
@@ 250,7 243,10 @@ func (db *DB) spaceCopyContentTypes(t *sql.Tx, next, prevS space.Space) error {
}
func (db *DB) spaceCopyContent(t *sql.Tx, next space.Space, ct contenttype.ContentType, prevC content.Content, refmap map[string]content.Content) (bool, error) {
- var params []ContentNewParam
+ var (
+ params []ContentNewParam
+ skip bool
+ )
for _, prevF := range ct.Fields() {
prevV, ok := prevC.ValueByName(prevF.Name())
@@ 272,7 268,8 @@ func (db *DB) spaceCopyContent(t *sql.Tx, next space.Space, ct contenttype.Conte
case valuetype.Reference:
ref, ok := refmap[prevV.RefID()]
if !ok {
- return false, nil
+ skip = true
+ continue
}
params = append(params, ContentNewParam{prevV.Type(), prevV.Name(), ref.ID()})
@@ 281,7 278,8 @@ func (db *DB) spaceCopyContent(t *sql.Tx, next space.Space, ct contenttype.Conte
for _, refID := range prevV.RefListIDs() {
ref, ok := refmap[refID]
if !ok {
- return false, nil
+ skip = true
+ continue
}
IDs = append(IDs, ref.ID())
}
@@ 300,7 298,51 @@ func (db *DB) spaceCopyContent(t *sql.Tx, next space.Space, ct contenttype.Conte
refmap[prevC.ID()] = c
- return true, nil
+ return !skip, nil
+}
+
+func (db *DB) spaceUpdateContent(t *sql.Tx, next space.Space, ct contenttype.ContentType, prevC content.Content, refmap map[string]content.Content) error {
+ var params []ContentNewParam
+
+ for _, prevF := range ct.Fields() {
+ prevV, ok := prevC.ValueByName(prevF.Name())
+ if !ok {
+ if prevF.Type() == valuetype.Reference || prevF.Type() == valuetype.ReferenceList {
+ // Referenced content was deleted.
+ continue
+ }
+
+ // "null" field. E.G. empty StringSmall.
+ prevV = &ContentValue{
+ FieldType: string(prevF.Type()),
+ FieldName: prevF.Name(),
+ }
+ }
+
+ switch prevF.Type() {
+
+ case valuetype.Reference:
+ ref, ok := refmap[prevV.RefID()]
+ if !ok {
+ return errors.New("failed to copy reference value: content not created")
+ }
+ params = append(params, ContentNewParam{prevV.Type(), prevV.Name(), ref.ID()})
+
+ case valuetype.ReferenceList:
+ var IDs []string
+ for _, refID := range prevV.RefListIDs() {
+ ref, ok := refmap[refID]
+ if !ok {
+ return errors.New("failed to copy reference list value(s): content not created")
+ }
+ IDs = append(IDs, ref.ID())
+ }
+ params = append(params, ContentNewParam{prevV.Type(), prevV.Name(), strings.Join(IDs, "-")})
+
+ }
+ }
+
+ return db.contentUpdate(t, next, ct, refmap[prevC.ID()], params, []ContentUpdateParam{})
}
func (db *DB) spaceGet(t *sql.Tx, user user.User, spaceID string) (space.Space, error) {