예제 #1
0
    def setUp(self):
        now = datetime.utcnow()
        yesterday = now - timedelta(days=1)
        owner_id = uuid4().hex
        self.parent_case_id = uuid4().hex
        case = CommCareCase(
            case_id=self.parent_case_id,
            domain=self.domain,
            type='person',
            name='Joe',
            owner_id=owner_id,
            modified_on=yesterday,
            server_modified_on=yesterday,
        )
        self.parent_case = create_case(case)

        case = CommCareCase(
            case_id=uuid4().hex,
            domain=self.domain,
            type='temperature',
            case_json={
                'value': '36.2',
            },
            owner_id=owner_id,
            modified_on=yesterday,
            server_modified_on=yesterday,
        )
        index = CommCareCaseIndex(
            domain=self.domain,
            identifier='parent',
            referenced_type='person',
            referenced_id=self.parent_case_id,
            relationship_id=CommCareCaseIndex.CHILD,
        )
        self.child_case_1 = create_case_with_index(case, index)

        case = CommCareCase(
            case_id=uuid4().hex,
            domain=self.domain,
            type='temperature',
            case_json={
                'value': '36.6',
            },
            owner_id=owner_id,
            modified_on=now,
            server_modified_on=now,
        )
        index = CommCareCaseIndex(
            domain=self.domain,
            identifier='parent',
            referenced_type='person',
            referenced_id=self.parent_case_id,
            relationship_id=CommCareCaseIndex.CHILD,
        )
        self.child_case_2 = create_case_with_index(case, index)
예제 #2
0
    def setUp(self):
        now = datetime.utcnow()
        case_kwargs = {
            'owner_id': uuid4().hex,
            'modified_on': now,
            'server_modified_on': now,
        }
        self.host_case_id = uuid4().hex
        case = CommCareCase(
            case_id=self.host_case_id,
            domain=self.domain,
            type='person',
            name='Ted',
            **case_kwargs,
        )
        self.host_case = create_case(case)

        case = CommCareCase(
            case_id=uuid4().hex,
            domain=self.domain,
            type='person_name',
            name='Theodore',
            case_json={
                'given_names': 'Theodore John',
                'family_name': 'Kaczynski',
            },
            **case_kwargs,
        )
        index = CommCareCaseIndex(
            domain=self.domain,
            identifier='host',
            referenced_type='person',
            referenced_id=self.host_case_id,
            relationship_id=CommCareCaseIndex.EXTENSION,
        )
        self.ext_case_1 = create_case_with_index(case, index)

        case = CommCareCase(
            case_id=uuid4().hex,
            domain=self.domain,
            type='person_name',
            name='Unabomber',
            case_json={
                'given_names': 'Unabomber',
            },
            **case_kwargs,
        )
        index = CommCareCaseIndex(
            domain=self.domain,
            identifier='host',
            referenced_type='person',
            referenced_id=self.host_case_id,
            relationship_id=CommCareCaseIndex.EXTENSION,
        )
        self.ext_case_2 = create_case_with_index(case, index)
예제 #3
0
 def setUp(self):
     i1 = {
         'identifier': 'i1',
         'referenced_type': 't1',
         'referenced_id': 'id1',
     }
     i2 = {
         'identifier': 'i2',
         'referenced_type': 't2',
         'referenced_id': 'id2',
     }
     self.i1 = CommCareCaseIndex(**i1)
     self.i2 = CommCareCaseIndex(**i2)
     self.case = CommCareCase(indices=[i1, i2])
예제 #4
0
def _add_unique_constraint_to_case_index_table(db):
    """This will add a unique index concurrently and also a table constraint that uses the index.
    The result will be the same as adding a 'unique_together' option in the Django model.
    """
    create_index_sql = """
        CREATE UNIQUE INDEX CONCURRENTLY {index_name} on {case_index_table} ("case_id", "identifier")
    """.format(
        case_index_table=CommCareCaseIndex._meta.db_table,
        index_name=UNIQIE_INDEX_NAME,
    )

    add_constraint_sql = """
        ALTER TABLE {case_index_table} ADD CONSTRAINT {index_name} UNIQUE USING INDEX {index_name}
    """.format(
        case_index_table=CommCareCaseIndex._meta.db_table,
        index_name=UNIQIE_INDEX_NAME,
    )

    try:
        with CommCareCaseIndex.get_cursor_for_partition_db(db) as cursor:
            log_sql(create_index_sql)
            cursor.execute(create_index_sql)
            log_sql(add_constraint_sql)
            cursor.execute(add_constraint_sql)
    except:  # noqa: E722
        # if the index creation failed make sure we remove it otherwise we
        # are left with an invalid index
        _drop_index(db, UNIQIE_INDEX_NAME)
        raise
예제 #5
0
def _drop_index(db, index_name):
    """Drop the index if it exists"""
    drop_identifier_index = """
            DROP INDEX CONCURRENTLY IF EXISTS {index_name}
        """.format(index_name=index_name)
    with CommCareCaseIndex.get_cursor_for_partition_db(db) as cursor:
        log_sql(drop_identifier_index)
        cursor.execute(drop_identifier_index)
예제 #6
0
def _add_temp_index(db):
    """Add an index to the 'identifier' column to make queries faster."""
    add_identifier_index = """
        CREATE INDEX CONCURRENTLY {identifier_index_name} ON {case_index_table} (identifier)
    """.format(case_index_table=CommCareCaseIndex._meta.db_table,
               identifier_index_name=IDENTIFIER_INDEX_NAME)
    with CommCareCaseIndex.get_cursor_for_partition_db(db) as cursor:
        if not _index_exists(db, IDENTIFIER_INDEX_NAME):
            log_sql(add_identifier_index)
            cursor.execute(add_identifier_index)
예제 #7
0
 def test_constructor_ignores_doc_type(self):
     # Just ensure it doesn't raise an exception
     data = {
         'doc_type': 'CommCareCaseIndex',
         'identifier': 'my_parent',
         'relationship': 'child',
         'referenced_type': 'comunidad',
         'referenced_id': 'ed285193-3795-4b39-b08b-ac9ad941527f'
     }
     CommCareCaseIndex(**data)
예제 #8
0
    def test_fields(self):
        data = {
            'identifier': 'my_parent',
            'relationship': 'child',
            'referenced_type': 'some_type',
            'referenced_id': 'some_id'
        }
        index = CommCareCaseIndex(**data)

        self.assertEqual(index.identifier, 'my_parent')
        self.assertEqual(index.relationship, 'child')
        self.assertEqual(index.referenced_type, 'some_type')
        self.assertEqual(index.referenced_id, 'some_id')
예제 #9
0
def _mock_case(case_id, props=None, domain=TARGET_DOMAIN, case_type="patient"):
    props = props if props is not None else {
        "existing_prop": uuid.uuid4().hex,
        "existing_blank_prop": ""
    }
    case = CommCareCase(
        domain=domain, type=case_type, case_id=case_id,
        name=None, external_id=None,
        case_json=props,
    )
    case.cached_indices = [
        CommCareCaseIndex(
            domain=domain, case_id=case_id,
            identifier="parent_c", referenced_type="parent_type",
            referenced_id="parent_case_id", relationship_id=CommCareCaseIndex.CHILD
        ),
        CommCareCaseIndex(
            domain=domain, case_id=case_id,
            identifier="host_c", referenced_type="host_type",
            referenced_id="host_case_id", relationship_id=CommCareCaseIndex.EXTENSION
        )
    ]
    return case
예제 #10
0
def _get_case_ids_with_dupe_indices(db):
    """Get case_ids that have duplicate indices (same identifier)
    """
    case_id_with_dupes_sql = """
        SELECT case_id, identifier, count(*)
        FROM {case_index_table}
        GROUP BY case_id, identifier
        HAVING count(*) > 1
    """.format(case_index_table=CommCareCaseIndex._meta.db_table)

    with CommCareCaseIndex.get_cursor_for_partition_db(db) as cursor:
        log_sql(case_id_with_dupes_sql)
        cursor.execute(case_id_with_dupes_sql)
        rows_with_dupes = fetchall_as_namedtuple(cursor)
        case_ids = {row.case_id for row in rows_with_dupes}
    return case_ids
예제 #11
0
def _delete_duplicate_indices(case_ids, db):
    """Delete duplicate indices on cases only if they point to the same target case and
    have the same identifier and relationship"""
    delete_dupes_sql = """
        DELETE FROM {case_index_table} WHERE id in (
        SELECT id FROM (
          SELECT id, case_id, row_number() OVER (PARTITION BY case_id, identifier, referenced_id, relationship_id)
          FROM {case_index_table}
          JOIN (SELECT UNNEST(%s) AS case_id) AS cx USING (case_id)) as indices
        WHERE row_number > 1
        )
    """.format(case_index_table=CommCareCaseIndex._meta.db_table)

    for chunk in chunked(case_ids, 100, list):
        with CommCareCaseIndex.get_cursor_for_partition_db(db) as cursor:
            log_sql(delete_dupes_sql % repr(chunk))
            cursor.execute(delete_dupes_sql, [chunk])
예제 #12
0
    def _apply_index_action(self, action):
        if not action.indices:
            return

        for index_update in action.indices:
            if self.case.has_index(index_update.identifier):
                # update
                index = self.case.get_index(index_update.identifier)
                index.referenced_type = index_update.referenced_type
                index.referenced_id = index_update.referenced_id
                index.relationship = index_update.relationship
                self.case.track_update(index)
            else:
                # no id, no index
                if index_update.referenced_id:
                    index = CommCareCaseIndex(
                        domain=self.case.domain,
                        case=self.case,
                        identifier=index_update.identifier,
                        referenced_type=index_update.referenced_type,
                        referenced_id=index_update.referenced_id,
                        relationship=index_update.relationship)
                    self.case.track_create(index)
예제 #13
0
def _index_exists(db, index_name):
    with CommCareCaseIndex.get_cursor_for_partition_db(db).cursor() as cursor:
        sql = "SELECT to_regclass(%s) IS NOT NULL as index_exists"
        log_sql(sql % repr(index_name))
        cursor.execute(sql, [index_name])
        return cursor.fetchone()[0]
예제 #14
0
 def indices(self):
     return [
         CommCareCaseIndex(**index) for index in self._data['indices']
         if index["referenced_id"]
     ]
예제 #15
0
 def test_relationship_id_is_set_by_relationship(self):
     index = CommCareCaseIndex(relationship='extension')
     self.assertEqual(index.relationship_id, 2)