retold-facto 0.0.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.
Files changed (92) hide show
  1. package/.claude/launch.json +11 -0
  2. package/.dockerignore +8 -0
  3. package/.quackage.json +19 -0
  4. package/Dockerfile +26 -0
  5. package/bin/retold-facto.js +909 -0
  6. package/examples/facto-government-data.sqlite +0 -0
  7. package/examples/government-data-catalog.json +137 -0
  8. package/examples/government-data-loader.js +1432 -0
  9. package/package.json +91 -0
  10. package/scripts/facto-download.js +425 -0
  11. package/source/Retold-Facto.js +1042 -0
  12. package/source/services/Retold-Facto-BeaconProvider.js +511 -0
  13. package/source/services/Retold-Facto-CatalogManager.js +1252 -0
  14. package/source/services/Retold-Facto-DataLakeService.js +1642 -0
  15. package/source/services/Retold-Facto-DatasetManager.js +417 -0
  16. package/source/services/Retold-Facto-IngestEngine.js +1315 -0
  17. package/source/services/Retold-Facto-ProjectionEngine.js +3960 -0
  18. package/source/services/Retold-Facto-RecordManager.js +360 -0
  19. package/source/services/Retold-Facto-SchemaManager.js +1110 -0
  20. package/source/services/Retold-Facto-SourceFolderScanner.js +2243 -0
  21. package/source/services/Retold-Facto-SourceManager.js +730 -0
  22. package/source/services/Retold-Facto-StoreConnectionManager.js +441 -0
  23. package/source/services/Retold-Facto-ThroughputMonitor.js +478 -0
  24. package/source/services/web-app/codemirror-entry.js +7 -0
  25. package/source/services/web-app/pict-app/Pict-Application-Facto-Configuration.json +9 -0
  26. package/source/services/web-app/pict-app/Pict-Application-Facto.js +70 -0
  27. package/source/services/web-app/pict-app/Pict-Facto-Bundle.js +11 -0
  28. package/source/services/web-app/pict-app/providers/Pict-Provider-Facto-UI.js +66 -0
  29. package/source/services/web-app/pict-app/providers/Pict-Provider-Facto.js +69 -0
  30. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Catalog.js +93 -0
  31. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Connections.js +42 -0
  32. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Datasets.js +605 -0
  33. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Projections.js +188 -0
  34. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Scanner.js +80 -0
  35. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Schema.js +116 -0
  36. package/source/services/web-app/pict-app/providers/facto-api/Facto-API-Sources.js +104 -0
  37. package/source/services/web-app/pict-app/views/PictView-Facto-Catalog.js +526 -0
  38. package/source/services/web-app/pict-app/views/PictView-Facto-Datasets.js +173 -0
  39. package/source/services/web-app/pict-app/views/PictView-Facto-Ingest.js +259 -0
  40. package/source/services/web-app/pict-app/views/PictView-Facto-Layout.js +191 -0
  41. package/source/services/web-app/pict-app/views/PictView-Facto-Projections.js +231 -0
  42. package/source/services/web-app/pict-app/views/PictView-Facto-Records.js +326 -0
  43. package/source/services/web-app/pict-app/views/PictView-Facto-Scanner.js +624 -0
  44. package/source/services/web-app/pict-app/views/PictView-Facto-Sources.js +201 -0
  45. package/source/services/web-app/pict-app/views/PictView-Facto-Throughput.js +456 -0
  46. package/source/services/web-app/pict-app-full/Pict-Application-Facto-Full-Configuration.json +14 -0
  47. package/source/services/web-app/pict-app-full/Pict-Application-Facto-Full.js +391 -0
  48. package/source/services/web-app/pict-app-full/providers/PictRouter-Facto-Configuration.json +56 -0
  49. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-BottomBar.js +68 -0
  50. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Connections.js +340 -0
  51. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Dashboard.js +149 -0
  52. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Dashboards.js +819 -0
  53. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Datasets.js +178 -0
  54. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-IngestJobs.js +99 -0
  55. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Layout.js +62 -0
  56. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-MappingEditor.js +158 -0
  57. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-ProjectionDetail.js +1120 -0
  58. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Projections.js +172 -0
  59. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-QueryPanel.js +119 -0
  60. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-RecordViewer.js +663 -0
  61. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Records.js +648 -0
  62. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Scanner.js +1017 -0
  63. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaDetail.js +1404 -0
  64. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaDocEditor.js +1036 -0
  65. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaEditor.js +636 -0
  66. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SchemaResearch.js +357 -0
  67. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SourceDetail.js +822 -0
  68. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SourceEditor.js +1036 -0
  69. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-SourceResearch.js +487 -0
  70. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Sources.js +165 -0
  71. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-Throughput.js +439 -0
  72. package/source/services/web-app/pict-app-full/views/PictView-Facto-Full-TopBar.js +335 -0
  73. package/source/services/web-app/pict-app-full/views/projections/Facto-Projections-Constants.js +71 -0
  74. package/source/services/web-app/web/chart.min.js +20 -0
  75. package/source/services/web-app/web/codemirror-bundle.js +30099 -0
  76. package/source/services/web-app/web/css/facto-themes.css +467 -0
  77. package/source/services/web-app/web/css/facto.css +502 -0
  78. package/source/services/web-app/web/index.html +28 -0
  79. package/source/services/web-app/web/retold-facto.js +12138 -0
  80. package/source/services/web-app/web/retold-facto.js.map +1 -0
  81. package/source/services/web-app/web/retold-facto.min.js +2 -0
  82. package/source/services/web-app/web/retold-facto.min.js.map +1 -0
  83. package/source/services/web-app/web/simple/index.html +17 -0
  84. package/test/Facto_Browser_Integration_tests.js +798 -0
  85. package/test/RetoldFacto_tests.js +4117 -0
  86. package/test/fixtures/weather-readings.csv +17 -0
  87. package/test/fixtures/weather-stations.csv +9 -0
  88. package/test/model/MeadowModel-Extended.json +8497 -0
  89. package/test/model/MeadowModel-PICT.json +1 -0
  90. package/test/model/MeadowModel.json +1355 -0
  91. package/test/model/ddl/Facto.ddl +225 -0
  92. package/test/model/fable-configuration.json +14 -0
@@ -0,0 +1,172 @@
1
+ const libPictView = require('pict-view');
2
+
3
+ const _ViewConfiguration =
4
+ {
5
+ ViewIdentifier: "Facto-Full-Projections",
6
+
7
+ DefaultRenderable: "Facto-Full-Projections-Content",
8
+ DefaultDestinationAddress: "#Facto-Full-Content-Container",
9
+
10
+ AutoRender: false,
11
+
12
+ CSS: ``,
13
+
14
+ Templates:
15
+ [
16
+ {
17
+ Hash: "Facto-Full-Projections-Template",
18
+ Template: /*html*/`
19
+ <div class="facto-content">
20
+ <div class="facto-content-header">
21
+ <h1>Projections</h1>
22
+ <p>Define schemas and deploy projections to external stores.</p>
23
+ </div>
24
+
25
+ <div style="display:flex; align-items:center; justify-content:space-between; margin-bottom:1em;">
26
+ <div class="facto-section-title" style="margin:0;">Projection Datasets</div>
27
+ <button class="facto-btn facto-btn-primary" onclick="{~P~}.views['Facto-Full-Projections'].createProjection()">+ New Projection</button>
28
+ </div>
29
+ <div id="Facto-Proj-List"></div>
30
+ </div>
31
+ `
32
+ }
33
+ ],
34
+
35
+ Renderables:
36
+ [
37
+ {
38
+ RenderableHash: "Facto-Full-Projections-Content",
39
+ TemplateHash: "Facto-Full-Projections-Template",
40
+ DestinationAddress: "#Facto-Full-Content-Container",
41
+ RenderMethod: "replace"
42
+ }
43
+ ]
44
+ };
45
+
46
+ class FactoFullProjectionsView extends libPictView
47
+ {
48
+ constructor(pFable, pOptions, pServiceHash)
49
+ {
50
+ super(pFable, pOptions, pServiceHash);
51
+
52
+ // Defer AppData initialization — Facto state is set up in onAfterInitializeAsync
53
+ if (this.pict.AppData.Facto)
54
+ {
55
+ this.pict.AppData.Facto.Projections = [];
56
+ }
57
+ }
58
+
59
+ onAfterRender(pRenderable, pRenderDestinationAddress, pRecord, pContent)
60
+ {
61
+ this.pict.providers.Facto.loadProjections().then(
62
+ () =>
63
+ {
64
+ this.refreshProjectionList();
65
+ }).catch(
66
+ (pError) =>
67
+ {
68
+ this.pict.views['Pict-Section-Modal'].toast('Error loading projections: ' + pError.message, {type: 'error'});
69
+ });
70
+
71
+ return super.onAfterRender(pRenderable, pRenderDestinationAddress, pRecord, pContent);
72
+ }
73
+
74
+ refreshProjectionList()
75
+ {
76
+ let tmpContainer = document.getElementById('Facto-Proj-List');
77
+ if (!tmpContainer) return;
78
+
79
+ if (this.pict.AppData.Facto.Projections.length === 0)
80
+ {
81
+ tmpContainer.innerHTML = '<div class="facto-card" style="text-align:center; padding:2em; color:var(--facto-text-tertiary);">No projection datasets yet. Create one to get started.</div>';
82
+ return;
83
+ }
84
+
85
+ let tmpHtml = '<table class="facto-table"><thead><tr>';
86
+ tmpHtml += '<th>ID</th><th>Name</th><th>Schema Ver.</th><th>Actions</th>';
87
+ tmpHtml += '</tr></thead><tbody>';
88
+
89
+ for (let i = 0; i < this.pict.AppData.Facto.Projections.length; i++)
90
+ {
91
+ let tmpProj = this.pict.AppData.Facto.Projections[i];
92
+ tmpHtml += '<tr>';
93
+ tmpHtml += '<td>' + tmpProj.IDDataset + '</td>';
94
+ tmpHtml += '<td><strong>' + (tmpProj.Name || '\u2014') + '</strong></td>';
95
+ tmpHtml += '<td>v' + (tmpProj.SchemaVersion || 0) + '</td>';
96
+ tmpHtml += '<td>';
97
+ tmpHtml += '<button class="facto-btn facto-btn-primary facto-btn-small" onclick="pict.PictApplication.navigateTo(\'/Projection/' + tmpProj.IDDataset + '\')">View</button> ';
98
+ tmpHtml += '<button class="facto-btn facto-btn-danger facto-btn-small" onclick="pict.views[\'Facto-Full-Projections\'].deleteProjection(' + tmpProj.IDDataset + ', \'' + (tmpProj.Name || '').replace(/'/g, "\\'") + '\')">Delete</button>';
99
+ tmpHtml += '</td>';
100
+ tmpHtml += '</tr>';
101
+ }
102
+
103
+ tmpHtml += '</tbody></table>';
104
+ tmpContainer.innerHTML = tmpHtml;
105
+ }
106
+
107
+ createProjection()
108
+ {
109
+ let tmpName = prompt('Projection name:');
110
+ if (!tmpName) return;
111
+
112
+ this.pict.providers.Facto.createDataset(
113
+ {
114
+ Name: tmpName,
115
+ Type: 'Projection',
116
+ Description: 'Projection dataset'
117
+ }).then(
118
+ (pResponse) =>
119
+ {
120
+ if (pResponse && pResponse.Error)
121
+ {
122
+ this.pict.views['Pict-Section-Modal'].toast('Error: ' + pResponse.Error, {type: 'error'});
123
+ return;
124
+ }
125
+
126
+ // Navigate to the new projection's detail page
127
+ if (pResponse && pResponse.IDDataset)
128
+ {
129
+ this.pict.PictApplication.navigateTo('/Projection/' + pResponse.IDDataset);
130
+ }
131
+ else
132
+ {
133
+ // Fallback: reload the list
134
+ this.pict.providers.Facto.loadProjections().then(
135
+ (pResult) =>
136
+ {
137
+ this.pict.AppData.Facto.Projections = (pResult && pResult.Projections) ? pResult.Projections : [];
138
+ this.refreshProjectionList();
139
+ });
140
+ }
141
+ });
142
+ }
143
+
144
+ async deleteProjection(pIDDataset, pName)
145
+ {
146
+ let tmpConfirmed = await this.pict.views['Pict-Section-Modal'].confirm('Delete projection "' + (pName || pIDDataset) + '"? This will remove the dataset and all associated mappings and stores.', { title: 'Delete Projection', confirmLabel: 'Delete', dangerous: true });
147
+ if (!tmpConfirmed) return;
148
+
149
+ this.pict.providers.Facto.deleteProjection(pIDDataset).then(
150
+ (pResponse) =>
151
+ {
152
+ if (pResponse && pResponse.Error)
153
+ {
154
+ this.pict.views['Pict-Section-Modal'].toast('Error deleting projection: ' + pResponse.Error, {type: 'error'});
155
+ return;
156
+ }
157
+
158
+ this.pict.views['Pict-Section-Modal'].toast('Projection deleted.', {type: 'success'});
159
+
160
+ this.pict.providers.Facto.loadProjections().then(
161
+ (pResult) =>
162
+ {
163
+ this.pict.AppData.Facto.Projections = (pResult && pResult.Projections) ? pResult.Projections : [];
164
+ this.refreshProjectionList();
165
+ });
166
+ });
167
+ }
168
+ }
169
+
170
+ module.exports = FactoFullProjectionsView;
171
+
172
+ module.exports.default_configuration = _ViewConfiguration;
@@ -0,0 +1,119 @@
1
+ const libPictView = require('pict-view');
2
+
3
+ const _ViewConfiguration =
4
+ {
5
+ ViewIdentifier: "Facto-Full-QueryPanel",
6
+
7
+ DefaultRenderable: "Facto-Full-QueryPanel-Content",
8
+ DefaultDestinationAddress: "#Facto-Proj-Query-Container",
9
+
10
+ AutoRender: false,
11
+
12
+ CSS: ``,
13
+
14
+ Templates:
15
+ [
16
+ {
17
+ Hash: "Facto-Full-QueryPanel-Template",
18
+ Template: /*html*/`
19
+ <div>
20
+ <div style="margin-bottom:1em;">
21
+ <button class="facto-btn facto-btn-secondary facto-btn-small" onclick="{~P~}.views['Facto-Full-ProjectionDetail'].closeQuery()">&larr; Back to Projection</button>
22
+ </div>
23
+
24
+ <div class="facto-section">
25
+ <div class="facto-section-title">Warehouse Summary</div>
26
+ <div id="Facto-Full-Projections-Summary" class="facto-card-grid"></div>
27
+ </div>
28
+
29
+ <div class="facto-section" style="margin-top:1.5em;">
30
+ <div class="facto-section-title">Query Records</div>
31
+ <div class="facto-inline-group">
32
+ <div>
33
+ <label>Dataset ID</label>
34
+ <input type="number" id="Facto-Full-Proj-DatasetID" placeholder="e.g. 1">
35
+ </div>
36
+ <div>
37
+ <label>Type Filter</label>
38
+ <select id="Facto-Full-Proj-Type">
39
+ <option value="">All</option>
40
+ <option value="Raw">Raw</option>
41
+ <option value="Compositional">Compositional</option>
42
+ <option value="Projection">Projection</option>
43
+ </select>
44
+ </div>
45
+ </div>
46
+ <button class="facto-btn facto-btn-primary" onclick="{~P~}.views['Facto-Full-QueryPanel'].runQuery()">Run Query</button>
47
+ <button class="facto-btn facto-btn-secondary" onclick="{~P~}.views['Facto-Full-QueryPanel'].runAggregate()">Aggregate</button>
48
+ </div>
49
+ <div id="Facto-Full-Projections-Results" class="facto-projection-results" style="display:none;"></div>
50
+ </div>
51
+ `
52
+ }
53
+ ],
54
+
55
+ Renderables:
56
+ [
57
+ {
58
+ RenderableHash: "Facto-Full-QueryPanel-Content",
59
+ TemplateHash: "Facto-Full-QueryPanel-Template",
60
+ DestinationAddress: "#Facto-Proj-Query-Container",
61
+ RenderMethod: "replace"
62
+ }
63
+ ]
64
+ };
65
+
66
+ class FactoFullQueryPanelView extends libPictView
67
+ {
68
+ constructor(pFable, pOptions, pServiceHash)
69
+ {
70
+ super(pFable, pOptions, pServiceHash);
71
+ }
72
+
73
+ runQuery()
74
+ {
75
+ let tmpDatasetID = parseInt(this.pict.providers.FactoUI.getVal('Facto-Full-Proj-DatasetID')) || 0;
76
+ let tmpType = this.pict.providers.FactoUI.getVal('Facto-Full-Proj-Type');
77
+
78
+ let tmpParams = {};
79
+ if (tmpDatasetID) tmpParams.IDDataset = tmpDatasetID;
80
+ if (tmpType) tmpParams.Type = tmpType;
81
+
82
+ this.pict.providers.Facto.queryRecords(tmpParams).then(
83
+ (pResponse) =>
84
+ {
85
+ this._showResults('Query Results', pResponse);
86
+ });
87
+ }
88
+
89
+ runAggregate()
90
+ {
91
+ let tmpDatasetID = parseInt(this.pict.providers.FactoUI.getVal('Facto-Full-Proj-DatasetID')) || 0;
92
+
93
+ let tmpParams = {};
94
+ if (tmpDatasetID) tmpParams.IDDataset = tmpDatasetID;
95
+
96
+ this.pict.providers.Facto.aggregateRecords(tmpParams).then(
97
+ (pResponse) =>
98
+ {
99
+ this._showResults('Aggregate Results', pResponse);
100
+ });
101
+ }
102
+
103
+ _showResults(pTitle, pData)
104
+ {
105
+ let tmpContainer = document.getElementById('Facto-Full-Projections-Results');
106
+ if (!tmpContainer) return;
107
+ tmpContainer.style.display = 'block';
108
+
109
+ let tmpRecordCount = (pData && pData.Records) ? pData.Records.length : (pData && pData.Aggregations) ? pData.Aggregations.length : 0;
110
+ let tmpHtml = '<h3>' + pTitle + ' (' + tmpRecordCount + ')</h3>';
111
+ tmpHtml += '<pre>' + JSON.stringify(pData, null, 2) + '</pre>';
112
+ tmpHtml += '<button class="facto-btn facto-btn-secondary" style="margin-top:0.5em;" onclick="document.getElementById(\'Facto-Full-Projections-Results\').style.display=\'none\'">Close</button>';
113
+ tmpContainer.innerHTML = tmpHtml;
114
+ }
115
+ }
116
+
117
+ module.exports = FactoFullQueryPanelView;
118
+
119
+ module.exports.default_configuration = _ViewConfiguration;