teamplay 0.5.0-alpha.19 → 0.5.0-alpha.20

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,7 +1,7 @@
1
1
  import { raw } from '@nx-js/observer-util';
2
2
  import { getRaw } from './dataTree.js';
3
3
  import getSignal from "./getSignal.js";
4
- import { QuerySubscriptions, hashQuery, Query, HASH, PARAMS, COLLECTION_NAME, parseQueryHash } from './Query.js';
4
+ import { QuerySubscriptions, hashQuery, Query, cloneQueryParams, HASH, PARAMS, COLLECTION_NAME, parseQueryHash } from './Query.js';
5
5
  import Signal, { SEGMENTS } from "./Signal.js";
6
6
  import { getIdFieldsForSegments, isPlainObject } from "./idFields.js";
7
7
  import { delPrivateData, getPrivateData, setPrivateData } from './privateData.js';
@@ -64,7 +64,7 @@ export function getAggregationRowId(row, collectionName) {
64
64
  }
65
65
  }
66
66
  export function getAggregationSignal(collectionName, params, options) {
67
- params = JSON.parse(JSON.stringify(params));
67
+ params = cloneQueryParams(collectionName, params);
68
68
  const transportHash = hashQuery(collectionName, params);
69
69
  const { root, signalOptions } = parseAggregationSignalOptions(options);
70
70
  const $aggregation = getSignal(root, [AGGREGATIONS, transportHash], signalOptions);
package/dist/orm/Query.js CHANGED
@@ -465,7 +465,7 @@ export class QuerySubscriptions {
465
465
  }
466
466
  subscribe($query, { intent = 'subscribe' } = {}) {
467
467
  const collectionName = $query[COLLECTION_NAME];
468
- const params = cloneQueryParams($query[PARAMS]);
468
+ const params = cloneQueryParams(collectionName, $query[PARAMS]);
469
469
  const transportHash = $query[HASH];
470
470
  const rootId = getOwningRootId($query);
471
471
  const ownerKey = getQueryOwnerKey(rootId, transportHash);
@@ -920,7 +920,7 @@ export function materializeQueryDataDocsToCollection(collectionName, docs) {
920
920
  }
921
921
  }
922
922
  export function hashQuery(collectionName, params) {
923
- params = normalizeQueryParamsForHash(params);
923
+ params = normalizeQueryParamsForHash(collectionName, params);
924
924
  // TODO: probably makes sense to use fast-stable-json-stringify for this because of the params
925
925
  return JSON.stringify({ query: [collectionName, params] });
926
926
  }
@@ -934,7 +934,7 @@ export function parseQueryHash(hash) {
934
934
  }
935
935
  }
936
936
  export function getQuerySignal(collectionName, params, options) {
937
- params = cloneQueryParams(params);
937
+ params = cloneQueryParams(collectionName, params);
938
938
  const transportHash = hashQuery(collectionName, params);
939
939
  const { root, signalOptions } = parseQuerySignalOptions(options);
940
940
  const signalHash = getScopedSignalHash(root?.[ROOT_ID] ?? signalOptions.rootId, transportHash, 'querySignal');
@@ -987,10 +987,9 @@ function getOwningRootId($query) {
987
987
  function getQueryOwnerKey(rootId, transportHash) {
988
988
  return getScopedSignalHash(rootId, transportHash, 'queryOwner');
989
989
  }
990
- function cloneQueryParams(params) {
991
- if (!isCompatEnv())
992
- return JSON.parse(JSON.stringify(params));
993
- return cloneQueryParamsCompat(params);
990
+ export function cloneQueryParams(collectionName, params) {
991
+ warnIfCompatQueryParamsHaveUndefinedFields(collectionName, params);
992
+ return JSON.parse(JSON.stringify(params));
994
993
  }
995
994
  function parseQuerySignalOptions(options) {
996
995
  if (!options || typeof options !== 'object') {
@@ -1002,27 +1001,55 @@ function parseQuerySignalOptions(options) {
1002
1001
  const { root, ...signalOptions } = options;
1003
1002
  return { root, signalOptions };
1004
1003
  }
1005
- function normalizeQueryParamsForHash(params) {
1004
+ function normalizeQueryParamsForHash(collectionName, params) {
1005
+ warnIfCompatQueryParamsHaveUndefinedFields(collectionName, params);
1006
+ return params;
1007
+ }
1008
+ const warnedUndefinedQueryParamKeys = new Set();
1009
+ function warnIfCompatQueryParamsHaveUndefinedFields(collectionName, params) {
1006
1010
  if (!isCompatEnv())
1007
- return params;
1008
- return cloneQueryParamsCompat(params);
1011
+ return;
1012
+ const paths = getUndefinedQueryParamFieldPaths(params);
1013
+ if (paths.length === 0)
1014
+ return;
1015
+ const key = `${collectionName || '<unknown>'}:${paths.join(',')}`;
1016
+ if (warnedUndefinedQueryParamKeys.has(key))
1017
+ return;
1018
+ warnedUndefinedQueryParamKeys.add(key);
1019
+ console.warn('[teamplay] Compat query params contain object fields with undefined values. ' +
1020
+ 'TeamPlay now clones query params like non-compat mode, so these fields are dropped ' +
1021
+ 'instead of being converted to null. Normalize query params explicitly.', {
1022
+ collectionName,
1023
+ paths
1024
+ }, new Error().stack);
1025
+ }
1026
+ function getUndefinedQueryParamFieldPaths(value) {
1027
+ const paths = [];
1028
+ collectUndefinedQueryParamFieldPaths(value, '', paths, new WeakSet());
1029
+ return paths;
1009
1030
  }
1010
- // Racer compat: keep query keys with undefined values by normalizing them to null
1011
- // instead of dropping them via JSON serialization.
1012
- function cloneQueryParamsCompat(value) {
1013
- if (value === undefined)
1014
- return null;
1031
+ function collectUndefinedQueryParamFieldPaths(value, path, paths, seen) {
1015
1032
  if (value == null || typeof value !== 'object')
1016
- return value;
1017
- if (Array.isArray(value))
1018
- return value.map(item => cloneQueryParamsCompat(item));
1019
- const object = {};
1033
+ return;
1034
+ if (seen.has(value))
1035
+ return;
1036
+ seen.add(value);
1037
+ if (Array.isArray(value)) {
1038
+ for (let i = 0; i < value.length; i++) {
1039
+ collectUndefinedQueryParamFieldPaths(value[i], `${path}[${i}]`, paths, seen);
1040
+ }
1041
+ return;
1042
+ }
1020
1043
  for (const key in value) {
1021
- if (Object.prototype.hasOwnProperty.call(value, key)) {
1022
- object[key] = cloneQueryParamsCompat(value[key]);
1044
+ if (!Object.prototype.hasOwnProperty.call(value, key))
1045
+ continue;
1046
+ const childPath = path ? `${path}.${key}` : key;
1047
+ if (value[key] === undefined) {
1048
+ paths.push(childPath);
1049
+ continue;
1023
1050
  }
1051
+ collectUndefinedQueryParamFieldPaths(value[key], childPath, paths, seen);
1024
1052
  }
1025
- return object;
1026
1053
  }
1027
1054
  function createPendingDestroyEntry() {
1028
1055
  let resolvePending;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "teamplay",
3
- "version": "0.5.0-alpha.19",
3
+ "version": "0.5.0-alpha.20",
4
4
  "description": "Full-stack signals ORM with multiplayer",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -134,5 +134,5 @@
134
134
  ]
135
135
  },
136
136
  "license": "MIT",
137
- "gitHead": "4bafa99265d8aed36e952d89d8d0ed0082748ad5"
137
+ "gitHead": "f1a50d980e3748d58b85e565c0dc40291a4806f0"
138
138
  }