lutaml 0.10.1 → 0.10.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
2
  SHA256:
3
- metadata.gz: 380893deae7b963ad1177e3cec77bcb1752dfb15efd8560a952535e58bdec608
4
- data.tar.gz: cab5e523724906b6a9ff202a335195c73b7762521acc8550705b1fae66784edf
3
+ metadata.gz: ded60358e2c376c21bdb7ebf2c7f64b3aa679b33110da44a42e52f1e65cf5d8c
4
+ data.tar.gz: 15dc9978e43a8a6d58d351593ee51121d97400c601b9af614873407a4ba850db
5
5
  SHA512:
6
- metadata.gz: 7332ae8e47d87b493f825a017aef535f9002997dd729b8b7f858e7361225aab4e20428bb64e208ff4b46d4335e166566c4277c68b9a04e0874197aeb42acd475
7
- data.tar.gz: 864cbb3fc456851627645c86083c08e52599c65dd2867f4014f956b114708fe952ccb97c00a526f2d41b2d9c7d725f8b990081b1a30ddaae899fd89c9dc65e01
6
+ metadata.gz: eca6cd5f0852c060a99b8a7b0535d72fff5012ac4b1ac2a882b80a0dd0908cb8fe765a9ab4f2b2d0e62ba5a63b922b250c3075389beebe3a56aab5d0be9ca836
7
+ data.tar.gz: fc00eca740523779c80a84d95b42cd93ff0b5e7bd407f42326c833db26317eaedad6917c409c6286e9f1c60bf47d0a00bad2e3f6fc1dfaed31db9a884126406f
data/.rubocop_todo.yml CHANGED
@@ -1,46 +1,137 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2026-04-20 02:27:04 UTC using RuboCop version 1.86.1.
3
+ # on 2026-04-24 10:12:08 UTC using RuboCop version 1.86.1.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
7
7
  # versions of RuboCop, may require this file to be generated again.
8
8
 
9
- # Offense count: 11
9
+ # Offense count: 28
10
10
  # This cop supports safe autocorrection (--autocorrect).
11
- # Configuration parameters: TreatCommentsAsGroupSeparators, ConsiderPunctuation.
12
- Bundler/OrderedGems:
11
+ # Configuration parameters: EnforcedStyle, IndentationWidth.
12
+ # SupportedStyles: with_first_argument, with_fixed_indentation
13
+ Layout/ArgumentAlignment:
13
14
  Exclude:
14
- - 'Gemfile'
15
+ - 'lib/lutaml/qea/database.rb'
16
+ - 'spec/lutaml/qea/database_spec.rb'
17
+ - 'spec/lutaml/qea/factory/class_transformer_spec.rb'
18
+ - 'spec/lutaml/qea/factory/package_transformer_spec.rb'
19
+ - 'spec/lutaml/qea/verification/comprehensive_equivalence_spec.rb'
15
20
 
16
21
  # Offense count: 2
17
22
  # This cop supports safe autocorrection (--autocorrect).
18
- Layout/ClosingParenthesisIndentation:
23
+ # Configuration parameters: EnforcedStyle, IndentationWidth.
24
+ # SupportedStyles: with_first_element, with_fixed_indentation
25
+ Layout/ArrayAlignment:
19
26
  Exclude:
20
- - 'lib/lutaml/qea/verification/document_verifier.rb'
27
+ - 'spec/lutaml/qea/verification/equivalence_integration_spec.rb'
21
28
 
22
29
  # Offense count: 2
23
30
  # This cop supports safe autocorrection (--autocorrect).
24
- # Configuration parameters: EnforcedStyle, IndentationWidth.
25
- # SupportedStyles: consistent, consistent_relative_to_receiver, special_for_inner_method_call, special_for_inner_method_call_in_parentheses
26
- Layout/FirstArgumentIndentation:
31
+ # Configuration parameters: EnforcedStyleAlignWith.
32
+ # SupportedStylesAlignWith: either, start_of_block, start_of_line
33
+ Layout/BlockAlignment:
34
+ Exclude:
35
+ - 'lib/lutaml/uml_repository/queries/class_query.rb'
36
+ - 'spec/lutaml/qea/verification/equivalence_integration_spec.rb'
37
+
38
+ # Offense count: 1
39
+ # This cop supports safe autocorrection (--autocorrect).
40
+ Layout/BlockEndNewline:
41
+ Exclude:
42
+ - 'spec/lutaml/qea/verification/equivalence_integration_spec.rb'
43
+
44
+ # Offense count: 2
45
+ # This cop supports safe autocorrection (--autocorrect).
46
+ # Configuration parameters: AllowForAlignment.
47
+ Layout/CommentIndentation:
48
+ Exclude:
49
+ - 'lib/lutaml/qea/factory/class_transformer.rb'
50
+
51
+ # Offense count: 2
52
+ # This cop supports safe autocorrection (--autocorrect).
53
+ Layout/ElseAlignment:
54
+ Exclude:
55
+ - 'lib/lutaml/qea/factory/class_transformer.rb'
56
+ - 'lib/lutaml/uml_repository/queries/class_query.rb'
57
+
58
+ # Offense count: 1
59
+ # This cop supports safe autocorrection (--autocorrect).
60
+ # Configuration parameters: EmptyLineBetweenMethodDefs, EmptyLineBetweenClassDefs, EmptyLineBetweenModuleDefs, DefLikeMacros, AllowAdjacentOneLineDefs, NumberOfEmptyLines.
61
+ Layout/EmptyLineBetweenDefs:
62
+ Exclude:
63
+ - 'lib/lutaml/uml_repository/statistics_calculator.rb'
64
+
65
+ # Offense count: 1
66
+ # This cop supports safe autocorrection (--autocorrect).
67
+ Layout/EmptyLines:
68
+ Exclude:
69
+ - 'lib/lutaml/uml_repository/statistics_calculator.rb'
70
+
71
+ # Offense count: 2
72
+ # This cop supports safe autocorrection (--autocorrect).
73
+ # Configuration parameters: EnforcedStyle.
74
+ # SupportedStyles: empty_lines, no_empty_lines
75
+ Layout/EmptyLinesAroundBlockBody:
76
+ Exclude:
77
+ - 'lib/lutaml/qea/factory/class_transformer.rb'
78
+ - 'lib/lutaml/qea/factory/enum_transformer.rb'
79
+
80
+ # Offense count: 1
81
+ # This cop supports safe autocorrection (--autocorrect).
82
+ # Configuration parameters: EnforcedStyleAlignWith.
83
+ # SupportedStylesAlignWith: keyword, variable, start_of_line
84
+ Layout/EndAlignment:
85
+ Exclude:
86
+ - 'lib/lutaml/qea/factory/class_transformer.rb'
87
+
88
+ # Offense count: 16
89
+ # This cop supports safe autocorrection (--autocorrect).
90
+ # Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
91
+ # SupportedHashRocketStyles: key, separator, table
92
+ # SupportedColonStyles: key, separator, table
93
+ # SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
94
+ Layout/HashAlignment:
95
+ Exclude:
96
+ - 'spec/lutaml/qea/factory/class_transformer_spec.rb'
97
+ - 'spec/lutaml/qea/factory/package_transformer_spec.rb'
98
+
99
+ # Offense count: 1
100
+ # This cop supports safe autocorrection (--autocorrect).
101
+ # Configuration parameters: EnforcedStyle.
102
+ # SupportedStyles: normal, indented_internal_methods
103
+ Layout/IndentationConsistency:
27
104
  Exclude:
28
- - 'lib/lutaml/qea/verification/document_verifier.rb'
105
+ - 'lib/lutaml/qea/factory/class_transformer.rb'
106
+
107
+ # Offense count: 6
108
+ # This cop supports safe autocorrection (--autocorrect).
109
+ # Configuration parameters: Width, EnforcedStyleAlignWith, AllowedPatterns.
110
+ # SupportedStylesAlignWith: start_of_line, relative_to_receiver
111
+ Layout/IndentationWidth:
112
+ Exclude:
113
+ - 'lib/lutaml/qea/factory/class_transformer.rb'
114
+ - 'lib/lutaml/uml_repository/queries/class_query.rb'
115
+ - 'spec/lutaml/qea/verification/equivalence_integration_spec.rb'
29
116
 
30
- # Offense count: 63
117
+ # Offense count: 99
31
118
  # This cop supports safe autocorrection (--autocorrect).
32
119
  # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
33
120
  # URISchemes: http, https
34
121
  Layout/LineLength:
35
122
  Enabled: false
36
123
 
37
- # Offense count: 2
124
+ # Offense count: 22
38
125
  # This cop supports safe autocorrection (--autocorrect).
39
- # Configuration parameters: EnforcedStyle.
40
- # SupportedStyles: symmetrical, new_line, same_line
41
- Layout/MultilineMethodCallBraceLayout:
126
+ # Configuration parameters: AllowInHeredoc.
127
+ Layout/TrailingWhitespace:
42
128
  Exclude:
43
- - 'lib/lutaml/qea/verification/document_verifier.rb'
129
+ - 'lib/lutaml/qea/database.rb'
130
+ - 'spec/lutaml/qea/database_spec.rb'
131
+ - 'spec/lutaml/qea/factory/class_transformer_spec.rb'
132
+ - 'spec/lutaml/qea/factory/package_transformer_spec.rb'
133
+ - 'spec/lutaml/qea/verification/comprehensive_equivalence_spec.rb'
134
+ - 'spec/lutaml/qea/verification/equivalence_integration_spec.rb'
44
135
 
45
136
  # Offense count: 1
46
137
  Lint/BinaryOperatorWithIdenticalOperands:
@@ -58,6 +149,11 @@ Lint/ConstantDefinitionInBlock:
58
149
  - 'spec/lutaml/model_transformations_spec.rb'
59
150
  - 'spec/lutaml/uml_repository/presenters/presenter_factory_spec.rb'
60
151
 
152
+ # Offense count: 1
153
+ Lint/CopDirectiveSyntax:
154
+ Exclude:
155
+ - 'lib/lutaml/uml_repository/repository.rb'
156
+
61
157
  # Offense count: 8
62
158
  # Configuration parameters: IgnoreLiteralBranches, IgnoreConstantBranches, IgnoreDuplicateElseBranch.
63
159
  Lint/DuplicateBranch:
@@ -107,13 +203,24 @@ Lint/UnusedMethodArgument:
107
203
  Exclude:
108
204
  - 'lib/lutaml/cli/uml/export_command.rb'
109
205
 
110
- # Offense count: 3
206
+ # Offense count: 1
207
+ # This cop supports safe autocorrection (--autocorrect).
208
+ # Configuration parameters: ContextCreatingMethods, MethodCreatingMethods.
209
+ Lint/UselessAccessModifier:
210
+ Exclude:
211
+ - 'lib/lutaml/uml_repository/statistics_calculator.rb'
212
+
213
+ # Offense count: 8
111
214
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
112
215
  Metrics/AbcSize:
113
216
  Exclude:
217
+ - 'lib/lutaml/converter/xmi_to_uml.rb'
114
218
  - 'lib/lutaml/model_transformations/parsers/base_parser.rb'
219
+ - 'lib/lutaml/qea/database.rb'
115
220
  - 'lib/lutaml/uml_repository/index_builder.rb'
221
+ - 'lib/lutaml/uml_repository/queries/class_query.rb'
116
222
  - 'lib/lutaml/uml_repository/queries/inheritance_query.rb'
223
+ - 'lib/lutaml/xmi/parsers/xmi_base.rb'
117
224
 
118
225
  # Offense count: 1
119
226
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
@@ -121,26 +228,36 @@ Metrics/AbcSize:
121
228
  Metrics/BlockLength:
122
229
  Max: 28
123
230
 
124
- # Offense count: 4
231
+ # Offense count: 11
125
232
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
126
233
  Metrics/CyclomaticComplexity:
127
234
  Exclude:
128
235
  - 'lib/lutaml/cli/tree_view_formatter.rb'
129
236
  - 'lib/lutaml/converter/xmi_to_uml.rb'
237
+ - 'lib/lutaml/qea/database.rb'
238
+ - 'lib/lutaml/qea/factory/enum_transformer.rb'
239
+ - 'lib/lutaml/uml_repository/index_builder.rb'
240
+ - 'lib/lutaml/uml_repository/queries/class_query.rb'
130
241
  - 'lib/lutaml/uml_repository/queries/inheritance_query.rb'
131
242
  - 'lib/lutaml/uml_repository/queries/search_query.rb'
243
+ - 'lib/lutaml/xmi/parsers/xmi_base.rb'
132
244
 
133
- # Offense count: 5
245
+ # Offense count: 11
134
246
  # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
135
247
  Metrics/MethodLength:
136
- Max: 14
248
+ Max: 27
137
249
 
138
- # Offense count: 2
250
+ # Offense count: 8
139
251
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
140
252
  Metrics/PerceivedComplexity:
141
253
  Exclude:
254
+ - 'lib/lutaml/converter/xmi_to_uml.rb'
255
+ - 'lib/lutaml/qea/database.rb'
142
256
  - 'lib/lutaml/qea/factory/enum_transformer.rb'
257
+ - 'lib/lutaml/uml_repository/index_builder.rb'
258
+ - 'lib/lutaml/uml_repository/queries/class_query.rb'
143
259
  - 'lib/lutaml/uml_repository/queries/inheritance_query.rb'
260
+ - 'lib/lutaml/xmi/parsers/xmi_base.rb'
144
261
 
145
262
  # Offense count: 2
146
263
  # Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
@@ -158,10 +275,11 @@ Naming/PredicateMethod:
158
275
  Exclude:
159
276
  - 'lib/lutaml/qea/factory/document_builder.rb'
160
277
 
161
- # Offense count: 4
278
+ # Offense count: 5
162
279
  # Configuration parameters: MinSize.
163
280
  Performance/CollectionLiteralInLoop:
164
281
  Exclude:
282
+ - 'lib/lutaml/xmi/parsers/xmi_base.rb'
165
283
  - 'spec/lutaml/qea/infrastructure/table_reader_spec.rb'
166
284
  - 'spec/lutaml/uml_repository/index_builder_spec.rb'
167
285
  - 'spec/lutaml/uml_repository/queries/inheritance_query_spec.rb'
@@ -206,7 +324,7 @@ RSpec/ContextWording:
206
324
  RSpec/DescribeClass:
207
325
  Enabled: false
208
326
 
209
- # Offense count: 651
327
+ # Offense count: 656
210
328
  # Configuration parameters: CountAsOne.
211
329
  RSpec/ExampleLength:
212
330
  Max: 108
@@ -236,7 +354,7 @@ RSpec/IndexedLet:
236
354
  - 'spec/lutaml/qea/repositories/base_repository_spec.rb'
237
355
  - 'spec/lutaml/qea/repositories/object_repository_spec.rb'
238
356
 
239
- # Offense count: 26
357
+ # Offense count: 48
240
358
  # Configuration parameters: AssignmentOnly.
241
359
  RSpec/InstanceVariable:
242
360
  Exclude:
@@ -274,11 +392,11 @@ RSpec/MessageSpies:
274
392
  - 'spec/lutaml/uml_repository/presenters/diagram_presenter_spec.rb'
275
393
  - 'spec/lutaml/uml_repository/repository_spec.rb'
276
394
 
277
- # Offense count: 943
395
+ # Offense count: 945
278
396
  RSpec/MultipleExpectations:
279
397
  Max: 26
280
398
 
281
- # Offense count: 118
399
+ # Offense count: 130
282
400
  # Configuration parameters: AllowSubject.
283
401
  RSpec/MultipleMemoizedHelpers:
284
402
  Max: 11
@@ -347,6 +465,17 @@ Security/MarshalLoad:
347
465
  - 'lib/lutaml/uml_repository/package_loader.rb'
348
466
  - 'spec/lutaml/uml_repository/package_exporter_spec.rb'
349
467
 
468
+ # Offense count: 1
469
+ # This cop supports safe autocorrection (--autocorrect).
470
+ # Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, AllowedMethods, AllowedPatterns, AllowBracesOnProceduralOneLiners, BracesRequiredMethods.
471
+ # SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces
472
+ # ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object
473
+ # FunctionalMethods: let, let!, subject, watch
474
+ # AllowedMethods: lambda, proc, it
475
+ Style/BlockDelimiters:
476
+ Exclude:
477
+ - 'spec/lutaml/qea/verification/equivalence_integration_spec.rb'
478
+
350
479
  # Offense count: 2
351
480
  # This cop supports safe autocorrection (--autocorrect).
352
481
  Style/ComparableClamp:
@@ -364,6 +493,19 @@ Style/EvalWithLocation:
364
493
  Exclude:
365
494
  - 'spec/lutaml/cli/uml/search_command_spec.rb'
366
495
 
496
+ # Offense count: 2
497
+ # This cop supports unsafe autocorrection (--autocorrect-all).
498
+ Style/IdenticalConditionalBranches:
499
+ Exclude:
500
+ - 'lib/lutaml/qea/factory/class_transformer.rb'
501
+
502
+ # Offense count: 1
503
+ # This cop supports safe autocorrection (--autocorrect).
504
+ # Configuration parameters: AllowIfModifier.
505
+ Style/IfInsideElse:
506
+ Exclude:
507
+ - 'lib/lutaml/uml_repository/queries/class_query.rb'
508
+
367
509
  # Offense count: 1
368
510
  # This cop supports unsafe autocorrection (--autocorrect-all).
369
511
  Style/PartitionInsteadOfDoubleSelect:
@@ -376,3 +518,11 @@ Style/SafeNavigationChainLength:
376
518
  Exclude:
377
519
  - 'lib/lutaml/qea/validation/attribute_validator.rb'
378
520
  - 'lib/lutaml/qea/validation/operation_validator.rb'
521
+
522
+ # Offense count: 1
523
+ # This cop supports safe autocorrection (--autocorrect).
524
+ # Configuration parameters: EnforcedStyle, MinSize.
525
+ # SupportedStyles: percent, brackets
526
+ Style/SymbolArray:
527
+ Exclude:
528
+ - 'lib/lutaml/xmi/parsers/xmi_base.rb'
data/Gemfile CHANGED
@@ -9,7 +9,6 @@ gem "parsanol", "1.3.9"
9
9
 
10
10
  gem "canon"
11
11
  gem "lutaml-model", github: "lutaml/lutaml-model", branch: "main"
12
- gem "moxml", github: "lutaml/moxml", branch: "main"
13
12
  gem "openssl", "~> 3.0"
14
13
  gem "rack-test"
15
14
  gem "rake"
@@ -126,9 +126,7 @@ module Lutaml
126
126
  def create_uml_diagrams(node_id) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
127
127
  return [] if @xmi_root_model.extension&.diagrams&.diagram.nil?
128
128
 
129
- diagrams = @xmi_root_model.extension.diagrams.diagram.select do |d|
130
- d.model.package == node_id
131
- end
129
+ diagrams = diagram_lookup[node_id]
132
130
 
133
131
  diagrams.map do |diagram|
134
132
  ::Lutaml::Uml::Diagram.new.tap do |dia|
@@ -145,6 +143,17 @@ module Lutaml
145
143
  end
146
144
  end
147
145
 
146
+ # Lazy-built hash index for O(1) diagram lookups by package
147
+ # @return [Hash] Mapping of package_id => [diagrams]
148
+ def diagram_lookup
149
+ @diagram_lookup ||= begin
150
+ idx = Hash.new { |h, k| h[k] = [] }
151
+ diagrams = @xmi_root_model.extension&.diagrams&.diagram || []
152
+ diagrams.each { |d| idx[d.model.package] << d if d.model&.package }
153
+ idx
154
+ end
155
+ end
156
+
148
157
  def create_uml_class_attributes(klass) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength
149
158
  return [] if klass.owned_attribute.nil?
150
159
 
@@ -268,7 +268,9 @@ module Lutaml
268
268
  # @param id [Integer] Package ID
269
269
  # @return [Models::EaPackage, nil] The package or nil if not found
270
270
  def find_package(id)
271
- packages.find { |pkg| pkg.package_id == id }
271
+ @packages_by_id ||= build_group_index(packages, :package_id,
272
+ single: true)
273
+ @packages_by_id[id]
272
274
  end
273
275
 
274
276
  # Find an attribute by ID
@@ -276,7 +278,8 @@ module Lutaml
276
278
  # @param id [Integer] Attribute ID
277
279
  # @return [Models::EaAttribute, nil] The attribute or nil if not found
278
280
  def find_attribute(id)
279
- attributes.find { |attr| attr.id == id }
281
+ @attributes_by_id ||= build_group_index(attributes, :id, single: true)
282
+ @attributes_by_id[id]
280
283
  end
281
284
 
282
285
  # Find a connector by ID
@@ -284,7 +287,9 @@ module Lutaml
284
287
  # @param id [Integer] Connector ID
285
288
  # @return [Models::EaConnector, nil] The connector or nil if not found
286
289
  def find_connector(id)
287
- connectors.find { |conn| conn.connector_id == id }
290
+ @connectors_by_id ||= build_group_index(connectors, :connector_id,
291
+ single: true)
292
+ @connectors_by_id[id]
288
293
  end
289
294
 
290
295
  # Find a diagram by ID
@@ -292,7 +297,9 @@ module Lutaml
292
297
  # @param id [Integer] Diagram ID
293
298
  # @return [Models::EaDiagram, nil] The diagram or nil if not found
294
299
  def find_diagram(id)
295
- diagrams.find { |diag| diag.diagram_id == id }
300
+ @diagrams_by_id ||= build_group_index(diagrams, :diagram_id,
301
+ single: true)
302
+ @diagrams_by_id[id]
296
303
  end
297
304
 
298
305
  # Check if database is empty
@@ -309,6 +316,102 @@ module Lutaml
309
316
  @collections.keys
310
317
  end
311
318
 
319
+ # Find object by ea_guid
320
+ #
321
+ # @param ea_guid [String] Object GUID
322
+ # @return [Models::EaObject, nil] The object or nil if not found
323
+ def find_object_by_guid(ea_guid)
324
+ @objects_by_guid ||= build_group_index(objects, :ea_guid, single: true)
325
+ @objects_by_guid[ea_guid]
326
+ end
327
+
328
+ # Get attributes for a specific object
329
+ #
330
+ # @param object_id [Integer] Object ID
331
+ # @return [Array<Models::EaAttribute>] Attributes for the object
332
+ def attributes_for_object(object_id)
333
+ @attributes_by_object_id ||= build_group_index(attributes,
334
+ :ea_object_id)
335
+ @attributes_by_object_id[object_id] || []
336
+ end
337
+
338
+ # Get operations for a specific object
339
+ #
340
+ # @param object_id [Integer] Object ID
341
+ # @return [Array<Models::EaOperation>] Operations for the object
342
+ def operations_for_object(object_id)
343
+ @operations_by_object_id ||= build_group_index(operations,
344
+ :ea_object_id)
345
+ @operations_by_object_id[object_id] || []
346
+ end
347
+
348
+ # Get operation parameters for a specific operation
349
+ #
350
+ # @param operation_id [Integer] Operation ID
351
+ # @return [Array<Models::EaOperationParam>] Parameters for the operation
352
+ def operation_params_for(operation_id)
353
+ @operation_params_by_id ||= build_group_index(operation_params,
354
+ :operationid)
355
+ @operation_params_by_id[operation_id] || []
356
+ end
357
+
358
+ # Get connectors involving a specific object (start or end)
359
+ #
360
+ # @param object_id [Integer] Object ID
361
+ # @return [Array<Models::EaConnector>] Connectors for the object
362
+ def connectors_for_object(object_id)
363
+ @connectors_by_start ||= build_group_index(connectors, :start_object_id)
364
+ @connectors_by_end ||= build_group_index(connectors, :end_object_id)
365
+ (@connectors_by_start[object_id] || []) +
366
+ (@connectors_by_end[object_id] || [])
367
+ end
368
+
369
+ # Get child packages for a parent
370
+ #
371
+ # @param parent_id [Integer] Parent package ID
372
+ # @return [Array<Models::EaPackage>] Child packages
373
+ def child_packages_for(parent_id)
374
+ @packages_by_parent ||= build_group_index(packages, :parent_id)
375
+ @packages_by_parent[parent_id] || []
376
+ end
377
+
378
+ # Get objects in a specific package
379
+ #
380
+ # @param package_id [Integer] Package ID
381
+ # @return [Array<Models::EaObject>] Objects in the package
382
+ def objects_in_package(package_id)
383
+ @objects_by_package_id ||= build_group_index(objects, :package_id)
384
+ @objects_by_package_id[package_id] || []
385
+ end
386
+
387
+ # Get diagrams in a specific package
388
+ #
389
+ # @param package_id [Integer] Package ID
390
+ # @return [Array<Models::EaDiagram>] Diagrams in the package
391
+ def diagrams_in_package(package_id)
392
+ @diagrams_by_package_id ||= build_group_index(diagrams, :package_id)
393
+ @diagrams_by_package_id[package_id] || []
394
+ end
395
+
396
+ # Get diagram objects for a specific diagram
397
+ #
398
+ # @param diagram_id [Integer] Diagram ID
399
+ # @return [Array<Models::EaDiagramObject>] Diagram objects
400
+ def diagram_objects_for(diagram_id)
401
+ @diagram_objects_by_id ||= build_group_index(diagram_objects,
402
+ :diagram_id)
403
+ @diagram_objects_by_id[diagram_id] || []
404
+ end
405
+
406
+ # Get diagram links for a specific diagram
407
+ #
408
+ # @param diagram_id [Integer] Diagram ID
409
+ # @return [Array<Models::EaDiagramLink>] Diagram links
410
+ def diagram_links_for(diagram_id)
411
+ @diagram_links_by_id ||= build_group_index(diagram_links, :diagramid)
412
+ @diagram_links_by_id[diagram_id] || []
413
+ end
414
+
312
415
  # Freeze all collections to make database immutable
313
416
  #
314
417
  # @return [self]
@@ -316,9 +419,59 @@ module Lutaml
316
419
  # Memoize repositories before freezing
317
420
  objects
318
421
 
422
+ # Eagerly build all lookup indexes before freezing
423
+ build_lookup_indexes
424
+
319
425
  @collections.freeze
320
426
  super
321
427
  end
428
+
429
+ private
430
+
431
+ # Build a group index from a collection by a given attribute.
432
+ # BaseRepository overrides group_by to take a symbol (not a block),
433
+ # so we use each_with_object instead.
434
+ #
435
+ # @param collection [Array] Collection to index
436
+ # @param method [Symbol] Attribute method to group by
437
+ # @param single [Boolean] If true, return single object (last match)
438
+ # instead of array
439
+ # @return [Hash] Group index
440
+ def build_group_index(collection, method, single: false)
441
+ if single
442
+ collection.each_with_object({}) do |item, hash|
443
+ key = item.send(method)
444
+ hash[key] = item if key
445
+ end
446
+ else
447
+ collection.each_with_object({}) do |item, hash|
448
+ key = item.send(method)
449
+ (hash[key] ||= []) << item if key
450
+ end
451
+ end
452
+ end
453
+
454
+ # Eagerly build all lazy lookup indexes before freezing
455
+ def build_lookup_indexes
456
+ @objects_by_guid = build_group_index(objects, :ea_guid, single: true)
457
+ @attributes_by_object_id = build_group_index(attributes, :ea_object_id)
458
+ @operations_by_object_id = build_group_index(operations, :ea_object_id)
459
+ @operation_params_by_id = build_group_index(operation_params,
460
+ :operationid)
461
+ @connectors_by_start = build_group_index(connectors, :start_object_id)
462
+ @connectors_by_end = build_group_index(connectors, :end_object_id)
463
+ @packages_by_parent = build_group_index(packages, :parent_id)
464
+ @objects_by_package_id = build_group_index(objects, :package_id)
465
+ @diagrams_by_package_id = build_group_index(diagrams, :package_id)
466
+ @diagram_objects_by_id = build_group_index(diagram_objects, :diagram_id)
467
+ @diagram_links_by_id = build_group_index(diagram_links, :diagramid)
468
+ # Also build hash indexes for find_* methods
469
+ @packages_by_id = build_group_index(packages, :package_id, single: true)
470
+ @connectors_by_id = build_group_index(connectors, :connector_id,
471
+ single: true)
472
+ @diagrams_by_id = build_group_index(diagrams, :diagram_id, single: true)
473
+ @attributes_by_id = build_group_index(attributes, :id, single: true)
474
+ end
322
475
  end
323
476
  end
324
477
  end
@@ -71,11 +71,7 @@ module Lutaml
71
71
  def find_object(object_id)
72
72
  return nil if object_id.nil?
73
73
 
74
- query = "SELECT * FROM t_object WHERE Object_ID = ?"
75
- rows = database.connection.execute(query, object_id)
76
- return nil if rows.empty?
77
-
78
- Models::EaObject.from_db_row(rows.first)
74
+ database.find_object(object_id)
79
75
  end
80
76
 
81
77
  # Build cardinality from string
@@ -55,16 +55,10 @@ module Lutaml
55
55
  def lookup_type_xmi_id(classifier_id) # rubocop:disable Metrics/AbcSize
56
56
  return nil if classifier_id.nil? || classifier_id.to_i.zero?
57
57
 
58
- query = "SELECT ea_guid FROM t_object WHERE Object_ID = ?"
59
- rows = database.connection.execute(query, [classifier_id])
60
- return nil if rows.empty?
61
-
62
- ea_guid = if rows.first.is_a?(Hash)
63
- rows.first["ea_guid"] || rows.first[:ea_guid]
64
- else
65
- rows.first[0]
66
- end
67
- normalize_guid_to_xmi_format(ea_guid, "EAID")
58
+ obj = database.find_object(classifier_id.to_i)
59
+ return nil unless obj
60
+
61
+ normalize_guid_to_xmi_format(obj.ea_guid, "EAID")
68
62
  end
69
63
 
70
64
  # Build cardinality from lower and upper bounds
@@ -120,11 +120,7 @@ module Lutaml
120
120
  def find_object_by_id(object_id)
121
121
  return nil if object_id.nil?
122
122
 
123
- query = "SELECT * FROM t_object WHERE Object_ID = ?"
124
- rows = database.connection.execute(query, object_id)
125
- return nil if rows.empty?
126
-
127
- Models::EaObject.from_db_row(rows.first)
123
+ database.find_object(object_id)
128
124
  end
129
125
  end
130
126
  end