Home > other >  how can i make natural key values unqiue with a function
how can i make natural key values unqiue with a function

Time:10-05

is there a way I can create a function to prevent my unique key values from changing, or raise an error if there is an attempt to change unique keys values? i am writing an update function for a database to update entries, but i want to make it so if the "unique key values " are in the payload to be updated it will raise an error

mydict = {
'name': 'cameron', # natural keys
'age': '29',       #also natural key
'city': 'boston',
}

CodePudding user response:

A simple example will be as follows:

class MyDict(dict):
    NATURAL_KEYS = ["name", "age"]

    def __setitem__(self, key, value):
        if key in self.NATURAL_KEYS:
            raise KeyError(f"My natural key `{key}`'s value is prevented from changing.")

        super().__setitem__(key, value)

enter image description here

You can read more info here: https://realpython.com/inherit-python-dict/#creating-dictionary-like-classes-in-python.

CodePudding user response:

Looking at existing database designs, they typically only allow updating entire database entries, the dict in your case, rather than only a part of the entry.

An update function would typically look like:

natural_keys = ['name', 'age']
database: Dict[tuple, dict]: ...

def update(new_entry: dict):
    keys = tuple(new_entry[k] for k in natural_keys)
    if keys in database:  # update existing entries
       database[keys] = new_entry
    else:  # raise error if there are no entries with these natural keys
       raise ValueError(f"there are no entries with natural keys {keys}")

This way you will never really change the natural keys, only updating existing entries with the same natural keys.

Of course, you will need an insert function to insert new entries with new natural keys.

So there is never really the problem of preventing user from changing natural keys.

Alternatively

For detailed controls, you can create a class and control property setting via property setter

For example,

class MyDict:
    def __init__(self, name, age, city):
        self._name = name
        self._age = age
        self.city = city

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self, value):
        raise ValueError("can't set name")

    @property
    def age(self):
        return self._age

    @age.setter
    def age(self, value):
        raise ValueError("can't set age")

So you can define

my_dict = MyDict(name='cameron', age=29, city='boston')

You can set city

my_dict.city = 'new york'

But you will get ValueError when you try to set name and age.

In more advanced usage, you can use descriptors to handle general attribute setting

import logging


class PreventSetting:

    def __set_name__(self, owner, name):
        self.public_name = name
        self.private_name = '_'   name

    def __get__(self, obj, objtype=None):
        value = getattr(obj, self.private_name)
        logging.info('Accessing %r giving %r', self.public_name, value)
        return value

    def __set__(self, obj, value):
        # if defining for 1st time
        if not hasattr(obj, self.private_name):
            logging.info('Updating %r to %r', self.public_name, value)
            setattr(obj, self.private_name, value)
        else:
            # raise error for setting value after 1st time
            raise ValueError(f"can't set {self.public_name}")


class MyDict:
    name = PreventSetting()  # First descriptor instance
    age = PreventSetting()  # Second descriptor instance

    def __init__(self, name, age, city):
        self.name = name  # Calls the first descriptor __set__
        self.age = age  # Calls the second descriptor __set__
        self.city = city

CodePudding user response:

Poorly formulated question. What is natural key?

Anyways, if you want to restrict the values of the keys, you can compute whether the new value is valid (by an algorithm that deal with natural keys) and then throw exceptions with raise ValueError() statement.

CodePudding user response:

def verify(new, dc: dictionary):
   """Verifies if the passed value is present in the dictionary keys."""
   return False if new in dc.keys else True
  • Related