Class: Dmp::DynamoAdapter
- Inherits:
-
Object
- Object
- Dmp::DynamoAdapter
- Defined in:
- lib/dmp/dynamo_adapter.rb
Overview
DMP adapter for an AWS DynamoDB Table rubocop:disable Metrics/ClassLength
Constant Summary collapse
- MSG_DEFAULT =
'Unable to process your request.'
- MSG_EXISTS =
'DMP already exists. Try :update instead.'
- MSG_NOT_FOUND =
'DMP does not exist.'
- MSG_FORBIDDEN =
'You cannot update the DMP.'
- MSG_NO_DMP_ID =
'A DMP ID could not be registered at this time.'
- MSG_UNKNOWN =
'DMP does not exist. Try :create instead.'
- MSG_NO_HISTORICALS =
'You cannot modify a historical version of the DMP.'
Instance Method Summary collapse
-
#create(json: {}) ⇒ Object
Add a record to the table rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity.
-
#delete(p_key:, json: {}) ⇒ Object
Delete/Tombstone a record in the table rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity.
-
#dmps_for_provenance ⇒ Object
Fetch the DMPs for the provenance rubocop:disable Metrics/MethodLength.
-
#find_by_json(json:) ⇒ Object
Find a DMP based on the contents of the incoming JSON rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity.
-
#find_by_pk(p_key:, s_key: Dmp::MetadataHandler::LATEST_VERSION) ⇒ Object
Find the DMP by its PK and SK.
-
#initialize(provenance:, debug: false) ⇒ DynamoAdapter
constructor
Initialize an instance by setting the provenance and connecting to the DB.
-
#update(p_key:, json: {}) ⇒ Object
Update a record in the table rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity.
Constructor Details
#initialize(provenance:, debug: false) ⇒ DynamoAdapter
Initialize an instance by setting the provenance and connecting to the DB
22 23 24 25 26 27 28 29 |
# File 'lib/dmp/dynamo_adapter.rb', line 22 def initialize(provenance:, debug: false) @provenance = Dmp::MetadataHandler.append_pk_prefix(provenance: provenance) @debug_mode = debug @client = Aws::DynamoDB::Client.new( region: ENV['AWS_REGION'] ) end |
Instance Method Details
#create(json: {}) ⇒ Object
Add a record to the table rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/dmp/dynamo_adapter.rb', line 101 def create(json: {}) json = prepare_json(json: json) return { status: 400, error: MSG_DEFAULT } if json.nil? || @provenance.nil? # Try to find it first result = find_by_json(json: json) return { status: 500, error: result.fetch(:error, MSG_DEFAULT) } if result[:status] == 500 # Abort if found return { status: 400, error: MSG_EXISTS } if result.fetch(:items, []).any? # allocate a DMP ID p_key = preregister_dmp_id p "PRE REGISTERED DMP ID: #{p_key.inspect}" return { status: 500, error: MSG_NO_DMP_ID } if p_key.nil? # Add the DMPHub specific attributes and then save json = Dmp::MetadataHandler.annotate_json(provenance: @provenance, json: json, p_key: p_key) p "ANNOTATED:" pp json p "PUTTING ITEM:" response = @client.put_item( { table_name: ENV['AWS_DYNAMO_TABLE_NAME'], item: json, return_consumed_capacity: @debug_mode ? 'TOTAL' : 'NONE' } ) # Fetch the newly created record response = find_by_pk(p_key: p_key, s_key: Dmp::MetadataHandler::LATEST_VERSION) return { status: 500, error: MSG_DEFAULT } unless response[:status] == 200 p 'CREATED!?' pp response[:items] { status: 201, items: response[:items] } rescue Aws::DynamoDB::Errors::DuplicateItemException { status: 405, error: MSG_EXISTS } rescue Aws::Errors::ServiceError => e { status: 500, error: "#{MSG_DEFAULT} - #{e.}" } end |
#delete(p_key:, json: {}) ⇒ Object
Delete/Tombstone a record in the table rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
# File 'lib/dmp/dynamo_adapter.rb', line 207 def delete(p_key:, json: {}) json = prepare_json(json: json) return { status: 400, error: MSG_DEFAULT } if json.nil? || p_key.nil? || @provenance.nil? # Verify that the JSON is for the same DMP in the PK dmp_id = json.fetch('dmp_id', {}) return { status: 403, error: MSG_FORBIDDEN } unless Dmp::DmpIdHandler.dmp_id_to_pk(json: dmp_id) == p_key # Try to find it first result = find_by_json(json: json) return { status: 500, error: result.fetch(:error, MSG_DEFAULT) } if result[:status] == 500 # Abort if NOT found return { status: 404, error: MSG_NOT_FOUND } unless result[:status] == 200 && result.fetch(:items, []).any? dmp = result[:items].first&.item return { status: 404, error: MSG_NOT_FOUND } if dmp.nil? # Only allow this if the provenance is the owner of the DMP! return { status: 403, error: MSG_FORBIDDEN } unless dmp['dmphub_provenance_id'] == @provenance # Make sure they're not trying to update a historical copy of the DMP return { status: 405, error: MSG_NO_HISTORICALS } if dmp['SK'] != Dmp::MetadataHandler::LATEST_VERSION response = @client.update_item( { table_name: ENV['AWS_DYNAMO_TABLE_NAME'], key: { PK: dmp['PK'], SK: Dmp::MetadataHandler::LATEST_VERSION }, update_expression: 'SET SK = :sk, dmphub_deleted_at = :deletion_date', expression_attribute_values: { sk: Dmp::MetadataHandler::TOMBSTONE_VERSION, deletion_date: Time.now.iso8601 }, return_consumed_capacity: @debug_mode ? 'TOTAL' : 'NONE', return_values: 'ALL_NEW' } ) { status: 200, items: response.items.map(&:item).compact.uniq } rescue Aws::Errors::ServiceError => e { status: 500, error: "#{MSG_DEFAULT} - #{e.}" } end |
#dmps_for_provenance ⇒ Object
Fetch the DMPs for the provenance rubocop:disable Metrics/MethodLength
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/dmp/dynamo_adapter.rb', line 33 def dmps_for_provenance return { status: 404, error: MSG_NOT_FOUND } if @provenance.nil? response = @client.query( { table_name: ENV['AWS_DYNAMO_TABLE_NAME'], key_conditions: { PK: { attribute_value_list: ["PROVENANCE##{@provenance}"], comparison_operator: 'EQ' }, SK: { attribute_value_list: ['DMPS'], comparison_operator: 'EQ' } } } ) { status: 200, items: response.items.map(&:item).compact.uniq } rescue Aws::Errors::ServiceError => e { status: 500, error: "#{MSG_DEFAULT} - #{e.}" } end |
#find_by_json(json:) ⇒ Object
Find a DMP based on the contents of the incoming JSON rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/dmp/dynamo_adapter.rb', line 82 def find_by_json(json:) return { status: 404, error: MSG_NOT_FOUND } if json.nil? || (json['PK'].nil? && json['dmp_id'].nil?) pk = json['PK'] # Translate the incoming :dmp_id into a PK pk = Dmp::DmpIdHandler.dmp_id_to_pk(json: json.fetch('dmp_id', {})) if pk.nil? # find_by_PK response = find_by_pk(p_key: pk, s_key: json['SK']) unless pk.nil? return response unless response[:status] != 404 # find_by_dmphub_provenance_id -> if no PK and no dmp_id result find_by_dmphub_provenance_identifier(json: json) end |
#find_by_pk(p_key:, s_key: Dmp::MetadataHandler::LATEST_VERSION) ⇒ Object
Find the DMP by its PK and SK
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/dmp/dynamo_adapter.rb', line 58 def find_by_pk(p_key:, s_key: Dmp::MetadataHandler::LATEST_VERSION) return { status: 404, error: MSG_NOT_FOUND } if p_key.nil? s_key = Dmp::MetadataHandler::LATEST_VERSION if s_key.nil? || s_key.strip == '' p "FINDING BY PK: PK - #{p_key.inspect} / SK - #{s_key.inspect}" response = @client.get_item( { table_name: ENV['AWS_DYNAMO_TABLE_NAME'], key: { PK: p_key, SK: s_key }, consistent_read: false, return_consumed_capacity: @debug_mode ? 'TOTAL' : 'NONE' } ) return { status: 404, error: MSG_NOT_FOUND } if response[:item].nil? || response[:item].empty? { status: 200, items: [response[:item]] } rescue Aws::Errors::ServiceError => e { status: 500, error: "#{MSG_DEFAULT} - #{e.}" } end |
#update(p_key:, json: {}) ⇒ Object
Update a record in the table rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/dmp/dynamo_adapter.rb', line 149 def update(p_key:, json: {}) json = prepare_json(json: json) return { status: 400, error: MSG_DEFAULT } if json.nil? || p_key.nil? || @provenance.nil? # Verify that the JSON is for the same DMP in the PK dmp_id = json.fetch('dmp_id', {}) return { status: 403, error: MSG_FORBIDDEN } unless Dmp::DmpIdHandler.dmp_id_to_pk(json: dmp_id) == p_key # Try to find it first result = find_by_json(json: json) return { status: 500, error: result.fetch(:error, MSG_DEFAULT) } if result[:status] == 500 dmp = result[:items].first&.item return { status: 404, error: MSG_NOT_FOUND } if dmp.nil? # Only allow this if the provenance is the owner of the DMP! return { status: 403, error: MSG_FORBIDDEN } unless dmp['dmphub_provenance_id'] == @provenance # Make sure they're not trying to update a historical copy of the DMP return { status: 405, error: MSG_NO_HISTORICALS } if dmp['SK'] != Dmp::MetadataHandler::LATEST_VERSION # version the old :latest version_result = version_it(dmp: dmp) return version_result if version_result[:status] != 200 # Add the DMPHub specific attributes and then save it json = Dmp::MetadataHandler.annotate_json(provenance: @provenance, json: json, p_key: p_key) p "BEFORE:" pp json p '===================================' p '' json = splice_json(original_version: version_result[:items].first&.item, new_version: json) # p '' p "AFTER:" pp json response = @client.put_item( { table_name: ENV['AWS_DYNAMO_TABLE_NAME'], item: json, return_consumed_capacity: @debug_mode ? 'TOTAL' : 'NONE' } ) # Update the provenance keys! # Update the ancillary keys for orcids, affiliations, provenance { status: 200, items: response.items.map(&:item).compact.uniq } rescue Aws::DynamoDB::Errors::DuplicateItemException { status: 405, error: MSG_EXISTS } rescue Aws::Errors::ServiceError => e { status: 500, error: "#{MSG_DEFAULT} - #{e.}" } end |