akido_lib 0.2.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 3b8e6fcf27fb482c5a7a11574807f9b845b779115ee88b8c4df9942e5494fe82
4
+ data.tar.gz: 8328a4d17ac37d9514bf2326b4934d189b95e1b50494efbc83cae0883a5c55ca
5
+ SHA512:
6
+ metadata.gz: 3ef0033896b726ebe9d6d404c9034758fe08b3276f917d94adcdb9de2def7e83b62ab9c7ec55dfc0c8a6b24f8f87eaa64bea72af6f1741c9b3df68c604b5ae4e
7
+ data.tar.gz: fcc636945b3a9bebb88c32bc1f8d5c2258f316d87609b8ed48b682eca02c3a15983170352125bc80d1554b34bc2b0f956f6072ec09923d1e9551fcc37ec63da1
data/README.md ADDED
@@ -0,0 +1,135 @@
1
+ # AkidoLib
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ How to use my plugin.
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'akido_lib'
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+ ```bash
21
+ $ gem install akido_lib
22
+ ```
23
+
24
+ ## Extra Classes/Methods
25
+ ### `AkidoLib::Bundle`
26
+ We're liable to add some utility methods to `AkidoLib::Bundle`, since it's the
27
+ main entry point into what comes back from the server.
28
+
29
+ #### Methods
30
+ * `#to_a`
31
+
32
+ `Bundle#to_a` works exactly as you'd expect: the full bundle is read from the
33
+ server, and then turned into an array. Useful for when you want to call `#map`
34
+ or `#select` on what gets returned in a bundle.
35
+
36
+
37
+
38
+ ### `AkidoLib::Query`
39
+ `Query` exists to bridge the gap between `FHIR::Client` and ActiveRecord-y
40
+ syntax, which most Rails developers seem to think in. Its syntax should be
41
+ familiar to those familiar with `ActiveRecord::Relation`, specifically `#all`
42
+ and `#where`.
43
+
44
+ #### Methods
45
+ ##### Class Methods
46
+ * `.set_base_url!(base_url)`
47
+
48
+ Ordinarily, new Queries reach back to `FHIR::Model.client` to get their base
49
+ URL, but if it isn't set, or if you just want to overwrite it, you can do so.
50
+
51
+ * `.new(resource, base_url)`
52
+
53
+ You probably won't call this method — most Queries will be created using
54
+ methods on `FHIR::Model`.
55
+
56
+ When a Query is created, it needs two things to be meaningful: a base URL to
57
+ hit, and the name of a FHIR resource. This method takes both as arguments. The
58
+ resource name is required, but `base_url` is optional — if `base_url` is set
59
+ on `AkidoLib::Query`, that will be used, otherwise it will default to the base
60
+ URL set on `AkidoLib::Model.client`.
61
+
62
+ ##### Instance Methods
63
+ * `#where(conditions)`
64
+
65
+ The `where` method is the main entry point for adding constraints to the
66
+ query. It accepts all of the
67
+ [parameters](https://www.hl7.org/fhir/search.html#all) for FHIR searching,
68
+ with the caveat that parameter names should be written as Ruby-style symbols, without the
69
+ leading underscore and in `snake_case` instead of `camelCase` — e.g.
70
+ `_lastUpdated` becomes `:last_updated`.
71
+
72
+
73
+ * `#last_updated(date)`
74
+
75
+ `#where` has the advantage of being able to set more than one property at a
76
+ time, but the disadvantage that it doesn't cast any of the values to be more
77
+ palatable to the server. Because of how precise FHIR servers can be about
78
+ their date requirements, `#last_updated` is a convenience method that lets you
79
+ pass a date, then sets `_lastUpdated` to the XML-encoded version of that date.
80
+
81
+ * `#include(relation)`
82
+
83
+ Shorthand for adding `_include=[Relation]` to your query. Takes a sting, e.g.
84
+ `'Encounter:Patient'`. Can take option after the name of the relation to
85
+ include. There is currenlty one option implemented: passing `:rev => true`
86
+ will insert the relation as a `_revinclude` instead of an `_include`.
87
+ ```
88
+ AkidoLib::Encounter.where(:last_updated =>2.weeks.ago).include("Encounter:Patient")
89
+ ```
90
+
91
+ * `#custom(key, value)`
92
+
93
+ `#where` is prescriptive — it has opinions about how query keys should looks
94
+ (i.e. they should be preceded with an underscore, they should be camelCase,
95
+ etc.). `#custom` has no such prescriptions: whatever you pass in will be
96
+ assigned to the query as a key and a value.
97
+
98
+
99
+ * `#fetch!`
100
+
101
+ Intended to be the last method called on a chain of queries. Will execute the
102
+ query to which it is attached, and return the `AkidoLib::Bundle` that comes
103
+ back from the server.
104
+
105
+ _Note: one of two `Query` methods that doesn't itself return a `Query`
106
+ (returns an `AkidoLab::Bundle`)._
107
+
108
+ * `#url`
109
+
110
+ Sometimes you just need to peer into the inner workings of `Query` and see
111
+ what it's doing, maybe to paste a URL into Postman or `curl`. This is
112
+ precisely that utility method.
113
+
114
+ _Note: the second of two `Query` methods that doesn't return a `Query`
115
+ (returns a string)._
116
+
117
+ ### `AkidoLib::Model`
118
+
119
+ `AkidoLib::Model` is another one of those classes that we'll periodically open
120
+ up to add new functionality. For now, the main thing is adding methods that
121
+ return `AkidoLib::Query` objects.
122
+
123
+ #### Methods
124
+ * `#all`
125
+
126
+ When called on a FHIR model, `#all` will return an `AkidoLib::Query` object
127
+ pointed at the base level of that resource — e.g. `FHIR::Encounter.all` will
128
+ return a `Query` with a URL of `<BaseURL>/Encounter`
129
+
130
+
131
+ ## Contributing
132
+ Contribution directions go here.
133
+
134
+ ## License
135
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,17 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'AkidoLib'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.md')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ require 'bundler/gem_tasks'
data/lib/akido_lib.rb ADDED
@@ -0,0 +1,21 @@
1
+ require 'fhir_client'
2
+ require 'redis-objects'
3
+
4
+ require_relative 'akido_lib/version'
5
+ require_relative './ext/rest_client'
6
+
7
+ require_relative './bundle'
8
+ require_relative './caching'
9
+ require_relative './query'
10
+
11
+ module AkidoLib
12
+ include FHIR
13
+
14
+ def self.setup(base_url, server_config = {})
15
+ self::Model.client = AkidoLib::Client.new(base_url)
16
+
17
+ self::Model.client.default_format = FHIR::Formats::ResourceFormat::RESOURCE_XML_DSTU2
18
+
19
+ RestClient.set_config(server_config)
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ module AkidoLib
2
+ VERSION = '0.2.0'
3
+ end
data/lib/bundle.rb ADDED
@@ -0,0 +1,9 @@
1
+ module FHIR
2
+ class Bundle
3
+ def to_a
4
+ array = @entry.map(&:resource)
5
+ array += next_bundle if next_bundle
6
+ array
7
+ end
8
+ end
9
+ end
data/lib/caching.rb ADDED
@@ -0,0 +1,42 @@
1
+ module AkidoLib
2
+ module ReferenceInstanceExtensions
3
+ def read
4
+ model, id = reference.match(/(\D+)\/(\d+)/).captures
5
+ cached_models = Redis::HashKey.new(model)
6
+ if matching_cached_model = cached_models[id]
7
+ return "FHIR::#{model}".constantize.new(JSON.parse(matching_cached_model))
8
+ else
9
+ model = super
10
+ cached_models[model.id] = model.to_json
11
+ return model
12
+ end
13
+ end
14
+ end
15
+
16
+ module ModelClassExtensions
17
+ def cache!
18
+ model = self.to_s.demodulize
19
+ cache = Redis::HashKey.new(model)
20
+
21
+ records = self.search.to_a
22
+ records.each do |record|
23
+ cache[record.id] = record.to_json
24
+
25
+ end
26
+ end
27
+
28
+ def cached
29
+ model = self.class.to_s.demodulize
30
+
31
+ Redis::HashKey.new(model).values.map do |record|
32
+ self.new(JSON.parse(record))
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ class FHIR::Reference
39
+ prepend AkidoLib::ReferenceInstanceExtensions
40
+ end
41
+
42
+ FHIR::Model.singleton_class.prepend AkidoLib::ModelClassExtensions
@@ -0,0 +1,45 @@
1
+ module RestClient
2
+ @@config = {}
3
+
4
+ def self.get_config
5
+ @@config
6
+ end
7
+
8
+ def self.set_config(**config)
9
+ config.each do |key, value|
10
+ @@config[key] = value unless key == :url || key == :method
11
+ end
12
+ end
13
+
14
+ def self.clear_config
15
+ @@config = {}
16
+ end
17
+
18
+ def self.get(url, headers={}, &block)
19
+ Request.execute(:method => :get, :url => url, :headers => headers, **@@config, &block)
20
+ end
21
+
22
+ def self.post(url, payload, headers={}, &block)
23
+ Request.execute(:method => :post, :url => url, :payload => payload, :headers => headers, **@@config, &block)
24
+ end
25
+
26
+ def self.patch(url, payload, headers={}, &block)
27
+ Request.execute(:method => :patch, :url => url, :payload => payload, :headers => headers, **@@config, &block)
28
+ end
29
+
30
+ def self.put(url, payload, headers={}, &block)
31
+ Request.execute(:method => :put, :url => url, :payload => payload, :headers => headers, **@@config, &block)
32
+ end
33
+
34
+ def self.delete(url, headers={}, &block)
35
+ Request.execute(:method => :delete, :url => url, :headers => headers, **@@config, &block)
36
+ end
37
+
38
+ def self.head(url, headers={}, &block)
39
+ Request.execute(:method => :head, :url => url, :headers => headers, **@@config, &block)
40
+ end
41
+
42
+ def self.options(url, headers={}, &block)
43
+ Request.execute(:method => :options, :url => url, :headers => headers, **@@config, &block)
44
+ end
45
+ end
@@ -0,0 +1,12 @@
1
+ module Akido
2
+ module Generators
3
+ class SetupGenerator < Rails::Generators::Base
4
+ source_root File.expand_path('../templates', __FILE__)
5
+
6
+ def install_initializer
7
+ template 'initializer.rb', 'config/initializers/akido.rb'
8
+ end
9
+ end
10
+ end
11
+ end
12
+
@@ -0,0 +1,19 @@
1
+ config = {
2
+ :ssl_ca_file => "#{Rails.root}/config/ssl/ca.cert.pem"
3
+ }
4
+
5
+ if (cert_path = ENV["SSL_CERT_PATH"]) &&
6
+ File.exist?("#{Rails.root}/#{cert_path}")
7
+ raw_cert = File.read("#{Rails.root}/#{cert_path}")
8
+ cert = OpenSSL::X509::Certificate.new(raw_cert)
9
+ config[:ssl_client_cert] = cert
10
+ end
11
+
12
+ if (key_path = ENV['SSL_KEY_PATH']) &&
13
+ File.exist?("#{Rails.root}/#{key_path}")
14
+ raw_key = File.read("#{Rails.root}/#{key_path}")
15
+ key = OpenSSL::PKey::RSA.new(raw_key, ENV['SSL_KEY_PASSPHRASE'])
16
+ config[:ssl_client_key] = key
17
+ end
18
+
19
+ AkidoLib.setup(ENV['PLATFORM_URL'], config)
data/lib/query.rb ADDED
@@ -0,0 +1,86 @@
1
+ module AkidoLib
2
+ class Query
3
+ FILTERS = [
4
+ :content,
5
+ :id,
6
+ :last_updated,
7
+ :profile,
8
+ :query,
9
+ :security,
10
+ :tag,
11
+ :text,
12
+ :filter
13
+ ]
14
+
15
+ def initialize(resource, base_url)
16
+ @base_url = if base_url
17
+ base_url
18
+ elsif @@base_url
19
+ @@base_url
20
+ else
21
+ AkidoLib::Model
22
+ .client
23
+ .full_resource_url(:resource => @model)
24
+ end
25
+
26
+ @resource = resource
27
+ @query = []
28
+ end
29
+
30
+ def where(filters)
31
+ filters.each do |filter, value|
32
+ if FILTERS.include?(filter.to_s.underscore.downcase.to_sym)
33
+ @query.push({ "_#{filter.to_s.camelize(:lower)}".to_sym => value })
34
+ end
35
+ end
36
+
37
+ return self
38
+ end
39
+
40
+ def include(relation, options)
41
+ key = if options[:rev]
42
+ :_revinclude
43
+ else
44
+ :_include
45
+ end
46
+
47
+ @query.push({key => relation})
48
+ end
49
+
50
+ def last_updated(date)
51
+ @query.push({:_lastUpdated => date.xmlschema})
52
+ end
53
+
54
+ def custom(key, value)
55
+ @query.push({key => value})
56
+ end
57
+
58
+ def unset(key)
59
+ key = "_#{key.to_s.camelize(:lower)}".to_sym
60
+
61
+ @query.reject! do |param|
62
+ param.keys.include?(key)
63
+ end
64
+ end
65
+
66
+ def url
67
+ "#{@base_url}/#{resource_name}?#{query_string}"
68
+ end
69
+
70
+ def fetch!
71
+ end
72
+
73
+ def self.set_base_url!(base_url)
74
+ @@base_url = base_url
75
+ end
76
+
77
+ private
78
+ def resource_name
79
+ @resource.to_s.demodulize
80
+ end
81
+
82
+ def query_string
83
+ @query.map(&:to_query).join("&")
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,45 @@
1
+ module RestClient
2
+ @@config = {}
3
+
4
+ def self.get_config
5
+ @@config
6
+ end
7
+
8
+ def self.set_config(**config)
9
+ config.each do |key, value|
10
+ @@config[key] = value unless key == :url || key == :method
11
+ end
12
+ end
13
+
14
+ def self.clear_config
15
+ @@config = {}
16
+ end
17
+
18
+ def self.get(url, headers={}, &block)
19
+ Request.execute(:method => :get, :url => url, :headers => headers, **@@config, &block)
20
+ end
21
+
22
+ def self.post(url, payload, headers={}, &block)
23
+ Request.execute(:method => :post, :url => url, :payload => payload, :headers => headers, **@@config, &block)
24
+ end
25
+
26
+ def self.patch(url, payload, headers={}, &block)
27
+ Request.execute(:method => :patch, :url => url, :payload => payload, :headers => headers, **@@config, &block)
28
+ end
29
+
30
+ def self.put(url, payload, headers={}, &block)
31
+ Request.execute(:method => :put, :url => url, :payload => payload, :headers => headers, **@@config, &block)
32
+ end
33
+
34
+ def self.delete(url, headers={}, &block)
35
+ Request.execute(:method => :delete, :url => url, :headers => headers, **@@config, &block)
36
+ end
37
+
38
+ def self.head(url, headers={}, &block)
39
+ Request.execute(:method => :head, :url => url, :headers => headers, **@@config, &block)
40
+ end
41
+
42
+ def self.options(url, headers={}, &block)
43
+ Request.execute(:method => :options, :url => url, :headers => headers, **@@config, &block)
44
+ end
45
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :akido_lib do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: akido_lib
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Dean Tambling
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-05-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 5.1.6
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 5.1.6
27
+ - !ruby/object:Gem::Dependency
28
+ name: fhir_client
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.8.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.8.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: redis-objects
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Description of AkidoLib.
56
+ email:
57
+ - dean.tambling@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - README.md
63
+ - Rakefile
64
+ - lib/akido_lib.rb
65
+ - lib/akido_lib/version.rb
66
+ - lib/bundle.rb
67
+ - lib/caching.rb
68
+ - lib/ext/rest_client.rb
69
+ - lib/generators/akido/setup_generator.rb
70
+ - lib/generators/akido/templates/initializer.rb
71
+ - lib/query.rb
72
+ - lib/rest_client_config.rb
73
+ - lib/tasks/akido_lib_tasks.rake
74
+ homepage: http://akidolabs.com
75
+ licenses:
76
+ - MIT
77
+ metadata: {}
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubygems_version: 3.0.3.1
94
+ signing_key:
95
+ specification_version: 4
96
+ summary: Summary of AkidoLib.
97
+ test_files: []