from copy import copy, deepcopy import json from datetime import datetime def parse_iso_date(date: str) -> datetime: return datetime.strptime(date, '%Y-%m-%dT%H:%M:%S.000%z') def fmt_iso_date(date: datetime) -> str: return date.strftime('%Y-%m-%dT%H:%M:%S.000%z') PROPERTY_DEFAULT = { int: 'LONG', str: 'STRING', float: 'DOUBLE', } """ type: [external, simple, complex] content-type[complex]: """ PROPERTY_TYPES = { 'BINARY': { 'type': 'complex', 'content-type': 'jcr-value/binary' }, 'BOOLEAN': { 'type': 'simple', 'serialize': json.dumps }, 'DATE': { 'type': 'complex', 'content-type': 'jcr-value/date', 'serialize': fmt_iso_date, 'deserialize': parse_iso_date }, 'DECIMAL': { 'type': 'complex', 'content-type': 'jcr-value/decimal', 'serialize': str, }, 'DOUBLE': { 'type': 'simple', 'serialize': str, }, 'LONG': { 'type': 'simple', 'serialize': str, }, 'NAME': {}, 'PATH': {}, 'REFERENCE': {}, 'STRING': { 'type': 'simple', 'serialize': json.dumps, 'deserialize': json.loads }, 'UNDEFINED': {}, 'URI': {}, 'WEAKREFERENCE': {}, } class Property: pass class Node: def __init__(self, path: str, primary_type: str, is_new: bool = True, data: dict = None): # TODO validate path and type self.path = path self.data = data or {} self.data['jcr:primaryType'] = primary_type self.original_path = copy(path) self.original_data = deepcopy(data) self.is_new = is_new def _build_diff(self) -> str: if self.is_new: return self._build_diff_new() else: return self._build_diff_change() def _build_diff_new(self) -> str: data = [] ptype_dict = {'jcr:primaryType': self.data['jcr:primaryType']} data.append(f'+{self.path} : {json.dumps(ptype_dict)}') for key, value in self.data: if key == 'jcr:primaryType': continue # primaryType is handled differently data.append(f'^{self.path}/{key} : {json.dumps(value)}') return '\n'.join(data) + '\n'