metas.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. # Copyright © 2023 Ingram Micro Inc. All rights reserved.
  2. from django.db.models import base
  3. from dj_cqrs.constants import ALL_BASIC_FIELDS
  4. from dj_cqrs.registries import MasterRegistry, ReplicaRegistry
  5. from dj_cqrs.signals import MasterSignals
  6. from dj_cqrs.tracker import CQRSTracker
  7. class MasterMeta(base.ModelBase):
  8. def __new__(mcs, name, bases, attrs, **kwargs):
  9. model_cls = super(MasterMeta, mcs).__new__(mcs, name, bases, attrs, **kwargs)
  10. if name != 'MasterMixin':
  11. mcs.register(model_cls)
  12. return model_cls
  13. @staticmethod
  14. def register(model_cls):
  15. _MetaUtils.check_cqrs_id(model_cls)
  16. MasterMeta._check_correct_configuration(model_cls)
  17. if model_cls.CQRS_TRACKED_FIELDS is not None:
  18. MasterMeta._check_cqrs_tracked_fields(model_cls)
  19. CQRSTracker.add_to_model(model_cls)
  20. if model_cls.CQRS_SERIALIZER is None:
  21. MasterMeta._check_cqrs_fields(model_cls)
  22. MasterRegistry.register_model(model_cls)
  23. MasterSignals.register_model(model_cls)
  24. return model_cls
  25. @staticmethod
  26. def _check_cqrs_tracked_fields(model_cls):
  27. """Check that the CQRS_TRACKED_FIELDS has correct configuration.
  28. :param dj_cqrs.mixins.MasterMixin model_cls: CQRS Master Model.
  29. :raises: AssertionError
  30. """
  31. tracked_fields = model_cls.CQRS_TRACKED_FIELDS
  32. if isinstance(tracked_fields, (list, tuple)):
  33. _MetaUtils._check_no_duplicate_names(
  34. model_cls,
  35. tracked_fields,
  36. 'CQRS_TRACKED_FIELDS',
  37. )
  38. _MetaUtils._check_unexisting_names(model_cls, tracked_fields, 'CQRS_TRACKED_FIELDS')
  39. return
  40. e = 'Model {0}: Invalid configuration for CQRS_TRACKED_FIELDS'.format(model_cls.__name__)
  41. assert isinstance(tracked_fields, str) and tracked_fields == ALL_BASIC_FIELDS, e
  42. @staticmethod
  43. def _check_correct_configuration(model_cls):
  44. """Check that model has correct CQRS configuration.
  45. :param dj_cqrs.mixins.MasterMixin model_cls: CQRS Master Model.
  46. :raises: AssertionError
  47. """
  48. if model_cls.CQRS_FIELDS != ALL_BASIC_FIELDS:
  49. e = "Model {0}: CQRS_FIELDS can't be set together with CQRS_SERIALIZER.".format(
  50. model_cls.__name__,
  51. )
  52. assert model_cls.CQRS_SERIALIZER is None, e
  53. @staticmethod
  54. def _check_cqrs_fields(model_cls):
  55. """Check that model has correct CQRS fields configuration.
  56. :param dj_cqrs.mixins.MasterMixin model_cls: CQRS Master Model.
  57. :raises: AssertionError
  58. """
  59. if model_cls.CQRS_FIELDS != ALL_BASIC_FIELDS:
  60. cqrs_field_names = list(model_cls.CQRS_FIELDS)
  61. _MetaUtils.check_cqrs_field_setting(model_cls, cqrs_field_names, 'CQRS_FIELDS')
  62. class ReplicaMeta(base.ModelBase):
  63. def __new__(mcs, *args):
  64. model_cls = super(ReplicaMeta, mcs).__new__(mcs, *args)
  65. if args[0] != 'ReplicaMixin':
  66. mcs.register(model_cls)
  67. return model_cls
  68. @staticmethod
  69. def register(model_cls):
  70. _MetaUtils.check_cqrs_id(model_cls)
  71. ReplicaMeta._check_cqrs_mapping(model_cls)
  72. ReplicaRegistry.register_model(model_cls)
  73. @staticmethod
  74. def _check_cqrs_mapping(model_cls):
  75. """Check that model has correct CQRS mapping configuration.
  76. :param dj_cqrs.mixins.ReplicaMixin model_cls: CQRS Replica Model.
  77. :raises: AssertionError
  78. """
  79. cqrs_mapping = getattr(model_cls, 'CQRS_MAPPING', None)
  80. if cqrs_mapping is not None:
  81. cqrs_field_names = list(cqrs_mapping.values())
  82. _MetaUtils.check_cqrs_field_setting(model_cls, cqrs_field_names, 'CQRS_MAPPING')
  83. class _MetaUtils:
  84. @classmethod
  85. def check_cqrs_field_setting(cls, model_cls, cqrs_field_names, cqrs_attr):
  86. cls._check_no_duplicate_names(model_cls, cqrs_field_names, cqrs_attr)
  87. cls._check_id_in_names(model_cls, cqrs_field_names, cqrs_attr)
  88. cls._check_unexisting_names(model_cls, cqrs_field_names, cqrs_attr)
  89. @staticmethod
  90. def check_cqrs_id(model_cls):
  91. """Check that CQRS Model has CQRS_ID set up."""
  92. assert model_cls.CQRS_ID, 'CQRS_ID must be set for every model, that uses CQRS.'
  93. @staticmethod
  94. def _check_no_duplicate_names(model_cls, cqrs_field_names, cqrs_attr):
  95. model_name = model_cls.__name__
  96. e = 'Duplicate names in {0} field for model {1}.'.format(cqrs_attr, model_name)
  97. assert len(set(cqrs_field_names)) == len(cqrs_field_names), e
  98. @staticmethod
  99. def _check_unexisting_names(model_cls, cqrs_field_names, cqrs_attr):
  100. opts = model_cls._meta
  101. model_name = model_cls.__name__
  102. model_field_names = {f.name for f in opts.fields}
  103. e = '{0} field is not correctly set for model {1}.'.format(cqrs_attr, model_name)
  104. assert not set(cqrs_field_names) - model_field_names, e
  105. @staticmethod
  106. def _check_id_in_names(model_cls, cqrs_field_names, cqrs_attr):
  107. opts = model_cls._meta
  108. model_name = model_cls.__name__
  109. pk_name = opts.pk.name
  110. e = 'PK is not in {0} for model {1}.'.format(cqrs_attr, model_name)
  111. assert pk_name in cqrs_field_names, e