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

How can I create a unique constraint on a skeleton over multiple bones? #1256

Open
sveneberth opened this issue Sep 10, 2024 · 1 comment
Open
Labels
help wanted Extra attention is needed Priority: High After critical issues are fixed, these should be dealt with before any further issues. question Further information is requested

Comments

@sveneberth
Copy link
Member

sveneberth commented Sep 10, 2024

I have these bones in a Skeleton:

name = StringBone(
)

module = SelectBone(
    values=lambda: {name: name for name in ModuleConf.MODULES},
)

Now I want to ensure there's at least one skeleton per permutation of the values:

for example

{name: "foo", module: "file", other_bone:"abc"}  # id: 1
{name: "bar", module: "file", other_bone:"456"}  # id: 2
{name: "foo", module: "user", other_bone:"abc"}  # id: 3
{name: "bar", module: "user", other_bone:"abc"}  # id: 4

can exist together.
But you should not able to add

{name: "foo", module: "file", other_bone: "def"}  # id: 5

because there's already an entry (ìd: 1) with {name: "foo", module: "file"}.

I tried to create a composition of these bones with a compute bone.

    unique_lock = StringBone(
        compute=Compute(lambda skel: f'{skel["module"]}_{skel["name"]}',
                        interval=ComputeInterval(ComputeMethod.OnWrite)),
        visible=False,
        unique=UniqueValue(UniqueLockMethod.SameValue, False, "Value already taken"),
    )

But this doesn't cause a client-error in fromClient and fails only in the skeleton toDB transaction:

  File "/.../lib/python3.11/site-packages/viur/core/skeleton.py", line 1029, in __txn_update
    raise ValueError(
ValueError: The unique value 'file_foo' of bone 'unique_lock' has been recently claimed!

Does anyone has an idea how I can simplify this / enforce a client error?

@sveneberth sveneberth added help wanted Extra attention is needed question Further information is requested Priority: High After critical issues are fixed, these should be dealt with before any further issues. labels Sep 10, 2024
@ArneGudermann
Copy link
Contributor

Maybe we can check this in getUniquePropertyIndexValues like:

    def getUniquePropertyIndexValues(self, skel: 'viur.core.skeleton.SkeletonInstance', name: str) -> list[str]:
        val = skel[name]
        if self.compute:
            match self.compute.interval.method:
                case ComputeMethod.OnWrite:
                    val = self._compute(skel, name)

                case ComputeMethod.Lifetime:
                    now = utils.utcNow()

                    last_update = \
                        skel.accessedValues.get(f"_viur_compute_{name}_") \
                        or skel.dbEntity.get(f"_viur_compute_{name}_")

                    if not last_update or last_update + self.compute.interval.lifetime < now:
                        val = self._compute(skel, name)

                case ComputeMethod.Once:
                    if name not in skel.dbEntity:
                        val = self._compute(skel, name)

        if val is None:
            return []
        return self._hashValueForUniquePropertyIndex(val)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed Priority: High After critical issues are fixed, these should be dealt with before any further issues. question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants