text: # -*- test-case-name: txdav.common.datastore.upgrade.sql.test -*-
  # #
  # Copyright (c) 2011-2017 Apple Inc. All rights reserved.
  #
  # Licensed under the Apache License, Version 2.0 (the "License");
  # you may not use this file except in compliance with the License.
  # You may obtain a copy of the License at
  #
  # http://www.apache.org/licenses/LICENSE-2.0
  #
  # Unless required by applicable law or agreed to in writing, software
  # distributed under the License is distributed on an "AS IS" BASIS,
  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  # See the License for the specific language governing permissions and
  # limitations under the License.
  # #
  
  from twext.enterprise.dal.syntax import Update
  
  from twisted.internet.defer import inlineCallbacks
  
  from txdav.base.propertystore.base import PropertyName
  from txdav.common.datastore.sql_tables import _ABO_KIND_GROUP, schema
  from txdav.common.datastore.upgrade.sql.upgrades.util import updateAddressBookDataVersion, \
      doToEachHomeNotAtVersion, removeProperty, cleanPropertyStore, \
      logUpgradeStatus
  from txdav.xml import element
  
  """
  AddressBook Data upgrade from database version 1 to 2
  """
  
  UPGRADE_TO_VERSION = 2
  
  
  @inlineCallbacks
  def doUpgrade(sqlStore):
      """
      fill in members tables and increment data version
      """
      yield populateMemberTables(sqlStore)
      yield removeResourceType(sqlStore)
  
      # bump data version
      yield updateAddressBookDataVersion(sqlStore, UPGRADE_TO_VERSION)
  
  
  @inlineCallbacks
  def populateMemberTables(sqlStore):
      """
      Set the group kind and and members tables
      """
      @inlineCallbacks
      def doIt(txn, homeResourceID):
          """
          KIND is set to person by schema upgrade.
          To upgrade MEMBERS and FOREIGN_MEMBERS:
              1. Set group KIND (avoids assert)
              2. Write groups.  Write logic will fill in MEMBERS and FOREIGN_MEMBERS
                  (Remember that all members resource IDs must already be in the address book).
          """
          home = yield txn.addressbookHomeWithResourceID(homeResourceID)
          abObjectResources = yield home.addressbook().objectResources()
          for abObject in abObjectResources:
              component = yield abObject.component()
              lcResourceKind = component.resourceKind().lower() if component.resourceKind() else component.resourceKind()
              if lcResourceKind == "group":
                  # update kind
                  abo = schema.ADDRESSBOOK_OBJECT
                  yield Update(
                      {abo.KIND: _ABO_KIND_GROUP},
                      Where=abo.RESOURCE_ID == abObject._resourceID,
                  ).on(txn)
                  abObject._kind = _ABO_KIND_GROUP
                  # update rest
                  yield abObject.setComponent(component)
  
      logUpgradeStatus("Starting Addressbook Populate Members")
  
      # Do this to each calendar home not already at version 2
      yield doToEachHomeNotAtVersion(sqlStore, schema.ADDRESSBOOK_HOME, UPGRADE_TO_VERSION, doIt, "Populate Members")
  
  
  @inlineCallbacks
  def removeResourceType(sqlStore):
      logUpgradeStatus("Starting Addressbook Remove Resource Type")
  
      sqlTxn = sqlStore.newTransaction(label="addressbook_upgrade_from_1_to_2.removeResourceType")
      yield removeProperty(sqlTxn, PropertyName.fromElement(element.ResourceType))
      yield sqlTxn.commit()
      yield cleanPropertyStore()
  
      logUpgradeStatus("End Addressbook Remove Resource Type")
  