Skip to content

Commit

Permalink
Support for Partial Indexes for PostgreSql and Sqlite
Browse files Browse the repository at this point in the history
Support for Partial Indexes was available in Doctrine 1 following
http://www.doctrine-project.org/jira/browse/DC-82. This commit
reintroduce support for Doctrine 2. We use the same syntax with an
optionnal "where" attribute for Index and UniqueConstraint.
  • Loading branch information
PowerKiKi committed Jul 22, 2014
1 parent 499f09f commit eeb7ff4
Show file tree
Hide file tree
Showing 15 changed files with 127 additions and 83 deletions.
12 changes: 12 additions & 0 deletions docs/en/reference/annotations-reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,12 @@ Required attributes:
- **name**: Name of the Index
- **columns**: Array of columns.

Optional attributes:

- **options**: Array of platform specific options

- **where**: SQL WHERE condition to be used for partial indexes. It will only have effect on supported platforms.

Example:

.. code-block:: php
Expand Down Expand Up @@ -1151,6 +1157,12 @@ Required attributes:
- **name**: Name of the Index
- **columns**: Array of columns.

Optional attributes:

- **options**: Array of platform specific options

- **where**: SQL WHERE condition to be used for partial indexes. It will only have effect on supported platforms.

Example:

.. code-block:: php
Expand Down
92 changes: 47 additions & 45 deletions doctrine-mapping.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
xmlns:orm="http://doctrine-project.org/schemas/orm/doctrine-mapping"
elementFormDefault="qualified">

<xs:annotation>
<xs:documentation><![CDATA[
This is the XML Schema for the object/relational
<xs:annotation>
<xs:documentation><![CDATA[
This is the XML Schema for the object/relational
mapping file used by the Doctrine ORM.
]]></xs:documentation>
</xs:annotation>
Expand All @@ -23,27 +23,27 @@
<xs:anyAttribute namespace="##other"/>
</xs:complexType>
</xs:element>

<xs:complexType name="emptyType">
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>

<xs:complexType name="cascade-type">
<xs:sequence>
<xs:element name="cascade-all" type="orm:emptyType" minOccurs="0"/>
<xs:element name="cascade-persist" type="orm:emptyType" minOccurs="0"/>
<xs:element name="cascade-merge" type="orm:emptyType" minOccurs="0"/>
<xs:element name="cascade-remove" type="orm:emptyType" minOccurs="0"/>
<xs:element name="cascade-refresh" type="orm:emptyType" minOccurs="0"/>
<xs:element name="cascade-all" type="orm:emptyType" minOccurs="0"/>
<xs:element name="cascade-persist" type="orm:emptyType" minOccurs="0"/>
<xs:element name="cascade-merge" type="orm:emptyType" minOccurs="0"/>
<xs:element name="cascade-remove" type="orm:emptyType" minOccurs="0"/>
<xs:element name="cascade-refresh" type="orm:emptyType" minOccurs="0"/>
<xs:element name="cascade-detach" type="orm:emptyType" minOccurs="0"/>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>

<xs:simpleType name="lifecycle-callback-type">
<xs:restriction base="xs:token">
<xs:enumeration value="prePersist"/>
Expand All @@ -64,7 +64,7 @@
<xs:enumeration value="NONSTRICT_READ_WRITE"/>
</xs:restriction>
</xs:simpleType>

<xs:complexType name="lifecycle-callback">
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
Expand All @@ -73,7 +73,7 @@
<xs:attribute name="method" type="xs:NMTOKEN" use="required" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>

<xs:complexType name="lifecycle-callbacks">
<xs:sequence>
<xs:element name="lifecycle-callback" type="orm:lifecycle-callback" minOccurs="1" maxOccurs="unbounded" />
Expand Down Expand Up @@ -199,7 +199,7 @@
<xs:attribute name="read-only" type="xs:boolean" default="false" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>

<xs:complexType name="option" mixed="true">
<xs:sequence minOccurs="0" maxOccurs="unbounded">
<xs:element name="option" type="orm:option"/>
Expand Down Expand Up @@ -245,41 +245,41 @@
<xs:enumeration value="NOTIFY"/>
</xs:restriction>
</xs:simpleType>

<xs:simpleType name="inheritance-type">
<xs:restriction base="xs:token">
<xs:enumeration value="SINGLE_TABLE"/>
<xs:enumeration value="JOINED"/>
<xs:enumeration value="TABLE_PER_CLASS"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="generator-strategy">
<xs:restriction base="xs:token">

<xs:simpleType name="generator-strategy">
<xs:restriction base="xs:token">
<xs:enumeration value="NONE"/>
<xs:enumeration value="TABLE"/>
<xs:enumeration value="SEQUENCE"/>
<xs:enumeration value="IDENTITY"/>
<xs:enumeration value="AUTO"/>
<xs:enumeration value="UUID"/>
<xs:enumeration value="TABLE"/>
<xs:enumeration value="SEQUENCE"/>
<xs:enumeration value="IDENTITY"/>
<xs:enumeration value="AUTO"/>
<xs:enumeration value="UUID"/>
<xs:enumeration value="CUSTOM" />
</xs:restriction>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="fk-action">
<xs:restriction base="xs:token">
<xs:enumeration value="CASCADE"/>
<xs:enumeration value="RESTRICT"/>

<xs:simpleType name="fk-action">
<xs:restriction base="xs:token">
<xs:enumeration value="CASCADE"/>
<xs:enumeration value="RESTRICT"/>
<xs:enumeration value="SET NULL"/>
</xs:restriction>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="fetch-type">
<xs:restriction base="xs:token">
<xs:enumeration value="EAGER"/>

<xs:simpleType name="fetch-type">
<xs:restriction base="xs:token">
<xs:enumeration value="EAGER"/>
<xs:enumeration value="LAZY"/>
<xs:enumeration value="EXTRA_LAZY"/>
</xs:restriction>
</xs:restriction>
</xs:simpleType>

<xs:complexType name="field">
Expand All @@ -299,13 +299,13 @@
<xs:attribute name="scale" type="xs:integer" use="optional" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>

<xs:complexType name="embedded">
<xs:attribute name="name" type="xs:string" use="required" />
<xs:attribute name="class" type="xs:string" use="required" />
<xs:attribute name="column-prefix" type="xs:string" use="optional" />
</xs:complexType>

<xs:complexType name="discriminator-column">
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
Expand All @@ -317,42 +317,44 @@
<xs:attribute name="column-definition" type="xs:string" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>

<xs:complexType name="unique-constraint">
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:attribute name="name" type="xs:NMTOKEN" use="optional"/>
<xs:attribute name="columns" type="xs:string" use="required"/>
<xs:attribute name="where" type="xs:string" use="optional"/>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>

<xs:complexType name="unique-constraints">
<xs:sequence>
<xs:element name="unique-constraint" type="orm:unique-constraint" minOccurs="1" maxOccurs="unbounded"/>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>

<xs:complexType name="index">
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:attribute name="name" type="xs:NMTOKEN" use="optional"/>
<xs:attribute name="columns" type="xs:string" use="required"/>
<xs:attribute name="flags" type="xs:string" use="optional"/>
<xs:attribute name="where" type="xs:string" use="optional"/>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>

<xs:complexType name="indexes">
<xs:sequence>
<xs:element name="index" type="orm:index" minOccurs="1" maxOccurs="unbounded"/>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
</xs:sequence>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>

<xs:complexType name="discriminator-mapping">
<xs:sequence>
<xs:any minOccurs="0" maxOccurs="unbounded" namespace="##other"/>
Expand All @@ -361,7 +363,7 @@
<xs:attribute name="class" type="xs:string" use="required"/>
<xs:anyAttribute namespace="##other"/>
</xs:complexType>

<xs:complexType name="discriminator-map">
<xs:sequence>
<xs:element name="discriminator-mapping" type="orm:discriminator-mapping" minOccurs="1" maxOccurs="unbounded"/>
Expand Down Expand Up @@ -509,7 +511,7 @@
<xs:attribute name="fetch" type="orm:fetch-type" default="LAZY" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>

<xs:complexType name="many-to-one">
<xs:sequence>
<xs:element name="cache" type="orm:cache" minOccurs="0" maxOccurs="1"/>
Expand All @@ -528,7 +530,7 @@
<xs:attribute name="inversed-by" type="xs:NMTOKEN" />
<xs:anyAttribute namespace="##other"/>
</xs:complexType>

<xs:complexType name="one-to-one">
<xs:sequence>
<xs:element name="cache" type="orm:cache" minOccurs="0" maxOccurs="1"/>
Expand Down
10 changes: 9 additions & 1 deletion lib/Doctrine/ORM/Mapping/Driver/AnnotationDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,15 @@ public function loadMetadataForClass($className, ClassMetadata $metadata)
if ($tableAnnot->indexes !== null) {
foreach ($tableAnnot->indexes as $indexAnnot) {
$index = array('columns' => $indexAnnot->columns);

if ( ! empty($indexAnnot->flags)) {
$index['flags'] = $indexAnnot->flags;
}

if (! empty($indexAnnot->where)) {
$index['where'] = $indexAnnot->where;
}

if ( ! empty($indexAnnot->name)) {
$primaryTable['indexes'][$indexAnnot->name] = $index;
} else {
Expand All @@ -118,6 +122,10 @@ public function loadMetadataForClass($className, ClassMetadata $metadata)
if ($tableAnnot->uniqueConstraints !== null) {
foreach ($tableAnnot->uniqueConstraints as $uniqueConstraintAnnot) {
$uniqueConstraint = array('columns' => $uniqueConstraintAnnot->columns);

if ( ! empty($uniqueConstraintAnnot->where)) {
$uniqueConstraint['where'] = $uniqueConstraintAnnot->where;
}

if ( ! empty($uniqueConstraintAnnot->name)) {
$primaryTable['uniqueConstraints'][$uniqueConstraintAnnot->name] = $uniqueConstraint;
Expand Down
26 changes: 15 additions & 11 deletions lib/Doctrine/ORM/Mapping/Driver/XmlDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -196,11 +196,15 @@ public function loadMetadataForClass($className, ClassMetadata $metadata)
$metadata->table['indexes'] = array();
foreach ($xmlRoot->indexes->index as $indexXml) {
$index = array('columns' => explode(',', (string) $indexXml['columns']));

if (isset($indexXml['flags'])) {
$index['flags'] = explode(',', (string) $indexXml['flags']);
}


if (isset($indexXml['where'])) {
$index['where'] = $indexXml['where'];
}

if (isset($indexXml['name'])) {
$metadata->table['indexes'][(string) $indexXml['name']] = $index;
} else {
Expand All @@ -212,17 +216,17 @@ public function loadMetadataForClass($className, ClassMetadata $metadata)
// Evaluate <unique-constraints..>
if (isset($xmlRoot->{'unique-constraints'})) {
$metadata->table['uniqueConstraints'] = array();
foreach ($xmlRoot->{'unique-constraints'}->{'unique-constraint'} as $unique) {
$columns = explode(',', (string)$unique['columns']);
foreach ($xmlRoot->{'unique-constraints'}->{'unique-constraint'} as $uniqueXml) {
$unique = array('columns' => explode(',', (string) $uniqueXml['columns']));

if (isset($unique['name'])) {
$metadata->table['uniqueConstraints'][(string)$unique['name']] = array(
'columns' => $columns
);
if (isset($uniqueXml['where'])) {
$unique['where'] = $uniqueXml['where'];
}

if (isset($uniqueXml['name'])) {
$metadata->table['uniqueConstraints'][(string)$uniqueXml['name']] = $unique;
} else {
$metadata->table['uniqueConstraints'][] = array(
'columns' => $columns
);
$metadata->table['uniqueConstraints'][] = $unique;
}
}
}
Expand Down
25 changes: 15 additions & 10 deletions lib/Doctrine/ORM/Mapping/Driver/YamlDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -220,27 +220,32 @@ public function loadMetadataForClass($className, ClassMetadata $metadata)
}
}

if (isset($indexYml['where'])) {
$index['where'] = $indexYml['where'];
}

$metadata->table['indexes'][$indexYml['name']] = $index;
}
}

// Evaluate uniqueConstraints
if (isset($element['uniqueConstraints'])) {
foreach ($element['uniqueConstraints'] as $name => $unique) {
if ( ! isset($unique['name'])) {
$unique['name'] = $name;
foreach ($element['uniqueConstraints'] as $name => $uniqueYml) {
if ( ! isset($uniqueYml['name'])) {
$uniqueYml['name'] = $name;
}

if (is_string($unique['columns'])) {
$columns = explode(',', $unique['columns']);
$columns = array_map('trim', $columns);
if (is_string($uniqueYml['columns'])) {
$unique = array('columns' => array_map('trim', explode(',', $uniqueYml['columns'])));
} else {
$columns = $unique['columns'];
$unique = array('columns' => $uniqueYml['columns']);
}

$metadata->table['uniqueConstraints'][$unique['name']] = array(
'columns' => $columns
);
if (isset($uniqueYml['where'])) {
$unique['where'] = $uniqueYml['where'];
}

$metadata->table['uniqueConstraints'][$uniqueYml['name']] = $unique;
}
}

Expand Down
5 changes: 5 additions & 0 deletions lib/Doctrine/ORM/Mapping/Index.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,9 @@ final class Index implements Annotation
* @var array<string>
*/
public $flags;

/**
* @var string
*/
public $where;
}
5 changes: 5 additions & 0 deletions lib/Doctrine/ORM/Mapping/UniqueConstraint.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@ final class UniqueConstraint implements Annotation
* @var array<string>
*/
public $columns;

/**
* @var string
*/
public $where;
}
Loading

0 comments on commit eeb7ff4

Please sign in to comment.