Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: self-referencing models #238

Closed
jamesharr opened this issue Aug 9, 2023 · 2 comments
Closed

Feature request: self-referencing models #238

jamesharr opened this issue Aug 9, 2023 · 2 comments

Comments

@jamesharr
Copy link
Contributor

jamesharr commented Aug 9, 2023

Environment

  • DiffSync version: 1.8.0

Proposed Functionality

Support a self-referencing models, where a given model can be a child of itself to support infinite-depth hierarchies.

For the most part, DiffSync seems to support this,

Use Case

Note that we're currently not sure if we need this functionality. We're exploring options and our problem might be solved by a flat object hierarchy with object ordering. Never the less, I figured I'd start a discussion thread about it in case others had a need for this and/or if this is actually a bug.

Example use-cases:

  • Directory structures (LDAP, Active Directory)
  • Site/Location structures
  • File system

Example model with some test code.

from __future__ import annotations

import json
from typing import List, Mapping

import structlog
from diffsync import DiffSync, DiffSyncModel, Diff
from diffsync.enum import DiffSyncStatus, DiffSyncFlags
from structlog.stdlib import BoundLogger

class Tenant(DiffSyncModel):
    _modelname = "tenant"
    _identifiers = ("name",)
    _shortname = ()
    _attributes = ("display",)
    _children = {"tenant": "children"}

    children: List[Tenant] = []

    name: str
    display: str


class TestBackend(DiffSync):
    tenant = Tenant
    top_level = [ "tenant" ]
    logger: BoundLogger

    def __init__(self, logger=None, dry_run=None):
        super().__init__()

        self.logger = structlog.get_logger("TestBackend")

    def load1(self) -> None:
        """Load an example tree"""

        # Create some sample things
        t1 = Tenant(name="a", display="All the things")
        self.add(t1)

        t2 = Tenant(name="a/b", display="Buzz")
        t1.add_child(t2)
        self.add(t2)

        t3 = Tenant(name="a/b/c", display="See you later")
        t2.add_child(t3)
        self.add(t3)

    def load2(self) -> None:
        """Load an example tree, similar to load1(), except with some attribute changets"""

        # Create some sample things
        t1 = Tenant(name="a", display="Al the tings")
        self.add(t1)

        t2 = Tenant(name="a/b", display="bzzzz")
        t1.add_child(t2)
        self.add(t2)

        t3 = Tenant(name="a/b/c", display="See you now")
        t2.add_child(t3)
        self.add(t3)

def demo1():
    be1 = TestBackend()
    be1.load1()

    be2 = TestBackend()
    be2.load2()

    # Preview diff
    diff = be1.diff_to(be2)
    print(diff.str())
    print(diff.dict())
    # NOTE: The diff shows some duplicates

    # Sync
    be1.sync_to(be2)
    # Note that `a/b` is updated 2 times
    # Note that `a/b/c` is updated 3 times
@Kircheneer
Copy link
Collaborator

I believe there is at least some overlap with #225 here - can you check if that would work for you as well?

@jamesharr
Copy link
Contributor Author

Duh, yeah, this is a duplicate

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants