metamodel 0.1.5 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/metamodel/command/build/resolver.rb +72 -0
- data/lib/metamodel/command/build/translator.rb +52 -0
- data/lib/metamodel/command/build.rb +13 -14
- data/lib/metamodel/record/association.rb +40 -0
- data/lib/metamodel/record/model.rb +118 -0
- data/lib/metamodel/record/property.rb +99 -0
- data/lib/metamodel/template/attributes.swift +1 -1
- data/lib/metamodel/template/foreign_key.swift +18 -18
- data/lib/metamodel/template/model_query.swift +14 -2
- data/lib/metamodel/version.rb +1 -1
- data/lib/metamodel.rb +0 -1
- metadata +7 -5
- data/lib/metamodel/command/build/parser.rb +0 -67
- data/lib/metamodel/model/model.rb +0 -116
- data/lib/metamodel/model/property.rb +0 -114
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d1b98b98f7bd126d83e0066d44beb8beb5708351
|
4
|
+
data.tar.gz: 48f9bb451aeb155aaa3a6cbd7ee426b7e0aa1467
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a2de3e544e6e583d81a84d51bc82ec98aebe2b7fc0a0d73b11ebfe4624a0ab06a8c42b00c03132e3a210644d306247360376f0711ecd902ad6406d72413c1e48
|
7
|
+
data.tar.gz: 0947bc3d2862f25536d744e963bc0213ffaaaf63c4a9dbc60ff4f368813859dd5306d8b10c66822dcb15efcaef943ed9db9fc5e183d971c7566902d631b0eb9a
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|

|
2
2
|
|
3
|
-
# MetaModel
|
3
|
+
# MetaModel [](https://gitter.im/MModel/MetaModel?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
4
4
|
|
5
5
|
[](https://github.com/draveness/metamodel/blob/master/LICENSE)
|
6
6
|
[](http://rubygems.org/gems/metamodel)
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module MetaModel
|
2
|
+
class Command
|
3
|
+
class Build
|
4
|
+
class Resolver
|
5
|
+
|
6
|
+
include Config::Mixin
|
7
|
+
|
8
|
+
require 'metamodel/record/model'
|
9
|
+
require 'metamodel/record/property'
|
10
|
+
require 'metamodel/record/association'
|
11
|
+
|
12
|
+
attr_accessor :models
|
13
|
+
attr_accessor :associations
|
14
|
+
|
15
|
+
attr_accessor :current_model
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@models = []
|
19
|
+
@associations = []
|
20
|
+
end
|
21
|
+
|
22
|
+
def resolve
|
23
|
+
UI.section "Analyzing Metafile" do
|
24
|
+
metafile_path = config.metafile_path
|
25
|
+
eval File.read(metafile_path)
|
26
|
+
end
|
27
|
+
return models, associations
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def metamodel_version(version)
|
33
|
+
raise Informative,
|
34
|
+
"Meta file #{version} not matched with current metamodel version #{VERSION}" if version != VERSION
|
35
|
+
end
|
36
|
+
|
37
|
+
def define(model_name)
|
38
|
+
UI.message '-> '.green + "Resolving `#{model_name.to_s.camelize}`"
|
39
|
+
@current_model = Record::Model.new(model_name)
|
40
|
+
yield
|
41
|
+
@models << current_model
|
42
|
+
end
|
43
|
+
|
44
|
+
def attr(key, type = :string, *args)
|
45
|
+
current_model.properties << Record::Property.new(key, type, args)
|
46
|
+
end
|
47
|
+
|
48
|
+
def has_one(name, model_name = nil)
|
49
|
+
model_name = name.to_s.singularize.camelize if model_name.nil?
|
50
|
+
association = Record::Association.new(name, current_model.name, model_name, :has_one)
|
51
|
+
@associations << association
|
52
|
+
end
|
53
|
+
|
54
|
+
def has_many(name, model_name = nil)
|
55
|
+
model_name = name.to_s.singularize.camelize if model_name.nil?
|
56
|
+
raise Informative, "has_many relation can't be created with optional model name" if model_name.end_with? "?"
|
57
|
+
association = Record::Association.new(name, current_model.name, model_name, :has_many)
|
58
|
+
@associations << association
|
59
|
+
end
|
60
|
+
|
61
|
+
def belongs_to(name, model_name = nil)
|
62
|
+
model_name = name.to_s.singularize.camelize if model_name.nil?
|
63
|
+
association = Record::Association.new(name, current_model.name, model_name, :belongs_to)
|
64
|
+
@associations << association
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module MetaModel
|
2
|
+
class Command
|
3
|
+
class Build
|
4
|
+
class Translator
|
5
|
+
require 'metamodel/record/model'
|
6
|
+
require 'metamodel/record/property'
|
7
|
+
require 'metamodel/record/association'
|
8
|
+
|
9
|
+
attr_reader :models
|
10
|
+
attr_reader :associations
|
11
|
+
|
12
|
+
def initialize(models, associations)
|
13
|
+
@models = models
|
14
|
+
@associations = associations
|
15
|
+
end
|
16
|
+
|
17
|
+
def translate
|
18
|
+
name_model_hash = Hash[@models.collect { |model| [model.name, model] }]
|
19
|
+
@associations.map! do |association|
|
20
|
+
major_model = name_model_hash[association.major_model]
|
21
|
+
major_model.associations << association
|
22
|
+
association.major_model = major_model
|
23
|
+
association.secondary_model = name_model_hash[association.secondary_model]
|
24
|
+
raise Informative, "Associations not satisfied in `Metafile`" \
|
25
|
+
unless [association.major_model, association.secondary_model].compact.size == 2
|
26
|
+
association
|
27
|
+
end
|
28
|
+
|
29
|
+
@associations.each do |association|
|
30
|
+
major_model = association.major_model
|
31
|
+
secondary_model = association.secondary_model
|
32
|
+
case association.relation
|
33
|
+
when :has_one then
|
34
|
+
property = Record::Property.new(major_model.foreign_id, :int, :foreign, :default => 0)
|
35
|
+
secondary_model.properties << property
|
36
|
+
when :has_many then
|
37
|
+
property = Record::Property.new(major_model.foreign_id, :int, :foreign, :default => 0)
|
38
|
+
secondary_model.properties << property
|
39
|
+
when :belongs_to then
|
40
|
+
property = Record::Property.new(secondary_model.foreign_id, :int, :foreign, :default => 0)
|
41
|
+
major_model.properties << property
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
@models.each do |model|
|
46
|
+
model.properties.uniq! { |prop| [prop.name] }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -3,8 +3,9 @@ require 'git'
|
|
3
3
|
module MetaModel
|
4
4
|
class Command
|
5
5
|
class Build < Command
|
6
|
-
require 'metamodel/command/build/
|
6
|
+
require 'metamodel/command/build/resolver'
|
7
7
|
require 'metamodel/command/build/renderer'
|
8
|
+
require 'metamodel/command/build/translator'
|
8
9
|
|
9
10
|
self.summary = "Build a MetaModel.framework from Metafile"
|
10
11
|
self.description = <<-DESC
|
@@ -21,7 +22,8 @@ module MetaModel
|
|
21
22
|
def run
|
22
23
|
UI.section "Building MetaModel.framework in project" do
|
23
24
|
clone_project
|
24
|
-
|
25
|
+
models, associations = resolve_template
|
26
|
+
@models = compact_associtions_into_models models, associations
|
25
27
|
validate_models
|
26
28
|
render_model_files
|
27
29
|
update_initialize_method
|
@@ -36,28 +38,24 @@ module MetaModel
|
|
36
38
|
else
|
37
39
|
UI.section "Cloning MetaModel project into `./metamodel` folder" do
|
38
40
|
Git.clone(config.metamodel_template_uri, 'metamodel', :depth => 1)
|
39
|
-
UI.message "Using `#{metamodel_xcode_project}` to build module"
|
41
|
+
UI.message "Using `#{config.metamodel_xcode_project}` to build module"
|
40
42
|
end
|
41
43
|
end
|
42
44
|
end
|
43
45
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
46
|
+
def resolve_template
|
47
|
+
resolver = Resolver.new
|
48
|
+
resolver.resolve
|
49
|
+
end
|
50
|
+
|
51
|
+
def compact_associtions_into_models(models, associations)
|
52
|
+
Translator.new(models, associations).translate
|
47
53
|
end
|
48
54
|
|
49
55
|
def validate_models
|
50
56
|
existing_types = @models.map { |m| m.properties.map { |property| property.type } }.flatten.uniq
|
51
57
|
unsupported_types = existing_types - supported_types
|
52
58
|
raise Informative, "Unsupported types #{unsupported_types}" unless unsupported_types == []
|
53
|
-
|
54
|
-
@models.each do |main|
|
55
|
-
main.relation_properties.each do |property|
|
56
|
-
@models.each do |secondary|
|
57
|
-
property.relation_model = secondary if property.type == secondary.name
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
59
|
end
|
62
60
|
|
63
61
|
def render_model_files
|
@@ -65,6 +63,7 @@ module MetaModel
|
|
65
63
|
Renderer.render(@models)
|
66
64
|
end
|
67
65
|
end
|
66
|
+
#
|
68
67
|
def update_initialize_method
|
69
68
|
template = File.read File.expand_path(File.join(File.dirname(__FILE__), "../template/metamodel.swift"))
|
70
69
|
result = ErbalT::render_from_hash(template, { :models => @models })
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module MetaModel
|
2
|
+
module Record
|
3
|
+
class Association
|
4
|
+
attr_reader :name
|
5
|
+
attr_reader :type
|
6
|
+
attr_reader :relation
|
7
|
+
attr_reader :through
|
8
|
+
attr_accessor :major_model
|
9
|
+
attr_accessor :secondary_model
|
10
|
+
|
11
|
+
def initialize(name, major_model, secondary_model, relation, through = nil)
|
12
|
+
@name = name.to_s.camelize :lower
|
13
|
+
@relation = relation
|
14
|
+
@through = through
|
15
|
+
@major_model = major_model
|
16
|
+
@secondary_model = secondary_model
|
17
|
+
end
|
18
|
+
|
19
|
+
def has_one?
|
20
|
+
@relation == :has_one
|
21
|
+
end
|
22
|
+
|
23
|
+
def has_many?
|
24
|
+
@relation == :has_many
|
25
|
+
end
|
26
|
+
|
27
|
+
def belongs_to?
|
28
|
+
@relation == :belongs_to
|
29
|
+
end
|
30
|
+
|
31
|
+
def type
|
32
|
+
case @relation
|
33
|
+
when :has_one then secondary_model.name
|
34
|
+
when :has_many then secondary_model.name
|
35
|
+
when :belongs_to then major_model.name
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module MetaModel
|
2
|
+
module Record
|
3
|
+
class Model
|
4
|
+
attr_reader :name
|
5
|
+
attr_reader :properties
|
6
|
+
attr_reader :associations
|
7
|
+
|
8
|
+
def initialize(name)
|
9
|
+
@name = name.to_s.camelize
|
10
|
+
@properties = []
|
11
|
+
@associations = []
|
12
|
+
|
13
|
+
validate
|
14
|
+
end
|
15
|
+
|
16
|
+
def properties_exclude_id
|
17
|
+
@properties.select { |property| property.name != "id" }
|
18
|
+
end
|
19
|
+
|
20
|
+
def foreign_id
|
21
|
+
"#{name}_id".camelize(:lower)
|
22
|
+
end
|
23
|
+
|
24
|
+
def table_name
|
25
|
+
name.tableize
|
26
|
+
end
|
27
|
+
|
28
|
+
def relation_name
|
29
|
+
"#{name}Relation"
|
30
|
+
end
|
31
|
+
|
32
|
+
def all_properties
|
33
|
+
all_properties = properties.clone
|
34
|
+
all_properties.push Property.primary_id
|
35
|
+
all_properties
|
36
|
+
end
|
37
|
+
|
38
|
+
def validate
|
39
|
+
property_keys = @properties.map { |property| property.name }
|
40
|
+
|
41
|
+
@properties << Property.new(:id, :int, :unique, :default => 0) unless property_keys.include? "id"
|
42
|
+
end
|
43
|
+
|
44
|
+
def hash_value
|
45
|
+
self.hash.to_s(16)
|
46
|
+
end
|
47
|
+
|
48
|
+
def property_key_value_pairs(cast = false)
|
49
|
+
key_value_pairs_with_property @properties, cast
|
50
|
+
end
|
51
|
+
|
52
|
+
def property_key_value_pairs_without_property(property)
|
53
|
+
key_value_pairs_with_property @properties.select { |element| element.name != property }
|
54
|
+
end
|
55
|
+
|
56
|
+
def property_exclude_id_key_value_pairs(cast = false)
|
57
|
+
key_value_pairs_with_property properties_exclude_id, cast
|
58
|
+
end
|
59
|
+
|
60
|
+
def property_key_type_pairs
|
61
|
+
key_type_pairs_with_property @properties
|
62
|
+
end
|
63
|
+
|
64
|
+
def property_key_type_pairs_without_property(property)
|
65
|
+
key_type_pairs_with_property @properties.select { |element| element.name != property }
|
66
|
+
end
|
67
|
+
|
68
|
+
def property_exclude_id_key_type_pairs
|
69
|
+
key_type_pairs_with_property properties_exclude_id
|
70
|
+
end
|
71
|
+
|
72
|
+
def build_table
|
73
|
+
table = "CREATE TABLE #{table_name}"
|
74
|
+
main_sql = @properties.map do |property|
|
75
|
+
result = "#{property.name} #{property.database_type}"
|
76
|
+
result << " PRIMARY KEY" if property.is_primary?
|
77
|
+
result << " UNIQUE" if property.is_unique?
|
78
|
+
result << " DEFAULT #{property.default_value}" if property.has_default_value?
|
79
|
+
result
|
80
|
+
end
|
81
|
+
foreign_sql = @properties.map do |property|
|
82
|
+
next unless property.is_foreign?
|
83
|
+
reference_table_name = property.type.tableize
|
84
|
+
"FOREIGN KEY(#{property.name}) REFERENCES #{reference_table_name}(_id)"
|
85
|
+
end
|
86
|
+
|
87
|
+
table + "(_id INTEGER PRIMARY KEY, #{(main_sql + foreign_sql).compact.join(", ")});"
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def key_value_pairs_with_property(properties, cast = false)
|
93
|
+
properties.map do |property|
|
94
|
+
if cast
|
95
|
+
"#{property.name}: #{property.type_without_optional}(#{property.name})"
|
96
|
+
else
|
97
|
+
"#{property.name}: #{property.name}"
|
98
|
+
end
|
99
|
+
end.join(", ")
|
100
|
+
end
|
101
|
+
|
102
|
+
def key_type_pairs_with_property(properties)
|
103
|
+
properties.enum_for(:each_with_index).map do |property, index|
|
104
|
+
has_default_value = property.has_default_value?
|
105
|
+
default_value = property.type_without_optional == "String" ? "\"#{property.default_value}\"" : property.default_value
|
106
|
+
|
107
|
+
result = "#{property.name}: #{property.type.to_s}#{if has_default_value then " = " + "#{default_value}" end}"
|
108
|
+
if index == 0
|
109
|
+
"#{property.name} #{result}"
|
110
|
+
else
|
111
|
+
result
|
112
|
+
end
|
113
|
+
end.join(", ")
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module MetaModel
|
2
|
+
module Record
|
3
|
+
class Property
|
4
|
+
attr_accessor :name
|
5
|
+
attr_reader :type
|
6
|
+
attr_reader :modifiers
|
7
|
+
|
8
|
+
def initialize(json_key, type = :string, *modifiers)
|
9
|
+
@name = json_key.to_s.camelize(:lower)
|
10
|
+
@type = convert_symbol_to_type type
|
11
|
+
|
12
|
+
@modifiers = {}
|
13
|
+
@modifiers.default = false
|
14
|
+
|
15
|
+
modifiers.flatten.map do |modifier|
|
16
|
+
@modifiers[modifier] = true if modifier.is_a? Symbol
|
17
|
+
@modifiers[:default] = modifier[:default] if modifier.is_a? Hash and modifier[:default]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class << self
|
22
|
+
def primary_id
|
23
|
+
property = Property.new(:_id, :int, :primary)
|
24
|
+
property.name = :_id
|
25
|
+
property
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def type_without_optional
|
30
|
+
return type.to_s[0..-2] if type.to_s.end_with? "?"
|
31
|
+
type
|
32
|
+
end
|
33
|
+
|
34
|
+
def database_type
|
35
|
+
case type_without_optional
|
36
|
+
when "String" then "TEXT"
|
37
|
+
when "Int" then "INTEGER"
|
38
|
+
when "Bool" then "INTEGER"
|
39
|
+
when "Double" then "REAL"
|
40
|
+
when "NSDate" then "REAL"
|
41
|
+
else raise Informative, "Unsupported type #{self.type}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def real_type
|
46
|
+
case type_without_optional
|
47
|
+
when "String" then "String"
|
48
|
+
when "Int" then "Int64"
|
49
|
+
when "Bool" then "Int64"
|
50
|
+
when "Double" then "Double"
|
51
|
+
when "NSDate" then "Double"
|
52
|
+
else raise Informative, "Unsupported type #{self.type}"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def convert_symbol_to_type(symbol)
|
57
|
+
case symbol
|
58
|
+
when :int then "Int"
|
59
|
+
when :double then "Double"
|
60
|
+
when :bool then "Bool"
|
61
|
+
when :string then "String"
|
62
|
+
when :date then "NSDate"
|
63
|
+
else symbol.to_s.camelize
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
def is_array?
|
69
|
+
@type.pluralize == str
|
70
|
+
end
|
71
|
+
|
72
|
+
def is_unique?
|
73
|
+
@modifiers.include? :unique
|
74
|
+
end
|
75
|
+
|
76
|
+
def is_primary?
|
77
|
+
@modifiers.include? :primary
|
78
|
+
end
|
79
|
+
|
80
|
+
def is_foreign?
|
81
|
+
@modifiers.include? :foreign
|
82
|
+
end
|
83
|
+
|
84
|
+
def is_optional?
|
85
|
+
@type.to_s.end_with? "?"
|
86
|
+
end
|
87
|
+
|
88
|
+
def has_default_value?
|
89
|
+
!!@modifiers[:default]
|
90
|
+
end
|
91
|
+
|
92
|
+
def default_value
|
93
|
+
has_default_value? ? modifiers[:default] : ""
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -1,23 +1,23 @@
|
|
1
|
-
<% model.
|
1
|
+
<% model.associations.each do |association| %><% if association.has_many? %>
|
2
2
|
<%= """public extension #{model.name} {
|
3
|
-
func append#{
|
3
|
+
func append#{association.type}(element: #{association.type}) {
|
4
4
|
var element = element
|
5
5
|
element.update(#{model.foreign_id}: id)
|
6
6
|
}
|
7
7
|
|
8
|
-
func create#{
|
9
|
-
return #{
|
8
|
+
func create#{association.type}(#{association.secondary_model.property_key_type_pairs_without_property model.foreign_id}) -> #{association.type}? {
|
9
|
+
return #{association.type}.create(#{association.secondary_model.property_key_value_pairs_without_property model.foreign_id}, #{model.foreign_id}: self.id)
|
10
10
|
}
|
11
11
|
|
12
|
-
func delete#{
|
13
|
-
#{
|
12
|
+
func delete#{association.type}(id: Int) {
|
13
|
+
#{association.type}.filter(.#{model.foreign_id}, value: id).findBy(id: id).first?.delete
|
14
14
|
}
|
15
|
-
var #{
|
15
|
+
var #{association.name}: [#{association.type}] {
|
16
16
|
get {
|
17
|
-
return #{
|
17
|
+
return #{association.type}.filter(.id, value: id).result
|
18
18
|
}
|
19
19
|
set {
|
20
|
-
#{
|
20
|
+
#{association.name}.forEach { (element) in
|
21
21
|
var element = element
|
22
22
|
element.update(#{model.foreign_id}: 0)
|
23
23
|
}
|
@@ -27,28 +27,28 @@
|
|
27
27
|
}
|
28
28
|
}
|
29
29
|
}
|
30
|
-
}""" %><% elsif
|
30
|
+
}""" %><% elsif association.belongs_to? %>
|
31
31
|
<%= """public extension #{model.name} {
|
32
|
-
var #{
|
32
|
+
var #{association.name}: #{association.type}? {
|
33
33
|
get {
|
34
|
-
return #{
|
34
|
+
return #{association.type}.find(id)
|
35
35
|
}
|
36
36
|
set {
|
37
37
|
guard let newValue = newValue else { return }
|
38
|
-
update(#{
|
38
|
+
update(#{association.secondary_model.foreign_id}: newValue.id)
|
39
39
|
}
|
40
40
|
}
|
41
41
|
|
42
|
-
}""" %><% elsif
|
42
|
+
}""" %><% elsif association.has_one? %>
|
43
43
|
<%= """public extension #{model.name} {
|
44
|
-
var #{
|
44
|
+
var #{association.name}: #{association.type}? {
|
45
45
|
get {
|
46
|
-
return #{
|
46
|
+
return #{association.type}.find(id)
|
47
47
|
}
|
48
48
|
set {
|
49
|
-
#{
|
49
|
+
#{association.type}.filter(.#{model.foreign_id}, value: id).deleteAll
|
50
50
|
guard var newValue = newValue else { return }
|
51
|
-
newValue.update(
|
51
|
+
newValue.update(#{model.foreign_id}: id)
|
52
52
|
}
|
53
53
|
}
|
54
54
|
}"""%><% end %><% end %>
|
@@ -3,6 +3,18 @@ public extension <%= model.name %> {
|
|
3
3
|
get { return <%= model.relation_name %>() }
|
4
4
|
}
|
5
5
|
|
6
|
+
static var first: <%= model.name %>? {
|
7
|
+
get {
|
8
|
+
return <%= model.relation_name %>().orderBy(.id, asc: true).first
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
12
|
+
static var last: <%= model.name %>? {
|
13
|
+
get {
|
14
|
+
return <%= model.relation_name %>().orderBy(.id, asc: false).first
|
15
|
+
}
|
16
|
+
}
|
17
|
+
|
6
18
|
static func first(length: UInt) -> <%= model.relation_name %> {
|
7
19
|
return <%= model.relation_name %>().orderBy(.id, asc: true).limit(length)
|
8
20
|
}
|
@@ -18,8 +30,8 @@ public extension <%= model.name %> {
|
|
18
30
|
static func findBy(id id: Int) -> <%= model.name %>? {
|
19
31
|
return <%= model.relation_name %>().findBy(id: id).first
|
20
32
|
}
|
21
|
-
|
22
|
-
|
33
|
+
<% model.properties_exclude_id.each do |property| %><%= """
|
34
|
+
static func findBy(#{property.name} #{property.name}: #{property.type_without_optional}) -\> #{model.name}? {
|
23
35
|
return #{model.relation_name}().findBy(#{property.name}: #{property.name}).first
|
24
36
|
}
|
25
37
|
""" %><% end %>
|
data/lib/metamodel/version.rb
CHANGED
data/lib/metamodel.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metamodel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Draveness Zuo
|
@@ -148,14 +148,16 @@ files:
|
|
148
148
|
- lib/metamodel.rb
|
149
149
|
- lib/metamodel/command.rb
|
150
150
|
- lib/metamodel/command/build.rb
|
151
|
-
- lib/metamodel/command/build/parser.rb
|
152
151
|
- lib/metamodel/command/build/renderer.rb
|
152
|
+
- lib/metamodel/command/build/resolver.rb
|
153
|
+
- lib/metamodel/command/build/translator.rb
|
153
154
|
- lib/metamodel/command/clean.rb
|
154
155
|
- lib/metamodel/command/generate.rb
|
155
156
|
- lib/metamodel/command/init.rb
|
156
157
|
- lib/metamodel/config.rb
|
157
|
-
- lib/metamodel/
|
158
|
-
- lib/metamodel/model
|
158
|
+
- lib/metamodel/record/association.rb
|
159
|
+
- lib/metamodel/record/model.rb
|
160
|
+
- lib/metamodel/record/property.rb
|
159
161
|
- lib/metamodel/template/attributes.swift
|
160
162
|
- lib/metamodel/template/file_header.swift
|
161
163
|
- lib/metamodel/template/foreign_key.swift
|
@@ -189,7 +191,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
189
191
|
version: '0'
|
190
192
|
requirements: []
|
191
193
|
rubyforge_project:
|
192
|
-
rubygems_version: 2.
|
194
|
+
rubygems_version: 2.6.4
|
193
195
|
signing_key:
|
194
196
|
specification_version: 4
|
195
197
|
summary: The Cocoa models generator.
|
@@ -1,67 +0,0 @@
|
|
1
|
-
module MetaModel
|
2
|
-
class Command
|
3
|
-
class Build
|
4
|
-
class Parser
|
5
|
-
|
6
|
-
include Config::Mixin
|
7
|
-
|
8
|
-
require 'metamodel/model/model'
|
9
|
-
require 'metamodel/model/property'
|
10
|
-
require 'metamodel/command/build/renderer'
|
11
|
-
|
12
|
-
def initialize
|
13
|
-
@models = []
|
14
|
-
end
|
15
|
-
|
16
|
-
def parse
|
17
|
-
UI.section "Analyzing Metafile" do
|
18
|
-
metafile_path = config.metafile_path
|
19
|
-
eval File.read(metafile_path)
|
20
|
-
end
|
21
|
-
@models
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def metamodel_version(version)
|
27
|
-
raise Informative,
|
28
|
-
"Meta file #{version} not matched with current metamodel version #{VERSION}" if version != VERSION
|
29
|
-
end
|
30
|
-
|
31
|
-
def define(model_name)
|
32
|
-
UI.message '-> '.green + "Resolving `#{model_name.to_s.camelize}`"
|
33
|
-
@models << Model.new(model_name)
|
34
|
-
yield
|
35
|
-
end
|
36
|
-
|
37
|
-
def attr(key, type = :string, *args)
|
38
|
-
current_model.properties << Property.new(key, type, args)
|
39
|
-
end
|
40
|
-
|
41
|
-
def has_one(name, model = nil)
|
42
|
-
model = name.to_s.singularize.camelize if model.nil?
|
43
|
-
current_model.relation_properties << Property.new(name, model, :has_one)
|
44
|
-
end
|
45
|
-
|
46
|
-
def has_many(name, model = nil)
|
47
|
-
model = name.to_s.singularize.camelize if model.nil?
|
48
|
-
property = Property.new(name, model, :has_many)
|
49
|
-
raise Informative, "Property type in has_many relation can't be optional" if property.is_optional?
|
50
|
-
current_model.relation_properties << property
|
51
|
-
end
|
52
|
-
|
53
|
-
def belongs_to(name, model = nil)
|
54
|
-
model = name.to_s.singularize.camelize if model.nil?
|
55
|
-
current_model.relation_properties << Property.new(name, model, :belongs_to)
|
56
|
-
current_model.properties << Property.new("#{name}_id".camelize, "Int", :foreign, :default => 0)
|
57
|
-
end
|
58
|
-
|
59
|
-
private
|
60
|
-
|
61
|
-
def current_model
|
62
|
-
@models.last
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
@@ -1,116 +0,0 @@
|
|
1
|
-
module MetaModel
|
2
|
-
|
3
|
-
class Model
|
4
|
-
attr_reader :name
|
5
|
-
attr_reader :properties
|
6
|
-
attr_reader :relation_properties
|
7
|
-
|
8
|
-
def initialize(name)
|
9
|
-
@name = name.to_s
|
10
|
-
@properties = []
|
11
|
-
@relation_properties = []
|
12
|
-
|
13
|
-
validate
|
14
|
-
end
|
15
|
-
|
16
|
-
def properties_exclude_id
|
17
|
-
@properties.select { |property| property.name != "id" }
|
18
|
-
end
|
19
|
-
|
20
|
-
def foreign_id
|
21
|
-
"#{name}_id".camelize(:lower)
|
22
|
-
end
|
23
|
-
|
24
|
-
def table_name
|
25
|
-
name.tableize
|
26
|
-
end
|
27
|
-
|
28
|
-
def relation_name
|
29
|
-
"#{name}Relation"
|
30
|
-
end
|
31
|
-
|
32
|
-
def all_properties
|
33
|
-
all_properties = properties.clone
|
34
|
-
all_properties.push Property.primary_id
|
35
|
-
all_properties
|
36
|
-
end
|
37
|
-
|
38
|
-
def validate
|
39
|
-
property_keys = @properties.map { |property| property.name }
|
40
|
-
|
41
|
-
unless property_keys.include? "id"
|
42
|
-
property_id = Property.new(:id, :int, :unique, :default => 0)
|
43
|
-
@properties << property_id
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def hash_value
|
48
|
-
self.hash.to_s(16)
|
49
|
-
end
|
50
|
-
|
51
|
-
def property_key_value_pairs(cast = false)
|
52
|
-
key_value_pairs_with_property @properties, cast
|
53
|
-
end
|
54
|
-
|
55
|
-
def property_key_value_pairs_without_property(property)
|
56
|
-
key_value_pairs_with_property @properties.select { |element| element.name != property }
|
57
|
-
end
|
58
|
-
|
59
|
-
def property_exclude_id_key_value_pairs(cast = false)
|
60
|
-
key_value_pairs_with_property properties_exclude_id, cast
|
61
|
-
end
|
62
|
-
|
63
|
-
def property_key_type_pairs
|
64
|
-
key_type_pairs_with_property @properties
|
65
|
-
end
|
66
|
-
|
67
|
-
def property_key_type_pairs_without_property(property)
|
68
|
-
key_type_pairs_with_property @properties.select { |element| element.name != property }
|
69
|
-
end
|
70
|
-
|
71
|
-
def property_exclude_id_key_type_pairs
|
72
|
-
key_type_pairs_with_property properties_exclude_id
|
73
|
-
end
|
74
|
-
|
75
|
-
def build_table
|
76
|
-
table = "CREATE TABLE #{table_name}"
|
77
|
-
main_sql = @properties.map do |property|
|
78
|
-
result = "#{property.name} #{property.database_type}"
|
79
|
-
result << " PRIMARY KEY" if property.is_primary?
|
80
|
-
result << " UNIQUE" if property.is_unique?
|
81
|
-
result << " DEFAULT #{property.default_value}" if property.has_default_value?
|
82
|
-
result
|
83
|
-
end
|
84
|
-
foreign_sql = @properties.map do |property|
|
85
|
-
next unless property.is_foreign?
|
86
|
-
reference_table_name = property.type.tableize
|
87
|
-
"FOREIGN KEY(#{property.name}) REFERENCES #{reference_table_name}(_id)"
|
88
|
-
end
|
89
|
-
|
90
|
-
table + "(_id INTEGER PRIMARY KEY, #{(main_sql + foreign_sql).compact.join(", ")});"
|
91
|
-
|
92
|
-
end
|
93
|
-
|
94
|
-
private
|
95
|
-
|
96
|
-
def key_value_pairs_with_property(properties, cast = false)
|
97
|
-
properties.map do |property|
|
98
|
-
if cast
|
99
|
-
"#{property.name}: #{property.type_without_optional}(#{property.name})"
|
100
|
-
else
|
101
|
-
"#{property.name}: #{property.name}"
|
102
|
-
end
|
103
|
-
end.join(", ")
|
104
|
-
end
|
105
|
-
|
106
|
-
def key_type_pairs_with_property(properties)
|
107
|
-
properties.map do |property|
|
108
|
-
has_default_value = property.has_default_value?
|
109
|
-
default_value = property.type_without_optional == "String" ? "\"#{property.default_value}\"" : property.default_value
|
110
|
-
"#{property.name} #{property.name}: #{property.type.to_s}#{if has_default_value then " = " + "#{default_value}" end}"
|
111
|
-
end.join(", ")
|
112
|
-
end
|
113
|
-
|
114
|
-
end
|
115
|
-
|
116
|
-
end
|
@@ -1,114 +0,0 @@
|
|
1
|
-
module MetaModel
|
2
|
-
|
3
|
-
class Property
|
4
|
-
attr_accessor :name
|
5
|
-
attr_accessor :relation_model
|
6
|
-
attr_reader :json_key
|
7
|
-
attr_reader :type
|
8
|
-
attr_reader :modifiers
|
9
|
-
|
10
|
-
def initialize(json_key, type = :string, *modifiers)
|
11
|
-
@json_key = json_key
|
12
|
-
@name = json_key.to_s.camelize(:lower)
|
13
|
-
@type = convert_symbol_to_type type
|
14
|
-
|
15
|
-
@modifiers = {}
|
16
|
-
@modifiers.default = false
|
17
|
-
|
18
|
-
modifiers.flatten.map do |modifier|
|
19
|
-
@modifiers[modifier] = true if modifier.is_a? Symbol
|
20
|
-
@modifiers[:default] = modifier[:default] if modifier.is_a? Hash and modifier[:default]
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
class << self
|
25
|
-
def primary_id
|
26
|
-
property = Property.new(:_id, :int, :primary)
|
27
|
-
property.name = :_id
|
28
|
-
property
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def type_without_optional
|
33
|
-
return type.to_s[0..-2] if type.to_s.end_with? "?"
|
34
|
-
type
|
35
|
-
end
|
36
|
-
|
37
|
-
def database_type
|
38
|
-
case type_without_optional
|
39
|
-
when "String" then "TEXT"
|
40
|
-
when "Int" then "INTEGER"
|
41
|
-
when "Bool" then "INTEGER"
|
42
|
-
when "Double" then "REAL"
|
43
|
-
when "NSDate" then "REAL"
|
44
|
-
else raise Informative, "Unsupported type #{self.type}"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def real_type
|
49
|
-
case type_without_optional
|
50
|
-
when "String" then "String"
|
51
|
-
when "Int" then "Int64"
|
52
|
-
when "Bool" then "Int64"
|
53
|
-
when "Double" then "Double"
|
54
|
-
when "NSDate" then "Double"
|
55
|
-
else raise Informative, "Unsupported type #{self.type}"
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
def convert_symbol_to_type(symbol)
|
60
|
-
case symbol
|
61
|
-
when :int then "Int"
|
62
|
-
when :double then "Double"
|
63
|
-
when :bool then "Bool"
|
64
|
-
when :string then "String"
|
65
|
-
when :date then "NSDate"
|
66
|
-
else symbol.to_s.camelize
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
|
71
|
-
def is_array?
|
72
|
-
@type.pluralize == str
|
73
|
-
end
|
74
|
-
|
75
|
-
def is_unique?
|
76
|
-
@modifiers.include? :unique
|
77
|
-
end
|
78
|
-
|
79
|
-
def is_primary?
|
80
|
-
@modifiers.include? :primary
|
81
|
-
end
|
82
|
-
|
83
|
-
def is_foreign?
|
84
|
-
@modifiers.include? :foreign
|
85
|
-
end
|
86
|
-
|
87
|
-
def is_optional?
|
88
|
-
@type.to_s.end_with? "?"
|
89
|
-
end
|
90
|
-
|
91
|
-
def has_one?
|
92
|
-
@modifiers.include? :has_one
|
93
|
-
end
|
94
|
-
|
95
|
-
def has_many?
|
96
|
-
@modifiers.include? :has_many
|
97
|
-
end
|
98
|
-
|
99
|
-
def belongs_to?
|
100
|
-
@modifiers.include? :belongs_to
|
101
|
-
end
|
102
|
-
|
103
|
-
def has_default_value?
|
104
|
-
!!@modifiers[:default]
|
105
|
-
end
|
106
|
-
|
107
|
-
def default_value
|
108
|
-
has_default_value? ? modifiers[:default] : ""
|
109
|
-
end
|
110
|
-
|
111
|
-
private
|
112
|
-
end
|
113
|
-
|
114
|
-
end
|