any_query 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/any_query/adapters/base.rb +173 -0
- data/lib/any_query/adapters/csv.rb +61 -0
- data/lib/any_query/adapters/fixed_length.rb +71 -0
- data/lib/any_query/adapters/http.rb +213 -0
- data/lib/any_query/adapters/sql.rb +100 -0
- data/lib/any_query/adapters.rb +13 -0
- data/lib/any_query/config.rb +12 -0
- data/lib/any_query/field.rb +7 -0
- data/lib/any_query/query.rb +70 -0
- data/lib/any_query/version.rb +5 -0
- data/lib/any_query.rb +58 -0
- data/spec/any_query/csv_spec.rb +44 -0
- data/spec/any_query/fixed_length_spec.rb +47 -0
- data/spec/any_query/http_spec.rb +161 -0
- data/spec/any_query/sql_spec.rb +58 -0
- data/spec/fixtures/sample.csv +3 -0
- data/spec/fixtures/sample.txt +2 -0
- data/spec/spec_helper.rb +32 -0
- data/spec/support/schema.rb +146 -0
- metadata +137 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnyQuery
|
4
|
+
# @api private
|
5
|
+
class Query
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
delegate_missing_to :to_a
|
9
|
+
|
10
|
+
def initialize(model, adapter)
|
11
|
+
@model = model
|
12
|
+
@adapter = adapter
|
13
|
+
end
|
14
|
+
|
15
|
+
def joins(model, primary_key, foreign_key, into:, as: :single, strategy: :default)
|
16
|
+
dup.joins!(model, primary_key, foreign_key, into:, as:, strategy:)
|
17
|
+
end
|
18
|
+
|
19
|
+
def with_single
|
20
|
+
dup.joins!(:show, :id, :id, into: :single, as: :single, strategy: :single)
|
21
|
+
end
|
22
|
+
|
23
|
+
def where(options)
|
24
|
+
dup.where!(options)
|
25
|
+
end
|
26
|
+
|
27
|
+
def select(*args)
|
28
|
+
dup.select!(*args)
|
29
|
+
end
|
30
|
+
|
31
|
+
def limit(limit)
|
32
|
+
dup.limit!(limit)
|
33
|
+
end
|
34
|
+
|
35
|
+
def find(id)
|
36
|
+
@adapter.load_single(@model, id, [])
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_a
|
40
|
+
@adapter.load(@model, select: @select, joins: @joins, where: @where, limit: @limit)
|
41
|
+
end
|
42
|
+
|
43
|
+
def each(&block)
|
44
|
+
to_a.each(&block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def joins!(model, primary_key, foreign_key, into:, as: :single, strategy: :default)
|
48
|
+
@joins ||= []
|
49
|
+
@joins << ({ model:, primary_key:, foreign_key:, into:, as:, strategy: })
|
50
|
+
self
|
51
|
+
end
|
52
|
+
|
53
|
+
def select!(*args)
|
54
|
+
@select ||= []
|
55
|
+
@select += args
|
56
|
+
self
|
57
|
+
end
|
58
|
+
|
59
|
+
def where!(options)
|
60
|
+
@where ||= []
|
61
|
+
@where << options
|
62
|
+
self
|
63
|
+
end
|
64
|
+
|
65
|
+
def limit!(limit)
|
66
|
+
@limit = limit
|
67
|
+
self
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
data/lib/any_query.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'httparty'
|
4
|
+
require 'active_support/all'
|
5
|
+
require 'active_record'
|
6
|
+
require 'active_model'
|
7
|
+
|
8
|
+
# AnyQuery is a library to help you build queries for different data sources
|
9
|
+
module AnyQuery
|
10
|
+
extend ActiveSupport::Concern
|
11
|
+
extend ActiveSupport::Autoload
|
12
|
+
|
13
|
+
autoload :Config
|
14
|
+
autoload :Adapters
|
15
|
+
autoload :Query
|
16
|
+
|
17
|
+
included do
|
18
|
+
delegate_missing_to :@attributes
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
@attributes = OpenStruct.new
|
23
|
+
end
|
24
|
+
|
25
|
+
module ClassMethods
|
26
|
+
def adapter(name, &block)
|
27
|
+
config = "AnyQuery::Adapters::#{name.to_s.classify}::Config".constantize.new(&block)
|
28
|
+
@adapter = "AnyQuery::Adapters::#{name.to_s.classify}".constantize.new(config)
|
29
|
+
end
|
30
|
+
|
31
|
+
delegate_missing_to :all
|
32
|
+
|
33
|
+
# @return [AnyQuery::Adapters::Base]
|
34
|
+
def _adapter
|
35
|
+
@adapter
|
36
|
+
end
|
37
|
+
|
38
|
+
# @param [Symbol] name
|
39
|
+
# @param [Hash] options
|
40
|
+
# @option options [Symbol] :type
|
41
|
+
# @option options [String] :format
|
42
|
+
# @option options [Integer] :length
|
43
|
+
# @option options [Proc] :transform
|
44
|
+
def field(name, options = {})
|
45
|
+
fields[name] = options
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [Hash]
|
49
|
+
def fields
|
50
|
+
@fields ||= {}
|
51
|
+
end
|
52
|
+
|
53
|
+
# @return [AnyQuery::Query]
|
54
|
+
def all
|
55
|
+
Query.new(self, @adapter)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe ArticleCSV do
|
6
|
+
it 'returns records' do
|
7
|
+
expect(described_class.all.to_a).to have(2).items
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'can be finded' do
|
11
|
+
result = described_class.find(2)
|
12
|
+
expect(result.id).to eq(2)
|
13
|
+
expect(result.user_id).to eq(1)
|
14
|
+
expect(result.title).to eq('the article 2')
|
15
|
+
expect(result.body).to eq('this is the body of your article 2')
|
16
|
+
expect(result.status).to eq(2)
|
17
|
+
expect(result.created_at).to eq('2023-03-10T18:28:02Z'.to_datetime)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'can be filtered' do
|
21
|
+
expect(described_class.where(status: 1).to_a).to have(1).items
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'can be limited' do
|
25
|
+
expect(described_class.limit(1).to_a).to have(1).items
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'can be joined' do
|
29
|
+
expect do
|
30
|
+
described_class.joins(UserSQL, :id, :user_id, into: :user).to_a.first
|
31
|
+
end.to match_query(/SELECT "users".* FROM "users"/)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'can be selected with nested selectors' do
|
35
|
+
results = described_class
|
36
|
+
.joins(UserSQL, :id, :user_id, into: :user, as: :single)
|
37
|
+
.select(:id, :title, %i[user email])
|
38
|
+
.to_a
|
39
|
+
|
40
|
+
expect(results).to eq(
|
41
|
+
[[1, 'the article', 'test@test.com'], [2, 'the article 2', 'test@test.com']]
|
42
|
+
)
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe ArticleFL do
|
6
|
+
it 'returns records' do
|
7
|
+
expect(described_class.all.to_a).to have(2).items
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'can be finded' do
|
11
|
+
result = described_class.find(2)
|
12
|
+
expect(result.id).to eq(2)
|
13
|
+
expect(result.user_id).to eq(1)
|
14
|
+
expect(result.title).to eq('this is another sample')
|
15
|
+
expect(result.body).to eq('this is an example of a body for an article that is very long and dirty')
|
16
|
+
expect(result.status).to eq(2)
|
17
|
+
expect(result.created_at).to eq('2023-12-31T19:00:00Z'.to_datetime)
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'can be filtered' do
|
21
|
+
expect(described_class.where(status: 1).to_a).to have(1).items
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'can be limited' do
|
25
|
+
expect(described_class.limit(1).to_a).to have(1).items
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'can be joined' do
|
29
|
+
expect do
|
30
|
+
described_class.joins(UserSQL, :id, :user_id, into: :user).to_a.first
|
31
|
+
end.to match_query(/SELECT "users".* FROM "users"/)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'can be selected with nested selectors' do
|
35
|
+
results = described_class
|
36
|
+
.joins(UserSQL, :id, :user_id, into: :user, as: :single)
|
37
|
+
.select(:id, :title, %i[user email])
|
38
|
+
.to_a
|
39
|
+
|
40
|
+
expect(results).to eq(
|
41
|
+
[
|
42
|
+
[1, 'this is a sample', 'test@test.com'],
|
43
|
+
[2, 'this is another sample', 'test@test.com']
|
44
|
+
]
|
45
|
+
)
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe ArticleHTTP do
|
6
|
+
before do
|
7
|
+
stub_request(:get, 'http://example.com/articles?page=0&some_query_param=1')
|
8
|
+
.to_return(
|
9
|
+
headers: { content_type: 'application/json' },
|
10
|
+
body: JSON.dump(
|
11
|
+
{
|
12
|
+
items: [
|
13
|
+
{
|
14
|
+
id: 1,
|
15
|
+
user_id: 1,
|
16
|
+
name: 'some article'
|
17
|
+
},
|
18
|
+
{
|
19
|
+
id: 2,
|
20
|
+
user_id: 1,
|
21
|
+
name: 'some article 2'
|
22
|
+
}
|
23
|
+
]
|
24
|
+
}
|
25
|
+
)
|
26
|
+
)
|
27
|
+
|
28
|
+
stub_request(:get, 'http://example.com/articles?page=1&some_query_param=1')
|
29
|
+
.to_return(
|
30
|
+
headers: { content_type: 'application/json' },
|
31
|
+
body: '{ "items": [] }'
|
32
|
+
)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'returns records' do
|
36
|
+
expect(described_class.all.to_a).to have(2).items
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'can be finded' do
|
40
|
+
stub_request(:get, 'http://example.com/articles/1')
|
41
|
+
.to_return(
|
42
|
+
headers: { content_type: 'application/json' },
|
43
|
+
body: JSON.dump(
|
44
|
+
{
|
45
|
+
id: 1,
|
46
|
+
user_id: 1,
|
47
|
+
title: 'some article'
|
48
|
+
}
|
49
|
+
)
|
50
|
+
)
|
51
|
+
result = described_class.find(1)
|
52
|
+
expect(result.id).to eq(1)
|
53
|
+
expect(result.user_id).to eq(1)
|
54
|
+
expect(result.title).to eq('some article')
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'can be filtered' do
|
58
|
+
stub_request(:get, 'http://example.com/articles?page=0&some_query_param=1&status=1')
|
59
|
+
.to_return(
|
60
|
+
headers: { content_type: 'application/json' },
|
61
|
+
body: JSON.dump(
|
62
|
+
{
|
63
|
+
items: [
|
64
|
+
{
|
65
|
+
id: 1,
|
66
|
+
name: 'some article'
|
67
|
+
}
|
68
|
+
]
|
69
|
+
}
|
70
|
+
)
|
71
|
+
)
|
72
|
+
stub_request(:get, 'http://example.com/articles?page=1&some_query_param=1&status=1')
|
73
|
+
.to_return(
|
74
|
+
headers: { content_type: 'application/json' },
|
75
|
+
body: '{ "items": [] }'
|
76
|
+
)
|
77
|
+
|
78
|
+
expect(described_class.where(status: 1).to_a).to have(1).items
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'can be limited' do
|
82
|
+
expect(described_class.limit(1).to_a).to have(1).items
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'can be joined with SQL' do
|
86
|
+
described_class.joins(UserSQL, :id, :user_id, into: :user).to_a.first
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'can be joined with itself using the show endpoint' do
|
90
|
+
stub_request(:get, 'http://example.com/articles/1')
|
91
|
+
.to_return(
|
92
|
+
headers: { content_type: 'application/json' },
|
93
|
+
body: JSON.dump(
|
94
|
+
{
|
95
|
+
id: 1,
|
96
|
+
user_id: 1,
|
97
|
+
title: 'some article',
|
98
|
+
some_additional_field: 'some value'
|
99
|
+
}
|
100
|
+
)
|
101
|
+
)
|
102
|
+
|
103
|
+
stub_request(:get, 'http://example.com/articles/2')
|
104
|
+
.to_return(
|
105
|
+
headers: { content_type: 'application/json' },
|
106
|
+
body: JSON.dump(
|
107
|
+
{
|
108
|
+
id: 2,
|
109
|
+
user_id: 1,
|
110
|
+
title: 'some article 2',
|
111
|
+
some_additional_field: 'some value'
|
112
|
+
}
|
113
|
+
)
|
114
|
+
)
|
115
|
+
|
116
|
+
result = described_class.with_single.to_a.first
|
117
|
+
expect(result.some_additional_field).to eq('some value')
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'can be joined with HTTP(s)' do
|
121
|
+
stub_request(:get, 'http://example.com/users?id%5B%5D=1&some_query_param=true')
|
122
|
+
.to_return(
|
123
|
+
headers: { content_type: 'application/json' },
|
124
|
+
body: JSON.dump(
|
125
|
+
items: [
|
126
|
+
{ "id": 1, "email": 'gianni@gianni.com' }
|
127
|
+
],
|
128
|
+
cursor: '123123123'
|
129
|
+
)
|
130
|
+
)
|
131
|
+
|
132
|
+
stub_request(:get, 'http://example.com/users?id%5B%5D=1&some_query_param=true&cursor=123123123')
|
133
|
+
.to_return(
|
134
|
+
headers: { content_type: 'application/json' },
|
135
|
+
body: JSON.dump(
|
136
|
+
items: [],
|
137
|
+
cursor: '123123123'
|
138
|
+
)
|
139
|
+
)
|
140
|
+
|
141
|
+
result = described_class.joins(UserHTTP, :id, :user_id, into: :user).to_a.first
|
142
|
+
expect(result.user.email).to eq('gianni@gianni.com')
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'can be selected with nested selectors' do
|
146
|
+
results = described_class
|
147
|
+
.joins(UserSQL, :id, :user_id, into: :user, as: :single)
|
148
|
+
.select(:id, :title, %i[user email])
|
149
|
+
.to_a
|
150
|
+
|
151
|
+
expect(results).to have(2).items
|
152
|
+
expect(results[0]).to have(3).items
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'with url params' do
|
156
|
+
it 'can be filtered using query params' do
|
157
|
+
stub_request(:get, 'http://example.com/1/users')
|
158
|
+
ScopedUserHTTP.where(company_id: 1).to_a
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe ArticleSQL do
|
6
|
+
before do
|
7
|
+
ActiveRecord::Base.connection.execute('INSERT INTO articles VALUES (1, 1, "Title 1", "Body 1", 1, "2021-01-01 00:00:00", "2021-01-01 00:00:00")')
|
8
|
+
ActiveRecord::Base.connection.execute('INSERT INTO articles VALUES (2, 1, "Title 2", "Body 2", 2, "2021-01-01 00:00:00", "2021-01-01 00:00:00")')
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'returns records' do
|
12
|
+
expect(described_class.all.to_a).to have(2).items
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'can be finded' do
|
16
|
+
result = described_class.find(2)
|
17
|
+
expect(result.id).to eq(2)
|
18
|
+
expect(result.user_id).to eq(1)
|
19
|
+
expect(result.title).to eq('Title 2')
|
20
|
+
expect(result.body).to eq('Body 2')
|
21
|
+
expect(result.status).to eq(2)
|
22
|
+
expect(result.created_at).to eq('2021-01-01 00:00:00 UTC'.to_datetime)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'can be filtered' do
|
26
|
+
expect(described_class.where(status: 1).to_a).to have(1).items
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'can be limited' do
|
30
|
+
expect(described_class.limit(1).to_a).to have(1).items
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'can be joined' do
|
34
|
+
expect do
|
35
|
+
described_class.joins(UserSQL, :id, :user_id, into: :user).to_a.first
|
36
|
+
end.to match_query(/ LEFT OUTER JOIN "users"/)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'can be joined on many' do
|
40
|
+
ActiveRecord::Base.connection.execute('INSERT INTO comments VALUES (1, 1, "content")')
|
41
|
+
ActiveRecord::Base.connection.execute('INSERT INTO comments VALUES (2, 1, "content2")')
|
42
|
+
|
43
|
+
expect do
|
44
|
+
result = described_class.joins(CommentSQL, :id, :article_id, into: :comments, as: :list).to_a.first
|
45
|
+
expect(result.comments).to have(2).items
|
46
|
+
end.to match_query(/ LEFT OUTER JOIN "comments" ON "comments"/)
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'can be selected with nested selectors' do
|
50
|
+
results = described_class
|
51
|
+
.joins(UserSQL, :id, :user_id, into: :user, as: :single)
|
52
|
+
.select(:id, :title, %i[user email])
|
53
|
+
.to_a
|
54
|
+
|
55
|
+
expect(results).to have(2).items
|
56
|
+
expect(results[0]).to have(3).items
|
57
|
+
end
|
58
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# require 'rails'
|
2
|
+
# require 'action_controller/railtie'
|
3
|
+
# require 'action_mailer/railtie'
|
4
|
+
# require 'action_view/railtie'
|
5
|
+
# require 'rspec/rails'
|
6
|
+
# require 'cancancan'
|
7
|
+
# require 'active_model_serializers'
|
8
|
+
require 'any_query'
|
9
|
+
require 'rspec/collection_matchers'
|
10
|
+
require 'rspec/sql_matcher'
|
11
|
+
require 'webmock/rspec'
|
12
|
+
|
13
|
+
# I18n.enforce_available_locales = false
|
14
|
+
RSpec::Expectations.configuration.warn_about_potential_false_positives = false
|
15
|
+
|
16
|
+
# Rails.application.config.eager_load = false
|
17
|
+
# Rails.application.config.active_record.legacy_connection_handling = false
|
18
|
+
|
19
|
+
Dir[File.expand_path('support/*.rb', __dir__)].each { |f| require f }
|
20
|
+
|
21
|
+
RSpec.configure do |config|
|
22
|
+
config.before(:suite) do
|
23
|
+
Schema.create
|
24
|
+
end
|
25
|
+
|
26
|
+
config.around(:each) do |example|
|
27
|
+
ActiveRecord::Base.transaction do
|
28
|
+
example.run
|
29
|
+
raise ActiveRecord::Rollback
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,146 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_record'
|
4
|
+
|
5
|
+
# @example
|
6
|
+
class ArticleSQL
|
7
|
+
include AnyQuery
|
8
|
+
|
9
|
+
adapter :sql do
|
10
|
+
url 'sqlite3::memory:'
|
11
|
+
primary_key :id
|
12
|
+
table 'articles'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# @example
|
17
|
+
class UserSQL
|
18
|
+
include AnyQuery
|
19
|
+
|
20
|
+
adapter :sql do
|
21
|
+
url 'sqlite3::memory:'
|
22
|
+
primary_key :id
|
23
|
+
table 'users'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# @example
|
28
|
+
class CommentSQL
|
29
|
+
include AnyQuery
|
30
|
+
|
31
|
+
adapter :sql do
|
32
|
+
url 'sqlite3::memory:'
|
33
|
+
primary_key :id
|
34
|
+
table 'comments'
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class ArticleHTTP
|
39
|
+
include AnyQuery
|
40
|
+
|
41
|
+
adapter :http do
|
42
|
+
url 'http://example.com'
|
43
|
+
primary_key :id
|
44
|
+
endpoint :list, :get, "/articles",
|
45
|
+
wrapper: [:items],
|
46
|
+
pagination: { type: :page },
|
47
|
+
default_params: {
|
48
|
+
query: { some_query_param: 1 },
|
49
|
+
headers: { 'Authorization': 'some' }
|
50
|
+
}
|
51
|
+
endpoint :show, :get, "/articles/{id}"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class UserHTTP
|
56
|
+
include AnyQuery
|
57
|
+
|
58
|
+
adapter :http do
|
59
|
+
url 'http://example.com'
|
60
|
+
primary_key :id
|
61
|
+
endpoint :list, :get, "/users",
|
62
|
+
wrapper: [:items],
|
63
|
+
pagination: { type: :cursor },
|
64
|
+
default_params: {
|
65
|
+
query: { some_query_param: true },
|
66
|
+
headers: { 'Authorization': 'some' }
|
67
|
+
}
|
68
|
+
endpoint :show, :get, "/users/{id}"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class ScopedUserHTTP
|
73
|
+
include AnyQuery
|
74
|
+
|
75
|
+
adapter :http do
|
76
|
+
url 'http://example.com'
|
77
|
+
primary_key :id
|
78
|
+
endpoint :list, :get, "/{company_id}/users",
|
79
|
+
wrapper: [:items],
|
80
|
+
pagination: { type: :none },
|
81
|
+
default_params: {
|
82
|
+
headers: { 'Authorization': 'some' }
|
83
|
+
}
|
84
|
+
endpoint :show, :get, "/{company_id}/users/{id}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class ArticleCSV
|
89
|
+
include AnyQuery
|
90
|
+
|
91
|
+
adapter :csv do
|
92
|
+
url File.join(__dir__, '../fixtures/sample.csv')
|
93
|
+
primary_key :id
|
94
|
+
end
|
95
|
+
|
96
|
+
field :id, type: :integer
|
97
|
+
field :user_id, type: :integer
|
98
|
+
field :title, type: :string
|
99
|
+
field :body, type: :string
|
100
|
+
field :status, type: :integer
|
101
|
+
field :created_at, type: :datetime, format: '%Y-%m-%d %H:%M:%S'
|
102
|
+
end
|
103
|
+
|
104
|
+
class ArticleFL
|
105
|
+
include AnyQuery
|
106
|
+
|
107
|
+
adapter :fixed_length do
|
108
|
+
url File.join(__dir__, '../fixtures/sample.txt')
|
109
|
+
primary_key :id
|
110
|
+
end
|
111
|
+
|
112
|
+
field :id, type: :integer, length: 4
|
113
|
+
field :user_id, type: :integer, length: 4
|
114
|
+
field :title, type: :string, length: 30
|
115
|
+
field :body, type: :string, length: 100
|
116
|
+
field :status, type: :integer, length: 1
|
117
|
+
field :created_at, type: :datetime, format: '%Y%m%d%H%M%S', length: 14
|
118
|
+
end
|
119
|
+
|
120
|
+
module Schema
|
121
|
+
def self.create
|
122
|
+
ActiveRecord::Migration.verbose = false
|
123
|
+
|
124
|
+
ActiveRecord::Schema.define do
|
125
|
+
create_table :users, force: true do |t|
|
126
|
+
t.string :email
|
127
|
+
t.timestamps null: false
|
128
|
+
end
|
129
|
+
|
130
|
+
create_table :articles, force: true do |t|
|
131
|
+
t.integer :user_id
|
132
|
+
t.string :title
|
133
|
+
t.text :body
|
134
|
+
t.integer :status
|
135
|
+
t.timestamps null: false
|
136
|
+
end
|
137
|
+
|
138
|
+
create_table :comments, force: true do |t|
|
139
|
+
t.integer :article_id
|
140
|
+
t.text :body
|
141
|
+
end
|
142
|
+
|
143
|
+
ActiveRecord::Base.connection.execute("INSERT INTO users VALUES (1, 'test@test.com', '2021-01-01 00:00:00', '2021-01-01 00:00:00')")
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|