polo 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3cc4c8cc8d6e2ecfb65d39c7ec4c49192c643388
4
- data.tar.gz: efdec09f03b61b966650144674799234e2c10369
3
+ metadata.gz: 241a2fd317d2b766497c31f824c4a9c76309df49
4
+ data.tar.gz: cdfa23f93211a11f43414aba198b9edcf9e6203a
5
5
  SHA512:
6
- metadata.gz: 10a1d5a28d71cfda25e83d108231dd2daa068075bdff5f356c37270039c090ddb3652246c5223a4bd3e1a3d30d2ce71a6e47961e7d73eecce4892ecf6fc55e5b
7
- data.tar.gz: af6ebc5a5f4f08cf7106ad53a24244e5b8cc1b0dab4c7cd988d88134e8357a888bee464627b589095e0d08f0b218f091e59af02cd7ef592a1c7f43196fee6a4a
6
+ metadata.gz: 63c36ebd40006d1f542474e86f4f91d343b1b99ab6b59054597f749274b3bdc919ea9ea2a5db8bfac2eafe46123030b55084ce2039767907b68555867acc3585
7
+ data.tar.gz: 4765c393aa6e1b19b784bcbc8d14dc22e3fcab1f8a7a048bb1dfdf01e3f269290a51957f271aead96e1fbedf24de87aab70949dd14018a010aa451932a97e4d6
@@ -0,0 +1,35 @@
1
+ ## 0.2.0
2
+
3
+ ### Breaking Changes
4
+
5
+ - None
6
+
7
+ ### Added
8
+
9
+ - [#8](https://github.com/IFTTT/polo/pull/8) Global settings
10
+ - [#17](https://github.com/IFTTT/polo/pull/17) Using random generator instead of character shuffle for data obfuscation
11
+ - [#18](https://github.com/IFTTT/polo/pull/18) Add a CHANGELOG
12
+ - [#20](https://github.com/IFTTT/polo/pull/20) Postgres Support
13
+
14
+ ### Fixed
15
+
16
+ - Typo fixes on the README: [#9](https://github.com/IFTTT/polo/pull/9), [#10](https://github.com/IFTTT/polo/pull/10)
17
+ - [#11]() Some ActiveRecord classes do not use id as the primary key
18
+ - [#25](https://github.com/IFTTT/polo/pull/25) Fix Custom Strategy
19
+
20
+ ## 0.1.0
21
+
22
+ ### Breaking Changes
23
+
24
+ - None
25
+
26
+ ### Added
27
+
28
+ - [#2](https://github.com/IFTTT/polo/pull/2) Add :ignore and :override options to deal with data collision
29
+ - [#3](https://github.com/IFTTT/polo/pull/3) Add option to obfuscate fields
30
+ - [#4](https://github.com/IFTTT/polo/pull/4) Add intro to Update / Ignore section
31
+ - [#6](https://github.com/IFTTT/polo/pull/6) Set up Appraisal to run specs across Rails 3.2 through 4.2
32
+
33
+ ### Fixed
34
+
35
+ - [#7](https://github.com/IFTTT/polo/pull/7) Fix casting of values
data/README.md CHANGED
@@ -1,4 +1,5 @@
1
1
  [![Open Source at IFTTT](http://ifttt.github.io/images/open-source-ifttt.svg)](http://ifttt.github.io)
2
+ [![Build Status](https://travis-ci.org/IFTTT/polo.svg?branch=master)](https://travis-ci.org/IFTTT/polo)
2
3
 
3
4
  ![Polo](https://raw.githubusercontent.com/IFTTT/polo/images/images/polo.png "Polo")
4
5
 
@@ -9,6 +10,9 @@ Polo takes an `ActiveRecord::Base` seed object and traverses every whitelisted `
9
10
 
10
11
  You can then save those SQL `INSERTS` to .sql file and import the data to your favorite environment.
11
12
 
13
+ # Motivation
14
+ Read our [blog post](https://medium.com/engineering-at-ifttt/happier-rails-development-with-polo-9df6819136d3#.f8ll3azeq) or check out this [presentation](https://speakerdeck.com/nettofarah/polo-working-with-real-world-data-in-development).
15
+
12
16
  ## Usage
13
17
  Given the following data model:
14
18
  ```ruby
@@ -74,7 +78,8 @@ INSERT INTO `ingredients` (`id`, `name`, `quantity`) VALUES (4, 'Cheese', '2 sli
74
78
 
75
79
  Occasionally, you might have a dataset that you want to refresh. A production database that has data that might be useful on your local copy of the database. Polo doesn't have an opinion about your data; if you try to import data with a key that's already in your local database, Polo doesn't necessarily know how you want to handle that conflict.
76
80
 
77
- Advanced users will find the `on_duplicate` option to be helpful in this context. It gives Polo instructions on how to handle collisions. *Note: This feature is currently only supported for MySQL databases. (PRs for other databases are welcome!)*
81
+ Advanced users will find the `on_duplicate` option to be helpful in this context. It gives Polo instructions on how to handle collisions.
82
+ *Note: This feature is currently only supported for MySQL databases. (PRs for other databases are welcome!)*
78
83
 
79
84
  There are two possible values for the `on_duplicate` key: `:ignore` and `:override`. Ignore keeps the old data. Override keeps the new data. If there's a collision and the on_duplicate param is not set, Polo will simpy stop importing the data.
80
85
 
@@ -128,9 +133,26 @@ Polo::Traveler.explore(AR::Chef, 1)
128
133
  INSERT INTO `chefs` (`id`, `name`, `email`) VALUES (1, 'Netto', 'eahorctmaagfo.nitm@l')
129
134
  ```
130
135
 
131
- Warning: This is not a security feature. Fields can still easily be rearranged back to their original format. Polo will simply scramble the order of strings so you don't accidentaly end up causing side effects when using production data in development.
136
+ Warning: This is not a security feature. Fields can still easily be rearranged back to their original format. Polo will simply scramble the order of strings so you don't accidentally end up causing side effects when using production data in development. It is not a good practice to use highly sensitive data in development.
137
+
138
+ #### Advanced Obfuscation
139
+
140
+ For more advanced obfuscation, you can pass in a custom obfuscation strategy.
141
+ Polo will take in a lambda that can be used to transform sensitive data.
142
+
143
+ ````ruby
144
+ Polo.configure do
145
+ email_strategy = lambda {|e| "#{e.split("@")[0]}_test@example.com" }
146
+ credit_card_strategy = lambda {|_| "4111111111111111"}
147
+ obfuscate({email: email_strategy, credit_card: credit_card_strategy})
148
+ end
149
+
150
+ Polo::Traveler.explore(AR::Chef, 1)
151
+ ````
132
152
 
133
- It is not a good practice to use highly sensitive data in development.
153
+ ```sql
154
+ INSERT INTO `chefs` (`id`, `name`, `email`) VALUES (1, 'Netto', 'netto_test.@example.com')
155
+ ```
134
156
 
135
157
  ## Installation
136
158
 
@@ -152,7 +174,7 @@ $ gem install polo
152
174
 
153
175
  ## Contributing
154
176
 
155
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/polo. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
177
+ Bug reports and pull requests are welcome on GitHub at https://github.com/IFTTT/polo. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
156
178
 
157
179
  To run the specs across all supported version of Rails, check out the repo and
158
180
  follow these steps:
@@ -14,10 +14,12 @@ module Polo
14
14
  # ActiveSupport::Notifications block and collecting every generate SQL query.
15
15
  #
16
16
  def collect
17
- ActiveSupport::Notifications.subscribed(collector, 'sql.active_record') do
18
- base_finder = @base_class.includes(@dependency_tree).where(id: @id)
19
- collect_sql(@base_class, base_finder.to_sql)
20
- base_finder.to_a
17
+ unprepared_statement do
18
+ ActiveSupport::Notifications.subscribed(collector, 'sql.active_record') do
19
+ base_finder = @base_class.includes(@dependency_tree).where(@base_class.primary_key => @id)
20
+ collect_sql(@base_class, base_finder.to_sql)
21
+ base_finder.to_a
22
+ end
21
23
  end
22
24
 
23
25
  @selects.compact.uniq
@@ -33,8 +35,9 @@ module Polo
33
35
  #
34
36
  def collector
35
37
  lambda do |name, start, finish, id, payload|
38
+ return unless payload[:name] =~ /^(.*) Load$/
36
39
  begin
37
- class_name = payload[:name].gsub(' Load', '').constantize
40
+ class_name = $1.constantize
38
41
  sql = payload[:sql]
39
42
  collect_sql(class_name, sql)
40
43
  rescue ActiveRecord::StatementInvalid, NameError
@@ -49,5 +52,15 @@ module Polo
49
52
  sql: sql
50
53
  }
51
54
  end
55
+
56
+ def unprepared_statement
57
+ if ActiveRecord::Base.connection.respond_to?(:unprepared_statement)
58
+ ActiveRecord::Base.connection.unprepared_statement do
59
+ yield
60
+ end
61
+ else
62
+ yield
63
+ end
64
+ end
52
65
  end
53
66
  end
@@ -4,13 +4,30 @@ module Polo
4
4
  attr_reader :on_duplicate_strategy, :blacklist
5
5
 
6
6
  def initialize(options={})
7
- options = { on_duplicate: nil, obfuscate: [] }.merge(options)
7
+ options = { on_duplicate: nil, obfuscate: {} }.merge(options)
8
8
  @on_duplicate_strategy = options[:on_duplicate]
9
- @blacklist = options[:obfuscate]
9
+ obfuscate(options[:obfuscate])
10
10
  end
11
11
 
12
+ # TODO: document this
13
+ # This normalizes an array or hash of fields to a hash of
14
+ # { field_name => strategy }
12
15
  def obfuscate(*fields)
13
- @blacklist = fields
16
+ if fields.is_a?(Array)
17
+ fields = fields.flatten
18
+ end
19
+
20
+ fields_and_strategies = {}
21
+
22
+ fields.each do |field|
23
+ if field.is_a?(Symbol) || field.is_a?(String)
24
+ fields_and_strategies[field] = nil
25
+ elsif field.is_a?(Hash)
26
+ fields_and_strategies = fields_and_strategies.merge(field)
27
+ end
28
+ end
29
+
30
+ @blacklist = fields_and_strategies
14
31
  end
15
32
 
16
33
  def on_duplicate(strategy)
@@ -25,7 +25,7 @@ module Polo
25
25
  end
26
26
 
27
27
  if fields = @configuration.blacklist
28
- obfuscate!(active_record_instances, fields.map(&:to_s))
28
+ obfuscate!(active_record_instances, fields)
29
29
  end
30
30
 
31
31
  active_record_instances
@@ -35,12 +35,25 @@ module Polo
35
35
 
36
36
  def obfuscate!(instances, fields)
37
37
  instances.each do |instance|
38
- next if (instance.attributes.keys & fields).empty?
39
- fields.each do |field|
40
- value = instance.attributes[field] || ''
41
- instance.send("#{field}=", value.split('').shuffle.join)
38
+ next if intersection(instance.attributes.keys, fields).empty?
39
+
40
+ fields.each do |field, strategy|
41
+ value = instance.attributes[field.to_s] || ''
42
+ instance.send("#{field}=", new_field_value(field, strategy, value))
42
43
  end
43
44
  end
44
45
  end
46
+
47
+ def intersection(attrs, fields)
48
+ attrs & fields.keys.map(&:to_s)
49
+ end
50
+
51
+ def new_field_value(field, strategy, value)
52
+ if strategy.nil?
53
+ value.split("").shuffle.join
54
+ else
55
+ strategy.call(value)
56
+ end
57
+ end
45
58
  end
46
59
  end
@@ -1,3 +1,3 @@
1
1
  module Polo
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Netto Farah
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2015-09-14 00:00:00.000000000 Z
11
+ date: 2015-12-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -107,6 +107,7 @@ files:
107
107
  - ".ruby-version"
108
108
  - ".travis.yml"
109
109
  - Appraisals
110
+ - CHANGELOG.md
110
111
  - CODE_OF_CONDUCT.md
111
112
  - Gemfile
112
113
  - LICENSE.txt