@memberjunction/sqlserver-dataprovider 3.3.0 → 4.0.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.
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /**
3
2
  * @fileoverview SQL Server Data Provider for MemberJunction
4
3
  *
@@ -11,49 +10,25 @@
11
10
  * @version 2.0
12
11
  * @since 1.0
13
12
  */
14
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
15
- if (k2 === undefined) k2 = k;
16
- var desc = Object.getOwnPropertyDescriptor(m, k);
17
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
18
- desc = { enumerable: true, get: function() { return m[k]; } };
19
- }
20
- Object.defineProperty(o, k2, desc);
21
- }) : (function(o, m, k, k2) {
22
- if (k2 === undefined) k2 = k;
23
- o[k2] = m[k];
24
- }));
25
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
26
- Object.defineProperty(o, "default", { enumerable: true, value: v });
27
- }) : function(o, v) {
28
- o["default"] = v;
29
- });
30
- var __importStar = (this && this.__importStar) || function (mod) {
31
- if (mod && mod.__esModule) return mod;
32
- var result = {};
33
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
34
- __setModuleDefault(result, mod);
35
- return result;
36
- };
37
- Object.defineProperty(exports, "__esModule", { value: true });
38
- exports.SQLServerDataProvider = void 0;
39
13
  /**************************************************************************************************************
40
14
  * The SQLServerDataProvider provides a data provider for the entities framework that uses SQL Server directly
41
15
  * In practice - this FILE will NOT exist in the entities library, we need to move to its own separate project
42
16
  * so it is only included by the consumer of the entities library if they want to use it.
43
17
  **************************************************************************************************************/
44
- const core_1 = require("@memberjunction/core");
45
- const queryParameterProcessor_1 = require("./queryParameterProcessor");
46
- const core_entities_1 = require("@memberjunction/core-entities");
47
- const aiengine_1 = require("@memberjunction/aiengine");
48
- const queue_1 = require("@memberjunction/queue");
49
- const sql = __importStar(require("mssql"));
50
- const rxjs_1 = require("rxjs");
51
- const SQLServerTransactionGroup_1 = require("./SQLServerTransactionGroup");
52
- const SqlLogger_js_1 = require("./SqlLogger.js");
53
- const actions_1 = require("@memberjunction/actions");
54
- const encryption_1 = require("@memberjunction/encryption");
55
- const uuid_1 = require("uuid");
56
- const global_1 = require("@memberjunction/global");
18
+ import { ApplicationInfo, EntityFieldTSType, ProviderType, UserInfo, AuditLogTypeInfo, AuthorizationInfo, TransactionItem, EntityPermissionType, EntitySaveOptions, LogError, StripStopWords, LogStatus, CompositeKey, EntityDeleteOptions, BaseEntityResult, Metadata, DatabaseProviderBase, QueryCache, InMemoryLocalStorageProvider, } from '@memberjunction/core';
19
+ import { QueryParameterProcessor } from './queryParameterProcessor.js';
20
+ import { NodeFileSystemProvider } from './NodeFileSystemProvider.js';
21
+ import { ViewInfo, } from '@memberjunction/core-entities';
22
+ import { AIEngine } from '@memberjunction/aiengine';
23
+ import { QueueManager } from '@memberjunction/queue';
24
+ import sql from 'mssql';
25
+ import { BehaviorSubject, Subject, concatMap, from, tap, catchError, of } from 'rxjs';
26
+ import { SQLServerTransactionGroup } from './SQLServerTransactionGroup.js';
27
+ import { SqlLoggingSessionImpl } from './SqlLogger.js';
28
+ import { EntityActionEngineServer } from '@memberjunction/actions';
29
+ import { EncryptionEngine } from '@memberjunction/encryption';
30
+ import { v4 as uuidv4 } from 'uuid';
31
+ import { MJGlobal, SQLExpressionValidator } from '@memberjunction/global';
57
32
  /**
58
33
  * Core SQL execution function - handles the actual database query execution
59
34
  * This is outside the class to allow both static and instance methods to use it
@@ -155,24 +130,27 @@ async function executeSQLCore(query, parameters, context, options) {
155
130
  * await provider.Config();
156
131
  * ```
157
132
  */
158
- class SQLServerDataProvider extends core_1.DatabaseProviderBase {
159
- _pool;
160
- // Instance transaction properties
161
- _transaction;
162
- _transactionDepth = 0;
163
- _savepointCounter = 0;
164
- _savepointStack = [];
165
- // Query cache instance
166
- queryCache = new core_1.QueryCache();
167
- // Removed _transactionRequest - creating new Request objects for each query to avoid concurrency issues
168
- _localStorageProvider;
169
- _bAllowRefresh = true;
170
- _recordDupeDetector;
171
- _needsDatetimeOffsetAdjustment = false;
172
- _datetimeOffsetTestComplete = false;
173
- static _sqlLoggingSessionsKey = 'MJ_SQLServerDataProvider_SqlLoggingSessions';
133
+ export class SQLServerDataProvider extends DatabaseProviderBase {
134
+ constructor() {
135
+ super(...arguments);
136
+ this._transactionDepth = 0;
137
+ this._savepointCounter = 0;
138
+ this._savepointStack = [];
139
+ // Query cache instance
140
+ this.queryCache = new QueryCache();
141
+ this._bAllowRefresh = true;
142
+ this._needsDatetimeOffsetAdjustment = false;
143
+ this._datetimeOffsetTestComplete = false;
144
+ // Instance SQL execution queue for serializing transaction queries
145
+ // Non-transactional queries bypass this queue for maximum parallelism
146
+ this._sqlQueue$ = new Subject();
147
+ // Transaction state management
148
+ this._transactionState$ = new BehaviorSubject(false);
149
+ this._deferredTasks = [];
150
+ }
151
+ static { this._sqlLoggingSessionsKey = 'MJ_SQLServerDataProvider_SqlLoggingSessions'; }
174
152
  get _sqlLoggingSessions() {
175
- const g = global_1.MJGlobal.Instance.GetGlobalObjectStore();
153
+ const g = MJGlobal.Instance.GetGlobalObjectStore();
176
154
  if (g) {
177
155
  if (!g[SQLServerDataProvider._sqlLoggingSessionsKey]) {
178
156
  g[SQLServerDataProvider._sqlLoggingSessionsKey] = new Map();
@@ -183,14 +161,6 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
183
161
  throw new Error('No global object store available for SQL logging session');
184
162
  }
185
163
  }
186
- // Instance SQL execution queue for serializing transaction queries
187
- // Non-transactional queries bypass this queue for maximum parallelism
188
- _sqlQueue$ = new rxjs_1.Subject();
189
- // Subscription for the queue processor
190
- _queueSubscription;
191
- // Transaction state management
192
- _transactionState$ = new rxjs_1.BehaviorSubject(false);
193
- _deferredTasks = [];
194
164
  /**
195
165
  * Observable that emits the current transaction state (true when active, false when not)
196
166
  * External code can subscribe to this to know when transactions start and end
@@ -258,7 +228,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
258
228
  return super.Config(configData, providerToUse); // now parent class can do it's config
259
229
  }
260
230
  catch (e) {
261
- (0, core_1.LogError)(e);
231
+ LogError(e);
262
232
  throw e;
263
233
  }
264
234
  }
@@ -270,13 +240,13 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
270
240
  // Each instance gets its own queue processor, but only do this ONCE if we get this method called more than once we don't need to reinit
271
241
  // the sub, taht would cause duplicate rprocessing.
272
242
  if (!this._queueSubscription) {
273
- this._queueSubscription = this._sqlQueue$.pipe((0, rxjs_1.concatMap)(item => (0, rxjs_1.from)(executeSQLCore(item.query, item.parameters, item.context, item.options)).pipe(
243
+ this._queueSubscription = this._sqlQueue$.pipe(concatMap(item => from(executeSQLCore(item.query, item.parameters, item.context, item.options)).pipe(
274
244
  // Handle success
275
- (0, rxjs_1.tap)(result => item.resolve(result)),
245
+ tap(result => item.resolve(result)),
276
246
  // Handle errors
277
- (0, rxjs_1.catchError)(error => {
247
+ catchError(error => {
278
248
  item.reject(error);
279
- return (0, rxjs_1.of)(null); // Continue processing queue even on errors
249
+ return of(null); // Continue processing queue even on errors
280
250
  })))).subscribe();
281
251
  }
282
252
  }
@@ -348,9 +318,9 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
348
318
  * ```
349
319
  */
350
320
  async CreateSqlLogger(filePath, options) {
351
- const sessionId = (0, uuid_1.v4)();
321
+ const sessionId = uuidv4();
352
322
  const mjCoreSchema = this.ConfigData.MJCoreSchemaName;
353
- const session = new SqlLogger_js_1.SqlLoggingSessionImpl(sessionId, filePath, {
323
+ const session = new SqlLoggingSessionImpl(sessionId, filePath, {
354
324
  defaultSchemaName: mjCoreSchema,
355
325
  ...options // if defaultSchemaName is not provided, it will use the MJCoreSchemaName, otherwise
356
326
  // the caller's defaultSchemaName will be used
@@ -504,7 +474,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
504
474
  */
505
475
  static async LogSQLStatement(query, parameters, description, isMutation = false, simpleSQLFallback, contextUser) {
506
476
  // Get the current provider instance
507
- const provider = core_1.Metadata.Provider;
477
+ const provider = Metadata.Provider;
508
478
  if (provider && provider._sqlLoggingSessions.size > 0) {
509
479
  await provider._logSqlStatement(query, parameters, description, false, isMutation, simpleSQLFallback, contextUser);
510
480
  }
@@ -668,7 +638,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
668
638
  };
669
639
  }
670
640
  catch (e) {
671
- (0, core_1.LogError)(e);
641
+ LogError(e);
672
642
  const errorMessage = e instanceof Error ? e.message : String(e);
673
643
  return {
674
644
  Success: false,
@@ -721,7 +691,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
721
691
  let finalSQL = query.SQL;
722
692
  let appliedParameters = {};
723
693
  if (query.UsesTemplate) {
724
- const processingResult = queryParameterProcessor_1.QueryParameterProcessor.processQueryTemplate(query, parameters);
694
+ const processingResult = QueryParameterProcessor.processQueryTemplate(query, parameters);
725
695
  if (!processingResult.success) {
726
696
  throw new Error(processingResult.error);
727
697
  }
@@ -730,7 +700,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
730
700
  }
731
701
  else if (parameters && Object.keys(parameters).length > 0) {
732
702
  // Warn if parameters were provided but query doesn't use templates
733
- (0, core_1.LogStatus)('Warning: Parameters provided but query does not use templates. Parameters will be ignored.');
703
+ LogStatus('Warning: Parameters provided but query does not use templates. Parameters will be ignored.');
734
704
  }
735
705
  return { finalSQL, appliedParameters };
736
706
  }
@@ -746,7 +716,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
746
716
  if (!cachedEntry) {
747
717
  return null;
748
718
  }
749
- (0, core_1.LogStatus)(`Cache hit for query ${query.Name} (${query.ID})`);
719
+ LogStatus(`Cache hit for query ${query.Name} (${query.ID})`);
750
720
  // Apply pagination to cached results
751
721
  const { paginatedResult, totalRowCount } = this.applyQueryPagination(cachedEntry.results, params);
752
722
  const remainingTTL = (cachedEntry.timestamp + (cachedEntry.ttlMinutes * 60 * 1000)) - Date.now();
@@ -829,7 +799,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
829
799
  }
830
800
  // Cache the full result set (before pagination)
831
801
  this.queryCache.set(query.ID, parameters, results, cacheConfig);
832
- (0, core_1.LogStatus)(`Cached results for query ${query.Name} (${query.ID})`);
802
+ LogStatus(`Cached results for query ${query.Name} (${query.ID})`);
833
803
  }
834
804
  /**
835
805
  * Internal implementation of batch query execution.
@@ -951,7 +921,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
951
921
  };
952
922
  }
953
923
  catch (e) {
954
- (0, core_1.LogError)(e);
924
+ LogError(e);
955
925
  return {
956
926
  success: false,
957
927
  results: [],
@@ -1092,7 +1062,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
1092
1062
  else
1093
1063
  stack.push(variable); // add to the stack for circular reference detection
1094
1064
  // variable values is the view ID of the view that we want to get its WHERE CLAUSE, so we need to get the view entity
1095
- const innerViewEntity = await core_entities_1.ViewInfo.GetViewEntity(variableValue, user);
1065
+ const innerViewEntity = await ViewInfo.GetViewEntity(variableValue, user);
1096
1066
  if (innerViewEntity) {
1097
1067
  // we have the inner view, so now call this function recursively to get the where clause for the inner view
1098
1068
  const innerWhere = await this.RenderViewWhereClause(innerViewEntity, user, stack);
@@ -1115,7 +1085,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
1115
1085
  return sWhere;
1116
1086
  }
1117
1087
  catch (e) {
1118
- (0, core_1.LogError)(e);
1088
+ LogError(e);
1119
1089
  throw e;
1120
1090
  }
1121
1091
  }
@@ -1126,7 +1096,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
1126
1096
  // This is the internal implementation - pre/post processing is handled by ProviderBase.RunView()
1127
1097
  // Log aggregate input for debugging
1128
1098
  if (params?.Aggregates?.length) {
1129
- (0, core_1.LogStatus)(`[SQLServerDataProvider] InternalRunView received aggregates: entityName=${params.EntityName}, viewID=${params.ViewID}, viewName=${params.ViewName}, aggregateCount=${params.Aggregates.length}, aggregates=${JSON.stringify(params.Aggregates.map(a => ({ expression: a.expression, alias: a.alias })))}`);
1099
+ LogStatus(`[SQLServerDataProvider] InternalRunView received aggregates: entityName=${params.EntityName}, viewID=${params.ViewID}, viewName=${params.ViewName}, aggregateCount=${params.Aggregates.length}, aggregates=${JSON.stringify(params.Aggregates.map(a => ({ expression: a.expression, alias: a.alias })))}`);
1130
1100
  }
1131
1101
  const startTime = new Date();
1132
1102
  try {
@@ -1138,9 +1108,9 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
1138
1108
  if (params.ViewEntity)
1139
1109
  viewEntity = params.ViewEntity;
1140
1110
  else if (params.ViewID && params.ViewID.length > 0)
1141
- viewEntity = await core_entities_1.ViewInfo.GetViewEntity(params.ViewID, contextUser);
1111
+ viewEntity = await ViewInfo.GetViewEntity(params.ViewID, contextUser);
1142
1112
  else if (params.ViewName && params.ViewName.length > 0)
1143
- viewEntity = await core_entities_1.ViewInfo.GetViewEntityByName(params.ViewName, contextUser);
1113
+ viewEntity = await ViewInfo.GetViewEntityByName(params.ViewName, contextUser);
1144
1114
  if (!viewEntity) {
1145
1115
  // if we don't have viewEntity, that means it is a dynamic view, so we need EntityName at a minimum
1146
1116
  if (!params.EntityName || params.EntityName.length === 0)
@@ -1244,9 +1214,9 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
1244
1214
  }
1245
1215
  }
1246
1216
  // NEXT, apply Row Level Security (RLS)
1247
- if (!entityInfo.UserExemptFromRowLevelSecurity(user, core_1.EntityPermissionType.Read)) {
1217
+ if (!entityInfo.UserExemptFromRowLevelSecurity(user, EntityPermissionType.Read)) {
1248
1218
  // user is NOT exempt from RLS, so we need to apply it
1249
- const rlsWhereClause = entityInfo.GetUserRowLevelSecurityWhereClause(user, core_1.EntityPermissionType.Read, '');
1219
+ const rlsWhereClause = entityInfo.GetUserRowLevelSecurityWhereClause(user, EntityPermissionType.Read, '');
1250
1220
  if (rlsWhereClause && rlsWhereClause.length > 0) {
1251
1221
  if (bHasWhere) {
1252
1222
  whereSQL += ` AND (${rlsWhereClause})`;
@@ -1330,7 +1300,12 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
1330
1300
  resultMap[key] = results[index];
1331
1301
  });
1332
1302
  // Process data results
1333
- const retData = resultMap['data'] || [];
1303
+ let retData = resultMap['data'] || [];
1304
+ // Process rows for datetime conversion and field-level decryption
1305
+ // This is critical for encrypted fields - without this, encrypted data stays encrypted in the UI
1306
+ if (retData.length > 0 && params.ResultType !== 'count_only') {
1307
+ retData = await this.ProcessEntityRows(retData, entityInfo, contextUser);
1308
+ }
1334
1309
  // Process count results - also check if we need count based on result length
1335
1310
  let rowCount = null;
1336
1311
  if (willNeedCount && resultMap['count']) {
@@ -1422,7 +1397,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
1422
1397
  }
1423
1398
  catch (e) {
1424
1399
  const exceptionStopTime = new Date();
1425
- (0, core_1.LogError)(e);
1400
+ LogError(e);
1426
1401
  return {
1427
1402
  RowCount: 0,
1428
1403
  TotalRowCount: 0,
@@ -1561,7 +1536,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
1561
1536
  };
1562
1537
  }
1563
1538
  catch (e) {
1564
- (0, core_1.LogError)(e);
1539
+ LogError(e);
1565
1540
  return {
1566
1541
  success: false,
1567
1542
  results: [],
@@ -1644,8 +1619,8 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
1644
1619
  }
1645
1620
  }
1646
1621
  // Row Level Security
1647
- if (!entityInfo.UserExemptFromRowLevelSecurity(user, core_1.EntityPermissionType.Read)) {
1648
- const rlsWhereClause = entityInfo.GetUserRowLevelSecurityWhereClause(user, core_1.EntityPermissionType.Read, '');
1622
+ if (!entityInfo.UserExemptFromRowLevelSecurity(user, EntityPermissionType.Read)) {
1623
+ const rlsWhereClause = entityInfo.GetUserRowLevelSecurityWhereClause(user, EntityPermissionType.Read, '');
1649
1624
  if (rlsWhereClause && rlsWhereClause.length > 0) {
1650
1625
  if (bHasWhere) {
1651
1626
  whereSQL += ` AND (${rlsWhereClause})`;
@@ -1740,7 +1715,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
1740
1715
  return results.map(r => r.RecordID);
1741
1716
  }
1742
1717
  catch (e) {
1743
- (0, core_1.LogError)(e);
1718
+ LogError(e);
1744
1719
  return [];
1745
1720
  }
1746
1721
  }
@@ -1777,7 +1752,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
1777
1752
  return results;
1778
1753
  }
1779
1754
  catch (e) {
1780
- (0, core_1.LogError)(e);
1755
+ LogError(e);
1781
1756
  return [];
1782
1757
  }
1783
1758
  }
@@ -1824,7 +1799,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
1824
1799
  // Validate: if impliedDeletes < 0, there are unexplained rows on the server
1825
1800
  // This could happen with direct SQL inserts that bypassed MJ's tracking
1826
1801
  if (impliedDeletes < 0) {
1827
- (0, core_1.LogStatus)(`Differential validation failed for ${entityInfo.Name}: impliedDeletes=${impliedDeletes} (negative). ` +
1802
+ LogStatus(`Differential validation failed for ${entityInfo.Name}: impliedDeletes=${impliedDeletes} (negative). ` +
1828
1803
  `clientRowCount=${clientRowCount}, newInserts=${newInserts}, serverRowCount=${serverRowCount}. ` +
1829
1804
  `Falling back to full refresh.`);
1830
1805
  return this.runFullQueryAndReturn(params, viewIndex, contextUser);
@@ -1832,7 +1807,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
1832
1807
  // Validate: if impliedDeletes > actualDeletes, there are "hidden" deletes
1833
1808
  // not tracked in RecordChanges (e.g., direct SQL deletes)
1834
1809
  if (impliedDeletes > actualDeletes) {
1835
- (0, core_1.LogStatus)(`Differential validation failed for ${entityInfo.Name}: hidden deletes detected. ` +
1810
+ LogStatus(`Differential validation failed for ${entityInfo.Name}: hidden deletes detected. ` +
1836
1811
  `impliedDeletes=${impliedDeletes}, actualDeletes=${actualDeletes}. ` +
1837
1812
  `clientRowCount=${clientRowCount}, newInserts=${newInserts}, serverRowCount=${serverRowCount}. ` +
1838
1813
  `Falling back to full refresh.`);
@@ -1855,7 +1830,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
1855
1830
  };
1856
1831
  }
1857
1832
  catch (e) {
1858
- (0, core_1.LogError)(e);
1833
+ LogError(e);
1859
1834
  return {
1860
1835
  viewIndex,
1861
1836
  status: 'error',
@@ -1910,7 +1885,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
1910
1885
  if (!aggregates || aggregates.length === 0) {
1911
1886
  return { aggregateSQL: null, validationErrors: [] };
1912
1887
  }
1913
- const validator = global_1.SQLExpressionValidator.Instance;
1888
+ const validator = SQLExpressionValidator.Instance;
1914
1889
  const validationErrors = [];
1915
1890
  const validExpressions = [];
1916
1891
  const fieldNames = entityInfo.Fields.map(f => f.Name);
@@ -2054,7 +2029,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2054
2029
  if (field)
2055
2030
  fieldList.push(field);
2056
2031
  else
2057
- (0, core_1.LogError)(`Field ${f} not found in entity ${entityInfo.Name}`);
2032
+ LogError(`Field ${f} not found in entity ${entityInfo.Name}`);
2058
2033
  });
2059
2034
  }
2060
2035
  else {
@@ -2070,7 +2045,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2070
2045
  fieldList.push(c.EntityField);
2071
2046
  }
2072
2047
  else {
2073
- (0, core_1.LogError)(`View Field ${c.Name} doesn't match an Entity Field in entity ${entityInfo.Name}. This can happen if the view was saved with a field that no longer exists in the entity. It is best to update the view to remove this field.`);
2048
+ LogError(`View Field ${c.Name} doesn't match an Entity Field in entity ${entityInfo.Name}. This can happen if the view was saved with a field that no longer exists in the entity. It is best to update the view to remove this field.`);
2074
2049
  }
2075
2050
  }
2076
2051
  });
@@ -2083,7 +2058,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2083
2058
  }
2084
2059
  }
2085
2060
  catch (e) {
2086
- (0, core_1.LogError)(e);
2061
+ LogError(e);
2087
2062
  }
2088
2063
  finally {
2089
2064
  return fieldList;
@@ -2134,7 +2109,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2134
2109
  else {
2135
2110
  // we have multiple words, so we need to convert the spaces to AND
2136
2111
  // but first, let's strip the stopwords out of the string
2137
- u = (0, core_1.StripStopWords)(userSearchString);
2112
+ u = StripStopWords(userSearchString);
2138
2113
  // next, include "AND" between all the words so that we have a full text search on all the words
2139
2114
  u = u.replace(/ /g, ' AND ');
2140
2115
  }
@@ -2195,7 +2170,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2195
2170
  throw new Error(`Error saving audit log record`);
2196
2171
  }
2197
2172
  catch (err) {
2198
- (0, core_1.LogError)(err);
2173
+ LogError(err);
2199
2174
  return null;
2200
2175
  }
2201
2176
  }
@@ -2219,7 +2194,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2219
2194
  // START ---- IEntityDataProvider
2220
2195
  /**************************************************************************/
2221
2196
  get ProviderType() {
2222
- return core_1.ProviderType.Database;
2197
+ return ProviderType.Database;
2223
2198
  }
2224
2199
  async GetRecordFavoriteStatus(userId, entityName, CompositeKey, contextUser) {
2225
2200
  const id = await this.GetRecordFavoriteID(userId, entityName, CompositeKey, contextUser);
@@ -2235,7 +2210,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2235
2210
  return null;
2236
2211
  }
2237
2212
  catch (e) {
2238
- (0, core_1.LogError)(e);
2213
+ LogError(e);
2239
2214
  throw e;
2240
2215
  }
2241
2216
  }
@@ -2268,7 +2243,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2268
2243
  }
2269
2244
  }
2270
2245
  catch (e) {
2271
- (0, core_1.LogError)(e);
2246
+ LogError(e);
2272
2247
  throw e;
2273
2248
  }
2274
2249
  }
@@ -2278,7 +2253,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2278
2253
  return this.ExecuteSQL(sSQL, undefined, undefined, contextUser);
2279
2254
  }
2280
2255
  catch (e) {
2281
- (0, core_1.LogError)(e);
2256
+ LogError(e);
2282
2257
  throw e;
2283
2258
  }
2284
2259
  }
@@ -2298,7 +2273,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2298
2273
  // we do this in SQL by combining the pirmary key name and value for each row using the default separator defined by the CompositeKey class
2299
2274
  // the output of this should be like the following 'Field1|Value1||Field2|Value2||Field3|Value3' where the || is the CompositeKey.DefaultFieldDelimiter and the | is the CompositeKey.DefaultValueDelimiter
2300
2275
  const quotes = entity.FirstPrimaryKey.NeedsQuotes ? "'" : '';
2301
- const primaryKeySelectString = `CONCAT(${entity.PrimaryKeys.map((pk) => `'${pk.Name}|', CAST(${pk.Name} AS NVARCHAR(MAX))`).join(`,'${core_1.CompositeKey.DefaultFieldDelimiter}',`)})`;
2276
+ const primaryKeySelectString = `CONCAT(${entity.PrimaryKeys.map((pk) => `'${pk.Name}|', CAST(${pk.Name} AS NVARCHAR(MAX))`).join(`,'${CompositeKey.DefaultFieldDelimiter}',`)})`;
2302
2277
  // for this entity, check to see if it has any fields that are soft links, and for each of those, generate the SQL
2303
2278
  entity.Fields.filter((f) => f.EntityIDFieldName && f.EntityIDFieldName.length > 0).forEach((f) => {
2304
2279
  // each field in f must be processed
@@ -2327,7 +2302,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2327
2302
  const entityInfo = this.Entities.find((e) => e.Name.trim().toLowerCase() === entityDependency.EntityName?.trim().toLowerCase());
2328
2303
  const quotes = entityInfo.FirstPrimaryKey.NeedsQuotes ? "'" : '';
2329
2304
  const relatedEntityInfo = this.Entities.find((e) => e.Name.trim().toLowerCase() === entityDependency.RelatedEntityName?.trim().toLowerCase());
2330
- const primaryKeySelectString = `CONCAT(${entityInfo.PrimaryKeys.map((pk) => `'${pk.Name}|', CAST(${pk.Name} AS NVARCHAR(MAX))`).join(`,'${core_1.CompositeKey.DefaultFieldDelimiter}',`)})`;
2305
+ const primaryKeySelectString = `CONCAT(${entityInfo.PrimaryKeys.map((pk) => `'${pk.Name}|', CAST(${pk.Name} AS NVARCHAR(MAX))`).join(`,'${CompositeKey.DefaultFieldDelimiter}',`)})`;
2331
2306
  if (sSQL.length > 0)
2332
2307
  sSQL += ' UNION ALL ';
2333
2308
  sSQL += `SELECT
@@ -2377,13 +2352,13 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2377
2352
  // entityInfo.PrimaryKeys.forEach((pk) => {
2378
2353
  // pkeyValues.push({FieldName: pk.Name, Value: r[pk.Name]}) // add all of the primary keys, which often is as simple as just "ID", but this is generic way to do it
2379
2354
  // })
2380
- const compositeKey = new core_1.CompositeKey();
2355
+ const compositeKey = new CompositeKey();
2381
2356
  // the row r will have a PrimaryKeyValue field that is a string that is a concatenation of the primary key field names and values
2382
2357
  // we need to parse that out so that we can then pass it to the CompositeKey object
2383
2358
  const pkeys = {};
2384
- const keyValues = r.PrimaryKeyValue.split(core_1.CompositeKey.DefaultFieldDelimiter);
2359
+ const keyValues = r.PrimaryKeyValue.split(CompositeKey.DefaultFieldDelimiter);
2385
2360
  keyValues.forEach((kv) => {
2386
- const parts = kv.split(core_1.CompositeKey.DefaultValueDelimiter);
2361
+ const parts = kv.split(CompositeKey.DefaultValueDelimiter);
2387
2362
  pkeys[parts[0]] = parts[1];
2388
2363
  });
2389
2364
  compositeKey.LoadFromEntityInfoAndRecord(entityInfo, pkeys);
@@ -2399,7 +2374,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2399
2374
  }
2400
2375
  catch (e) {
2401
2376
  // log and throw
2402
- (0, core_1.LogError)(e);
2377
+ LogError(e);
2403
2378
  throw e;
2404
2379
  }
2405
2380
  }
@@ -2531,7 +2506,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2531
2506
  return result;
2532
2507
  }
2533
2508
  catch (e) {
2534
- (0, core_1.LogError)(e);
2509
+ LogError(e);
2535
2510
  await this.RollbackTransaction();
2536
2511
  // attempt to persist the status to the DB, although that might fail
2537
2512
  await this.CompleteMergeLogging(mergeRecordLog, result, contextUser);
@@ -2563,7 +2538,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2563
2538
  throw new Error(`Error saving record merge log`);
2564
2539
  }
2565
2540
  catch (e) {
2566
- (0, core_1.LogError)(e);
2541
+ LogError(e);
2567
2542
  throw e;
2568
2543
  }
2569
2544
  }
@@ -2595,7 +2570,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2595
2570
  }
2596
2571
  catch (e) {
2597
2572
  // do nothing here because we often will get here since some conditions lead to no DB updates possible...
2598
- (0, core_1.LogError)(e);
2573
+ LogError(e);
2599
2574
  // don't bubble up the error here as we're sometimes already in an exception block in caller
2600
2575
  }
2601
2576
  }
@@ -2648,7 +2623,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2648
2623
  let oldData = null;
2649
2624
  // use SQL Server CONCAT function to combine all of the primary key values and then combine them together
2650
2625
  // using the default field delimiter and default value delimiter as defined in the CompositeKey class
2651
- const concatPKIDString = `CONCAT(${entity.EntityInfo.PrimaryKeys.map((pk) => `'${pk.CodeName}','${core_1.CompositeKey.DefaultValueDelimiter}',${pk.Name}`).join(`,'${core_1.CompositeKey.DefaultFieldDelimiter}',`)})`;
2626
+ const concatPKIDString = `CONCAT(${entity.EntityInfo.PrimaryKeys.map((pk) => `'${pk.CodeName}','${CompositeKey.DefaultValueDelimiter}',${pk.Name}`).join(`,'${CompositeKey.DefaultFieldDelimiter}',`)})`;
2652
2627
  if (!bNewRecord)
2653
2628
  oldData = entity.GetAll(true); // get all the OLD values, only do for existing records, for new records, not relevant
2654
2629
  const logRecordChangeSQL = this.GetLogRecordChangeSQL(entity.GetAll(false), oldData, entity.EntityInfo.Name, '@ID', entity.EntityInfo, bNewRecord ? 'Create' : 'Update', user, false);
@@ -2706,7 +2681,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2706
2681
  * @internal
2707
2682
  */
2708
2683
  GetEntityAIActions(entityInfo, before) {
2709
- return aiengine_1.AIEngine.Instance.EntityAIActions.filter((a) => a.EntityID === entityInfo.ID && a.TriggerEvent.toLowerCase().trim() === (before ? 'before save' : 'after save'));
2684
+ return AIEngine.Instance.EntityAIActions.filter((a) => a.EntityID === entityInfo.ID && a.TriggerEvent.toLowerCase().trim() === (before ? 'before save' : 'after save'));
2710
2685
  }
2711
2686
  /**
2712
2687
  * Handles entity actions (non-AI) for save, delete, or validate operations
@@ -2721,14 +2696,14 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2721
2696
  async HandleEntityActions(entity, baseType, before, user) {
2722
2697
  // use the EntityActionEngine for this
2723
2698
  try {
2724
- const engine = actions_1.EntityActionEngineServer.Instance;
2699
+ const engine = EntityActionEngineServer.Instance;
2725
2700
  await engine.Config(false, user);
2726
2701
  const newRecord = entity.IsSaved ? false : true;
2727
2702
  const baseTypeType = baseType === 'save' ? (newRecord ? 'Create' : 'Update') : 'Delete';
2728
2703
  const invocationType = baseType === 'validate' ? 'Validate' : before ? 'Before' + baseTypeType : 'After' + baseTypeType;
2729
2704
  const invocationTypeEntity = engine.InvocationTypes.find((i) => i.Name === invocationType);
2730
2705
  if (!invocationTypeEntity) {
2731
- (0, core_1.LogError)(`Invocation Type ${invocationType} not found in metadata`);
2706
+ LogError(`Invocation Type ${invocationType} not found in metadata`);
2732
2707
  return [];
2733
2708
  // throw new Error(`Invocation Type ${invocationType} not found in metadata`);
2734
2709
  }
@@ -2746,7 +2721,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2746
2721
  return results;
2747
2722
  }
2748
2723
  catch (e) {
2749
- (0, core_1.LogError)(e);
2724
+ LogError(e);
2750
2725
  return [];
2751
2726
  }
2752
2727
  }
@@ -2765,10 +2740,10 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2765
2740
  if (baseType === 'delete')
2766
2741
  return;
2767
2742
  // Make sure AI Metadata is loaded here...
2768
- await aiengine_1.AIEngine.Instance.Config(false, user);
2743
+ await AIEngine.Instance.Config(false, user);
2769
2744
  const actions = this.GetEntityAIActions(entity.EntityInfo, before); // get the actions we need to do for this entity
2770
2745
  if (actions && actions.length > 0) {
2771
- const ai = aiengine_1.AIEngine.Instance;
2746
+ const ai = AIEngine.Instance;
2772
2747
  for (let i = 0; i < actions.length; i++) {
2773
2748
  const a = actions[i];
2774
2749
  if ((a.TriggerEvent === 'before save' && before) || (a.TriggerEvent === 'after save' && !before)) {
@@ -2791,11 +2766,11 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2791
2766
  }
2792
2767
  else {
2793
2768
  // No transaction active, add the task immediately
2794
- queue_1.QueueManager.AddTask('Entity AI Action', p, null, user);
2769
+ QueueManager.AddTask('Entity AI Action', p, null, user);
2795
2770
  }
2796
2771
  }
2797
2772
  catch (e) {
2798
- (0, core_1.LogError)(e.message);
2773
+ LogError(e.message);
2799
2774
  }
2800
2775
  }
2801
2776
  }
@@ -2803,16 +2778,16 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2803
2778
  }
2804
2779
  }
2805
2780
  catch (e) {
2806
- (0, core_1.LogError)(e);
2781
+ LogError(e);
2807
2782
  }
2808
2783
  }
2809
2784
  async Save(entity, user, options) {
2810
- const entityResult = new core_1.BaseEntityResult();
2785
+ const entityResult = new BaseEntityResult();
2811
2786
  try {
2812
2787
  entity.RegisterTransactionPreprocessing();
2813
2788
  const bNewRecord = !entity.IsSaved;
2814
2789
  if (!options)
2815
- options = new core_1.EntitySaveOptions();
2790
+ options = new EntitySaveOptions();
2816
2791
  const bReplay = !!options.ReplayOnly;
2817
2792
  if (!bReplay && !bNewRecord && !entity.EntityInfo.AllowUpdateAPI) {
2818
2793
  // existing record and not allowed to update
@@ -2880,7 +2855,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2880
2855
  // we are part of a transaction group, so just add our query to the list
2881
2856
  // and when the transaction is committed, we will send all the queries at once
2882
2857
  this._bAllowRefresh = false; // stop refreshes of metadata while we're doing work
2883
- entity.TransactionGroup.AddTransaction(new core_1.TransactionItem(entity, entityResult.Type === 'create' ? 'Create' : 'Update', sSQL, null, {
2858
+ entity.TransactionGroup.AddTransaction(new TransactionItem(entity, entityResult.Type === 'create' ? 'Create' : 'Update', sSQL, null, {
2884
2859
  dataSource: this._pool,
2885
2860
  simpleSQLFallback: entity.EntityInfo.TrackRecordChanges ? sqlDetails.simpleSQL : undefined,
2886
2861
  entityName: entity.EntityInfo.Name
@@ -2966,7 +2941,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
2966
2941
  this._bAllowRefresh = true; // allow refreshes again if we get a failure here
2967
2942
  entityResult.EndedAt = new Date();
2968
2943
  entityResult.Message = e.message;
2969
- (0, core_1.LogError)(e);
2944
+ LogError(e);
2970
2945
  throw e; // rethrow the error
2971
2946
  }
2972
2947
  }
@@ -3023,7 +2998,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
3023
2998
  */
3024
2999
  async generateSPParams(entity, isUpdate, contextUser) {
3025
3000
  // Generate a unique suffix for variable names to avoid collisions in batch scripts
3026
- const uniqueSuffix = '_' + (0, uuid_1.v4)().substring(0, 8).replace(/-/g, '');
3001
+ const uniqueSuffix = '_' + uuidv4().substring(0, 8).replace(/-/g, '');
3027
3002
  const declarations = [];
3028
3003
  const setStatements = [];
3029
3004
  const execParams = [];
@@ -3069,7 +3044,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
3069
3044
  if (f.Encrypt && f.EncryptionKeyID && value !== null && value !== undefined) {
3070
3045
  // Lazy-load encryption engine only when needed
3071
3046
  if (!encryptionEngine) {
3072
- encryptionEngine = encryption_1.EncryptionEngine.Instance;
3047
+ encryptionEngine = EncryptionEngine.Instance;
3073
3048
  await encryptionEngine.Config(false, contextUser);
3074
3049
  }
3075
3050
  // Only encrypt if the value is not already encrypted
@@ -3143,7 +3118,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
3143
3118
  generateSetStatementValue(f, value) {
3144
3119
  let val = value;
3145
3120
  switch (f.TSType) {
3146
- case core_1.EntityFieldTSType.Boolean:
3121
+ case EntityFieldTSType.Boolean:
3147
3122
  // check to see if the value is a string and if it is equal to true, if so, set the value to 1
3148
3123
  if (typeof value === 'string' && value.trim().toLowerCase() === 'true')
3149
3124
  val = 1;
@@ -3152,7 +3127,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
3152
3127
  else
3153
3128
  val = value ? 1 : 0;
3154
3129
  return val.toString();
3155
- case core_1.EntityFieldTSType.String:
3130
+ case EntityFieldTSType.String:
3156
3131
  // Handle string escaping for SET statements
3157
3132
  if (typeof val === 'string') {
3158
3133
  val = val.replace(/'/g, "''");
@@ -3164,7 +3139,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
3164
3139
  val = val.replace(/'/g, "''");
3165
3140
  }
3166
3141
  return `${f.UnicodePrefix}'${val}'`;
3167
- case core_1.EntityFieldTSType.Date:
3142
+ case EntityFieldTSType.Date:
3168
3143
  if (val !== null && val !== undefined) {
3169
3144
  if (typeof val === 'number') {
3170
3145
  // we have a timestamp - milliseconds since Unix Epoch
@@ -3177,7 +3152,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
3177
3152
  val = val.toISOString(); // convert the date to ISO format for storage in the DB
3178
3153
  }
3179
3154
  return `'${val}'`;
3180
- case core_1.EntityFieldTSType.Number:
3155
+ case EntityFieldTSType.Number:
3181
3156
  return val.toString();
3182
3157
  default:
3183
3158
  // For other types, convert to string and quote if needed
@@ -3195,7 +3170,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
3195
3170
  let quotes = '';
3196
3171
  let val = value;
3197
3172
  switch (f.TSType) {
3198
- case core_1.EntityFieldTSType.Boolean:
3173
+ case EntityFieldTSType.Boolean:
3199
3174
  // check to see if the value is a string and if it is equal to true, if so, set the value to 1
3200
3175
  if (typeof value === 'string' && value.trim().toLowerCase() === 'true')
3201
3176
  val = 1;
@@ -3204,10 +3179,10 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
3204
3179
  else
3205
3180
  val = value ? 1 : 0;
3206
3181
  break;
3207
- case core_1.EntityFieldTSType.String:
3182
+ case EntityFieldTSType.String:
3208
3183
  quotes = "'";
3209
3184
  break;
3210
- case core_1.EntityFieldTSType.Date:
3185
+ case EntityFieldTSType.Date:
3211
3186
  quotes = "'";
3212
3187
  if (val !== null && val !== undefined) {
3213
3188
  if (typeof val === 'number') {
@@ -3436,14 +3411,14 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
3436
3411
  bDiff = false; // this branch of logic ensures that undefined and null are treated the same
3437
3412
  else {
3438
3413
  switch (f.TSType) {
3439
- case core_1.EntityFieldTSType.String:
3414
+ case EntityFieldTSType.String:
3440
3415
  bDiff = oldData[key] !== newData[key];
3441
3416
  break;
3442
- case core_1.EntityFieldTSType.Date:
3417
+ case EntityFieldTSType.Date:
3443
3418
  bDiff = new Date(oldData[key]).getTime() !== new Date(newData[key]).getTime();
3444
3419
  break;
3445
- case core_1.EntityFieldTSType.Number:
3446
- case core_1.EntityFieldTSType.Boolean:
3420
+ case EntityFieldTSType.Number:
3421
+ case EntityFieldTSType.Boolean:
3447
3422
  bDiff = oldData[key] !== newData[key];
3448
3423
  break;
3449
3424
  }
@@ -3497,7 +3472,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
3497
3472
  const ret = d[0];
3498
3473
  // we need to post process the retrieval to see if we have any char or nchar fields and we need to remove their trailing spaces
3499
3474
  for (const field of entity.EntityInfo.Fields) {
3500
- if (field.TSType === core_1.EntityFieldTSType.String &&
3475
+ if (field.TSType === EntityFieldTSType.String &&
3501
3476
  field.Type.toLowerCase().includes('char') &&
3502
3477
  !field.Type.toLowerCase().includes('varchar')) {
3503
3478
  // trim trailing spaces for char and nchar fields
@@ -3536,7 +3511,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
3536
3511
  // Find the related entity info to process datetime fields correctly
3537
3512
  const relEntityInfo = this.Entities.find((e) => e.Name.trim().toLowerCase() === relInfo.RelatedEntity.trim().toLowerCase());
3538
3513
  if (relEntityInfo) {
3539
- ret[rel] = await this.ProcessEntityRows(rawRelData, relEntityInfo);
3514
+ ret[rel] = await this.ProcessEntityRows(rawRelData, relEntityInfo, user);
3540
3515
  }
3541
3516
  else {
3542
3517
  // Fallback if we can't find entity info
@@ -3629,11 +3604,11 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
3629
3604
  return { fullSQL: sSQL, simpleSQL: sSimpleSQL };
3630
3605
  }
3631
3606
  async Delete(entity, options, user) {
3632
- const result = new core_1.BaseEntityResult();
3607
+ const result = new BaseEntityResult();
3633
3608
  try {
3634
3609
  entity.RegisterTransactionPreprocessing();
3635
3610
  if (!options)
3636
- options = new core_1.EntityDeleteOptions();
3611
+ options = new EntityDeleteOptions();
3637
3612
  const bReplay = options.ReplayOnly;
3638
3613
  if (!entity.IsSaved && !bReplay)
3639
3614
  // existing record and not allowed to update
@@ -3661,7 +3636,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
3661
3636
  entity.RaiseReadyForTransaction();
3662
3637
  // we are part of a transaction group, so just add our query to the list
3663
3638
  // and when the transaction is committed, we will send all the queries at once
3664
- entity.TransactionGroup.AddTransaction(new core_1.TransactionItem(entity, 'Delete', sSQL, null, {
3639
+ entity.TransactionGroup.AddTransaction(new TransactionItem(entity, 'Delete', sSQL, null, {
3665
3640
  dataSource: this._pool,
3666
3641
  simpleSQLFallback: entity.EntityInfo.TrackRecordChanges ? sqlDetails.simpleSQL : undefined,
3667
3642
  entityName: entity.EntityInfo.Name
@@ -3742,7 +3717,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
3742
3717
  }
3743
3718
  }
3744
3719
  catch (e) {
3745
- (0, core_1.LogError)(e);
3720
+ LogError(e);
3746
3721
  result.Message = e.message;
3747
3722
  result.Success = false;
3748
3723
  result.EndedAt = new Date();
@@ -3814,7 +3789,15 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
3814
3789
  }
3815
3790
  else {
3816
3791
  // Process successful query result
3817
- const itemData = batchResults[queryIndex] || [];
3792
+ let itemData = batchResults[queryIndex] || [];
3793
+ // Process rows for datetime conversion and field-level decryption
3794
+ // This is critical for datasets that contain encrypted fields
3795
+ if (itemData.length > 0) {
3796
+ const entityInfo = useThisProvider.Entities.find(e => e.Name.trim().toLowerCase() === item.Entity.trim().toLowerCase());
3797
+ if (entityInfo) {
3798
+ itemData = await useThisProvider.ProcessEntityRows(itemData, entityInfo, contextUser);
3799
+ }
3800
+ }
3818
3801
  const itemUpdatedAt = new Date(item.DatasetItemUpdatedAt);
3819
3802
  const datasetUpdatedAt = new Date(item.DatasetUpdatedAt);
3820
3803
  const datasetMaxUpdatedAt = new Date(Math.max(itemUpdatedAt.getTime(), datasetUpdatedAt.getTime()));
@@ -3951,7 +3934,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
3951
3934
  // the reason we continue below if we have NOT loaded Entities is that when the system first bootstraps, DATASET gets loaded
3952
3935
  // FIRST before Entities are loaded to load the entity metadata so this would ALWAYS fail :)
3953
3936
  // entity not found, return a failed result, shouldn't ever get here due to the foreign key constraint on the table
3954
- (0, core_1.LogError)(`Entity not found for dataset item ${item.Code} in dataset ${datasetName}`);
3937
+ LogError(`Entity not found for dataset item ${item.Code} in dataset ${datasetName}`);
3955
3938
  return null;
3956
3939
  }
3957
3940
  else {
@@ -3965,7 +3948,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
3965
3948
  }
3966
3949
  });
3967
3950
  if (invalidColumns.length > 0) {
3968
- (0, core_1.LogError)(`Invalid columns specified for dataset item ${item.Code} in dataset ${datasetName}: ${invalidColumns.join(', ')}`);
3951
+ LogError(`Invalid columns specified for dataset item ${item.Code} in dataset ${datasetName}: ${invalidColumns.join(', ')}`);
3969
3952
  return null;
3970
3953
  }
3971
3954
  }
@@ -4084,7 +4067,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4084
4067
  const appEntities = await this.ExecuteSQL(`SELECT * FROM [${this.MJCoreSchemaName}].vwApplicationEntities ORDER BY ApplicationName`, undefined, undefined, contextUser);
4085
4068
  const ret = [];
4086
4069
  for (let i = 0; i < apps.length; i++) {
4087
- ret.push(new core_1.ApplicationInfo(this, {
4070
+ ret.push(new ApplicationInfo(this, {
4088
4071
  ...apps[i],
4089
4072
  ApplicationEntities: appEntities.filter((ae) => ae.ApplicationName.trim().toLowerCase() === apps[i].Name.trim().toLowerCase()),
4090
4073
  }));
@@ -4095,7 +4078,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4095
4078
  const alts = await this.ExecuteSQL(`SELECT * FROM [${this.MJCoreSchemaName}].vwAuditLogTypes`, null, undefined, contextUser);
4096
4079
  const ret = [];
4097
4080
  for (let i = 0; i < alts.length; i++) {
4098
- const alt = new core_1.AuditLogTypeInfo(alts[i]);
4081
+ const alt = new AuditLogTypeInfo(alts[i]);
4099
4082
  ret.push(alt);
4100
4083
  }
4101
4084
  return ret;
@@ -4105,7 +4088,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4105
4088
  const userRoles = await this.ExecuteSQL(`SELECT * FROM [${this.MJCoreSchemaName}].vwUserRoles ORDER BY UserID`, undefined, undefined, contextUser);
4106
4089
  const ret = [];
4107
4090
  for (let i = 0; i < users.length; i++) {
4108
- ret.push(new core_1.UserInfo(this, {
4091
+ ret.push(new UserInfo(this, {
4109
4092
  ...users[i],
4110
4093
  UserRoles: userRoles.filter((ur) => ur.UserID === users[i].ID),
4111
4094
  }));
@@ -4117,7 +4100,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4117
4100
  const authRoles = await this.ExecuteSQL(`SELECT * FROM [${this.MJCoreSchemaName}].vwAuthorizationRoles ORDER BY AuthorizationName`, undefined, undefined, contextUser);
4118
4101
  const ret = [];
4119
4102
  for (let i = 0; i < auths.length; i++) {
4120
- ret.push(new core_1.AuthorizationInfo(this, {
4103
+ ret.push(new AuthorizationInfo(this, {
4121
4104
  ...auths[i],
4122
4105
  AuthorizationRoles: authRoles.filter((ar) => ar.AuthorizationName.trim().toLowerCase() === auths[i].Name.trim().toLowerCase()),
4123
4106
  }));
@@ -4148,7 +4131,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4148
4131
  return rows;
4149
4132
  }
4150
4133
  // Find all datetime fields in the entity
4151
- const datetimeFields = entityInfo.Fields.filter((field) => field.TSType === core_1.EntityFieldTSType.Date);
4134
+ const datetimeFields = entityInfo.Fields.filter((field) => field.TSType === EntityFieldTSType.Date);
4152
4135
  // Find all encrypted fields in the entity
4153
4136
  const encryptedFields = entityInfo.Fields.filter((field) => field.Encrypt && field.EncryptionKeyID);
4154
4137
  // If there are no fields requiring processing, return the rows as-is
@@ -4160,7 +4143,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4160
4143
  // Get encryption engine instance (lazy - only if we have encrypted fields)
4161
4144
  let encryptionEngine = null;
4162
4145
  if (encryptedFields.length > 0) {
4163
- encryptionEngine = encryption_1.EncryptionEngine.Instance;
4146
+ encryptionEngine = EncryptionEngine.Instance;
4164
4147
  await encryptionEngine.Config(false, contextUser);
4165
4148
  }
4166
4149
  // Process each row - need to use Promise.all for async decryption
@@ -4249,7 +4232,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4249
4232
  // Log error but don't fail the entire operation
4250
4233
  // Return the encrypted value so the caller knows something is wrong
4251
4234
  const message = decryptError instanceof Error ? decryptError.message : String(decryptError);
4252
- (0, core_1.LogError)(`Failed to decrypt field "${field.Name}" on entity "${entityInfo.Name}": ${message}. ` +
4235
+ LogError(`Failed to decrypt field "${field.Name}" on entity "${entityInfo.Name}": ${message}. ` +
4253
4236
  'The encrypted value will be returned unchanged.');
4254
4237
  // Keep the encrypted value in the row - let the caller decide what to do
4255
4238
  }
@@ -4286,7 +4269,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4286
4269
  // This prevents EREQINPROG errors when multiple queries try to use the same transaction
4287
4270
  return new Promise((resolve, reject) => {
4288
4271
  this._sqlQueue$.next({
4289
- id: (0, uuid_1.v4)(),
4272
+ id: uuidv4(),
4290
4273
  query,
4291
4274
  parameters,
4292
4275
  context,
@@ -4605,7 +4588,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4605
4588
  }
4606
4589
  }
4607
4590
  catch (e) {
4608
- (0, core_1.LogError)(e);
4591
+ LogError(e);
4609
4592
  throw e;
4610
4593
  }
4611
4594
  }
@@ -4713,7 +4696,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4713
4696
  }
4714
4697
  catch (e) {
4715
4698
  this._transactionDepth--; // Restore depth on error
4716
- (0, core_1.LogError)(e);
4699
+ LogError(e);
4717
4700
  throw e; // force caller to handle
4718
4701
  }
4719
4702
  }
@@ -4744,7 +4727,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4744
4727
  }
4745
4728
  }
4746
4729
  catch (e) {
4747
- (0, core_1.LogError)(e);
4730
+ LogError(e);
4748
4731
  throw e; // force caller to handle
4749
4732
  }
4750
4733
  }
@@ -4770,7 +4753,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4770
4753
  const deferredCount = this._deferredTasks.length;
4771
4754
  this._deferredTasks = [];
4772
4755
  if (deferredCount > 0) {
4773
- (0, core_1.LogStatus)(`Cleared ${deferredCount} deferred tasks after transaction rollback`);
4756
+ LogStatus(`Cleared ${deferredCount} deferred tasks after transaction rollback`);
4774
4757
  }
4775
4758
  }
4776
4759
  else {
@@ -4796,7 +4779,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4796
4779
  this._savepointCounter = 0;
4797
4780
  this._transactionState$.next(false);
4798
4781
  }
4799
- (0, core_1.LogError)(e);
4782
+ LogError(e);
4800
4783
  throw e; // force caller to handle
4801
4784
  }
4802
4785
  }
@@ -4808,7 +4791,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4808
4791
  async RefreshIfNeeded() {
4809
4792
  // Skip refresh if a transaction is active
4810
4793
  if (this.isTransactionActive) {
4811
- (0, core_1.LogStatus)('Skipping metadata refresh - transaction is active');
4794
+ LogStatus('Skipping metadata refresh - transaction is active');
4812
4795
  return false;
4813
4796
  }
4814
4797
  // Call parent implementation if no transaction
@@ -4822,7 +4805,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4822
4805
  async processDeferredTasks() {
4823
4806
  if (this._deferredTasks.length === 0)
4824
4807
  return;
4825
- (0, core_1.LogStatus)(`Processing ${this._deferredTasks.length} deferred tasks after transaction commit`);
4808
+ LogStatus(`Processing ${this._deferredTasks.length} deferred tasks after transaction commit`);
4826
4809
  // Copy and clear the deferred tasks array
4827
4810
  const tasksToProcess = [...this._deferredTasks];
4828
4811
  this._deferredTasks = [];
@@ -4831,22 +4814,27 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4831
4814
  try {
4832
4815
  if (task.type === 'Entity AI Action') {
4833
4816
  // Process the AI action now that we're outside the transaction
4834
- await queue_1.QueueManager.AddTask('Entity AI Action', task.data, task.options, task.user);
4817
+ await QueueManager.AddTask('Entity AI Action', task.data, task.options, task.user);
4835
4818
  }
4836
4819
  // Add other task types here as needed
4837
4820
  }
4838
4821
  catch (error) {
4839
- (0, core_1.LogError)(`Failed to process deferred ${task.type} task: ${error}`);
4822
+ LogError(`Failed to process deferred ${task.type} task: ${error}`);
4840
4823
  // Continue processing other tasks even if one fails
4841
4824
  }
4842
4825
  }
4843
- (0, core_1.LogStatus)(`Completed processing deferred tasks`);
4826
+ LogStatus(`Completed processing deferred tasks`);
4844
4827
  }
4845
4828
  get LocalStorageProvider() {
4846
4829
  if (!this._localStorageProvider)
4847
- this._localStorageProvider = new core_1.InMemoryLocalStorageProvider();
4830
+ this._localStorageProvider = new InMemoryLocalStorageProvider();
4848
4831
  return this._localStorageProvider;
4849
4832
  }
4833
+ get FileSystemProvider() {
4834
+ if (!this._fileSystemProvider)
4835
+ this._fileSystemProvider = new NodeFileSystemProvider();
4836
+ return this._fileSystemProvider;
4837
+ }
4850
4838
  async GetEntityRecordNames(info, contextUser) {
4851
4839
  const promises = info.map(async (item) => {
4852
4840
  const r = await this.GetEntityRecordName(item.EntityName, item.CompositeKey, contextUser);
@@ -4870,13 +4858,13 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4870
4858
  return data[0][fields[0]]; // return first field
4871
4859
  }
4872
4860
  else {
4873
- (0, core_1.LogError)(`Entity ${entityName} record ${CompositeKey.ToString()} not found, returning null`);
4861
+ LogError(`Entity ${entityName} record ${CompositeKey.ToString()} not found, returning null`);
4874
4862
  return null;
4875
4863
  }
4876
4864
  }
4877
4865
  }
4878
4866
  catch (e) {
4879
- (0, core_1.LogError)(e);
4867
+ LogError(e);
4880
4868
  return null;
4881
4869
  }
4882
4870
  }
@@ -4887,7 +4875,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4887
4875
  else {
4888
4876
  const f = e.NameField;
4889
4877
  if (!f) {
4890
- (0, core_1.LogError)(`Entity ${entityName} does not have an IsNameField or a field with the column name of Name, returning null, use recordId`);
4878
+ LogError(`Entity ${entityName} does not have an IsNameField or a field with the column name of Name, returning null, use recordId`);
4891
4879
  return null;
4892
4880
  }
4893
4881
  else {
@@ -4906,7 +4894,7 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4906
4894
  }
4907
4895
  }
4908
4896
  async CreateTransactionGroup() {
4909
- return new SQLServerTransactionGroup_1.SQLServerTransactionGroup();
4897
+ return new SQLServerTransactionGroup();
4910
4898
  }
4911
4899
  /**************************************************************************/
4912
4900
  // END ---- IMetadataProvider
@@ -4915,5 +4903,4 @@ class SQLServerDataProvider extends core_1.DatabaseProviderBase {
4915
4903
  return this;
4916
4904
  }
4917
4905
  }
4918
- exports.SQLServerDataProvider = SQLServerDataProvider;
4919
4906
  //# sourceMappingURL=SQLServerDataProvider.js.map