├── .gitignore ├── .swift-version ├── .swiftlint.yml ├── .travis.yml ├── Assets ├── data_model_kit_200.png └── data_model_kit_full.png ├── Cartfile ├── DataModelKit.podspec ├── LICENSE ├── Package.resolved ├── Package.swift ├── README.md ├── Scripts ├── generate_docs.sh ├── launch_tests.sh └── publish_cocoapods.sh ├── Sources └── DataModelKit │ ├── Attribute.swift │ ├── AttributeType.swift │ ├── DataModel.swift │ ├── DataModelError.swift │ ├── DataModelKit.swift │ ├── Entity.swift │ ├── Relationship.swift │ └── UserInfo.swift ├── Tests ├── DataModelKitTests │ └── DataModelKitTests.swift ├── LinuxMain.swift └── Ressources │ └── Sample.xcdatamodel │ └── contents └── logo.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | -------------------------------------------------------------------------------- /.swift-version: -------------------------------------------------------------------------------- 1 | 4.0 2 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | included: # paths to include during linting. `--path` is ignored if present. 2 | - Sources 3 | excluded: # paths to ignore during linting. Takes precedence over `included`. 4 | - .build 5 | - .git -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: swift 2 | osx_image: xcode9 3 | 4 | script: 5 | - set -o pipefail 6 | - xcodebuild -version 7 | - xcodebuild -showsdks 8 | - sh Scripts/launch_tests.sh 9 | after_success: 10 | - bash <(curl -s https://codecov.io/bash) 11 | -------------------------------------------------------------------------------- /Assets/data_model_kit_200.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoissonBallon/DataModelKit/574dbfc730323b200a0b1d4b4e11e10597fec397/Assets/data_model_kit_200.png -------------------------------------------------------------------------------- /Assets/data_model_kit_full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoissonBallon/DataModelKit/574dbfc730323b200a0b1d4b4e11e10597fec397/Assets/data_model_kit_full.png -------------------------------------------------------------------------------- /Cartfile: -------------------------------------------------------------------------------- 1 | github "drmohundro/SWXMLHash" == "4.2.5" 2 | github "nvzqz/FileKit" == 5.0.0 3 | -------------------------------------------------------------------------------- /DataModelKit.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint EasyRealm.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | # Any lines starting with a # are optional, but their use is encouraged 6 | # To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | s.name = 'DataModelKit' 11 | s.version = '1.1.0' 12 | s.summary = 'DataModelKit is a simple and light framework for read and parse .xcdatamodel' 13 | 14 | # This description is used to generate tags and improve search results. 15 | # * Think: What does it do? Why did you write it? What is the focus? 16 | # * Try to keep it short, snappy and to the point. 17 | # * Write the description between the DESC delimiters below. 18 | # * Finally, don't worry about the indent, CocoaPods strips it! 19 | 20 | s.description = <<-DESC 21 | DataModelKit is a simple and light framework for parse and read *.xcdatamodel files. It provides an API for navigate and explore DataModel 22 | DESC 23 | 24 | s.homepage = 'https://github.com/PoissonBallon/DataModelKit' 25 | # s.screenshots = 'www.example.com/screenshots_1', 'www.example.com/screenshots_2' 26 | s.license = { type: 'MIT', file: 'LICENSE' } 27 | s.author = { 'Allan Vialatte' => 'allan.vialatte@icloud.com' } 28 | s.source = { git: 'https://github.com/PoissonBallon/DataModelKit.git', tag: s.version.to_s } 29 | s.social_media_url = 'https://twitter.com/poissonballon' 30 | s.ios.deployment_target = '10.0' 31 | s.osx.deployment_target = '10.11' 32 | s.tvos.deployment_target = '10.0' 33 | s.watchos.deployment_target = '3.0' 34 | s.ios.deployment_target = '9.0' 35 | s.source_files = 'Sources/**/*' 36 | s.dependency 'SWXMLHash', '4.2.5' 37 | s.dependency 'FileKit', '5.0.0' 38 | end 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Vialatte Allan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | { 5 | "package": "FileKit", 6 | "repositoryURL": "https://github.com/nvzqz/FileKit.git", 7 | "state": { 8 | "branch": null, 9 | "revision": "93505a1ad04b4a2de01abd751ace4f05c6db16a5", 10 | "version": "5.0.0" 11 | } 12 | }, 13 | { 14 | "package": "SWXMLHash", 15 | "repositoryURL": "https://github.com/drmohundro/SWXMLHash.git", 16 | "state": { 17 | "branch": null, 18 | "revision": "12496b370363034ccc919e1d72a99b9970b4941e", 19 | "version": "4.2.5" 20 | } 21 | } 22 | ] 23 | }, 24 | "version": 1 25 | } 26 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:4.0 2 | // The swift-tools-version declares the minimum version of Swift required to build this package. 3 | 4 | import PackageDescription 5 | 6 | let package = Package( 7 | name: "DataModelKit", 8 | products: [ 9 | .library(name: "DataModelKit", targets: ["DataModelKit"]), 10 | ], 11 | dependencies: [ 12 | .package(url:"https://github.com/drmohundro/SWXMLHash.git", from: "4.2.5"), 13 | .package(url:"https://github.com/nvzqz/FileKit.git", from: "5.0.0") 14 | ], 15 | targets: [ 16 | // Targets are the basic building blocks of a package. A target can define a module or a test suite. 17 | // Targets can depend on other targets in this package, and on products in packages which this package depends on. 18 | .target(name: "DataModelKit", dependencies: ["FileKit","SWXMLHash"]), 19 | .testTarget(name: "DataModelKitTests", dependencies: ["DataModelKit"]), 20 | ] 21 | ) 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 |

5 | DataModelKit 6 |

7 | 8 | 9 | 10 | [![Version](https://img.shields.io/cocoapods/v/DataModelKit.svg?style=flat)](https://cocoapods.org/pods/DataModelKit) 11 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 12 | [![Platform](https://img.shields.io/cocoapods/p/DataModelKit.svg?style=flat)](http://cocoapods.org/pods/DataModelKit) 13 | [![Build Status](https://travis-ci.org/PoissonBallon/DataModelKit.svg?branch=master)](https://travis-ci.org/PoissonBallon/DataModelKit) 14 | [![Swift 4](https://img.shields.io/badge/Language-Swift%204-orange.svg)](https://developer.apple.com/swift/) 15 | [![codecov](https://codecov.io/gh/PoissonBallon/DataModelKit/branch/master/graph/badge.svg)](https://codecov.io/gh/PoissonBallon/DataModelKit) 16 | [![License](https://img.shields.io/cocoapods/l/DataModelKit.svg?style=flat)](http://cocoapods.org/pods/DataModelKit) 17 | 18 | 19 | DataModelKit is a simple and light framework to parse and read __*.xcdatamodel__ files. It provides an API to navigate and explore __DataModel__ 20 | 21 | It's used in DataModelGen tools. _(available soon)_ 22 | 23 | ## Usage 24 | 25 | ### Init a DataModel Object 26 | 27 | ```swift 28 | import DataModelKit 29 | 30 | static let path = "Project/Ressources/Sample.xcdatamodel" 31 | let model = try? DataModel(with: DataModelKitTests.pathTest) 32 | 33 | print(model.entities) 34 | ``` 35 | 36 | ## Installation 37 | 38 | EasyRealm is available through [CocoaPods](http://cocoapods.org), [Carthage](https://github.com/Carthage/Carthage) and [SPM](https://github.com/apple/swift-package-manager). 39 | 40 | #### CocoaPods 41 | ```ruby 42 | use_frameworks! 43 | 44 | pod "DataModelKit" 45 | ``` 46 | 47 | #### Carthage 48 | ```ruby 49 | 50 | github 'PoissonBallon/DataModelKit' 51 | ``` 52 | 53 | #### SPM 54 | ```swift 55 | dependencies: [ 56 | .package(url: "https://github.com/PoissonBallon/DataModelKit.git", .upToNextMinor(from:"1.0.0")) 57 | ], 58 | ``` 59 | 60 | 61 | ## API 62 | 63 | DataModelKit provide somes structs with attribute to exploite your DataModel 64 | 65 | #### DataModel 66 | It is the root object of your DataModel 67 | 68 | ```swift 69 | 70 | public struct DataModel { 71 | public let path: Struct /// Path of the original file.xcdatamodel 72 | public let entities: [Entity] /// Parsed model's entities 73 | public let documentVersion: String /// Version of file.xcdatamodel 74 | public let systemVersion: String /// System version of file.xcdatamodel 75 | public let minimumToolsVersion: String /// Minimum tools version of file.xcdatamodel 76 | public let lastSavedToolsVersion: String /// Last saved tools version of file.xcdatamodel 77 | } 78 | ``` 79 | 80 | #### Entity 81 | 82 | ```swift 83 | public struct Entity { 84 | public let name: String /// 85 | public let userInfos: [UserInfo] 86 | public let attributes: [Attribute] 87 | public let relationships: [Relationship] 88 | } 89 | ``` 90 | 91 | #### Relationship 92 | 93 | ```swift 94 | public struct Relationship { 95 | public let name: String 96 | public let destination: String 97 | public let inverse: String? 98 | public let userInfo: [UserInfo] 99 | public let toMany: Bool 100 | public let toOne: Bool 101 | public let optional: Bool 102 | public let syncable: Bool 103 | public let ordered: Bool 104 | } 105 | 106 | ``` 107 | 108 | #### Attribute 109 | ```swift 110 | public struct Attribute { 111 | public let name: String 112 | public let optional: Bool 113 | public let indexed: Bool 114 | public let defaultValue: String? 115 | public let type: String 116 | public let userInfos: [UserInfo] 117 | } 118 | ``` 119 | 120 | ## Author 121 | 122 | * PoissonBallon [@poissonballon](https://twitter.com/poissonballon) 123 | 124 | ## License 125 | 126 | DataModelKit is available under the MIT license. See the LICENSE file for more info. 127 | 128 | ## Other 129 | 130 | * Thanks to [Adrien Groleas](https://adriengroleas.fr) for logo 131 | * Thanks to [@trpl](https://github.com/trpl) for text review 132 | -------------------------------------------------------------------------------- /Scripts/generate_docs.sh: -------------------------------------------------------------------------------- 1 | swift build 2 | sourcekitten doc --spm-module DataModelKit > datamodelkit.json 3 | jazzy \ 4 | --clean \ 5 | --sourcekitten-sourcefile datamodelkit.json \ 6 | --author Allan Vialatte \ 7 | --author_url https://github.com/PoissonBallon \ 8 | --github_url https://github.com/PoissonBallon/DataModelKit \ 9 | --module DataModelKit \ 10 | -------------------------------------------------------------------------------- /Scripts/launch_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | swift package generate-xcodeproj --enable-code-coverage 4 | dataModelPath=`cd Tests/Ressources/Sample.xcdatamodel;pwd`; 5 | echo "$dataModelPath" 6 | DATAMODEL_TEST_PATH=$dataModelPath xcodebuild -scheme DataModelKit-Package -enableCodeCoverage YES test | xcpretty 7 | -------------------------------------------------------------------------------- /Scripts/publish_cocoapods.sh: -------------------------------------------------------------------------------- 1 | pod lib lint --verbose --allow-warnings 2 | pod trunk push DataModelKit.podspec --allow-warnings 3 | -------------------------------------------------------------------------------- /Sources/DataModelKit/Attribute.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Attribute.swift 3 | // DataModelKit 4 | // 5 | // The MIT License (MIT) 6 | // 7 | // Copyright (c) 2017 Vialatte Allan 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | // 27 | 28 | import Foundation 29 | import SWXMLHash 30 | 31 | public struct Attribute { 32 | public let name: String 33 | public let optional: Bool 34 | public let indexed: Bool 35 | public let defaultValue: String? 36 | public let type: AttributeType 37 | public let userInfos: [UserInfo] 38 | } 39 | 40 | extension Attribute { 41 | 42 | public init(with node: XMLIndexer) throws { 43 | guard let name = node.element?.attribute(by: "name")?.text else { 44 | throw DataModelError.parserAttributeNameError 45 | } 46 | guard let tmp = node.element?.attribute(by: "attributeType")?.text, let type = AttributeType(rawValue: tmp) else { 47 | throw DataModelError.parserAttributeTypeError 48 | } 49 | 50 | self.name = name 51 | self.type = type 52 | self.optional = (node.element?.attribute(by: "optional")?.text == "YES") ? true : false 53 | self.indexed = (node.element?.attribute(by: "indexed")?.text == "YES") ? true : false 54 | self.defaultValue = node.element?.attribute(by: "defaultValueString")?.text 55 | self.userInfos = node["userInfo"].children.flatMap { try? UserInfo.init(with: $0) } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Sources/DataModelKit/AttributeType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // File.swift 3 | // DataModelKitPackageDescription 4 | // 5 | // Created by Allan Vialatte on 18/11/2017. 6 | // 7 | 8 | import Foundation 9 | 10 | public enum AttributeType: String { 11 | case undefined = "Undefined" 12 | case integer16 = "Integer 16" 13 | case integer32 = "Integer 32" 14 | case integer64 = "Integer 64" 15 | case decimal = "Decimal" 16 | case double = "Double" 17 | case float = "Float" 18 | case string = "String" 19 | case boolean = "Boolean" 20 | case date = "Date" 21 | case binaryData = "BinaryData" 22 | case uuid = "UUID" 23 | case uri = "URI" 24 | case transformable = "Transformable" 25 | } 26 | -------------------------------------------------------------------------------- /Sources/DataModelKit/DataModel.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataModel.swift 3 | // DataModelKit 4 | // 5 | // The MIT License (MIT) 6 | // 7 | // Copyright (c) 2017 Vialatte Allan 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | // 27 | 28 | import Foundation 29 | import FileKit 30 | import SWXMLHash 31 | 32 | /// DataModel 33 | public struct DataModel { 34 | private let root: XMLIndexer 35 | 36 | public let path: String /// Path of the original file.xcdatamodel 37 | public let entities: [Entity] /// Parsed model's entities 38 | public let documentVersion: String /// Version of file.xcdatamodel 39 | public let systemVersion: String /// System version of file.xcdatamodel 40 | public let minimumToolsVersion: String /// Minimum tools version of file.xcdatamodel 41 | public let lastSavedToolsVersion: String /// Last saved tools version of file.xcdatamodel 42 | } 43 | 44 | extension DataModel { 45 | 46 | /// Parse and init DataModel 47 | /// 48 | /// - Parameter path: Take the path of an file.xcdatamodel 49 | /// - Throws: throw different error if needed 50 | public init(with path: String) throws { 51 | 52 | let resolvedPath = Path(path).resolved 53 | let file = File.init(path: resolvedPath + "contents") 54 | 55 | guard resolvedPath.pathExtension == DataModelKit.dataModelExtension else { 56 | throw DataModelError.targetIsNotAnXcdataModel 57 | } 58 | guard file.exists else { 59 | throw DataModelError.targetHaveNotContent 60 | } 61 | guard let data = try? file.read() else { 62 | throw DataModelError.targetIsNotReadable 63 | } 64 | 65 | self.path = resolvedPath.description 66 | self.root = SWXMLHash.parse(data) 67 | self.documentVersion = self.root["model"].element?.attribute(by: "documentVersion")?.text ?? "" 68 | self.systemVersion = self.root["model"].element?.attribute(by: "systemVersion")?.text ?? "" 69 | self.minimumToolsVersion = self.root["model"].element?.attribute(by: "minimumToolsVersion")?.text ?? "" 70 | self.lastSavedToolsVersion = self.root["model"].element?.attribute(by: "lastSavedToolsVersion")?.text ?? "" 71 | self.entities = self.root["model"]["entity"].all.flatMap { try? Entity(with: $0) } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Sources/DataModelKit/DataModelError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataModelError.swift 3 | // DataModelKit 4 | // 5 | // The MIT License (MIT) 6 | // 7 | // Copyright (c) 2017 Vialatte Allan 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | // 27 | 28 | import Foundation 29 | 30 | public enum DataModelError: Error { 31 | 32 | // MARK: Target Reader Error 33 | case targetIsNotAnXcdataModel 34 | case targetHaveNotContent 35 | case targetIsNotReadable 36 | 37 | // MARK: Parser Entity Error 38 | case parserEntityNameError 39 | 40 | // MARK: Parser Attribute Error 41 | case parserAttributeNameError 42 | case parserAttributeTypeError 43 | 44 | // MARK: Parser UserInfo Error 45 | case parserUserInfoKeyError 46 | case parserUserInfoValueError 47 | 48 | // MARK: Parser Relationship Error 49 | case parserRelationshipNameError 50 | case parserRelationshipInverseError 51 | } 52 | -------------------------------------------------------------------------------- /Sources/DataModelKit/DataModelKit.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataModelKit.swift 3 | // DataModelKit 4 | // 5 | // The MIT License (MIT) 6 | // 7 | // Copyright (c) 2017 Vialatte Allan 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | // 27 | 28 | public struct DataModelKit { 29 | public static let dataModelExtension = "xcdatamodel" 30 | } 31 | -------------------------------------------------------------------------------- /Sources/DataModelKit/Entity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DataModelEntity.swift 3 | // DataModelKit 4 | // 5 | // The MIT License (MIT) 6 | // 7 | // Copyright (c) 2017 Vialatte Allan 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | // 27 | 28 | import Foundation 29 | import SWXMLHash 30 | 31 | public struct Entity { 32 | public let name: String 33 | public let userInfos: [UserInfo] 34 | public let attributes: [Attribute] 35 | public let relationships: [Relationship] 36 | } 37 | 38 | extension Entity { 39 | 40 | public init(with node: XMLIndexer) throws { 41 | guard let name = node.element?.attribute(by: "name")?.text else { 42 | throw DataModelError.parserEntityNameError 43 | } 44 | self.name = name 45 | self.attributes = node["attribute"].all.flatMap { try? Attribute.init(with: $0) } 46 | self.userInfos = node["userInfo"].children.flatMap { try? UserInfo.init(with: $0) } 47 | self.relationships = node["relationship"].all.flatMap { try? Relationship.init(with: $0) } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Sources/DataModelKit/Relationship.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Relationship.swift 3 | // DataModelKit 4 | // 5 | // The MIT License (MIT) 6 | // 7 | // Copyright (c) 2017 Vialatte Allan 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | // 27 | 28 | import Foundation 29 | import SWXMLHash 30 | 31 | public struct Relationship { 32 | public let name: String 33 | public let destination: String 34 | public let inverse: String? 35 | public let userInfo: [UserInfo] 36 | public let toMany: Bool 37 | public let toOne: Bool 38 | public let optional: Bool 39 | public let syncable: Bool 40 | public let ordered: Bool 41 | } 42 | 43 | extension Relationship { 44 | public init(with node: XMLIndexer) throws { 45 | guard let name = node.element?.attribute(by: "name")?.text else { 46 | throw DataModelError.parserRelationshipNameError 47 | } 48 | guard let destination = node.element?.attribute(by: "destinationEntity")?.text else { 49 | throw DataModelError.parserRelationshipInverseError 50 | } 51 | self.name = name 52 | self.destination = destination 53 | self.inverse = node.element?.attribute(by: "inverseName")?.text 54 | self.userInfo = node["userInfo"].children.flatMap { try? UserInfo.init(with: $0) } 55 | self.toMany = (node.element?.attribute(by: "toMany")?.text == "YES") ? true : false 56 | self.toOne = !self.toMany 57 | self.optional = (node.element?.attribute(by: "optional")?.text == "YES") ? true : false 58 | self.syncable = (node.element?.attribute(by: "syncable")?.text == "YES") ? true : false 59 | self.ordered = (node.element?.attribute(by: "ordered")?.text == "YES") ? true : false 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Sources/DataModelKit/UserInfo.swift: -------------------------------------------------------------------------------- 1 | // 2 | // UserInfo.swift 3 | // DataModelKitPackageDescription 4 | // 5 | // The MIT License (MIT) 6 | // 7 | // Copyright (c) 2017 Vialatte Allan 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy 10 | // of this software and associated documentation files (the "Software"), to deal 11 | // in the Software without restriction, including without limitation the rights 12 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | // copies of the Software, and to permit persons to whom the Software is 14 | // furnished to do so, subject to the following conditions: 15 | // 16 | // The above copyright notice and this permission notice shall be included in 17 | // all copies or substantial portions of the Software. 18 | // 19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | // THE SOFTWARE. 26 | // 27 | 28 | import Foundation 29 | import SWXMLHash 30 | 31 | public struct UserInfo { 32 | public let key: String 33 | public let value: String 34 | } 35 | 36 | extension UserInfo { 37 | 38 | public init(with node: XMLIndexer) throws { 39 | guard let key = node.element?.attribute(by: "key")?.text else { 40 | throw DataModelError.parserUserInfoKeyError 41 | } 42 | guard let value = node.element?.attribute(by: "value")?.text else { 43 | throw DataModelError.parserUserInfoValueError 44 | } 45 | 46 | self.key = key 47 | self.value = value 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Tests/DataModelKitTests/DataModelKitTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import DataModelKit 3 | 4 | class DataModelKitTests: XCTestCase { 5 | 6 | static let pathTest = ProcessInfo.processInfo.environment["DATAMODEL_TEST_PATH"] ?? "" 7 | static let sampleEntitiesCount = 6 8 | static let sampleArticleAttributesCount = 21 9 | static let sampleArticleFlagUserInfoCount = 3 10 | static let sampleArticleRelationhipCount = 2 11 | static let sampleArticleParagraphRelationhipCount = 1 12 | 13 | func testOpen() { 14 | let model = try? DataModel(with: DataModelKitTests.pathTest) 15 | XCTAssertNotNil(model) 16 | XCTAssertEqual(model!.documentVersion, "1.0") 17 | XCTAssertEqual(model!.systemVersion, "16G29") 18 | } 19 | 20 | func testCount() { 21 | let model = try! DataModel(with: DataModelKitTests.pathTest) 22 | XCTAssertEqual(model.entities.count, DataModelKitTests.sampleEntitiesCount) 23 | 24 | let article = model.entities.first { $0.name == "Article" } 25 | XCTAssertNotNil(article) 26 | XCTAssertEqual(article!.attributes.count, DataModelKitTests.sampleArticleAttributesCount) 27 | 28 | let flag = article?.attributes.first { $0.name == "flag" } 29 | XCTAssertNotNil(flag) 30 | XCTAssertEqual(flag!.userInfos.count, DataModelKitTests.sampleArticleFlagUserInfoCount) 31 | } 32 | 33 | func testRelationship() { 34 | let model = try! DataModel(with: DataModelKitTests.pathTest) 35 | 36 | let entitie = model.entities.first { $0.name == "ArticleParagraph" } 37 | guard let paragraph = entitie else { XCTFail();return } 38 | XCTAssertEqual(paragraph.relationships.count, DataModelKitTests.sampleArticleParagraphRelationhipCount) 39 | guard let relationship = paragraph.relationships.first else { XCTFail();return } 40 | XCTAssertEqual(relationship.name, "article") 41 | XCTAssertEqual(relationship.destination, "Article") 42 | XCTAssertEqual(relationship.inverse!, "paragraphs") 43 | XCTAssertEqual(relationship.optional, true) 44 | XCTAssertEqual(relationship.toOne, true) 45 | 46 | let entitieTwo = model.entities.first { $0.name == "Article" } 47 | guard let article = entitieTwo else { XCTFail();return } 48 | XCTAssertEqual(article.relationships.count, DataModelKitTests.sampleArticleRelationhipCount) 49 | let relaOne = article.relationships.first { $0.name == "images" } 50 | guard let images = relaOne else { XCTFail();return } 51 | XCTAssertEqual(images.destination, "ArticleImage") 52 | XCTAssertEqual(images.inverse, nil) 53 | XCTAssertEqual(images.toMany, true) 54 | 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import DataModelKitTests 3 | 4 | XCTMain([ 5 | testCase(DataModelKitTests.allTests), 6 | ]) 7 | -------------------------------------------------------------------------------- /Tests/Ressources/Sample.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PoissonBallon/DataModelKit/574dbfc730323b200a0b1d4b4e11e10597fec397/logo.png --------------------------------------------------------------------------------