Skip to content

Commit

Permalink
fix: preserve globalids for datasets that use change detection
Browse files Browse the repository at this point in the history
Closes #341
  • Loading branch information
stdavis committed Aug 2, 2021
1 parent 3bd02f7 commit 481f88a
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 5 deletions.
30 changes: 25 additions & 5 deletions src/forklift/change_detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
class ChangeDetection(object):
'''A class that models data obtained from the change detection tables
'''

def __init__(self, table_paths, root_folder, hash_table=hash_table):
self.hash_table = hash_table
if not arcpy.Exists(hash_table):
Expand Down Expand Up @@ -67,11 +68,22 @@ def update(self, crate):
elif crate.result[0] == Crate.CREATED:
status = Crate.CREATED

log.info(f'truncating {crate.destination}')
arcpy.management.TruncateTable(crate.destination)

with arcpy.EnvManager(geographicTransformations=crate.geographic_transformation):
arcpy.management.Append(crate.source, crate.destination, schema_type='NO_TEST')
if (_has_globalid_field(crate.source)):
log.info(f'deleting and copying {crate.destination}')
with arcpy.EnvManager(
geographicTransformations=crate.geographic_transformation,
preserveGlobalIds=True,
outputCoordinateSystem=crate.destination_coordinate_system
):
arcpy.management.Delete(crate.destination)
#: the only way to preserve global id values when exporting to fgdb is to use this tool
arcpy.conversion.FeatureClassToFeatureClass(crate.source, crate.destination_workspace, crate.destination_name)
else:
log.info(f'truncating and loading {crate.destination}')
arcpy.management.TruncateTable(crate.destination)

with arcpy.EnvManager(geographicTransformations=crate.geographic_transformation):
arcpy.management.Append(crate.source, crate.destination, schema_type='NO_TEST')

table_name = crate.source_name.lower()
with arcpy.da.UpdateCursor(self.hash_table, [hash_field], where_clause=f'{table_name_field} = \'{table_name}\'') as cursor:
Expand All @@ -87,6 +99,14 @@ def update(self, crate):
return (status, None)


def _has_globalid_field(table):
'''table: string - path to a feature class
returns a boolean indicating if the table has a GlobalId field
'''
return len(arcpy.ListFields(table, field_type='GlobalID')) > 0


def _get_hashes(table_paths):
'''table_paths: string[] - paths to change detection tables relative to the garage
root: string - path to root directory where table_paths is relative to
Expand Down
Binary file modified tests/data/UPDATE_TESTS.bak
Binary file not shown.
46 changes: 46 additions & 0 deletions tests/test_change_detection.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import logging
import unittest
from os import path
from pathlib import Path

from pytest import raises

Expand Down Expand Up @@ -113,3 +114,48 @@ def test_invalid_data(self):
result = change_detection.update(crate)

self.assertEqual(result[0], Crate.INVALID_DATA)

def test_preserves_globalids(self):
scratch_hash_table = str(Path(arcpy.env.scratchGDB) / Path(hash_table).name)
scratch_destination = str(Path(arcpy.env.scratchGDB) / 'GlobalIds')
temp_data = [scratch_hash_table, scratch_destination]
for dataset in temp_data:
if arcpy.Exists(dataset):
arcpy.management.Delete(dataset)
arcpy.management.Copy(hash_table, scratch_hash_table)
test_sde = str(Path(test_data_folder) / 'UPDATE_TESTS.sde')

change_detection = ChangeDetection(['ChangeDetection'], test_sde, hash_table=scratch_hash_table)

table = 'GlobalIds'
crate = Crate(table, test_sde, str(Path(scratch_destination).parent), Path(scratch_destination).name)
crate.result = (Crate.CREATED, None)
core._create_destination_data(crate, skip_hash_field=True)
change_detection.current_hashes[f'update_tests.dbo.{table.casefold()}'] = 'hash'
result = change_detection.update(crate)

self.assertEqual(result[0], Crate.CREATED)

with arcpy.da.SearchCursor(scratch_destination, ['GlobalID', 'NAME'], 'NAME = \'JUAB\'') as cursor:
self.assertEqual(next(cursor)[0], '{29B2946D-695C-4387-BAB7-4773B8DC0E6D}')

def test_can_handle_globalid_fields_without_index(self):
scratch_hash_table = str(Path(arcpy.env.scratchGDB) / Path(hash_table).name)
scratch_destination = str(Path(arcpy.env.scratchGDB) / 'GlobalIds')
temp_data = [scratch_hash_table, scratch_destination]
for dataset in temp_data:
if arcpy.Exists(dataset):
arcpy.management.Delete(dataset)
arcpy.management.Copy(hash_table, scratch_hash_table)
test_sde = str(Path(test_data_folder) / 'UPDATE_TESTS.sde')

change_detection = ChangeDetection(['ChangeDetection'], test_sde, hash_table=scratch_hash_table)

table = 'GlobalIdsNoIndex'
crate = Crate(table, test_sde, arcpy.env.scratchGDB, Path(scratch_destination).name)
crate.result = (Crate.CREATED, None)
core._create_destination_data(crate, skip_hash_field=True)
change_detection.current_hashes[f'update_tests.dbo.{table.casefold()}'] = 'hash'
result = change_detection.update(crate)

self.assertEqual(result[0], Crate.CREATED)

0 comments on commit 481f88a

Please sign in to comment.