supple 0.1.0

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.
@@ -0,0 +1,7 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", "4.1.0.beta2"
6
+
7
+ gemspec :path=>"../"
@@ -0,0 +1,145 @@
1
+ PATH
2
+ remote: ../
3
+ specs:
4
+ supple (0.1.0)
5
+ ansi
6
+ bonfig
7
+ connection_pool
8
+ elasticsearch
9
+ patron
10
+
11
+ GEM
12
+ remote: https://rubygems.org/
13
+ specs:
14
+ actionmailer (4.1.0.beta2)
15
+ actionpack (= 4.1.0.beta2)
16
+ actionview (= 4.1.0.beta2)
17
+ mail (~> 2.5.4)
18
+ actionpack (4.1.0.beta2)
19
+ actionview (= 4.1.0.beta2)
20
+ activesupport (= 4.1.0.beta2)
21
+ rack (~> 1.5.2)
22
+ rack-test (~> 0.6.2)
23
+ actionview (4.1.0.beta2)
24
+ activesupport (= 4.1.0.beta2)
25
+ builder (~> 3.1)
26
+ erubis (~> 2.7.0)
27
+ activemodel (4.1.0.beta2)
28
+ activesupport (= 4.1.0.beta2)
29
+ builder (~> 3.1)
30
+ activerecord (4.1.0.beta2)
31
+ activemodel (= 4.1.0.beta2)
32
+ activesupport (= 4.1.0.beta2)
33
+ arel (~> 5.0.0)
34
+ activesupport (4.1.0.beta2)
35
+ i18n (~> 0.6, >= 0.6.9)
36
+ json (~> 1.7, >= 1.7.7)
37
+ minitest (~> 5.1)
38
+ thread_safe (~> 0.1)
39
+ tzinfo (~> 1.1)
40
+ ansi (1.4.3)
41
+ appraisal (0.5.2)
42
+ bundler
43
+ rake
44
+ arel (5.0.0)
45
+ atomic (1.1.15)
46
+ bonfig (0.1.1)
47
+ builder (3.2.2)
48
+ coderay (1.1.0)
49
+ connection_pool (1.2.0)
50
+ diff-lcs (1.2.5)
51
+ elasticsearch (1.0.1)
52
+ elasticsearch-api (= 1.0.1)
53
+ elasticsearch-transport (= 1.0.1)
54
+ elasticsearch-api (1.0.1)
55
+ multi_json
56
+ elasticsearch-transport (1.0.1)
57
+ faraday
58
+ multi_json
59
+ erubis (2.7.0)
60
+ factory_girl (4.4.0)
61
+ activesupport (>= 3.0.0)
62
+ faraday (0.9.0)
63
+ multipart-post (>= 1.2, < 3)
64
+ hike (1.2.3)
65
+ i18n (0.6.9)
66
+ json (1.8.1)
67
+ mail (2.5.4)
68
+ mime-types (~> 1.16)
69
+ treetop (~> 1.4.8)
70
+ method_source (0.8.2)
71
+ mime-types (1.25.1)
72
+ minitest (5.3.0)
73
+ multi_json (1.9.0)
74
+ multipart-post (2.0.0)
75
+ patron (0.4.18)
76
+ polyglot (0.3.4)
77
+ pry (0.9.12.6)
78
+ coderay (~> 1.0)
79
+ method_source (~> 0.8)
80
+ slop (~> 3.4)
81
+ rack (1.5.2)
82
+ rack-test (0.6.2)
83
+ rack (>= 1.0)
84
+ rails (4.1.0.beta2)
85
+ actionmailer (= 4.1.0.beta2)
86
+ actionpack (= 4.1.0.beta2)
87
+ actionview (= 4.1.0.beta2)
88
+ activemodel (= 4.1.0.beta2)
89
+ activerecord (= 4.1.0.beta2)
90
+ activesupport (= 4.1.0.beta2)
91
+ bundler (>= 1.3.0, < 2.0)
92
+ railties (= 4.1.0.beta2)
93
+ sprockets-rails (~> 2.0.0)
94
+ railties (4.1.0.beta2)
95
+ actionpack (= 4.1.0.beta2)
96
+ activesupport (= 4.1.0.beta2)
97
+ rake (>= 0.8.7)
98
+ thor (>= 0.18.1, < 2.0)
99
+ rake (0.9.6)
100
+ rspec (2.14.1)
101
+ rspec-core (~> 2.14.0)
102
+ rspec-expectations (~> 2.14.0)
103
+ rspec-mocks (~> 2.14.0)
104
+ rspec-core (2.14.8)
105
+ rspec-expectations (2.14.5)
106
+ diff-lcs (>= 1.1.3, < 2.0)
107
+ rspec-mocks (2.14.6)
108
+ rubygems-tasks (0.2.4)
109
+ slop (3.4.7)
110
+ sprockets (2.11.0)
111
+ hike (~> 1.2)
112
+ multi_json (~> 1.0)
113
+ rack (~> 1.0)
114
+ tilt (~> 1.1, != 1.3.0)
115
+ sprockets-rails (2.0.1)
116
+ actionpack (>= 3.0)
117
+ activesupport (>= 3.0)
118
+ sprockets (~> 2.8)
119
+ sqlite3 (1.3.9)
120
+ thor (0.18.1)
121
+ thread_safe (0.2.0)
122
+ atomic (>= 1.1.7, < 2)
123
+ tilt (1.4.1)
124
+ treetop (1.4.15)
125
+ polyglot
126
+ polyglot (>= 0.3.1)
127
+ tzinfo (1.1.0)
128
+ thread_safe (~> 0.1)
129
+ yard (0.8.7.3)
130
+
131
+ PLATFORMS
132
+ ruby
133
+
134
+ DEPENDENCIES
135
+ appraisal
136
+ bundler
137
+ factory_girl
138
+ pry
139
+ rails (= 4.1.0.beta2)
140
+ rake
141
+ rspec
142
+ rubygems-tasks
143
+ sqlite3
144
+ supple!
145
+ yard
@@ -0,0 +1,38 @@
1
+ require 'elasticsearch'
2
+ require 'connection_pool'
3
+ require 'active_support/core_ext'
4
+ require 'bonfig'
5
+ require 'rails'
6
+
7
+
8
+
9
+ module Supple
10
+ extend Bonfig
11
+
12
+ bonfig do
13
+ config :index_name_method, default: Proc.new { |model| [model.table_name, Rails.env].join('_') }
14
+ config :index do
15
+ config :default_index_name, default: Proc.new { |model| [model.table_name, Rails.env].join('_') }
16
+ config :default_document_type, default: Proc.new { |model| model.table_name }
17
+ end
18
+ config :client do
19
+ config :size, default: 5
20
+ config :timeout, default: 1
21
+ end
22
+ end
23
+
24
+ def self.models
25
+ ActiveRecord::Base.descendants.select do |m|
26
+ m.included_modules.include?(Supple::Model)
27
+ end
28
+ end
29
+
30
+ def self.client
31
+ @client ||= Elasticsearch::Client.new(adapter: :patron)
32
+ end
33
+ end
34
+ require 'supple/defaults'
35
+ require 'supple/model/dsl'
36
+ require 'supple/model'
37
+ # require 'supple/index'
38
+ require 'supple/railtie' if defined?(Rails)
@@ -0,0 +1,30 @@
1
+ module Supple
2
+ SETTINGS = {
3
+ number_of_shards: 1,
4
+ number_of_replicas: 0,
5
+ analysis: {
6
+ analyzer: {
7
+ word_start_ngram: {
8
+ type: "custom",
9
+ tokenizer: "word_start_ngram_tokenizer",
10
+ filter: ["lowercase", "asciifolding"]
11
+ },
12
+ words: {
13
+ type: "custom",
14
+ tokenizer: "keyword",
15
+ filter: ["lowercase", "asciifolding"]
16
+ }
17
+ },
18
+ tokenizer: {
19
+ word_start_ngram_tokenizer: {
20
+ type: "edgeNGram",
21
+ min_gram: 1,
22
+ max_gram: 50,
23
+ token_chars: ["letter"]
24
+ }
25
+ }
26
+ }
27
+ }
28
+
29
+
30
+ end
@@ -0,0 +1,31 @@
1
+ module Supple
2
+ class IndexConfig < BasicObject
3
+ end
4
+ class Index
5
+ include ActiveSupport::DescendantsTracker
6
+
7
+ def self.settings(data = nil)
8
+ @settings = data unless data.nil?
9
+ @settings
10
+ end
11
+
12
+ def self.mappings(data = nil)
13
+ @mappings = data unless data.nil?
14
+ @mappings
15
+ end
16
+
17
+
18
+ with_options instance_writer: false do
19
+ cattr_accessor :model do
20
+ binding.pry
21
+ end
22
+ cattr_accessor :index_name do
23
+ [table_name, Rails.env].join('_')
24
+ end
25
+
26
+ cattr_accessor :document_type do
27
+ table_name
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,152 @@
1
+ module Supple
2
+ module WithClient
3
+ extend ActiveSupport::Concern
4
+ mattr_reader :client do
5
+ Supple.client
6
+ end
7
+ end
8
+
9
+ class Importer
10
+ def initialize(scope, index_name, document_type)
11
+ @scope = scope
12
+ @index_name = index_name
13
+ @document_type = document_type
14
+ end
15
+
16
+ def execute!
17
+ @scope.find_in_batches do |batch|
18
+ Supple.client.bulk({
19
+ index: @index_name,
20
+ type: @document_type,
21
+ body: transform_batch(batch)
22
+ })
23
+ end
24
+ end
25
+
26
+ protected
27
+
28
+ def transform_batch(batch)
29
+ batch.map { |a| { index: { _id: a.id, data: a.as_indexed_json } } }
30
+ end
31
+ end
32
+
33
+
34
+ class ModelClient
35
+ attr_reader :model
36
+ delegate :index_name, :document_type, :as_indexed_json, to: :model
37
+
38
+ def initialize(model)
39
+ @model = model
40
+ end
41
+
42
+ def index
43
+ run(:index, body: as_indexed_json)
44
+ end
45
+
46
+ def delete
47
+ run(:delete)
48
+ end
49
+
50
+ private
51
+
52
+ def run(method, extra = {})
53
+ action = Supple.client.method(method)
54
+ action.call({
55
+ index: index_name,
56
+ type: document_type,
57
+ id: model.id,
58
+ }).merge(extra)
59
+ end
60
+ end
61
+
62
+
63
+ class Config
64
+ def client
65
+ Supple.client
66
+ end
67
+ def initialize(model)
68
+ @model = model
69
+
70
+ @index_name_method = Supple.config.index.default_index_name
71
+ @document_type_method = Supple.config.index.default_document_type
72
+ end
73
+
74
+ def index_name(&block)
75
+ @index_name_method = block if block_given?
76
+ @index_name ||= @index_name_method.call(@model)
77
+ end
78
+
79
+ def document_type(&block)
80
+ @document_type_method = block if block_given?
81
+ @document_type ||= @document_type_method.call(@model)
82
+ end
83
+
84
+ def mappings(&block)
85
+ @mappings ||= {}
86
+ @mappings = DSL::Mapping.new(&block).to_hash if block_given?
87
+ @mappings
88
+ end
89
+
90
+ def index_scope
91
+ @model.all
92
+ end
93
+
94
+ def settings(data = {})
95
+ @settings ||= {}
96
+ @settings.merge! data
97
+ @settings
98
+ end
99
+
100
+
101
+ def reindex
102
+ alias_name = index_name
103
+ new_index_name = alias_name + "_" + Time.now.strftime("%Y%m%d%H%M%S%L")
104
+
105
+ document_mappings = {}
106
+ document_mappings[document_type] = mappings
107
+ client.indices.create index: new_index_name,
108
+ body: {
109
+ settings: settings,
110
+ mappings: document_mappings
111
+ }
112
+
113
+ if client.indices.exists_alias(name: alias_name)
114
+ existing_alias = client.indices.get_alias(name: alias_name)
115
+ Importer.new(index_scope, new_index_name, document_type).execute!
116
+ client.indices.delete index: existing_alias.keys
117
+ client.indices.put_alias index: new_index_name, name: alias_name
118
+ else
119
+ client.indices.put_alias index: new_index_name, name: alias_name
120
+ Importer.new(index_scope, new_index_name, document_type).execute!
121
+ end
122
+
123
+ end
124
+ end
125
+
126
+
127
+ module Model
128
+ extend ActiveSupport::Concern
129
+
130
+ def es
131
+ @es ||= ModelClient.new(self)
132
+ end
133
+
134
+ def as_indexed_json
135
+ as_json
136
+ end
137
+
138
+
139
+ included do
140
+ after_commit lambda { es.index }, on: [:update, :create]
141
+ after_commit lambda { es.delete }, on: :destroy
142
+ end
143
+
144
+ module ClassMethods
145
+ def supple &block
146
+ @supple ||= Supple::Config.new(self)
147
+ @supple.instance_eval(&block) if block_given?
148
+ @supple
149
+ end
150
+ end
151
+ end
152
+ end
@@ -0,0 +1,59 @@
1
+ module Supple
2
+ module DSL
3
+ class Mapping
4
+ def initialize(data = {}, &block)
5
+ @data = data
6
+ @data[property_key] ||= {}
7
+ instance_eval(&block) if block_given?
8
+ end
9
+
10
+ def prop(name, options = {}, &block)
11
+ if block_given?
12
+ @data[property_key][name] = Mapping.new(options).instance_eval(&block).to_hash
13
+ end
14
+ @data[property_key][name] = options
15
+ end
16
+
17
+ def dynamic_template(name, &block)
18
+ @data[:dynamic_templates] ||= []
19
+ dt = DynamicTemplate.new(name, &block)
20
+ @data[:dynamic_templates] << dt.to_hash
21
+ end
22
+
23
+ def to_hash
24
+ @data
25
+ end
26
+
27
+ private
28
+
29
+ def property_key
30
+ @data[:type].to_s == 'multi_field' ? :fields : :properties
31
+ end
32
+ end
33
+
34
+ class DynamicTemplate
35
+ def initialize(name, options = {}, &block)
36
+ @name = name
37
+ @options = options
38
+ @data = {}
39
+ instance_eval(&block) if block_given?
40
+ end
41
+
42
+ [:match, :unmatch, :match_mapping_type, :path_match, :path_unmatch, :match_pattern].each do |meth|
43
+ define_method(meth) do |val|
44
+ @data[meth] = val
45
+ end
46
+ end
47
+ def mapping(data = {}, &block)
48
+ mapping = Mapping.new(data)
49
+ mapping.instance_eval(&block) if block_given?
50
+ @data[:mapping] = mapping.to_hash
51
+ end
52
+
53
+ def to_hash
54
+ @options[@name] = @data
55
+ @options
56
+ end
57
+ end
58
+ end
59
+ end