basesite-shared-grid-lib 21.0.1-beta.7 → 21.0.1-beta.8

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.
@@ -317,7 +317,15 @@ class OdataProvider {
317
317
  if (!col.values || col.values.length === 0) {
318
318
  return '';
319
319
  }
320
- const equalsClauses = col.values.map((v) => me.odataOperator.equalsStr(colName, `'${me.encode(v)}'`, isCaseSensitiveStringFilter));
320
+ // Fill-cell / set-filter columns are always equality-matched against
321
+ // a fixed list of backend-provided values, so the casing on both
322
+ // sides is already known to match. Skip the tolower() wrap that the
323
+ // generic string operators apply — wrapping the column in tolower()
324
+ // forces a full scan because LOWER(col) cannot use any index, and
325
+ // SQL Server's default collation is already case-insensitive.
326
+ // Resulting predicate: `col eq 'Value'` (single) or
327
+ // `(col eq 'V1' or col eq 'V2')` (multi).
328
+ const equalsClauses = col.values.map((v) => me.odataOperator.equals(colName, `'${me.encode(v)}'`));
321
329
  return equalsClauses.length === 1
322
330
  ? equalsClauses[0]
323
331
  : `(${equalsClauses.join(' or ')})`;
@@ -2423,8 +2431,11 @@ class GridLibraryComponent {
2423
2431
  filterable: res.filterable,
2424
2432
  filter: 'agSetColumnFilter',
2425
2433
  filterParams: {
2426
- // Provide the raw values from the backend config; OData provider
2427
- // handles case-insensitive matching server-side via tolower().
2434
+ // Provide the raw values from the backend config exactly as
2435
+ // stored. The OData provider emits `(col eq 'Value')` for set
2436
+ // filters — no tolower() — and SQL Server's default collation
2437
+ // is case-insensitive, so casing on the wire just needs to
2438
+ // match what's in the column, not be normalized.
2428
2439
  values: (params) => this._getFillFilterValues(res, params),
2429
2440
  refreshValuesOnOpen: true,
2430
2441
  // Open with nothing checked so a user picking one option triggers
@@ -2540,6 +2551,35 @@ class GridLibraryComponent {
2540
2551
  }
2541
2552
  });
2542
2553
  }
2554
+ /**
2555
+ * Derive the $select field list for OData requests from the configured
2556
+ * column definitions. Includes every data-backed field but skips action
2557
+ * columns (buttons, action dropdowns) whose `field` isn't a real entity
2558
+ * property. Deduped so a field declared twice — e.g. for both display and
2559
+ * tooltip — only appears once in the select clause.
2560
+ */
2561
+ _getServerSelectFields() {
2562
+ const source = (this.initialColumnDef && this.initialColumnDef.length > 0)
2563
+ ? this.initialColumnDef
2564
+ : (this.columnDefs || []);
2565
+ const fields = new Set();
2566
+ for (const res of source) {
2567
+ if (!res)
2568
+ continue;
2569
+ // Skip action buttons — their `field` is usually a label slot, not a
2570
+ // backing entity property, and OData will 400 on unknown properties.
2571
+ if (res.isButton === true)
2572
+ continue;
2573
+ // Skip action dropdowns (e.g. "Create/View DAC") for the same reason.
2574
+ if (res.columnType === 'dropdown')
2575
+ continue;
2576
+ const field = res.field;
2577
+ if (typeof field === 'string' && field.length > 0) {
2578
+ fields.add(field);
2579
+ }
2580
+ }
2581
+ return Array.from(fields);
2582
+ }
2543
2583
  _getFillFilterValues(res, params) {
2544
2584
  const configured = res?.filterValues;
2545
2585
  if (Array.isArray(configured) && configured.length > 0) {
@@ -2746,17 +2786,20 @@ class GridLibraryComponent {
2746
2786
  // Add timeout to prevent infinite loading
2747
2787
  const API_TIMEOUT = 800000; //80 seconds
2748
2788
  let hasRetried = false;
2749
- // Fill-cell columns use the set filter, which only emits exact-match
2750
- // predicates (eq / in). Wrapping those in tolower() forces the DB to
2751
- // scan + lowercase every row (non-sargable), which was making filter
2752
- // requests ~10x+ slower than baseline. Skip tolower() for these
2753
- // columns by registering them as caseSensitive with the provider.
2754
- const fillCellFields = (this.initialColumnDef ?? [])
2755
- .filter((c) => c?.columnType === 'fill' && c?.field)
2756
- .map((c) => c.field);
2757
2789
  this.odataProvider = new OdataServerSideProvider({
2758
2790
  isCaseSensitiveStringFilter: false,
2759
- caseSensitiveColumns: fillCellFields,
2791
+ // Always send $select listing every data-backed field from columnDefs.
2792
+ // Without this, OData/EF projects the entire entity, which inflates
2793
+ // both the SQL projection and the JSON payload (and the AutoMapper
2794
+ // mapping cost). With it, the API returns only the columns the grid
2795
+ // actually renders. The OData provider already deletes options.select
2796
+ // for $apply/groupby requests, so aggregation queries aren't affected.
2797
+ beforeRequest: (options) => {
2798
+ const selectFields = this._getServerSelectFields();
2799
+ if (selectFields.length > 0) {
2800
+ options.select = selectFields;
2801
+ }
2802
+ },
2760
2803
  callApi: (options) => {
2761
2804
  const url = this.setExternalFilters(options);
2762
2805
  console.log('Server-side API call:', url);