mxrb 0.1.2 → 0.1.4
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 +4 -4
- data/bin/mxrb +458 -10
- data/docs/de-DE/README.md +1 -0
- data/docs/de-DE/oql-sql.md +42 -0
- data/docs/de-DE/project-structure.md +201 -2
- data/docs/de-DE/runtime-ruby.md +104 -0
- data/docs/de-DE/runtime-schema-migrations.md +44 -0
- data/docs/de-DE/validation-matrix.md +42 -4
- data/docs/en-US/README.md +1 -0
- data/docs/en-US/oql-sql.md +41 -0
- data/docs/en-US/project-structure.md +192 -2
- data/docs/en-US/runtime-ruby.md +100 -0
- data/docs/en-US/runtime-schema-migrations.md +41 -0
- data/docs/en-US/validation-matrix.md +39 -4
- data/docs/pt-BR/README.md +1 -0
- data/docs/pt-BR/entity-dsl.md +8 -0
- data/docs/pt-BR/oql-sql.md +41 -0
- data/docs/pt-BR/project-structure.md +197 -2
- data/docs/pt-BR/runtime-ruby.md +108 -0
- data/docs/pt-BR/runtime-schema-migrations.md +40 -0
- data/docs/pt-BR/validation-matrix.md +42 -5
- data/docs/pt-BR/writing.md +28 -0
- data/lib/mxrb/cli/help.rb +426 -0
- data/lib/mxrb/cli/release.rb +137 -0
- data/lib/mxrb/compiler/compatibility_analyzer.rb +1 -1
- data/lib/mxrb/compiler/data_grid_bundle_compiler.rb +8 -1
- data/lib/mxrb/compiler/domain_document_compiler.rb +3 -0
- data/lib/mxrb/compiler/gallery_bundle_compiler.rb +11 -1
- data/lib/mxrb/compiler/generic_widget_bundle_compiler.rb +76 -19
- data/lib/mxrb/compiler/legacy_custom_widget_compiler.rb +159 -0
- data/lib/mxrb/compiler/legacy_data_grid_compiler.rb +43 -7
- data/lib/mxrb/compiler/legacy_page_builder.rb +1248 -23
- data/lib/mxrb/compiler/packager.rb +27 -13
- data/lib/mxrb/compiler/page_bundle_compiler.rb +13 -4
- data/lib/mxrb/compiler/portable_packager.rb +16 -11
- data/lib/mxrb/compiler/web_bundle_builder.rb +5 -1
- data/lib/mxrb/compiler/web_shell_materializer.rb +42 -2
- data/lib/mxrb/compiler/widget_package_extractor.rb +3 -0
- data/lib/mxrb/domain_diagram/lifecycle.rb +272 -0
- data/lib/mxrb/domain_diagram.rb +409 -0
- data/lib/mxrb/dsl/builder.rb +62 -11
- data/lib/mxrb/environment.rb +226 -0
- data/lib/mxrb/exporter.rb +265 -45
- data/lib/mxrb/http/server.rb +107 -0
- data/lib/mxrb/initializer.rb +80 -9
- data/lib/mxrb/integrity/validator.rb +32 -7
- data/lib/mxrb/io/bson_codec.rb +42 -1
- data/lib/mxrb/io/mpr_file.rb +146 -3
- data/lib/mxrb/model/attribute.rb +3 -0
- data/lib/mxrb/model/entity.rb +44 -2
- data/lib/mxrb/model/microflow.rb +3 -1
- data/lib/mxrb/model/module.rb +71 -0
- data/lib/mxrb/model/page.rb +126 -15
- data/lib/mxrb/model/project.rb +3 -0
- data/lib/mxrb/modeler/catalog.rb +178 -0
- data/lib/mxrb/official_marketplace/module_package_importer.rb +23 -12
- data/lib/mxrb/official_marketplace/widget_package_installer.rb +15 -11
- data/lib/mxrb/official_marketplace.rb +9 -3
- data/lib/mxrb/oql/reverse_translator.rb +394 -0
- data/lib/mxrb/oql/server.rb +4 -8
- data/lib/mxrb/oql.rb +32 -4
- data/lib/mxrb/progress.rb +242 -0
- data/lib/mxrb/project_lifecycle.rb +5 -2
- data/lib/mxrb/ruby_app/exporter.rb +1749 -0
- data/lib/mxrb/ruby_app/preset.rb +506 -0
- data/lib/mxrb/ruby_app/session_manager.rb +122 -0
- data/lib/mxrb/ruby_app.rb +1361 -0
- data/lib/mxrb/runtime/access_control.rb +408 -0
- data/lib/mxrb/runtime/native.rb +1015 -93
- data/lib/mxrb/runtime/scheduler.rb +396 -0
- data/lib/mxrb/runtime/schema_migrator.rb +598 -0
- data/lib/mxrb/runtime/shared_store.rb +335 -0
- data/lib/mxrb/runtime/sqlite_store.rb +729 -0
- data/lib/mxrb/scaffold/generator.rb +11 -3
- data/lib/mxrb/team_server.rb +10 -7
- data/lib/mxrb/uml/activity_diagram.rb +118 -0
- data/lib/mxrb/uml/class_diagram.rb +118 -0
- data/lib/mxrb/uml/sequence_diagram.rb +112 -0
- data/lib/mxrb/uml/server.rb +146 -0
- data/lib/mxrb/uml/support.rb +35 -0
- data/lib/mxrb/version.rb +1 -1
- data/lib/mxrb/web_ui/assets/abnfDiagram-N423BO3Z-C4JD3cEC.js +1 -0
- data/lib/mxrb/web_ui/assets/arc-3Z53kgFp.js +1 -0
- data/lib/mxrb/web_ui/assets/architecture-TIHT7OUA-BStBTLea.js +1 -0
- data/lib/mxrb/web_ui/assets/architectureDiagram-T3A2C74G-DBwqnM4J.js +36 -0
- data/lib/mxrb/web_ui/assets/array-BifhSqXX.js +1 -0
- data/lib/mxrb/web_ui/assets/blockDiagram-VBNYF7ZC-DLtuHt-j.js +132 -0
- data/lib/mxrb/web_ui/assets/c4Diagram-5PPSVZJV-ConSk_pe.js +10 -0
- data/lib/mxrb/web_ui/assets/channel-BhPvD7Dt.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-2GRJ4B5K-D2HpWsf_.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-4I5QYGJK-CiIdNwaF.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-5RXB4S5H-Bu_AaEkE.js +231 -0
- data/lib/mxrb/web_ui/assets/chunk-5VM5RSS4-ZNzvKenW.js +15 -0
- data/lib/mxrb/web_ui/assets/chunk-6Q2QTUOP-wQkNmt_X.js +88 -0
- data/lib/mxrb/web_ui/assets/chunk-7BUUIJ7U-Bb538aSH.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-GF5L2VYU-G8MmiBzU.js +206 -0
- data/lib/mxrb/web_ui/assets/chunk-I66GZJ75-CulcrLPh.js +127 -0
- data/lib/mxrb/web_ui/assets/chunk-JQJVKLGR-ukjzcdlL.js +156 -0
- data/lib/mxrb/web_ui/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-KBJHAD2P-Wm35lYov.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-KEIR6QF5-BICK3FdT.js +161 -0
- data/lib/mxrb/web_ui/assets/chunk-NSK5VX7P-D2nYrCY4.js +2 -0
- data/lib/mxrb/web_ui/assets/chunk-QR6OTTB3-BrdIzg4Q.js +62 -0
- data/lib/mxrb/web_ui/assets/chunk-RYQCIY6F-CCfZMcW6.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-UBXNYLIW-BPEVYsFK.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-W5SLKNZC-2E6OPhA4.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-WRU74C26-CBIvOyWp.js +70 -0
- data/lib/mxrb/web_ui/assets/chunk-XXDRQBXY-pH58XAyl.js +1 -0
- data/lib/mxrb/web_ui/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
- data/lib/mxrb/web_ui/assets/classDiagram-JCYQIIEL-xiqo4D89.js +1 -0
- data/lib/mxrb/web_ui/assets/classDiagram-v2-OCEON4UE-xiqo4D89.js +1 -0
- data/lib/mxrb/web_ui/assets/cose-bilkent-JH36ORCC-t_flPpii.js +1 -0
- data/lib/mxrb/web_ui/assets/cynefin-VYW2F7L2-BIqktTEv.js +1 -0
- data/lib/mxrb/web_ui/assets/cynefinDiagram-MW4NZA55-C2d--lut.js +62 -0
- data/lib/mxrb/web_ui/assets/cytoscape.esm-B-NFISlW.js +321 -0
- data/lib/mxrb/web_ui/assets/dagre-Buvkdvvj.js +1 -0
- data/lib/mxrb/web_ui/assets/dagre-VZM6K2ZE-CSz2_tb5.js +4 -0
- data/lib/mxrb/web_ui/assets/defaultLocale-BFoDCU3G.js +1 -0
- data/lib/mxrb/web_ui/assets/diagram-7IWD3JNH-DCt7u7V_.js +30 -0
- data/lib/mxrb/web_ui/assets/diagram-B4RE2ZJO-DqZBqkMu.js +3 -0
- data/lib/mxrb/web_ui/assets/diagram-LBJQPF4R-ClIYbIsI.js +24 -0
- data/lib/mxrb/web_ui/assets/diagram-Q27KOJAE-DFxhvthJ.js +24 -0
- data/lib/mxrb/web_ui/assets/diagram-UB23O5K3-BSUTXptv.js +41 -0
- data/lib/mxrb/web_ui/assets/dist-D2qOEbeJ.js +1 -0
- data/lib/mxrb/web_ui/assets/domain-mGOZ1KCG.css +1 -0
- data/lib/mxrb/web_ui/assets/domain-qsjXhy4v.js +1 -0
- data/lib/mxrb/web_ui/assets/ebnfDiagram-BXEA7PRR-B5reICEi.js +1 -0
- data/lib/mxrb/web_ui/assets/erDiagram-JOGREHBK-Co5Mxn2p.js +85 -0
- data/lib/mxrb/web_ui/assets/eventmodeling-45OFAUF4-C1ylhSks.js +1 -0
- data/lib/mxrb/web_ui/assets/flowDiagram-UKHOOZJN-CHXaJIaS.js +1 -0
- data/lib/mxrb/web_ui/assets/ganttDiagram-PKOTCBZU-DPPPaWaz.js +292 -0
- data/lib/mxrb/web_ui/assets/gitGraph-TEB2WS4Q-qS77ywA9.js +1 -0
- data/lib/mxrb/web_ui/assets/gitGraphDiagram-DS77QQ5N-DpAv6-BT.js +106 -0
- data/lib/mxrb/web_ui/assets/graphlib-DS17s2tU.js +1 -0
- data/lib/mxrb/web_ui/assets/info-DKCQHKI2-C9VD1Y4e.js +1 -0
- data/lib/mxrb/web_ui/assets/infoDiagram-6WML65LV-Bk1kbcCy.js +2 -0
- data/lib/mxrb/web_ui/assets/init-C-OQMol4.js +1 -0
- data/lib/mxrb/web_ui/assets/ishikawaDiagram-WSZJBQD7-0gcISBFR.js +70 -0
- data/lib/mxrb/web_ui/assets/journeyDiagram-NVQOT4AX-Dt0RQnlh.js +139 -0
- data/lib/mxrb/web_ui/assets/jsx-runtime-DV0a5kSb.js +9 -0
- data/lib/mxrb/web_ui/assets/kanban-definition-27J2QSJJ-DIPQM7w9.js +89 -0
- data/lib/mxrb/web_ui/assets/katex-CXMH3UgJ.js +257 -0
- data/lib/mxrb/web_ui/assets/line-C0rYD-tL.js +1 -0
- data/lib/mxrb/web_ui/assets/linear-BPPxWorj.js +1 -0
- data/lib/mxrb/web_ui/assets/map-BaFkSB1l.js +1 -0
- data/lib/mxrb/web_ui/assets/mermaid-parser.core-B_UPzTxa.js +7 -0
- data/lib/mxrb/web_ui/assets/mindmap-definition-FAOFIHXS-CdJRSMuk.js +96 -0
- data/lib/mxrb/web_ui/assets/modeler-BNqHthwk.css +1 -0
- data/lib/mxrb/web_ui/assets/modeler-CQmqflbg.js +1 -0
- data/lib/mxrb/web_ui/assets/ordinal-BDEzSJ7C.js +1 -0
- data/lib/mxrb/web_ui/assets/packet-7NZHBO7P-CwQ4NSBs.js +1 -0
- data/lib/mxrb/web_ui/assets/path-fybaL0A-.js +1 -0
- data/lib/mxrb/web_ui/assets/pegDiagram-VL7TDLO6-D40S7ppx.js +1 -0
- data/lib/mxrb/web_ui/assets/pie-RZYD4A2V-CJroHMKh.js +1 -0
- data/lib/mxrb/web_ui/assets/pieDiagram-7S7Q4E2Y-QB54__BV.js +39 -0
- data/lib/mxrb/web_ui/assets/quadrantDiagram-CIZ2JOQS-DBhDS6ag.js +7 -0
- data/lib/mxrb/web_ui/assets/radar-I7S5WNFK-DdIUwd2d.js +1 -0
- data/lib/mxrb/web_ui/assets/railroad-3IZDKUUU-B1Lw6Xyq.js +1 -0
- data/lib/mxrb/web_ui/assets/railroad-abnf-AHOZXSZD-CQgQoeak.js +1 -0
- data/lib/mxrb/web_ui/assets/railroad-ebnf-EBAXGLYW-D7qEQ2x8.js +1 -0
- data/lib/mxrb/web_ui/assets/railroad-peg-LSFZ7HO6-C005Vxbb.js +1 -0
- data/lib/mxrb/web_ui/assets/railroadDiagram-AXF67PYL-BBP2qk7M.js +1 -0
- data/lib/mxrb/web_ui/assets/requirementDiagram-LRYGKXZP-D2cLsAoI.js +84 -0
- data/lib/mxrb/web_ui/assets/rough.esm-Dy-Kn_BL.js +1 -0
- data/lib/mxrb/web_ui/assets/sankeyDiagram-W5VNT64P-Bpi3FiP2.js +40 -0
- data/lib/mxrb/web_ui/assets/sequenceDiagram-SI44F4Z6-DCRcDlVe.js +162 -0
- data/lib/mxrb/web_ui/assets/sizeCapture-X5ZJPWSS-B0uUizjq.js +1 -0
- data/lib/mxrb/web_ui/assets/src-CvxfUak2.js +1 -0
- data/lib/mxrb/web_ui/assets/stateDiagram-OKZ733FA-C2GCEoxl.js +1 -0
- data/lib/mxrb/web_ui/assets/stateDiagram-v2-UEYNNEHI-D2gWgedh.js +1 -0
- data/lib/mxrb/web_ui/assets/swimlanes-SLNWSIFB-CRI9irEW.js +2 -0
- data/lib/mxrb/web_ui/assets/swimlanesDiagram-ULZ7WXOC-C5Wb_-hZ.js +8 -0
- data/lib/mxrb/web_ui/assets/theme-_mxc7BdY.css +1 -0
- data/lib/mxrb/web_ui/assets/timeline-definition-Z64GVDOM-B1-mNg-h.js +120 -0
- data/lib/mxrb/web_ui/assets/treeView-QDETBFTQ-7CTvIwKq.js +1 -0
- data/lib/mxrb/web_ui/assets/treemap-6X3UGDF4-CtL22pq5.js +1 -0
- data/lib/mxrb/web_ui/assets/uml-C3KAFGTq.js +51 -0
- data/lib/mxrb/web_ui/assets/uml-Dn-qd01X.css +1 -0
- data/lib/mxrb/web_ui/assets/vennDiagram-T6HMQDX7-BzVnUEAy.js +34 -0
- data/lib/mxrb/web_ui/assets/wardley-OPB4EBWU-JNi-QNag.js +1 -0
- data/lib/mxrb/web_ui/assets/wardleyDiagram-T6FBY63Y-BUwmAQ-B.js +78 -0
- data/lib/mxrb/web_ui/assets/xychartDiagram-ELKLHX3M-DEQS8sKp.js +7 -0
- data/lib/mxrb/web_ui/domain.html +15 -0
- data/lib/mxrb/web_ui/modeler.html +16 -0
- data/lib/mxrb/web_ui/uml.html +31 -0
- data/lib/mxrb/web_ui.rb +89 -0
- data/lib/mxrb/widget_certification.rb +208 -0
- data/lib/mxrb/writer.rb +278 -41
- data/lib/mxrb.rb +38 -8
- metadata +157 -5
data/lib/mxrb/initializer.rb
CHANGED
|
@@ -5,18 +5,30 @@ require 'tmpdir'
|
|
|
5
5
|
|
|
6
6
|
module Mxrb
|
|
7
7
|
# Creates the minimum editable Ruby project accepted by `mxrb generate`.
|
|
8
|
-
# rubocop:disable Metrics
|
|
8
|
+
# rubocop:disable Metrics
|
|
9
9
|
class Initializer
|
|
10
10
|
Result = Data.define(:root, :files)
|
|
11
11
|
NAME = /\A[A-Za-z][A-Za-z0-9_-]*\z/
|
|
12
|
+
MODES = %i[mendix ruby].freeze
|
|
12
13
|
COMPOUND_SUFFIXES = %w[service clinic portal demo api app kit].freeze
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
attr_reader :mode
|
|
16
|
+
|
|
17
|
+
def initialize(name, subject: :project, mxrb_path: nil, mode: :mendix, stack: nil)
|
|
15
18
|
@dir_name = name.to_s
|
|
16
19
|
raise ArgumentError, "#{subject} name must be snake_case or PascalCase" unless NAME.match?(@dir_name)
|
|
17
20
|
|
|
18
21
|
@module_name = to_pascal_case(@dir_name)
|
|
19
22
|
@mpr_name = "#{@module_name}.mpr"
|
|
23
|
+
@mode = mode.to_sym
|
|
24
|
+
raise ArgumentError, 'project mode must be mendix or ruby' unless MODES.include?(@mode)
|
|
25
|
+
|
|
26
|
+
@stack = stack&.to_sym
|
|
27
|
+
raise ArgumentError, 'Ruby stack presets require --mode ruby' if @stack && @mode != :ruby
|
|
28
|
+
if @stack && !RubyApp::Preset::NAMES.include?(@stack)
|
|
29
|
+
raise ArgumentError, "Ruby stack must be #{RubyApp::Preset::NAMES.join(' or ')}"
|
|
30
|
+
end
|
|
31
|
+
|
|
20
32
|
@mxrb_path = File.expand_path(mxrb_path) if mxrb_path
|
|
21
33
|
raise ArgumentError, "mxrb path does not exist: #{@mxrb_path}" if @mxrb_path && !File.directory?(@mxrb_path)
|
|
22
34
|
end
|
|
@@ -28,19 +40,61 @@ module Mxrb
|
|
|
28
40
|
|
|
29
41
|
FileUtils.mkdir_p(parent)
|
|
30
42
|
staging = Dir.mktmpdir(".#{@dir_name}.mxrb-init-", parent)
|
|
31
|
-
write_scaffold(staging)
|
|
43
|
+
mode == :ruby ? write_ruby_scaffold(staging) : write_scaffold(staging)
|
|
44
|
+
files = mode == :ruby ? generated_files(staging) : relative_files
|
|
32
45
|
FileUtils.mv(staging, root)
|
|
33
|
-
Result.new(root,
|
|
46
|
+
Result.new(root, files.map { File.join(root, _1) }.freeze)
|
|
34
47
|
ensure
|
|
35
48
|
FileUtils.rm_rf(staging) if staging && File.exist?(staging)
|
|
36
49
|
end
|
|
37
50
|
|
|
38
51
|
private
|
|
39
52
|
|
|
53
|
+
def write_ruby_scaffold(root)
|
|
54
|
+
bootstrap = File.join(root, '.mxrb-bootstrap')
|
|
55
|
+
write_scaffold(bootstrap)
|
|
56
|
+
target = File.join(bootstrap, @mpr_name)
|
|
57
|
+
previous = ENV['MXRB_OUTPUT_PATH']
|
|
58
|
+
library = @mxrb_path ? File.join(@mxrb_path, 'lib') : File.expand_path('..', __dir__)
|
|
59
|
+
added_load_path = !$LOAD_PATH.include?(library)
|
|
60
|
+
$LOAD_PATH.unshift(library) if added_load_path
|
|
61
|
+
ENV['MXRB_OUTPUT_PATH'] = target
|
|
62
|
+
load File.join(bootstrap, 'project.rb')
|
|
63
|
+
Exporter.new(target, root, mode: :ruby).export!(parallel: false)
|
|
64
|
+
pin_exported_gemfile(root) if @mxrb_path
|
|
65
|
+
RubyApp::Preset.apply!(root, @stack) if @stack
|
|
66
|
+
ensure
|
|
67
|
+
if previous
|
|
68
|
+
ENV['MXRB_OUTPUT_PATH'] = previous
|
|
69
|
+
else
|
|
70
|
+
ENV.delete('MXRB_OUTPUT_PATH')
|
|
71
|
+
end
|
|
72
|
+
$LOAD_PATH.delete(library) if added_load_path
|
|
73
|
+
FileUtils.rm_rf(bootstrap)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def generated_files(root)
|
|
77
|
+
Dir.glob(File.join(root, '**', '*'), File::FNM_DOTMATCH)
|
|
78
|
+
.select { File.file?(_1) }
|
|
79
|
+
.map { Pathname.new(_1).relative_path_from(Pathname.new(root)).to_s }
|
|
80
|
+
.sort
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def pin_exported_gemfile(root)
|
|
84
|
+
File.binwrite(
|
|
85
|
+
File.join(root, 'Gemfile'),
|
|
86
|
+
"# frozen_string_literal: true\n\nsource 'https://rubygems.org'\n" \
|
|
87
|
+
"gem 'mxrb', path: #{@mxrb_path.inspect}\n"
|
|
88
|
+
)
|
|
89
|
+
end
|
|
90
|
+
|
|
40
91
|
def write_scaffold(root)
|
|
41
92
|
write(root, 'Gemfile', gemfile)
|
|
42
93
|
write(root, '.gitignore', gitignore)
|
|
43
94
|
write(root, '.env.example', env_example)
|
|
95
|
+
environment_names.each do |name|
|
|
96
|
+
write(File.join(root, 'config', 'environments'), "#{name}.env.example", environment_example(name))
|
|
97
|
+
end
|
|
44
98
|
write(root, 'project.rb', project_rb)
|
|
45
99
|
write(File.join(root, 'app', 'navigation', 'responsive'), '.keep', '')
|
|
46
100
|
write_design_scaffold(root)
|
|
@@ -79,7 +133,8 @@ module Mxrb
|
|
|
79
133
|
['Gemfile', '.gitignore', '.env.example', 'project.rb',
|
|
80
134
|
*relative_module_files.map { File.join(module_prefix, _1) },
|
|
81
135
|
File.join('app', 'navigation', 'responsive', '.keep'),
|
|
82
|
-
*design_files.keys.map { File.join(*_1) }
|
|
136
|
+
*design_files.keys.map { File.join(*_1) },
|
|
137
|
+
*environment_names.map { File.join('config', 'environments', "#{_1}.env.example") }]
|
|
83
138
|
end
|
|
84
139
|
|
|
85
140
|
def relative_module_files
|
|
@@ -121,7 +176,6 @@ module Mxrb
|
|
|
121
176
|
source "https://rubygems.org"
|
|
122
177
|
|
|
123
178
|
#{gem_declaration}
|
|
124
|
-
gem "dotenv", "~> 3.0"
|
|
125
179
|
RUBY
|
|
126
180
|
end
|
|
127
181
|
|
|
@@ -131,6 +185,8 @@ module Mxrb
|
|
|
131
185
|
.env
|
|
132
186
|
.env.*
|
|
133
187
|
!.env.example
|
|
188
|
+
config/environments/*.env
|
|
189
|
+
!config/environments/*.env.example
|
|
134
190
|
TEXT
|
|
135
191
|
end
|
|
136
192
|
|
|
@@ -141,6 +197,21 @@ module Mxrb
|
|
|
141
197
|
TEXT
|
|
142
198
|
end
|
|
143
199
|
|
|
200
|
+
def environment_names = %w[development qa staging production]
|
|
201
|
+
|
|
202
|
+
def environment_example(name)
|
|
203
|
+
<<~TEXT
|
|
204
|
+
# Copy to #{name}.env. Process ENV still has highest precedence.
|
|
205
|
+
MXRB_DATABASE_PATH=.mxrb/runtime/#{name}.sqlite3
|
|
206
|
+
MXRB_SHARED_STORE_PATH=.mxrb/runtime/#{name}-shared.sqlite3
|
|
207
|
+
MXRB_SESSION_TTL=3600
|
|
208
|
+
MXRB_SCHEDULER_LEASE_TTL=300
|
|
209
|
+
MXRB_ALLOW_DESTRUCTIVE_MIGRATIONS=false
|
|
210
|
+
MXRB_AUTH_TOKENS=
|
|
211
|
+
MXRB_USERS_JSON=
|
|
212
|
+
TEXT
|
|
213
|
+
end
|
|
214
|
+
|
|
144
215
|
def gem_declaration
|
|
145
216
|
return 'gem "mxrb"' unless @mxrb_path
|
|
146
217
|
|
|
@@ -151,10 +222,10 @@ module Mxrb
|
|
|
151
222
|
<<~RUBY
|
|
152
223
|
# frozen_string_literal: true
|
|
153
224
|
|
|
154
|
-
require "dotenv/load"
|
|
155
|
-
Dotenv.load(File.join(__dir__, ".env"))
|
|
156
225
|
require "mxrb"
|
|
157
226
|
|
|
227
|
+
Mxrb::Environment.load(root: __dir__).apply
|
|
228
|
+
|
|
158
229
|
output = ENV.fetch("MXRB_OUTPUT_PATH", File.join(__dir__, "#{@mpr_name}"))
|
|
159
230
|
|
|
160
231
|
Mxrb.define(output) do
|
|
@@ -254,5 +325,5 @@ module Mxrb
|
|
|
254
325
|
RUBY
|
|
255
326
|
end
|
|
256
327
|
end
|
|
257
|
-
# rubocop:enable Metrics
|
|
328
|
+
# rubocop:enable Metrics
|
|
258
329
|
end
|
|
@@ -11,19 +11,26 @@ module Mxrb
|
|
|
11
11
|
class Validator
|
|
12
12
|
def initialize(path)
|
|
13
13
|
@path = path
|
|
14
|
+
@progress = Progress::NullTask.instance
|
|
14
15
|
end
|
|
15
16
|
|
|
16
17
|
def validate
|
|
17
|
-
@
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
Progress.with("Validating #{File.basename(@path)}") do |progress|
|
|
19
|
+
@progress = progress
|
|
20
|
+
@errors = []
|
|
21
|
+
@warnings = []
|
|
22
|
+
@mpr = IO::MprFile.open(@path, readonly: true)
|
|
23
|
+
validate_tables
|
|
24
|
+
progress.advance(detail: "MPR tables")
|
|
25
|
+
validate_units
|
|
26
|
+
validate_v2_files
|
|
27
|
+
progress.advance(detail: "v2 contents")
|
|
28
|
+
Result.new(errors: @errors, warnings: @warnings)
|
|
29
|
+
end
|
|
24
30
|
rescue Error => e
|
|
25
31
|
Result.new(errors: [e.message], warnings: @warnings || [])
|
|
26
32
|
ensure
|
|
33
|
+
@progress = Progress::NullTask.instance
|
|
27
34
|
@mpr&.close
|
|
28
35
|
end
|
|
29
36
|
|
|
@@ -40,8 +47,13 @@ module Mxrb
|
|
|
40
47
|
|
|
41
48
|
def validate_units
|
|
42
49
|
@units = @mpr.all_units
|
|
50
|
+
@legacy_identity_mismatches = @mpr.legacy_unit_identity_mismatches.to_set do |entry|
|
|
51
|
+
[entry.fetch(:unit_id), entry.fetch(:content_id), entry.fetch(:type)]
|
|
52
|
+
end
|
|
53
|
+
@progress.update(total: @units.size + 3, detail: "#{@units.size} units")
|
|
43
54
|
validate_root
|
|
44
55
|
validate_unit_ids
|
|
56
|
+
@progress.advance(detail: "unit tree")
|
|
45
57
|
validate_contents
|
|
46
58
|
end
|
|
47
59
|
|
|
@@ -78,6 +90,8 @@ module Mxrb
|
|
|
78
90
|
next unless doc
|
|
79
91
|
|
|
80
92
|
validate_doc_identity(unit, doc)
|
|
93
|
+
ensure
|
|
94
|
+
@progress&.advance(detail: "unit #{unit['UnitID']}")
|
|
81
95
|
end
|
|
82
96
|
end
|
|
83
97
|
|
|
@@ -102,6 +116,17 @@ module Mxrb
|
|
|
102
116
|
if doc_id.to_s.empty?
|
|
103
117
|
add_error("unit #{unit['UnitID']} missing $ID")
|
|
104
118
|
elsif doc_id != unit["UnitID"]
|
|
119
|
+
record_identity_mismatch(unit, doc_id, type)
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def record_identity_mismatch(unit, doc_id, type)
|
|
124
|
+
mismatch = [unit["UnitID"], doc_id, type]
|
|
125
|
+
if @legacy_identity_mismatches&.include?(mismatch)
|
|
126
|
+
add_warning(
|
|
127
|
+
"unit #{unit['UnitID']} preserves legacy content $ID mismatch #{doc_id}"
|
|
128
|
+
)
|
|
129
|
+
else
|
|
105
130
|
add_error("unit #{unit['UnitID']} content $ID mismatch #{doc_id}")
|
|
106
131
|
end
|
|
107
132
|
end
|
data/lib/mxrb/io/bson_codec.rb
CHANGED
|
@@ -11,7 +11,7 @@ module Mxrb
|
|
|
11
11
|
# - Arrays have a 4-byte int32 marker as first element (1=by-name, 2=part-secondary, 3=part-primary)
|
|
12
12
|
# - $ID can appear as String, BSON Binary, or {Data:, Subtype:} map
|
|
13
13
|
# - $Type uses storage names ("DomainModels$Entity") not SDK qualified names
|
|
14
|
-
module BsonCodec
|
|
14
|
+
module BsonCodec # rubocop:disable Metrics/ModuleLength
|
|
15
15
|
# ── UUID / BLOB conversion ─────────────────────────────────────────────
|
|
16
16
|
|
|
17
17
|
# Convert a 16-byte MS-GUID blob to UUID string.
|
|
@@ -49,12 +49,53 @@ module Mxrb
|
|
|
49
49
|
when BSON::Binary
|
|
50
50
|
blob_to_uuid(value.data)
|
|
51
51
|
when Hash
|
|
52
|
+
binary = extended_binary(value)
|
|
53
|
+
return blob_to_uuid(binary.data) if binary
|
|
54
|
+
|
|
52
55
|
data = value["Data"] || value[:Data]
|
|
53
56
|
return nil unless data
|
|
54
57
|
blob_to_uuid(Base64.strict_decode64(data.to_s))
|
|
55
58
|
end
|
|
56
59
|
end
|
|
57
60
|
|
|
61
|
+
BINARY_SUBTYPES = {
|
|
62
|
+
"00" => :generic, "01" => :function, "02" => :old_binary,
|
|
63
|
+
"03" => :uuid_old, "04" => :uuid, "05" => :md5,
|
|
64
|
+
"80" => :user
|
|
65
|
+
}.freeze
|
|
66
|
+
|
|
67
|
+
# Restores BSON values serialized through JSON's canonical extended form.
|
|
68
|
+
# Architecture metadata uses JSON, so this conversion is required before
|
|
69
|
+
# a stored native document is written again during a version transition.
|
|
70
|
+
def self.restore_extended_json(value)
|
|
71
|
+
case value
|
|
72
|
+
when Hash
|
|
73
|
+
binary = extended_binary(value)
|
|
74
|
+
return binary if binary
|
|
75
|
+
|
|
76
|
+
value.to_h { |key, child| [key, restore_extended_json(child)] }
|
|
77
|
+
when Array
|
|
78
|
+
value.map { restore_extended_json(_1) }
|
|
79
|
+
else
|
|
80
|
+
value
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def self.extended_binary(value)
|
|
85
|
+
payload = value["$binary"] || value[:$binary]
|
|
86
|
+
return unless payload.is_a?(Hash)
|
|
87
|
+
|
|
88
|
+
base64 = payload["base64"] || payload[:base64]
|
|
89
|
+
return unless base64
|
|
90
|
+
|
|
91
|
+
subtype = payload["subType"] || payload[:subType] || "00"
|
|
92
|
+
BSON::Binary.new(
|
|
93
|
+
Base64.strict_decode64(base64.to_s.delete(" \t\r\n")),
|
|
94
|
+
BINARY_SUBTYPES.fetch(subtype.to_s.downcase, :generic)
|
|
95
|
+
)
|
|
96
|
+
end
|
|
97
|
+
private_class_method :extended_binary
|
|
98
|
+
|
|
58
99
|
# ── Array parsing ───────────────────────────────────────────────────────
|
|
59
100
|
|
|
60
101
|
# Mendix arrays have an int32 marker as first element.
|
data/lib/mxrb/io/mpr_file.rb
CHANGED
|
@@ -162,10 +162,10 @@ module Mxrb
|
|
|
162
162
|
# ── Writes ────────────────────────────────────────────────────────────
|
|
163
163
|
|
|
164
164
|
# Insert a new unit. Returns the assigned UUID.
|
|
165
|
-
def insert_unit(container_uuid:, containment_name:, contents_doc:)
|
|
165
|
+
def insert_unit(container_uuid:, containment_name:, contents_doc:, unit_uuid: nil)
|
|
166
166
|
raise ReadOnlyError, "Opened in read-only mode" if @readonly
|
|
167
167
|
|
|
168
|
-
uuid = BsonCodec.extract_id(contents_doc["$ID"] || contents_doc["\$ID"]) || SecureRandom.uuid
|
|
168
|
+
uuid = unit_uuid || BsonCodec.extract_id(contents_doc["$ID"] || contents_doc["\$ID"]) || SecureRandom.uuid
|
|
169
169
|
unless contents_doc.key?("$ID") || contents_doc.key?("\$ID")
|
|
170
170
|
contents_doc = { "$ID" => uuid }.merge(contents_doc)
|
|
171
171
|
end
|
|
@@ -223,6 +223,31 @@ module Mxrb
|
|
|
223
223
|
true
|
|
224
224
|
end
|
|
225
225
|
|
|
226
|
+
# Repairs stale Unit.ContentsHash metadata without reserializing or
|
|
227
|
+
# otherwise changing the BSON/mxunit payload. Returns an audit trail.
|
|
228
|
+
def repair_content_hashes!
|
|
229
|
+
raise ReadOnlyError, "Opened in read-only mode" if @readonly
|
|
230
|
+
|
|
231
|
+
repairs = []
|
|
232
|
+
transaction do
|
|
233
|
+
all_units.each do |unit|
|
|
234
|
+
bytes = content_bytes(unit)
|
|
235
|
+
next if bytes.to_s.empty?
|
|
236
|
+
|
|
237
|
+
previous = unit['ContentsHash'].to_s
|
|
238
|
+
current = BsonCodec.contents_hash(bytes)
|
|
239
|
+
next if previous == current
|
|
240
|
+
|
|
241
|
+
@db.execute(
|
|
242
|
+
'UPDATE Unit SET ContentsHash = ? WHERE UnitID = ?',
|
|
243
|
+
[current, BsonCodec.uuid_to_blob(unit.fetch('UnitID'))]
|
|
244
|
+
)
|
|
245
|
+
repairs << { unit_id: unit.fetch('UnitID'), previous:, current: }
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
repairs
|
|
249
|
+
end
|
|
250
|
+
|
|
226
251
|
def delete_unit(uuid)
|
|
227
252
|
raise ReadOnlyError, "Opened in read-only mode" if @readonly
|
|
228
253
|
@db.execute("DELETE FROM Unit WHERE UnitID = ?", [BsonCodec.uuid_to_blob(uuid)])
|
|
@@ -463,7 +488,7 @@ module Mxrb
|
|
|
463
488
|
def architecture_definition
|
|
464
489
|
return nil unless tables.include?("_MxrbArchitecture")
|
|
465
490
|
json = @db.get_first_value("SELECT Definition FROM _MxrbArchitecture WHERE ID = 1")
|
|
466
|
-
json && JSON.parse(json, symbolize_names: true)
|
|
491
|
+
json && BsonCodec.restore_extended_json(JSON.parse(json, symbolize_names: true))
|
|
467
492
|
end
|
|
468
493
|
|
|
469
494
|
def write_architecture_definition(definition)
|
|
@@ -481,6 +506,124 @@ module Mxrb
|
|
|
481
506
|
)
|
|
482
507
|
end
|
|
483
508
|
|
|
509
|
+
# Ruby/React sources are stored outside the Mendix Unit tree. Mendix can
|
|
510
|
+
# keep editing the native model while MXRB can later restore the exact
|
|
511
|
+
# conventional application sources on a Ruby-mode export.
|
|
512
|
+
def ruby_app_sources
|
|
513
|
+
return [] unless tables.include?("_MxrbRubySource")
|
|
514
|
+
|
|
515
|
+
has_mode = table_info("_MxrbRubySource").any? { (_1["name"] || _1[:name]) == "Mode" }
|
|
516
|
+
columns = has_mode ? "Path, Contents, Sha256, Mode" : "Path, Contents, Sha256"
|
|
517
|
+
@db.execute("SELECT #{columns} FROM _MxrbRubySource ORDER BY Path").map do |row|
|
|
518
|
+
fallback = row[0].to_s.start_with?('bin/') ? 0o755 : 0o644
|
|
519
|
+
{ path: row[0], contents: row[1], sha256: row[2], mode: has_mode ? row[3] : fallback }
|
|
520
|
+
end
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
def write_ruby_app_sources(files)
|
|
524
|
+
raise ReadOnlyError, "Opened in read-only mode" if @readonly
|
|
525
|
+
|
|
526
|
+
@db.execute(<<~SQL)
|
|
527
|
+
CREATE TABLE IF NOT EXISTS _MxrbRubySource (
|
|
528
|
+
Path TEXT PRIMARY KEY NOT NULL,
|
|
529
|
+
Contents BLOB NOT NULL,
|
|
530
|
+
Sha256 TEXT NOT NULL,
|
|
531
|
+
Mode INTEGER NOT NULL DEFAULT 420
|
|
532
|
+
)
|
|
533
|
+
SQL
|
|
534
|
+
unless table_info("_MxrbRubySource").any? { (_1["name"] || _1[:name]) == "Mode" }
|
|
535
|
+
@db.execute("ALTER TABLE _MxrbRubySource ADD COLUMN Mode INTEGER NOT NULL DEFAULT 420")
|
|
536
|
+
end
|
|
537
|
+
@db.execute("DELETE FROM _MxrbRubySource")
|
|
538
|
+
files.each do |file|
|
|
539
|
+
@db.execute(
|
|
540
|
+
"INSERT INTO _MxrbRubySource (Path, Contents, Sha256, Mode) VALUES (?, ?, ?, ?)",
|
|
541
|
+
[
|
|
542
|
+
file.fetch(:path), SQLite3::Blob.new(file.fetch(:contents)),
|
|
543
|
+
file.fetch(:sha256), file.fetch(:mode, 0o644)
|
|
544
|
+
]
|
|
545
|
+
)
|
|
546
|
+
end
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
# Cross-module Mendix associations do not expose native visual
|
|
550
|
+
# connection fields. Keep their ER-editor anchors in an MXRB-only table
|
|
551
|
+
# so the diagram remains editable without inventing unsupported BSON.
|
|
552
|
+
def domain_diagram_anchors
|
|
553
|
+
return {} unless tables.include?("_MxrbDomainDiagramAssociation")
|
|
554
|
+
|
|
555
|
+
@db.execute(<<~SQL).to_h do |row|
|
|
556
|
+
SELECT AssociationID, SourceAnchor, TargetAnchor
|
|
557
|
+
FROM _MxrbDomainDiagramAssociation
|
|
558
|
+
SQL
|
|
559
|
+
[row[0], { source_anchor: row[1], target_anchor: row[2] }]
|
|
560
|
+
end
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
def write_domain_diagram_anchors(layouts)
|
|
564
|
+
raise ReadOnlyError, "Opened in read-only mode" if @readonly
|
|
565
|
+
items = Array(layouts)
|
|
566
|
+
return 0 if items.empty?
|
|
567
|
+
|
|
568
|
+
@db.execute(<<~SQL)
|
|
569
|
+
CREATE TABLE IF NOT EXISTS _MxrbDomainDiagramAssociation (
|
|
570
|
+
AssociationID TEXT PRIMARY KEY NOT NULL,
|
|
571
|
+
SourceAnchor TEXT NOT NULL,
|
|
572
|
+
TargetAnchor TEXT NOT NULL
|
|
573
|
+
)
|
|
574
|
+
SQL
|
|
575
|
+
current = domain_diagram_anchors
|
|
576
|
+
items.count do |layout|
|
|
577
|
+
id = layout.fetch(:id).to_s
|
|
578
|
+
anchors = {
|
|
579
|
+
source_anchor: layout.fetch(:source_anchor).to_s,
|
|
580
|
+
target_anchor: layout.fetch(:target_anchor).to_s
|
|
581
|
+
}
|
|
582
|
+
next false if current[id] == anchors
|
|
583
|
+
|
|
584
|
+
@db.execute(
|
|
585
|
+
"INSERT OR REPLACE INTO _MxrbDomainDiagramAssociation " \
|
|
586
|
+
"(AssociationID, SourceAnchor, TargetAnchor) VALUES (?, ?, ?)",
|
|
587
|
+
[id, anchors.fetch(:source_anchor), anchors.fetch(:target_anchor)]
|
|
588
|
+
)
|
|
589
|
+
true
|
|
590
|
+
end
|
|
591
|
+
end
|
|
592
|
+
|
|
593
|
+
def legacy_unit_identity_mismatches
|
|
594
|
+
return [] unless tables.include?("_MxrbCompatibility")
|
|
595
|
+
|
|
596
|
+
@db.execute(<<~SQL).map do |row|
|
|
597
|
+
SELECT UnitID, ContentID, UnitType
|
|
598
|
+
FROM _MxrbCompatibility
|
|
599
|
+
WHERE Kind = 'legacy-unit-identity'
|
|
600
|
+
SQL
|
|
601
|
+
{ unit_id: row[0], content_id: row[1], type: row[2] }
|
|
602
|
+
end
|
|
603
|
+
end
|
|
604
|
+
|
|
605
|
+
def write_legacy_unit_identity_mismatches(mismatches)
|
|
606
|
+
raise ReadOnlyError, "Opened in read-only mode" if @readonly
|
|
607
|
+
|
|
608
|
+
@db.execute(<<~SQL)
|
|
609
|
+
CREATE TABLE IF NOT EXISTS _MxrbCompatibility (
|
|
610
|
+
Kind TEXT NOT NULL,
|
|
611
|
+
UnitID TEXT NOT NULL,
|
|
612
|
+
ContentID TEXT NOT NULL,
|
|
613
|
+
UnitType TEXT NOT NULL,
|
|
614
|
+
PRIMARY KEY (Kind, UnitID, ContentID)
|
|
615
|
+
)
|
|
616
|
+
SQL
|
|
617
|
+
@db.execute("DELETE FROM _MxrbCompatibility WHERE Kind = 'legacy-unit-identity'")
|
|
618
|
+
mismatches.each do |mismatch|
|
|
619
|
+
@db.execute(
|
|
620
|
+
"INSERT INTO _MxrbCompatibility (Kind, UnitID, ContentID, UnitType) VALUES (?, ?, ?, ?)",
|
|
621
|
+
["legacy-unit-identity", mismatch.fetch(:unit_id),
|
|
622
|
+
mismatch.fetch(:content_id), mismatch.fetch(:type)]
|
|
623
|
+
)
|
|
624
|
+
end
|
|
625
|
+
end
|
|
626
|
+
|
|
484
627
|
def close
|
|
485
628
|
@db.close
|
|
486
629
|
end
|
data/lib/mxrb/model/attribute.rb
CHANGED
|
@@ -7,6 +7,8 @@ module Mxrb
|
|
|
7
7
|
# Attributes are embedded in Entity BSON — NOT separate Unit rows.
|
|
8
8
|
# $Type: DomainModels$Attribute
|
|
9
9
|
class Attribute
|
|
10
|
+
DEFAULT_STRING_LENGTH = 200
|
|
11
|
+
|
|
10
12
|
# Maps DSL symbol → Mendix storage type name
|
|
11
13
|
TYPE_MAP = {
|
|
12
14
|
string: "DomainModels$StringAttributeType",
|
|
@@ -84,6 +86,7 @@ module Mxrb
|
|
|
84
86
|
def serialize_type
|
|
85
87
|
storage_type = TYPE_MAP[@type] || TYPE_MAP[:string]
|
|
86
88
|
base = { "$ID" => SecureRandom.uuid, "$Type" => storage_type }
|
|
89
|
+
base["length"] = @length || DEFAULT_STRING_LENGTH if storage_type == TYPE_MAP[:string]
|
|
87
90
|
base["localizeDate"] = true if @type == :datetime
|
|
88
91
|
base
|
|
89
92
|
end
|
data/lib/mxrb/model/entity.rb
CHANGED
|
@@ -10,7 +10,7 @@ module Mxrb
|
|
|
10
10
|
attr_accessor :id, :name, :qualified_name, :documentation,
|
|
11
11
|
:persistable, :location, :data_storage_guid,
|
|
12
12
|
:export_level, :generalization, :access_rules, :indexes,
|
|
13
|
-
:system_members
|
|
13
|
+
:system_members, :lifecycle, :source, :oql_query, :native_type
|
|
14
14
|
|
|
15
15
|
# Build from a BSON hash (embedded in DomainModel's "entities" array).
|
|
16
16
|
def self.from_bson(doc, _domain_model_id, mpr)
|
|
@@ -19,6 +19,9 @@ module Mxrb
|
|
|
19
19
|
e.name = doc["name"] || doc["Name"]
|
|
20
20
|
e.qualified_name = doc["$QualifiedName"] || doc["\$QualifiedName"]
|
|
21
21
|
e.documentation = doc["documentation"] || doc["Documentation"] || ""
|
|
22
|
+
e.native_type = doc["$Type"]
|
|
23
|
+
e.source = doc["source"] || doc["Source"]
|
|
24
|
+
e.oql_query = doc["oqlQuery"] || doc["OqlQuery"] || doc["OQLQuery"]
|
|
22
25
|
e.data_storage_guid = doc["dataStorageGuid"] || doc["DataStorageGuid"]
|
|
23
26
|
e.export_level = doc["exportLevel"] || doc["ExportLevel"] || "Hidden"
|
|
24
27
|
e.location = parse_location(doc["location"] || doc["Location"])
|
|
@@ -46,6 +49,8 @@ module Mxrb
|
|
|
46
49
|
# Access rules (embedded array with marker 3)
|
|
47
50
|
rule_arr = IO::BsonCodec.parse_array(doc["accessRules"] || doc["AccessRules"])[:items]
|
|
48
51
|
e.access_rules = rule_arr.map { parse_access_rule(_1) }
|
|
52
|
+
event_arr = IO::BsonCodec.parse_array(doc["eventHandlers"] || doc["EventHandlers"])[:items]
|
|
53
|
+
e.lifecycle = event_arr.map { parse_lifecycle(_1) }
|
|
49
54
|
|
|
50
55
|
e
|
|
51
56
|
end
|
|
@@ -58,6 +63,19 @@ module Mxrb
|
|
|
58
63
|
@generalization['generalization'] || @generalization['Generalization']
|
|
59
64
|
end
|
|
60
65
|
|
|
66
|
+
def oql_view?
|
|
67
|
+
source_type = @source.is_a?(Hash) ? @source.fetch('$Type', '') : ''
|
|
68
|
+
@native_type.to_s.match?(/ViewEntity/i) ||
|
|
69
|
+
source_type.match?(/OqlViewEntitySource/i) ||
|
|
70
|
+
!@oql_query.to_s.empty?
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def oql_source_document
|
|
74
|
+
return unless @source.is_a?(Hash)
|
|
75
|
+
|
|
76
|
+
@source['SourceDocument'] || @source['sourceDocument']
|
|
77
|
+
end
|
|
78
|
+
|
|
61
79
|
def to_bson
|
|
62
80
|
{
|
|
63
81
|
"$ID" => @id,
|
|
@@ -70,7 +88,7 @@ module Mxrb
|
|
|
70
88
|
"generalization" => serialize_generalization,
|
|
71
89
|
"attributes" => IO::BsonCodec.build_array(@attributes.map(&:to_bson)),
|
|
72
90
|
"validationRules" => IO::BsonCodec.build_array([]), # must come after attributes
|
|
73
|
-
"eventHandlers" => IO::BsonCodec.build_array(
|
|
91
|
+
"eventHandlers" => IO::BsonCodec.build_array(@lifecycle.to_a.map { lifecycle_bson(_1) }),
|
|
74
92
|
"indexes" => IO::BsonCodec.build_array([]),
|
|
75
93
|
"accessRules" => IO::BsonCodec.build_array(@access_rules.to_a),
|
|
76
94
|
"source" => nil,
|
|
@@ -150,6 +168,17 @@ module Mxrb
|
|
|
150
168
|
}
|
|
151
169
|
end
|
|
152
170
|
|
|
171
|
+
def self.parse_lifecycle(doc)
|
|
172
|
+
moment = doc["Moment"].to_s.downcase
|
|
173
|
+
event = doc["Event"].to_s.downcase
|
|
174
|
+
{
|
|
175
|
+
event: [moment, event].reject(&:empty?).join("_").to_sym,
|
|
176
|
+
handler: doc["Microflow"].to_s,
|
|
177
|
+
pass_event_object: doc.fetch("PassEventObject", true) == true,
|
|
178
|
+
raise_error_on_false: doc["RaiseErrorOnFalse"] == true
|
|
179
|
+
}
|
|
180
|
+
end
|
|
181
|
+
|
|
153
182
|
def self.parse_location(loc)
|
|
154
183
|
if loc.is_a?(String)
|
|
155
184
|
x, y = loc.split(';', 2).map(&:to_i)
|
|
@@ -175,6 +204,19 @@ module Mxrb
|
|
|
175
204
|
"hasChangedBy" => false,
|
|
176
205
|
}
|
|
177
206
|
end
|
|
207
|
+
|
|
208
|
+
def lifecycle_bson(callback)
|
|
209
|
+
moment, event = callback.fetch(:event).to_s.split("_", 2)
|
|
210
|
+
{
|
|
211
|
+
"$ID" => SecureRandom.uuid,
|
|
212
|
+
"$Type" => "DomainModels$EventHandler",
|
|
213
|
+
"Event" => event.to_s.capitalize,
|
|
214
|
+
"Moment" => moment.to_s.capitalize,
|
|
215
|
+
"Microflow" => callback.fetch(:handler).to_s,
|
|
216
|
+
"PassEventObject" => callback.fetch(:pass_event_object, true) == true,
|
|
217
|
+
"RaiseErrorOnFalse" => callback.fetch(:raise_error_on_false, false) == true
|
|
218
|
+
}
|
|
219
|
+
end
|
|
178
220
|
end
|
|
179
221
|
end
|
|
180
222
|
end
|
data/lib/mxrb/model/microflow.rb
CHANGED
|
@@ -8,7 +8,7 @@ module Mxrb
|
|
|
8
8
|
# ContainmentName: "Documents"
|
|
9
9
|
class Microflow < Unit
|
|
10
10
|
attr_reader :name, :documentation, :return_variable_name,
|
|
11
|
-
:allow_concurrent_execution, :mark_as_used, :excluded,
|
|
11
|
+
:allow_concurrent_execution, :apply_entity_access, :mark_as_used, :excluded,
|
|
12
12
|
:allowed_module_roles, :parameters, :return_type,
|
|
13
13
|
:objects, :flows
|
|
14
14
|
|
|
@@ -17,6 +17,7 @@ module Mxrb
|
|
|
17
17
|
@documentation = doc["Documentation"] || doc["documentation"] || ""
|
|
18
18
|
@return_variable_name = doc["ReturnVariableName"] || "ReturnValue"
|
|
19
19
|
@allow_concurrent_execution = doc["AllowConcurrentExecution"] != false
|
|
20
|
+
@apply_entity_access = doc["ApplyEntityAccess"] == true
|
|
20
21
|
@mark_as_used = doc["MarkAsUsed"] == true
|
|
21
22
|
@excluded = doc["Excluded"] == true
|
|
22
23
|
@allowed_module_roles = parse_array(doc["AllowedModuleRoles"])
|
|
@@ -43,6 +44,7 @@ module Mxrb
|
|
|
43
44
|
"Documentation" => @documentation || "",
|
|
44
45
|
"ReturnVariableName" => @return_variable_name || "ReturnValue",
|
|
45
46
|
"AllowConcurrentExecution" => @allow_concurrent_execution != false,
|
|
47
|
+
"ApplyEntityAccess" => @apply_entity_access == true,
|
|
46
48
|
"MarkAsUsed" => @mark_as_used || false,
|
|
47
49
|
"Excluded" => @excluded || false,
|
|
48
50
|
"AllowedModuleRoles" => IO::BsonCodec.build_array(@allowed_module_roles || [], marker: 1),
|