database-exporter 0.0.1
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 +7 -0
- data/.gitignore +39 -0
- data/.travis.yml +6 -0
- data/CHANGELOG.md +4 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +74 -0
- data/LICENSE +22 -0
- data/README.md +682 -0
- data/Rakefile +7 -0
- data/bin/database-exporter +48 -0
- data/database_exporter.gemspec +34 -0
- data/example_data/contentful_model.json +316 -0
- data/example_data/contentful_structure.json +89 -0
- data/example_data/example_settings.yml +25 -0
- data/example_data/mapping.json +119 -0
- data/lib/cli.rb +13 -0
- data/lib/configuration.rb +69 -0
- data/lib/converters/content_types_structure_creator.rb +58 -0
- data/lib/converters/contentful_model_to_json.rb +78 -0
- data/lib/database/export.rb +74 -0
- data/lib/database/modules/json_export.rb +79 -0
- data/lib/database/modules/relations_export.rb +270 -0
- data/lib/database/modules/utils.rb +20 -0
- data/lib/migrator.rb +29 -0
- data/lib/version.rb +3 -0
- data/spec/fixtures/database/data/assets/image/image_1.json +9 -0
- data/spec/fixtures/database/data/assets/image/image_2.json +9 -0
- data/spec/fixtures/database/data/assets/image/image_3.json +9 -0
- data/spec/fixtures/database/data/assets/image/image_4.json +9 -0
- data/spec/fixtures/database/data/collections/comment.json +18 -0
- data/spec/fixtures/database/data/collections/job_skills.json +13 -0
- data/spec/fixtures/database/data/collections/jobs.json +44 -0
- data/spec/fixtures/database/data/collections/profile.json +19 -0
- data/spec/fixtures/database/data/collections/user.json +36 -0
- data/spec/fixtures/database/data/entries/comment/comment_1.json +9 -0
- data/spec/fixtures/database/data/entries/comment/comment_2.json +9 -0
- data/spec/fixtures/database/data/entries/comment/comment_3.json +9 -0
- data/spec/fixtures/database/data/entries/comment/comment_4.json +9 -0
- data/spec/fixtures/database/data/entries/comment/comment_5.json +9 -0
- data/spec/fixtures/database/data/entries/job_skills/job_skills_1.json +7 -0
- data/spec/fixtures/database/data/entries/job_skills/job_skills_10.json +7 -0
- data/spec/fixtures/database/data/entries/job_skills/job_skills_2.json +7 -0
- data/spec/fixtures/database/data/entries/job_skills/job_skills_3.json +7 -0
- data/spec/fixtures/database/data/entries/job_skills/job_skills_4.json +7 -0
- data/spec/fixtures/database/data/entries/job_skills/job_skills_5.json +7 -0
- data/spec/fixtures/database/data/entries/job_skills/job_skills_6.json +7 -0
- data/spec/fixtures/database/data/entries/job_skills/job_skills_7.json +7 -0
- data/spec/fixtures/database/data/entries/job_skills/job_skills_8.json +7 -0
- data/spec/fixtures/database/data/entries/job_skills/job_skills_9.json +7 -0
- data/spec/fixtures/database/data/entries/jobs/jobs_1.json +56 -0
- data/spec/fixtures/database/data/entries/jobs/jobs_2.json +55 -0
- data/spec/fixtures/database/data/entries/jobs/jobs_4.json +49 -0
- data/spec/fixtures/database/data/entries/profile/profile_1.json +12 -0
- data/spec/fixtures/database/data/entries/profile/profile_2.json +12 -0
- data/spec/fixtures/database/data/entries/user/user_1.json +24 -0
- data/spec/fixtures/database/data/entries/user/user_2.json +20 -0
- data/spec/fixtures/database/data/helpers/job_add_id_comments.json +11 -0
- data/spec/fixtures/database/data/helpers/job_add_id_job_add_skills.json +24 -0
- data/spec/fixtures/database/data/helpers/user_id_job_adds.json +9 -0
- data/spec/fixtures/database/data/helpers/user_id_profiles.json +8 -0
- data/spec/fixtures/database/data/table_names.json +10 -0
- data/spec/fixtures/database/table_names.json +4 -0
- data/spec/fixtures/development.sqlite3 +0 -0
- data/spec/fixtures/json_responses/transformed_row.json +7 -0
- data/spec/fixtures/json_row/row.json +6 -0
- data/spec/fixtures/settings/contentful_model.json +316 -0
- data/spec/fixtures/settings/contentful_structure.json +89 -0
- data/spec/fixtures/settings/contentful_structure_test.json +82 -0
- data/spec/fixtures/settings/mapping.json +119 -0
- data/spec/fixtures/settings/settings.yml +27 -0
- data/spec/lib/configuration_spec.rb +17 -0
- data/spec/lib/database/export_spec.rb +49 -0
- data/spec/lib/database/json_export_spec.rb +49 -0
- data/spec/lib/database/relations_export_spec.rb +201 -0
- data/spec/lib/migrator_spec.rb +112 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/support/db_rows_json.rb +9 -0
- data/spec/support/shared_configuration.rb +27 -0
- metadata +358 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#PATH to all data
|
|
2
|
+
data_dir: PATH_TO_ALL_DATA
|
|
3
|
+
|
|
4
|
+
#Connecting to a database
|
|
5
|
+
adapter: postgres
|
|
6
|
+
host: localhost
|
|
7
|
+
database: database_name
|
|
8
|
+
user: username
|
|
9
|
+
password: password
|
|
10
|
+
|
|
11
|
+
# Extract data from models:
|
|
12
|
+
mapped:
|
|
13
|
+
tables:
|
|
14
|
+
- :table_name_1
|
|
15
|
+
- :table_name_2
|
|
16
|
+
- :table_name_3
|
|
17
|
+
- :table_name_4
|
|
18
|
+
|
|
19
|
+
## MAPPING ##
|
|
20
|
+
mapping_dir: example_data/mapping.json
|
|
21
|
+
contentful_structure_dir: example_data/contentful_structure.json
|
|
22
|
+
|
|
23
|
+
## CONVERT
|
|
24
|
+
content_model_json: example_data/contentful_model.json
|
|
25
|
+
converted_model_dir: example_data/contentful_structure.json
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
{
|
|
2
|
+
"JobAdds": {
|
|
3
|
+
"content_type": "Jobs",
|
|
4
|
+
"type": "entry",
|
|
5
|
+
"fields": {
|
|
6
|
+
"title": "name",
|
|
7
|
+
"description": "specification"
|
|
8
|
+
},
|
|
9
|
+
"links": {
|
|
10
|
+
"aggregate_belongs": [
|
|
11
|
+
{
|
|
12
|
+
"relation_to": "Users",
|
|
13
|
+
"primary_id": "user_id",
|
|
14
|
+
"field": "first_name"
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"aggregate_many": [
|
|
18
|
+
{
|
|
19
|
+
"primary_id": "job_add_id",
|
|
20
|
+
"relation_to": "Comments",
|
|
21
|
+
"field": "subject",
|
|
22
|
+
"save_as": "subjects_comments"
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"belongs_to": [
|
|
26
|
+
{
|
|
27
|
+
"relation_to": "Images",
|
|
28
|
+
"foreign_id": "image_id"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"relation_to": "Users",
|
|
32
|
+
"foreign_id": "user_id"
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
"many": [
|
|
36
|
+
{
|
|
37
|
+
"relation_to": "Comments",
|
|
38
|
+
"primary_id": "job_add_id"
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"many_through": [
|
|
42
|
+
{
|
|
43
|
+
"relation_to": "Skills",
|
|
44
|
+
"primary_id": "job_add_id",
|
|
45
|
+
"foreign_id": "skill_id",
|
|
46
|
+
"through": "JobAddSkills"
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"Comments": {
|
|
52
|
+
"content_type": "Comment",
|
|
53
|
+
"type": "entry",
|
|
54
|
+
"fields": {
|
|
55
|
+
"title": "subject",
|
|
56
|
+
"body": "content"
|
|
57
|
+
},
|
|
58
|
+
"links": {
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"Skills": {
|
|
62
|
+
"content_type": "Job Skills",
|
|
63
|
+
"type": "entry",
|
|
64
|
+
"fields": {
|
|
65
|
+
},
|
|
66
|
+
"links": {
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
"Profiles": {
|
|
70
|
+
"content_type": "Profile",
|
|
71
|
+
"type": "entry",
|
|
72
|
+
"fields": {
|
|
73
|
+
},
|
|
74
|
+
"links": {
|
|
75
|
+
"belongs_to": [
|
|
76
|
+
{
|
|
77
|
+
"relation_to": "Users",
|
|
78
|
+
"foreign_id": "user_id"
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"Users": {
|
|
84
|
+
"content_type": "User",
|
|
85
|
+
"type": "entry",
|
|
86
|
+
"fields": {
|
|
87
|
+
},
|
|
88
|
+
"links": {
|
|
89
|
+
"aggregate_has_one": [
|
|
90
|
+
{
|
|
91
|
+
"relation_to": "Profiles",
|
|
92
|
+
"primary_id": "user_id",
|
|
93
|
+
"field": "nickname",
|
|
94
|
+
"save_as": "custom_nick"
|
|
95
|
+
}
|
|
96
|
+
],
|
|
97
|
+
"has_one": [
|
|
98
|
+
{
|
|
99
|
+
"relation_to": "Profiles",
|
|
100
|
+
"primary_id": "user_id"
|
|
101
|
+
}
|
|
102
|
+
],
|
|
103
|
+
"many": [
|
|
104
|
+
{
|
|
105
|
+
"relation_to": "JobAdds",
|
|
106
|
+
"primary_id": "user_id"
|
|
107
|
+
}
|
|
108
|
+
]
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
"Images": {
|
|
112
|
+
"content_type": "Image",
|
|
113
|
+
"type": "asset",
|
|
114
|
+
"fields": {
|
|
115
|
+
},
|
|
116
|
+
"links": {
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
data/lib/cli.rb
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require 'sequel'
|
|
2
|
+
require 'active_support/core_ext/hash'
|
|
3
|
+
|
|
4
|
+
module Contentful
|
|
5
|
+
class Configuration
|
|
6
|
+
attr_reader :config,
|
|
7
|
+
:data_dir,
|
|
8
|
+
:collections_dir,
|
|
9
|
+
:entries_dir,
|
|
10
|
+
:assets_dir,
|
|
11
|
+
:contentful_structure,
|
|
12
|
+
:db,
|
|
13
|
+
:helpers_dir,
|
|
14
|
+
:converted_model_dir,
|
|
15
|
+
:content_types
|
|
16
|
+
|
|
17
|
+
def initialize(settings)
|
|
18
|
+
@config = settings
|
|
19
|
+
validate_required_parameters
|
|
20
|
+
@data_dir = config['data_dir']
|
|
21
|
+
@collections_dir = "#{data_dir}/collections"
|
|
22
|
+
@entries_dir = "#{data_dir}/entries"
|
|
23
|
+
@assets_dir = "#{data_dir}/assets"
|
|
24
|
+
@helpers_dir = "#{data_dir}/helpers"
|
|
25
|
+
@contentful_structure = load_contentful_structure_file
|
|
26
|
+
@db = adapter_setup
|
|
27
|
+
@converted_model_dir = settings['converted_model_dir']
|
|
28
|
+
@content_types = config['content_model_json']
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def validate_required_parameters
|
|
32
|
+
fail ArgumentError, 'Set PATH to data_dir. Folder where all data will be stored. View README' if config['data_dir'].nil?
|
|
33
|
+
fail ArgumentError, 'Set PATH to contentful structure JSON file. View README' if config['contentful_structure_dir'].nil?
|
|
34
|
+
fail ArgumentError, 'Set PATH to mapping structure JSON file. View README' if config['mapping_dir'].nil?
|
|
35
|
+
fail ArgumentError, 'Set PATH to Content model JSON file, which is downloaded structure from Contentful. View README' if config['converted_model_dir'].nil?
|
|
36
|
+
fail ArgumentError, 'Set PATH to converted contentful model and saved as JSON file. View README' if config['content_model_json'].nil?
|
|
37
|
+
define_adapter
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def define_adapter
|
|
41
|
+
%w(adapter host database).each do |param|
|
|
42
|
+
fail ArgumentError, "Set database connection parameters [adapter, host, database, user, password]. Missing the '#{param}' parameter! Password and User are optional. View README!" unless config[param]
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# If contentful_structure JSON file exists, it will load the file. If not, it will automatically create an empty file.
|
|
47
|
+
# This file is required to convert contentful model to contentful import structure.
|
|
48
|
+
def load_contentful_structure_file
|
|
49
|
+
file_exists? ? load_existing_contentful_structure_file : create_empty_contentful_structure_file
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def file_exists?
|
|
53
|
+
File.exists?(config['contentful_structure_dir'])
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def create_empty_contentful_structure_file
|
|
57
|
+
File.open(settings['contentful_structure_dir'], 'w') { |file| file.write({}) }
|
|
58
|
+
load_existing_contentful_structure_file
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def load_existing_contentful_structure_file
|
|
62
|
+
JSON.parse(File.read(config['contentful_structure_dir']), symbolize_names: true).with_indifferent_access
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def adapter_setup
|
|
66
|
+
Sequel.connect(:adapter => config['adapter'], :user => config['user'], :host => config['host'], :database => config['database'], :password => config['password'])
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module Contentful
|
|
2
|
+
module Converter
|
|
3
|
+
class ContentTypesStructureCreator
|
|
4
|
+
|
|
5
|
+
attr_reader :config
|
|
6
|
+
|
|
7
|
+
def initialize(config)
|
|
8
|
+
@config = config
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def create_content_type_json_file(content_type_name, values)
|
|
12
|
+
collection = {
|
|
13
|
+
id: values[:id],
|
|
14
|
+
name: values[:name],
|
|
15
|
+
description: values[:description],
|
|
16
|
+
displayField: values[:displayField],
|
|
17
|
+
fields: create_fields(values[:fields])
|
|
18
|
+
}
|
|
19
|
+
write_json_to_file("#{config.collections_dir}/#{content_type_name}.json", collection)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def create_fields(fields)
|
|
23
|
+
fields.each_with_object([]) do |(field, value), results|
|
|
24
|
+
results << {
|
|
25
|
+
name: create_field(field, value).capitalize,
|
|
26
|
+
id: create_field(field, value),
|
|
27
|
+
type: create_type_field(value),
|
|
28
|
+
link_type: create_link_type_field(value),
|
|
29
|
+
link: create_link_field(value)
|
|
30
|
+
}.compact
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def create_field(field, value)
|
|
35
|
+
value.is_a?(Hash) ? value[:id] : field
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def create_link_type_field(value)
|
|
39
|
+
value.is_a?(Hash) ? value[:link_type] : nil
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def create_type_field(value)
|
|
43
|
+
value.is_a?(Hash) ? value[:type] : value
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def create_link_field(value)
|
|
47
|
+
value.is_a?(Hash) ? value[:link] : nil
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def write_json_to_file(path, data)
|
|
51
|
+
File.open(path, 'w') do |file|
|
|
52
|
+
file.write(JSON.pretty_generate(data))
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require_relative 'content_types_structure_creator'
|
|
2
|
+
|
|
3
|
+
module Contentful
|
|
4
|
+
module Converter
|
|
5
|
+
class ContentfulModelToJson
|
|
6
|
+
|
|
7
|
+
attr_reader :config, :logger
|
|
8
|
+
|
|
9
|
+
FIELD_TYPE = %w( Link Array )
|
|
10
|
+
|
|
11
|
+
def initialize(settings)
|
|
12
|
+
@config = settings
|
|
13
|
+
@logger = Logger.new(STDOUT)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def create_content_type_json
|
|
17
|
+
logger.info 'Create JSON files with content types structure...'
|
|
18
|
+
config.contentful_structure.each do |content_type, values|
|
|
19
|
+
content_type_name = content_type_name(content_type)
|
|
20
|
+
create_directory(config.collections_dir)
|
|
21
|
+
ContentTypesStructureCreator.new(config).create_content_type_json_file(content_type_name, values)
|
|
22
|
+
end
|
|
23
|
+
logger.info 'Done!'
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def convert_to_import_form
|
|
27
|
+
logger.info 'Converting Contentful model to Contentful import structure...'
|
|
28
|
+
File.open(config.converted_model_dir, 'w') { |file| file.write({}) }
|
|
29
|
+
content_type_file = JSON.parse(File.read(config.content_types))['items']
|
|
30
|
+
content_type_file.each do |content_type|
|
|
31
|
+
parsed_content_type = {
|
|
32
|
+
id: content_type['sys']['id'],
|
|
33
|
+
name: content_type['name'],
|
|
34
|
+
description: content_type['description'],
|
|
35
|
+
displayField: content_type['displayField'],
|
|
36
|
+
fields: create_content_type_fields(content_type)
|
|
37
|
+
}
|
|
38
|
+
import_form = JSON.parse(File.read(config.converted_model_dir))
|
|
39
|
+
File.open(config.converted_model_dir, 'w') do |file|
|
|
40
|
+
file.write(JSON.pretty_generate(import_form.merge!(content_type['name'] => parsed_content_type)))
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
logger.info "Done! Contentful import structure file saved in #{config.converted_model_dir}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def create_content_type_fields(content_type)
|
|
47
|
+
content_type['fields'].each_with_object({}) do |(field, _value), results|
|
|
48
|
+
id = link_id(field)
|
|
49
|
+
results[id] = case field['type']
|
|
50
|
+
when 'Link'
|
|
51
|
+
{id: field['id'], type: field['linkType'], link: 'Link'}
|
|
52
|
+
when 'Array'
|
|
53
|
+
{id: field['id'], type: field['type'], link_type: field['items']['linkType'], link: field['items']['type']}
|
|
54
|
+
else
|
|
55
|
+
field['type']
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def link_id(field)
|
|
61
|
+
if FIELD_TYPE.include? field['type']
|
|
62
|
+
field['name'].capitalize
|
|
63
|
+
else
|
|
64
|
+
field['id']
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def content_type_name(content_type)
|
|
69
|
+
I18n.transliterate(content_type).underscore.tr(' ', '_')
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def create_directory(path)
|
|
73
|
+
FileUtils.mkdir_p(path) unless File.directory?(path)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
require 'active_support/core_ext/string'
|
|
2
|
+
require 'active_support/core_ext/hash/compact'
|
|
3
|
+
require 'active_support/core_ext/hash'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
require 'sequel'
|
|
6
|
+
require 'logger'
|
|
7
|
+
require_relative 'modules/json_export'
|
|
8
|
+
require_relative 'modules/relations_export'
|
|
9
|
+
require_relative 'modules/utils'
|
|
10
|
+
|
|
11
|
+
module Contentful
|
|
12
|
+
module Exporter
|
|
13
|
+
module Database
|
|
14
|
+
class Export
|
|
15
|
+
|
|
16
|
+
Encoding.default_external = 'utf-8'
|
|
17
|
+
|
|
18
|
+
include Contentful::Exporter::Database::JsonExport
|
|
19
|
+
include Contentful::Exporter::Database::RelationsExport
|
|
20
|
+
include Contentful::Exporter::Database::Utils
|
|
21
|
+
|
|
22
|
+
Sequel::Model.plugin :json_serializer
|
|
23
|
+
Sequel.datetime_class = DateTime
|
|
24
|
+
|
|
25
|
+
attr_reader :config, :mapping, :tables, :logger
|
|
26
|
+
|
|
27
|
+
def initialize(settings)
|
|
28
|
+
@config = settings
|
|
29
|
+
@mapping = mapping_structure
|
|
30
|
+
@tables = load_tables
|
|
31
|
+
@logger = Logger.new(STDOUT)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def tables_name
|
|
35
|
+
create_directory(config.data_dir)
|
|
36
|
+
write_json_to_file("#{config.data_dir}/table_names.json", config.db.tables)
|
|
37
|
+
logger.info "File with name of tables saved to #{"#{config.data_dir}/table_names.json"}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def save_data_as_json
|
|
41
|
+
tables.each do |table|
|
|
42
|
+
logger.info "Extracting data from #{"#{table} table"}..."
|
|
43
|
+
model_name = table.to_s.camelize
|
|
44
|
+
fail ArgumentError, "Missing model name in your mapping.json file. To extract data from #{table}, define structure for this model in mapping.json file or remove #{table} from settings.yml - mapped tables! View README." if missing_model_structure?(model_name)
|
|
45
|
+
content_type_name = mapping[model_name][:content_type]
|
|
46
|
+
save_object_to_file(table, content_type_name, model_name, asset?(model_name) ? config.assets_dir : config.entries_dir)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def create_data_relations
|
|
51
|
+
relations_from_mapping.each do |model_name, relations|
|
|
52
|
+
generate_relations_helper_indexes(relations)
|
|
53
|
+
map_relations_to_links(model_name, relations)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def mapping_structure
|
|
58
|
+
fail ArgumentError, 'Set PATH to contentful structure JSON file. Check README' unless config.config['mapping_dir']
|
|
59
|
+
JSON.parse(File.read(config.config['mapping_dir']), symbolize_names: true).with_indifferent_access
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def load_tables
|
|
63
|
+
fail ArgumentError, 'Before importing data from tables, define their names. Check README!' unless config.config['mapped'] && config.config['mapped']['tables']
|
|
64
|
+
config.config['mapped']['tables']
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def missing_model_structure?(model_name)
|
|
68
|
+
mapping[model_name].nil?
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
require 'i18n'
|
|
2
|
+
|
|
3
|
+
module Contentful
|
|
4
|
+
module Exporter
|
|
5
|
+
module Database
|
|
6
|
+
module JsonExport
|
|
7
|
+
|
|
8
|
+
def asset?(model_name)
|
|
9
|
+
mapping[model_name] && mapping[model_name][:type] == 'asset'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def save_object_to_file(table, content_type_name, model_name, type)
|
|
13
|
+
content_type_name = I18n.transliterate(content_type_name).underscore.tr(' ', '_')
|
|
14
|
+
create_directory("#{type}/#{content_type_name}")
|
|
15
|
+
config.db[table].each_with_index do |row, index|
|
|
16
|
+
index = index + 1
|
|
17
|
+
result = transform_row_into_hash(model_name, content_type_name, row, index)
|
|
18
|
+
write_json_to_file("#{type}/#{content_type_name}/#{result[:id]}.json", result)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def transform_row_into_hash(model_name, content_type_name, row, index)
|
|
23
|
+
id = row[:id] || index
|
|
24
|
+
logger.info "Saving #{content_type_name} - id: #{id}"
|
|
25
|
+
db_object = map_fields(model_name, row)
|
|
26
|
+
db_object[:id] = model_id(model_name, content_type_name, id)
|
|
27
|
+
db_object[:database_id] = id
|
|
28
|
+
db_object
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def model_id(model_name, content_type_name, id)
|
|
32
|
+
prefix = mapping[model_name][:prefix_id] || ''
|
|
33
|
+
"#{prefix}#{content_type_name}_#{id}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def map_fields(model_name, row)
|
|
37
|
+
row.each_with_object({}) do |(field_name, field_value), result|
|
|
38
|
+
field_name = mapped_field_name(field_name, model_name)
|
|
39
|
+
formatted_value = formatted_field_value(field_name, field_value, model_name)
|
|
40
|
+
result[field_name] = formatted_value
|
|
41
|
+
copy_field_value(field_name, formatted_value, model_name, result) if copy_field?(field_name, model_name)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def formatted_field_value(field_name, field_value, model_name)
|
|
46
|
+
has_mapping_value?(field_name, model_name) ? format_value(field_value) : field_value
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def copy_field_value(field_name, field_value, model_name, result)
|
|
50
|
+
copy_field = mapping[model_name][:copy][field_name]
|
|
51
|
+
result[copy_field] = format_value(field_value.to_s)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def format_value(field_value)
|
|
55
|
+
formatted_value = I18n.transliterate(field_value).tr(' ', '_').underscore
|
|
56
|
+
formatted_value.underscore.gsub(/\W/, '-').gsub(/\W\z/, '').gsub(/\A\W/, '').gsub('_', '-').gsub('--', '-').gsub('--', '-')
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def mapped_field_name(field_name, model_name)
|
|
60
|
+
has_mapping_for?(field_name, model_name) ? mapping[model_name][:fields][field_name] : field_name
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def has_mapping_for?(field_name, model_name)
|
|
64
|
+
mapping[model_name] && mapping[model_name][:fields][field_name].present?
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def has_mapping_value?(field_name, model_name)
|
|
68
|
+
mapping[model_name] && mapping[model_name][:format] && mapping[model_name][:format][field_name].present?
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def copy_field?(field_name, model_name)
|
|
72
|
+
mapping[model_name] && mapping[model_name][:copy] && mapping[model_name][:copy][field_name].present?
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|