motion_migrate 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.rvmrc +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +152 -0
- data/Rakefile +3 -0
- data/lib/motion_migrate/generate.rb +51 -0
- data/lib/motion_migrate/model.rb +10 -0
- data/lib/motion_migrate/motion_generate/entity.rb +15 -0
- data/lib/motion_migrate/motion_generate/io.rb +79 -0
- data/lib/motion_migrate/motion_generate/parser.rb +27 -0
- data/lib/motion_migrate/motion_generate/property.rb +171 -0
- data/lib/motion_migrate/motion_generate/relationship.rb +153 -0
- data/lib/motion_migrate/motion_model/property.rb +14 -0
- data/lib/motion_migrate/motion_model/relationship.rb +20 -0
- data/lib/motion_migrate.rb +20 -0
- data/lib/tasks/migrate.rake +53 -0
- data/lib/version.rb +3 -0
- data/motion_migrate.gemspec +21 -0
- data/spec/property_spec.rb +113 -0
- data/spec/relationship_spec.rb +54 -0
- data/spec_project/.gitignore +18 -0
- data/spec_project/Gemfile +6 -0
- data/spec_project/Rakefile +14 -0
- data/spec_project/app/app_delegate.rb +7 -0
- data/spec_project/app/models/pilot.rb +7 -0
- data/spec_project/app/models/plane.rb +11 -0
- data/spec_project/db/schema.xcdatamodeld/.xccurrentversion +8 -0
- data/spec_project/db/schema.xcdatamodeld/schema.1.xcdatamodel/contents +6 -0
- data/spec_project/db/schema.xcdatamodeld/schema.10.xcdatamodel/contents +18 -0
- data/spec_project/db/schema.xcdatamodeld/schema.2.xcdatamodel/contents +7 -0
- data/spec_project/db/schema.xcdatamodeld/schema.3.xcdatamodel/contents +7 -0
- data/spec_project/db/schema.xcdatamodeld/schema.4.xcdatamodel/contents +8 -0
- data/spec_project/db/schema.xcdatamodeld/schema.5.xcdatamodel/contents +9 -0
- data/spec_project/db/schema.xcdatamodeld/schema.6.xcdatamodel/contents +13 -0
- data/spec_project/db/schema.xcdatamodeld/schema.7.xcdatamodel/contents +14 -0
- data/spec_project/db/schema.xcdatamodeld/schema.8.xcdatamodel/contents +16 -0
- data/spec_project/db/schema.xcdatamodeld/schema.9.xcdatamodel/contents +16 -0
- data/spec_project/spec/helper.rb +8 -0
- data/spec_project/spec/property_spec.rb +57 -0
- data/spec_project/spec/relationship_spec.rb +105 -0
- data/spec_project/vendor/Podfile.lock +11 -0
- metadata +113 -0
@@ -0,0 +1,153 @@
|
|
1
|
+
module MotionMigrate
|
2
|
+
module MotionGenerate
|
3
|
+
module Relationship
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def belongs_to(name, options={})
|
10
|
+
relationship(name, :belongs_to, options)
|
11
|
+
end
|
12
|
+
|
13
|
+
def has_many(name, options={})
|
14
|
+
relationship(name, :has_many, options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def relationship(name, type, options={})
|
18
|
+
options.each { |key, value| raise_if_relationship_option_not_allowed(type, key) }
|
19
|
+
|
20
|
+
raise_if_relationship_options_missing(options)
|
21
|
+
raise_if_deletion_rule_not_allowed(options)
|
22
|
+
|
23
|
+
attributes = {
|
24
|
+
name: name,
|
25
|
+
optional: core_data_boolean(true),
|
26
|
+
deletionRule: core_data_string(:no_action),
|
27
|
+
syncable: core_data_boolean(true)
|
28
|
+
}
|
29
|
+
attributes.merge!({ minCount: 1, maxCount: 1 }) if type == :belongs_to
|
30
|
+
attributes.merge!(core_data_relationship_attributes(type, options))
|
31
|
+
relationships[self.entity_name] = {} if relationships[self.entity_name].nil?
|
32
|
+
relationships[self.entity_name][name] = attributes
|
33
|
+
attributes
|
34
|
+
end
|
35
|
+
|
36
|
+
def relationships
|
37
|
+
@@relationships ||= {}
|
38
|
+
end
|
39
|
+
|
40
|
+
def raise_if_relationship_option_not_allowed(type, option)
|
41
|
+
unless relationship_option_allowed?(type, option)
|
42
|
+
raise <<-ERROR
|
43
|
+
! The option must be one of the following:
|
44
|
+
!
|
45
|
+
! For type :belongs_to:
|
46
|
+
! :required
|
47
|
+
! :deletion_rule
|
48
|
+
! :class_name
|
49
|
+
! :inverse_of
|
50
|
+
! :spotlight
|
51
|
+
! :truth_file
|
52
|
+
! :transient
|
53
|
+
!
|
54
|
+
! For type :has_many:
|
55
|
+
! :required
|
56
|
+
! :min
|
57
|
+
! :max
|
58
|
+
! :deletion_rule
|
59
|
+
! :class_name
|
60
|
+
! :inverse_of
|
61
|
+
! :ordered
|
62
|
+
! :spotlight
|
63
|
+
! :truth_file
|
64
|
+
! :transient
|
65
|
+
ERROR
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def raise_if_relationship_options_missing(options)
|
70
|
+
unless relationship_options_complete?(options)
|
71
|
+
raise <<-ERROR
|
72
|
+
! One of these options are required:
|
73
|
+
! :class_name
|
74
|
+
! :inverse_of
|
75
|
+
ERROR
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def deletion_rule_allowed?(options)
|
80
|
+
allowed_deletion_rules = [
|
81
|
+
:nullify,
|
82
|
+
:cascade,
|
83
|
+
:deny
|
84
|
+
]
|
85
|
+
!options[:deletion_rule] || allowed_deletion_rules.include?(options[:deletion_rule])
|
86
|
+
end
|
87
|
+
|
88
|
+
def raise_if_deletion_rule_not_allowed(options)
|
89
|
+
unless deletion_rule_allowed?(options)
|
90
|
+
raise <<-ERROR
|
91
|
+
! One of these deletion rules are allowed:
|
92
|
+
! :nullify
|
93
|
+
! :cascade
|
94
|
+
! :deny
|
95
|
+
ERROR
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def relationship_options_complete?(options)
|
100
|
+
required_options = [:class_name, :inverse_of]
|
101
|
+
(required_options.uniq - options.keys.uniq).empty?
|
102
|
+
end
|
103
|
+
|
104
|
+
def relationship_option_allowed?(type, option)
|
105
|
+
allowed_options = {
|
106
|
+
has_many: [:ordered, :min, :max],
|
107
|
+
}[type] || []
|
108
|
+
|
109
|
+
allowed_options += [
|
110
|
+
:required,
|
111
|
+
:spotlight,
|
112
|
+
:truth_file,
|
113
|
+
:transient,
|
114
|
+
:inverse_of,
|
115
|
+
:class_name,
|
116
|
+
:deletion_rule
|
117
|
+
]
|
118
|
+
allowed_options.include?(option)
|
119
|
+
end
|
120
|
+
|
121
|
+
def core_data_relationship_attributes(type, options)
|
122
|
+
attributes = {}
|
123
|
+
|
124
|
+
options.each do |key, value|
|
125
|
+
case key
|
126
|
+
when :required
|
127
|
+
attributes[:optional] = core_data_boolean(value != true)
|
128
|
+
when :inverse_of
|
129
|
+
attributes[:inverseName] = value
|
130
|
+
when :class_name
|
131
|
+
attributes[:inverseEntity] = value
|
132
|
+
attributes[:destinationEntity] = value
|
133
|
+
when :deletion_rule
|
134
|
+
attributes[:deletionRule] = core_data_string(value)
|
135
|
+
when :transient
|
136
|
+
attributes[:transient] = core_data_boolean(value)
|
137
|
+
when :spotlight
|
138
|
+
attributes[:spotlightIndexingEnabled] = core_data_boolean(value)
|
139
|
+
when :truth_file
|
140
|
+
attributes[:storedInTruthFile] = core_data_boolean(value)
|
141
|
+
when :min
|
142
|
+
attributes[:minCount] = value
|
143
|
+
when :max
|
144
|
+
attributes[:maxCount] = value
|
145
|
+
end
|
146
|
+
end
|
147
|
+
attributes[:toMany] = core_data_boolean(type == :has_many)
|
148
|
+
attributes
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module MotionMigrate
|
2
|
+
module MotionModel
|
3
|
+
module Relationship
|
4
|
+
def self.included(base)
|
5
|
+
base.extend(ClassMethods)
|
6
|
+
end
|
7
|
+
|
8
|
+
module ClassMethods
|
9
|
+
def belongs_to(name, options={})
|
10
|
+
end
|
11
|
+
|
12
|
+
def has_many(name, options={})
|
13
|
+
end
|
14
|
+
|
15
|
+
def belongs_to(name, options={})
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
unless defined?(Motion::Project::Config)
|
2
|
+
raise "This file must be required within a RubyMotion project Rakefile."
|
3
|
+
end
|
4
|
+
|
5
|
+
Motion::Project::App.setup do |app|
|
6
|
+
Dir.glob(File.join(File.dirname(__FILE__), "motion_migrate/motion_model/**/*.rb")).each do |file|
|
7
|
+
app.files.unshift(file)
|
8
|
+
end
|
9
|
+
app.files.unshift(File.join(File.dirname(__FILE__), 'motion_migrate/model.rb'))
|
10
|
+
|
11
|
+
app.frameworks += ['CoreData'] unless app.frameworks.include?("CoreData")
|
12
|
+
end
|
13
|
+
|
14
|
+
module MotionMigrate
|
15
|
+
end
|
16
|
+
|
17
|
+
# Include rake files
|
18
|
+
Dir.glob(File.join(File.dirname(__FILE__), "tasks/**/*.rake")) do |task|
|
19
|
+
import task
|
20
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "nokogiri"
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
require "motion_migrate/motion_generate/entity"
|
5
|
+
require "motion_migrate/motion_generate/parser"
|
6
|
+
require "motion_migrate/motion_generate/property"
|
7
|
+
require "motion_migrate/motion_generate/relationship"
|
8
|
+
require "motion_migrate/generate"
|
9
|
+
require "motion_migrate/motion_generate/io"
|
10
|
+
|
11
|
+
namespace :db do
|
12
|
+
desc "Generate a version of the current database model as described in the models."
|
13
|
+
task :migrate do
|
14
|
+
schema_xml = MotionMigrate::Generate.build
|
15
|
+
MotionMigrate::IO.write(schema_xml)
|
16
|
+
end
|
17
|
+
|
18
|
+
desc "Go back to the previous version of the database model."
|
19
|
+
task :rollback do
|
20
|
+
if version = MotionMigrate::IO.current_schema_version
|
21
|
+
if version == 1
|
22
|
+
puts "! Can't rollback schema when version is 1."
|
23
|
+
else
|
24
|
+
schema = MotionMigrate::IO.current_schema
|
25
|
+
MotionMigrate::IO.write_current_schema(version - 1)
|
26
|
+
FileUtils.rm_rf(schema)
|
27
|
+
puts "# Data model rolled back to version #{version - 1}."
|
28
|
+
end
|
29
|
+
else
|
30
|
+
puts "! No schema found in this project."
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
namespace :schema do
|
35
|
+
desc "Dump the current version of the database model scheme."
|
36
|
+
task :dump do
|
37
|
+
if current_schema = MotionMigrate::IO.current_schema
|
38
|
+
puts File.open(File.join(current_schema, "contents")).read
|
39
|
+
else
|
40
|
+
puts "! No schema found in this project."
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
desc "Show the current version of the database model scheme."
|
45
|
+
task :version do
|
46
|
+
if version = MotionMigrate::IO.current_schema_version
|
47
|
+
puts "# Data model is currently at version #{version}."
|
48
|
+
else
|
49
|
+
puts "! No schema found in this project."
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/version.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "motion_migrate"
|
8
|
+
gem.version = MotionMigrate::VERSION
|
9
|
+
gem.authors = ["Jelle Vandebeeck"]
|
10
|
+
gem.email = ["jelle@fousa.be"]
|
11
|
+
gem.description = %q{Generate the Core Data model from your RubyMotion code.}
|
12
|
+
gem.summary = %q{Generate the Core Data model from your RubyMotion code. Never open XCode again!}
|
13
|
+
gem.homepage = "http://fousa.github.com/motion_migrate/"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
|
+
gem.require_paths = ["lib"]
|
18
|
+
|
19
|
+
gem.add_development_dependency 'rake'
|
20
|
+
gem.add_dependency 'nokogiri'
|
21
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
require "motion_migrate/motion_generate/entity"
|
4
|
+
require "motion_migrate/motion_generate/parser"
|
5
|
+
require "motion_migrate/motion_generate/property"
|
6
|
+
require "motion_migrate/motion_generate/relationship"
|
7
|
+
require "motion_migrate/generate"
|
8
|
+
|
9
|
+
module MotionMigrate
|
10
|
+
describe "property definitions in the model" do
|
11
|
+
before do
|
12
|
+
@allowed_options = {
|
13
|
+
required: true,
|
14
|
+
transient: true,
|
15
|
+
indexed: true,
|
16
|
+
spotlight: true,
|
17
|
+
truth_file: true
|
18
|
+
}
|
19
|
+
@filled_allowed_attributes = {
|
20
|
+
optional: "NO",
|
21
|
+
transient: "YES",
|
22
|
+
indexed: "YES",
|
23
|
+
spotlightIndexingEnabled: "YES",
|
24
|
+
storedInTruthFile: "YES",
|
25
|
+
syncable: "YES"
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
%w(string integer_16 integer_32 integer_64 decimal double float date binary_data boolean).each do |type|
|
30
|
+
it "should be able to define #{type}" do
|
31
|
+
type_string = type.split("_").each{|word| word.capitalize! }.join(" ")
|
32
|
+
type_string = "Binary" if type == "binary_data"
|
33
|
+
MotionMigrate::Model.property(:field, type).should == { :name => :field,
|
34
|
+
:attributeType => type_string,
|
35
|
+
:optional=>"YES",
|
36
|
+
:syncable => "YES" }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should error on undiffened types" do
|
41
|
+
lambda { MotionMigrate::Model.property(:field, :unknown) }.should raise_error
|
42
|
+
end
|
43
|
+
|
44
|
+
%w(string integer_16 integer_32 integer_64 decimal double float date binary_data boolean).each do |type|
|
45
|
+
it "should error on undiffened options for #{type}" do
|
46
|
+
lambda { MotionMigrate::Model.property(:field, type, :unknown => true) }.should raise_error
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should return the correct options for string" do
|
51
|
+
options = @allowed_options.merge({
|
52
|
+
min: "1",
|
53
|
+
max: "10",
|
54
|
+
default: "motion",
|
55
|
+
regex: "/we/"
|
56
|
+
})
|
57
|
+
MotionMigrate::Model.property(:field, :string, options).should == @filled_allowed_attributes.merge({ :name => :field,
|
58
|
+
:attributeType => "String",
|
59
|
+
:minValueString => "1",
|
60
|
+
:maxValueString => "10",
|
61
|
+
:defaultValueString => "motion",
|
62
|
+
:regularExpressionString => "/we/" })
|
63
|
+
end
|
64
|
+
|
65
|
+
%w(integer_16 integer_32 integer_64 decimal double float).each do |type|
|
66
|
+
it "should return the correct options for #{type}" do
|
67
|
+
options = @allowed_options.merge({
|
68
|
+
min: "1",
|
69
|
+
max: "10",
|
70
|
+
default: "5"
|
71
|
+
})
|
72
|
+
MotionMigrate::Model.property(:field, type, options).should == @filled_allowed_attributes.merge({ :name => :field,
|
73
|
+
:attributeType => type.split("_").each{|word| word.capitalize! }.join(" "),
|
74
|
+
:minValueString => "1",
|
75
|
+
:maxValueString => "10",
|
76
|
+
:defaultValueString => "5" })
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should return the correct options for boolean" do
|
81
|
+
options = @allowed_options.merge({
|
82
|
+
default: true
|
83
|
+
})
|
84
|
+
MotionMigrate::Model.property(:field, :boolean, options).should == @filled_allowed_attributes.merge({ :name => :field,
|
85
|
+
:attributeType => "Boolean",
|
86
|
+
:defaultValueString => "YES" })
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should return the correct options for binary_data" do
|
90
|
+
options = @allowed_options.merge({
|
91
|
+
external_storage: true
|
92
|
+
})
|
93
|
+
MotionMigrate::Model.property(:field, :binary_data, options).should == @filled_allowed_attributes.merge({ :name => :field,
|
94
|
+
:attributeType => "Binary",
|
95
|
+
:allowsExternalBinaryDataStorage => "YES" })
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should return the correct options for date" do
|
99
|
+
options = @allowed_options.merge({
|
100
|
+
min: DateTime.new(2013, 1, 1, 12, 0, 0),
|
101
|
+
max: DateTime.new(2013, 1, 31, 12, 0, 0),
|
102
|
+
default: DateTime.new(2013, 1, 5, 12, 0, 0)
|
103
|
+
})
|
104
|
+
MotionMigrate::Model.property(:field, :date, options).should == @filled_allowed_attributes.merge({ :name => :field,
|
105
|
+
:attributeType => "Date",
|
106
|
+
:minDateTimeInterval => "378738000",
|
107
|
+
:maxDateTimeInterval => "381330000",
|
108
|
+
:defaultDateTimeInterval => "379083600" })
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# Test all types + properties
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "motion_migrate/motion_generate/entity"
|
2
|
+
require "motion_migrate/motion_generate/parser"
|
3
|
+
require "motion_migrate/motion_generate/property"
|
4
|
+
require "motion_migrate/motion_generate/relationship"
|
5
|
+
require "motion_migrate/generate"
|
6
|
+
|
7
|
+
module MotionMigrate
|
8
|
+
describe "relationship definitions in the model" do
|
9
|
+
before do
|
10
|
+
@allowed_options = {
|
11
|
+
required: true,
|
12
|
+
transient: true,
|
13
|
+
class_name: "Test",
|
14
|
+
inverse_of: "test",
|
15
|
+
deletion_rule: :cascade,
|
16
|
+
spotlight: true,
|
17
|
+
truth_file: true
|
18
|
+
}
|
19
|
+
@filled_allowed_attributes = {
|
20
|
+
optional: "NO",
|
21
|
+
transient: "YES",
|
22
|
+
inverseEntity: "Test",
|
23
|
+
destinationEntity: "Test",
|
24
|
+
inverseName: "test",
|
25
|
+
deletionRule: "Cascade",
|
26
|
+
spotlightIndexingEnabled: "YES",
|
27
|
+
storedInTruthFile: "YES",
|
28
|
+
syncable: "YES"
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
%w(belongs_to has_many).each do |type|
|
33
|
+
it "should error on incomplete options for #{type}" do
|
34
|
+
lambda { MotionMigrate::Model.send(type, :field) }.should raise_error
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should error on undiffened options for #{type}" do
|
38
|
+
lambda { MotionMigrate::Model.send(type, :field, :class_name => "Test", :inverse_of => "test", :unknown => true) }.should raise_error
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should error on undiffened deletion rules for #{type}" do
|
42
|
+
lambda { MotionMigrate::Model.send(type, :field, :class_name => "Test", :inverse_of => "test", :deletion_rule => :unknown) }.should raise_error
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should return the correct options for belongs_to" do
|
47
|
+
MotionMigrate::Model.belongs_to(:field, @allowed_options).should == @filled_allowed_attributes.merge({ :toMany => "NO", :name => :field, :minCount => 1, :maxCount => 1 })
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should return the correct options for has_many" do
|
51
|
+
MotionMigrate::Model.has_many(:field, @allowed_options).should == @filled_allowed_attributes.merge({ :toMany => "YES", :name => :field })
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
$:.unshift("/Library/RubyMotion/lib")
|
3
|
+
require 'motion/project'
|
4
|
+
|
5
|
+
require 'bundler'
|
6
|
+
Bundler.require
|
7
|
+
|
8
|
+
Motion::Project::App.setup do |app|
|
9
|
+
app.name = 'Motion Migrate Spec Project'
|
10
|
+
|
11
|
+
app.pods do
|
12
|
+
pod 'MagicalRecord', '2.1'
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
class Pilot < MotionMigrate::Model
|
2
|
+
property :name, :string
|
3
|
+
|
4
|
+
belongs_to :plane, :class_name => "Plane", :inverse_of => :pilot
|
5
|
+
has_many :owned_planes, :class_name => "Plane", :inverse_of => :owner
|
6
|
+
has_many :flown_planes, :class_name => "Plane", :inverse_of => :flown_by_pilots
|
7
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Plane < MotionMigrate::Model
|
2
|
+
property :name, :string
|
3
|
+
property :multi_engine, :boolean, :default => false
|
4
|
+
property :first_flight_at, :date
|
5
|
+
property :flight_info, :binary_data
|
6
|
+
|
7
|
+
belongs_to :pilot, :class_name => "Pilot", :inverse_of => :plane
|
8
|
+
belongs_to :owner, :class_name => "Pilot", :inverse_of => :owned_planes
|
9
|
+
|
10
|
+
has_many :flown_by_pilots, :class_name => "Pilot", :inverse_of => :flown_planes
|
11
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
3
|
+
<plist version="1.0">
|
4
|
+
<dict>
|
5
|
+
<key>_XCCurrentVersionName</key>
|
6
|
+
<string>schema.10.xcdatamodel</string>
|
7
|
+
</dict>
|
8
|
+
</plist>
|
@@ -0,0 +1,6 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="11D50" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
3
|
+
<entity name="Plane" representedClassName="Plane" syncable="YES">
|
4
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
5
|
+
</entity>
|
6
|
+
</model>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="11D50" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
3
|
+
<entity name="Pilot" representedClassName="Pilot" syncable="YES">
|
4
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
5
|
+
<relationship name="plane" optional="YES" deletionRule="No Action" syncable="YES" minCount="1" maxCount="1" inverseEntity="Plane" destinationEntity="Plane" inverseName="pilot" toMany="NO"/>
|
6
|
+
<relationship name="owned_planes" optional="YES" deletionRule="No Action" syncable="YES" inverseEntity="Plane" destinationEntity="Plane" inverseName="owner" toMany="YES"/>
|
7
|
+
<relationship name="flown_planes" optional="YES" deletionRule="No Action" syncable="YES" inverseEntity="Plane" destinationEntity="Plane" inverseName="flown_by_pilots" toMany="YES"/>
|
8
|
+
</entity>
|
9
|
+
<entity name="Plane" representedClassName="Plane" syncable="YES">
|
10
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
11
|
+
<attribute name="multi_engine" attributeType="Boolean" optional="YES" syncable="YES" defaultValueString="NO"/>
|
12
|
+
<attribute name="first_flight_at" attributeType="Date" optional="YES" syncable="YES"/>
|
13
|
+
<attribute name="flight_info" attributeType="Binary" optional="YES" syncable="YES"/>
|
14
|
+
<relationship name="pilot" optional="YES" deletionRule="No Action" syncable="YES" minCount="1" maxCount="1" inverseEntity="Pilot" destinationEntity="Pilot" inverseName="plane" toMany="NO"/>
|
15
|
+
<relationship name="owner" optional="YES" deletionRule="No Action" syncable="YES" minCount="1" maxCount="1" inverseEntity="Pilot" destinationEntity="Pilot" inverseName="owned_planes" toMany="NO"/>
|
16
|
+
<relationship name="flown_by_pilots" optional="YES" deletionRule="No Action" syncable="YES" inverseEntity="Pilot" destinationEntity="Pilot" inverseName="flown_planes" toMany="YES"/>
|
17
|
+
</entity>
|
18
|
+
</model>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="11D50" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
3
|
+
<entity name="Plane" representedClassName="Plane" syncable="YES">
|
4
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
5
|
+
<attribute name="multi_engine" attributeType="Boolean" optional="YES" syncable="YES"/>
|
6
|
+
</entity>
|
7
|
+
</model>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="11D50" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
3
|
+
<entity name="Plane" representedClassName="Plane" syncable="YES">
|
4
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
5
|
+
<attribute name="multi_engine" attributeType="Boolean" optional="YES" syncable="YES" defaultValueString="NO"/>
|
6
|
+
</entity>
|
7
|
+
</model>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="11D50" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
3
|
+
<entity name="Plane" representedClassName="Plane" syncable="YES">
|
4
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
5
|
+
<attribute name="multi_engine" attributeType="Boolean" optional="YES" syncable="YES" defaultValueString="NO"/>
|
6
|
+
<attribute name="first_flight_at" attributeType="Date" optional="YES" syncable="YES"/>
|
7
|
+
</entity>
|
8
|
+
</model>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="11D50" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
3
|
+
<entity name="Plane" representedClassName="Plane" syncable="YES">
|
4
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
5
|
+
<attribute name="multi_engine" attributeType="Boolean" optional="YES" syncable="YES" defaultValueString="NO"/>
|
6
|
+
<attribute name="first_flight_at" attributeType="Date" optional="YES" syncable="YES"/>
|
7
|
+
<attribute name="flight_info" attributeType="Binary" optional="YES" syncable="YES"/>
|
8
|
+
</entity>
|
9
|
+
</model>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="11D50" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
3
|
+
<entity name="Plane" representedClassName="Plane" syncable="YES">
|
4
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
5
|
+
<attribute name="multi_engine" attributeType="Boolean" optional="YES" syncable="YES" defaultValueString="NO"/>
|
6
|
+
<attribute name="first_flight_at" attributeType="Date" optional="YES" syncable="YES"/>
|
7
|
+
<attribute name="flight_info" attributeType="Binary" optional="YES" syncable="YES"/>
|
8
|
+
<relationship name="pilot" optional="YES" deletionRule="No Action" syncable="YES" minCount="1" maxCount="1" inverseEntity="Pilot" destinationEntity="Pilot" inverseName="plane" toMany="NO"/>
|
9
|
+
</entity>
|
10
|
+
<entity name="Pilot" representedClassName="Pilot" syncable="YES">
|
11
|
+
<relationship name="plane" optional="YES" deletionRule="No Action" syncable="YES" minCount="1" maxCount="1" inverseEntity="Plane" destinationEntity="Plane" inverseName="pilot" toMany="NO"/>
|
12
|
+
</entity>
|
13
|
+
</model>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<model name="" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1811" systemVersion="11D50" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
3
|
+
<entity name="Pilot" representedClassName="Pilot" syncable="YES">
|
4
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
5
|
+
<relationship name="plane" optional="YES" deletionRule="No Action" syncable="YES" minCount="1" maxCount="1" inverseEntity="Plane" destinationEntity="Plane" inverseName="pilot" toMany="NO"/>
|
6
|
+
</entity>
|
7
|
+
<entity name="Plane" representedClassName="Plane" syncable="YES">
|
8
|
+
<attribute name="name" attributeType="String" optional="YES" syncable="YES"/>
|
9
|
+
<attribute name="multi_engine" attributeType="Boolean" optional="YES" syncable="YES" defaultValueString="NO"/>
|
10
|
+
<attribute name="first_flight_at" attributeType="Date" optional="YES" syncable="YES"/>
|
11
|
+
<attribute name="flight_info" attributeType="Binary" optional="YES" syncable="YES"/>
|
12
|
+
<relationship name="pilot" optional="YES" deletionRule="No Action" syncable="YES" minCount="1" maxCount="1" inverseEntity="Pilot" destinationEntity="Pilot" inverseName="plane" toMany="NO"/>
|
13
|
+
</entity>
|
14
|
+
</model>
|