| 12 | |
| 13 | |
| 14 | class Index: |
| 15 | suffix = "idx" |
| 16 | # The max length of the name of the index (restricted to 30 for |
| 17 | # cross-database compatibility with Oracle) |
| 18 | max_name_length = 30 |
| 19 | |
| 20 | def __init__( |
| 21 | self, |
| 22 | *expressions, |
| 23 | fields=(), |
| 24 | name=None, |
| 25 | db_tablespace=None, |
| 26 | opclasses=(), |
| 27 | condition=None, |
| 28 | include=None, |
| 29 | ): |
| 30 | if opclasses and not name: |
| 31 | raise ValueError("An index must be named to use opclasses.") |
| 32 | if not isinstance(condition, (NoneType, Q)): |
| 33 | raise ValueError("Index.condition must be a Q instance.") |
| 34 | if condition and not name: |
| 35 | raise ValueError("An index must be named to use condition.") |
| 36 | if not isinstance(fields, (list, tuple)): |
| 37 | raise ValueError("Index.fields must be a list or tuple.") |
| 38 | if not isinstance(opclasses, (list, tuple)): |
| 39 | raise ValueError("Index.opclasses must be a list or tuple.") |
| 40 | if not expressions and not fields: |
| 41 | raise ValueError( |
| 42 | "At least one field or expression is required to define an index." |
| 43 | ) |
| 44 | if expressions and fields: |
| 45 | raise ValueError( |
| 46 | "Index.fields and expressions are mutually exclusive.", |
| 47 | ) |
| 48 | if expressions and not name: |
| 49 | raise ValueError("An index must be named to use expressions.") |
| 50 | if expressions and opclasses: |
| 51 | raise ValueError( |
| 52 | "Index.opclasses cannot be used with expressions. Use " |
| 53 | "django.contrib.postgres.indexes.OpClass() instead." |
| 54 | ) |
| 55 | if opclasses and len(fields) != len(opclasses): |
| 56 | raise ValueError( |
| 57 | "Index.fields and Index.opclasses must have the same number of " |
| 58 | "elements." |
| 59 | ) |
| 60 | if fields and not all(isinstance(field, str) for field in fields): |
| 61 | raise ValueError("Index.fields must contain only strings with field names.") |
| 62 | if include and not name: |
| 63 | raise ValueError("A covering index must be named.") |
| 64 | if not isinstance(include, (NoneType, list, tuple)): |
| 65 | raise ValueError("Index.include must be a list or tuple.") |
| 66 | self.fields = list(fields) |
| 67 | # A list of 2-tuple with the field name and ordering ('' or 'DESC'). |
| 68 | self.fields_orders = [ |
| 69 | (field_name.removeprefix("-"), "DESC" if field_name.startswith("-") else "") |
| 70 | for field_name in self.fields |
| 71 | ] |
no outgoing calls