postjob 0.5.2 → 0.5.3
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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ddb381c651727adfa2e654b8e9902510ede3dad3
|
4
|
+
data.tar.gz: e84c5cace159a3b39ce3cb34fc479d882eb4147a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d05ff63ead66235f51259cf86ff4565fc2aa8cee2583dcf83bcfc3767b9685b6c91c100b9d86e230f888eb9ca28e4d1a5aae36a4d9b18bf25d23de9314ff703
|
7
|
+
data.tar.gz: de96874a8e293a2357bda35885f55aa14b152e9f849d796de98596edeec8a6481bea7c354a293dcaa02bd570ae94a58c96d0134a897a7e75273a04c5f26be48d
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# This is a pretty generic association loader.
|
2
|
+
module Postjob::Queue::Associations
|
3
|
+
extend self
|
4
|
+
|
5
|
+
#
|
6
|
+
# returns a Hash workflow_id => [ associated ]
|
7
|
+
#
|
8
|
+
def load(entities, association, model, foreign_key, singular: false)
|
9
|
+
expect! entities => Array
|
10
|
+
expect! association => Symbol
|
11
|
+
expect! model => %w(postjobs events)
|
12
|
+
expect! foreign_key => Symbol
|
13
|
+
|
14
|
+
return entities if entities.empty?
|
15
|
+
|
16
|
+
entity_ids = entities.pluck(:id)
|
17
|
+
|
18
|
+
# Load all matching associated objects
|
19
|
+
scope = ::Postjob::Queue.search(model, foreign_key => entity_ids).order_by("id")
|
20
|
+
|
21
|
+
associated = ::Simple::SQL.all(scope, into: Hash)
|
22
|
+
associated_by_id = stable_group_by_key(associated, foreign_key)
|
23
|
+
|
24
|
+
# Distribute the associated objects amongst the entities
|
25
|
+
if singular
|
26
|
+
entities.each do |entity|
|
27
|
+
entity[association] = associated_by_id[entity[:id]].last
|
28
|
+
end
|
29
|
+
else
|
30
|
+
entities.each do |entity|
|
31
|
+
entity[association] = associated_by_id[entity[:id]]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def stable_group_by_key(ary, key)
|
39
|
+
hsh = Hash.new { |h, k| h[k] = [] }
|
40
|
+
ary.each do |entity|
|
41
|
+
group = entity[key]
|
42
|
+
hsh[group] << entity
|
43
|
+
end
|
44
|
+
hsh
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require_relative "./database_info"
|
2
|
+
|
3
|
+
module Postjob::Queue::Search
|
4
|
+
class ScopeBuilder
|
5
|
+
DatabaseInfo = ::Postjob::Queue::DatabaseInfo
|
6
|
+
|
7
|
+
SCHEMA_NAME = ::Postjob::Queue::SCHEMA_NAME
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def build(model:, filter:, attributes:)
|
11
|
+
attributes ||= default_search_attributes(model)
|
12
|
+
|
13
|
+
builder(model).send(:scope, filter: filter, attributes: attributes)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# describes which attributes should be returned in addition to a model's columns.
|
19
|
+
EXTRA_SEARCH_ATTRIBUTES = {
|
20
|
+
"postjobs" => [
|
21
|
+
"workflow || COALESCE('@' || workflow_version, '') || args AS job",
|
22
|
+
"COALESCE((results->0)::varchar, error_message) AS result",
|
23
|
+
"(now() at time zone 'utc') - created_at AS age",
|
24
|
+
"updated_at - created_at AS runtime"
|
25
|
+
]
|
26
|
+
}
|
27
|
+
|
28
|
+
def default_search_attributes(model)
|
29
|
+
DatabaseInfo.table_columns("#{SCHEMA_NAME}.#{model}") + (EXTRA_SEARCH_ATTRIBUTES[model] || [])
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns the name of the column used for dynamic filtering.
|
33
|
+
def dynamic_filter(model)
|
34
|
+
case model
|
35
|
+
when "postjobs" then "tags"
|
36
|
+
else "attributes"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def builder(model)
|
41
|
+
@builders ||= {}
|
42
|
+
@builders[model] ||= new(model: model, dynamic_filter: dynamic_filter(model))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def initialize(model:, dynamic_filter:)
|
49
|
+
@model = model
|
50
|
+
@table_name = "#{SCHEMA_NAME}.#{model}"
|
51
|
+
@column_types = DatabaseInfo.column_types(@table_name)
|
52
|
+
@dynamic_filter = dynamic_filter
|
53
|
+
end
|
54
|
+
|
55
|
+
def scope(filter:, attributes:)
|
56
|
+
expect! filter => [Hash, nil]
|
57
|
+
expect! attributes => Array
|
58
|
+
|
59
|
+
# build Scope
|
60
|
+
scope = Simple::SQL::Scope.new("SELECT #{attributes.join(", ")} FROM #{@table_name}")
|
61
|
+
scope = apply_filters(scope, filter) if filter && !filter.empty?
|
62
|
+
scope
|
63
|
+
end
|
64
|
+
|
65
|
+
# apply the filter hash onto the passed in scope. This matches all filters
|
66
|
+
# with a name which is matching a column name against the column values.
|
67
|
+
# It matches every other filter value against an entry in the
|
68
|
+
# dynamic_filter column.
|
69
|
+
def apply_filters(scope, filter)
|
70
|
+
filter.each_key do |key|
|
71
|
+
expect! key => [Symbol, String]
|
72
|
+
end
|
73
|
+
|
74
|
+
converted_filters = filter.inject({}) do |hsh, (key, value)|
|
75
|
+
matches = convert_filter_value(value, key: key)
|
76
|
+
matches = matches.first if matches.length == 1
|
77
|
+
hsh.update key => matches
|
78
|
+
end
|
79
|
+
|
80
|
+
column_filters, tags_filters = converted_filters.partition { |key, _| !@column_types[key].nil? }
|
81
|
+
|
82
|
+
scope = scope.where(Hash[column_filters]) unless column_filters.empty?
|
83
|
+
scope = scope.where(@dynamic_filter => Hash[tags_filters]) unless tags_filters.empty?
|
84
|
+
|
85
|
+
scope
|
86
|
+
end
|
87
|
+
|
88
|
+
def convert_filter_value(value, key:)
|
89
|
+
value = Array(value)
|
90
|
+
|
91
|
+
case @column_types[key]
|
92
|
+
when "bigint" then value.map { |v| Integer(v) }
|
93
|
+
when "integer" then value.map { |v| Integer(v) }
|
94
|
+
when nil then value.map(&:to_s) + value.grep(/\A-?\d+\z/).map(&:to_i)
|
95
|
+
else value.map(&:to_s)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/lib/postjob/queue/search.rb
CHANGED
@@ -1,120 +1,30 @@
|
|
1
|
-
require_relative "
|
1
|
+
require_relative "search/scope_builder"
|
2
2
|
|
3
3
|
module Postjob::Queue
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
case model
|
17
|
-
when "postjobs" then "tags"
|
18
|
-
else "attributes"
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def builder(model)
|
23
|
-
@builders ||= {}
|
24
|
-
@builders[model] ||= new(model: model, dynamic_filter: dynamic_filter(model))
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def initialize(model:, dynamic_filter:)
|
31
|
-
@model = model
|
32
|
-
@table_name = "#{SCHEMA_NAME}.#{model}"
|
33
|
-
@column_types = ::Postjob::Queue::DatabaseInfo.column_types(@table_name)
|
34
|
-
@dynamic_filter = dynamic_filter
|
35
|
-
end
|
36
|
-
|
37
|
-
def scope(filter:, attributes:)
|
4
|
+
module Search
|
5
|
+
# Builds a search scope (see Simple::SQL::Scope) for the passed in filter criteria.
|
6
|
+
#
|
7
|
+
# Parameters:
|
8
|
+
#
|
9
|
+
# - model: the name of the postjob model, e.g. "postjobs", "events", ..
|
10
|
+
# - filter: a Hash of filter values and other options. options are denoted
|
11
|
+
# by a Symbol key.
|
12
|
+
#
|
13
|
+
# Note that the search scope is unsorted.
|
14
|
+
def search(model, filter = {})
|
15
|
+
expect! model => String
|
38
16
|
expect! filter => [Hash, nil]
|
39
|
-
expect! attributes => Array
|
40
|
-
|
41
|
-
# build Scope
|
42
|
-
scope = Simple::SQL::Scope.new("SELECT #{attributes.join(", ")} FROM #{@table_name}")
|
43
|
-
scope = apply_filters(scope, filter) if filter && !filter.empty?
|
44
|
-
scope
|
45
|
-
end
|
46
|
-
|
47
|
-
# apply the filter hash onto the passed in scope. This matches all filters
|
48
|
-
# with a name which is matching a column name against the column values.
|
49
|
-
# It matches every other filter value against an entry in the
|
50
|
-
# dynamic_filter column.
|
51
|
-
def apply_filters(scope, filter)
|
52
|
-
filter.each_key do |key|
|
53
|
-
expect! key => [Symbol, String]
|
54
|
-
end
|
55
17
|
|
56
|
-
|
57
|
-
matches = convert_filter_value(value, key: key)
|
58
|
-
matches = matches.first if matches.length == 1
|
59
|
-
hsh.update key => matches
|
60
|
-
end
|
18
|
+
filter = filter ? filter.dup : {}
|
61
19
|
|
62
|
-
|
63
|
-
|
64
|
-
scope = scope.where(Hash[column_filters]) unless column_filters.empty?
|
65
|
-
scope = scope.where(@dynamic_filter => Hash[tags_filters]) unless tags_filters.empty?
|
20
|
+
root_only = filter.delete(:root_only)
|
21
|
+
attributes = filter.delete(:attributes)
|
66
22
|
|
23
|
+
scope = ScopeBuilder.build(model: model, filter: filter, attributes: attributes)
|
24
|
+
scope = scope.where("root_id=id") if root_only && model == "postjobs"
|
67
25
|
scope
|
68
26
|
end
|
69
|
-
|
70
|
-
def convert_filter_value(value, key:)
|
71
|
-
value = Array(value)
|
72
|
-
|
73
|
-
case @column_types[key]
|
74
|
-
when "bigint" then value.map { |v| Integer(v) }
|
75
|
-
when "integer" then value.map { |v| Integer(v) }
|
76
|
-
when nil then value.map(&:to_s) + value.grep(/\A-?\d+\z/).map(&:to_i)
|
77
|
-
else value.map(&:to_s)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
# Builds a search scope (see Simple::SQL::Scope) for the passed in filter criteria.
|
83
|
-
#
|
84
|
-
# Parameters:
|
85
|
-
#
|
86
|
-
# - model: the name of the postjob model, e.g. "postjobs", "events", ..
|
87
|
-
# - filter: a Hash of filter values and other options. options are denoted
|
88
|
-
# by a Symbol key.
|
89
|
-
#
|
90
|
-
# Note that the search scope is unsorted.
|
91
|
-
def search(model, filter = {})
|
92
|
-
expect! model => String
|
93
|
-
expect! filter => [Hash, nil]
|
94
|
-
|
95
|
-
filter = filter ? filter.dup : {}
|
96
|
-
|
97
|
-
root_only = filter.delete(:root_only)
|
98
|
-
attributes = filter.delete(:attributes) || default_search_attributes(model)
|
99
|
-
|
100
|
-
scope = ScopeBuilder.build(model: model, filter: filter, attributes: attributes)
|
101
|
-
scope = scope.where("root_id=id") if root_only && model == "postjobs"
|
102
|
-
scope
|
103
27
|
end
|
104
28
|
|
105
|
-
|
106
|
-
|
107
|
-
# describes which attributes should be returned in addition to a model's columns.
|
108
|
-
EXTRA_SEARCH_ATTRIBUTES = {
|
109
|
-
"postjobs" => [
|
110
|
-
"workflow || COALESCE('@' || workflow_version, '') || args AS job",
|
111
|
-
"COALESCE((results->0)::varchar, error_message) AS result",
|
112
|
-
"(now() at time zone 'utc') - created_at AS age",
|
113
|
-
"updated_at - created_at AS runtime"
|
114
|
-
]
|
115
|
-
}
|
116
|
-
|
117
|
-
def default_search_attributes(model)
|
118
|
-
DatabaseInfo.table_columns("#{SCHEMA_NAME}.#{model}") + (EXTRA_SEARCH_ATTRIBUTES[model] || [])
|
119
|
-
end
|
29
|
+
extend Search
|
120
30
|
end
|
data/lib/postjob/queue.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: postjob
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- radiospiel
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-07-
|
11
|
+
date: 2018-07-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -261,10 +261,12 @@ files:
|
|
261
261
|
- lib/postjob/migrations/018_heartbeat.sql
|
262
262
|
- lib/postjob/migrations/019_heartbeat_indices.sql
|
263
263
|
- lib/postjob/queue.rb
|
264
|
-
- lib/postjob/queue/
|
264
|
+
- lib/postjob/queue/associations.rb
|
265
265
|
- lib/postjob/queue/encoder.rb
|
266
266
|
- lib/postjob/queue/notifications.rb
|
267
267
|
- lib/postjob/queue/search.rb
|
268
|
+
- lib/postjob/queue/search/database_info.rb
|
269
|
+
- lib/postjob/queue/search/scope_builder.rb
|
268
270
|
- lib/postjob/queue/settings.rb
|
269
271
|
- lib/postjob/record.rb
|
270
272
|
- lib/postjob/registry.rb
|
@@ -315,7 +317,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
315
317
|
version: '0'
|
316
318
|
requirements: []
|
317
319
|
rubyforge_project:
|
318
|
-
rubygems_version: 2.
|
320
|
+
rubygems_version: 2.5.1
|
319
321
|
signing_key:
|
320
322
|
specification_version: 4
|
321
323
|
summary: restartable, asynchronous, and distributed processes
|
File without changes
|