teamplay 0.1.13 → 0.1.15

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.
package/connect/index.js CHANGED
@@ -2,11 +2,8 @@ import Socket from '@teamplay/channel'
2
2
  import Connection from './sharedbConnection.cjs'
3
3
  import { connection, setConnection } from '../orm/connection.js'
4
4
 
5
- export default function connect ({
6
- baseUrl,
7
- ...options
8
- } = {}) {
5
+ export default function connect (options) {
9
6
  if (connection) return
10
- const socket = new Socket({ baseUrl, ...options })
7
+ const socket = new Socket(options)
11
8
  setConnection(new Connection(socket))
12
9
  }
package/orm/Signal.js CHANGED
@@ -12,13 +12,15 @@
12
12
  * in the raw data tree which have the same name as signal's methods
13
13
  */
14
14
  import uuid from '@teamplay/utils/uuid'
15
- import { get as _get, set as _set, del as _del, setPublicDoc as _setPublicDoc } from './dataTree.js'
15
+ import { get as _get, set as _set, del as _del, setPublicDoc as _setPublicDoc, getRaw } from './dataTree.js'
16
16
  import getSignal, { rawSignal } from './getSignal.js'
17
17
  import { IS_QUERY, HASH, QUERIES } from './Query.js'
18
18
  import { ROOT_FUNCTION, getRoot } from './Root.js'
19
19
  import { publicOnly } from './connection.js'
20
20
 
21
21
  export const SEGMENTS = Symbol('path segments targeting the particular node in the data tree')
22
+ export const ARRAY_METHOD = Symbol('run array method on the signal')
23
+ export const GET = Symbol('get the value of the signal - either observed or raw')
22
24
 
23
25
  export default class Signal extends Function {
24
26
  constructor (segments) {
@@ -36,13 +38,23 @@ export default class Signal extends Function {
36
38
  return uuid()
37
39
  }
38
40
 
39
- get () {
40
- if (arguments.length > 0) throw Error('Signal.get() does not accept any arguments')
41
+ [GET] (method) {
42
+ if (arguments.length > 1) throw Error('Signal[GET]() only accepts method as an argument')
41
43
  if (this[IS_QUERY]) {
42
44
  const hash = this[HASH]
43
- return _get([QUERIES, hash, 'docs'])
45
+ return method([QUERIES, hash, 'docs'])
44
46
  }
45
- return _get(this[SEGMENTS])
47
+ return method(this[SEGMENTS])
48
+ }
49
+
50
+ get () {
51
+ if (arguments.length > 0) throw Error('Signal.get() does not accept any arguments')
52
+ return this[GET](_get)
53
+ }
54
+
55
+ peek () {
56
+ if (arguments.length > 0) throw Error('Signal.peek() does not accept any arguments')
57
+ return this[GET](getRaw)
46
58
  }
47
59
 
48
60
  getId () {
@@ -62,19 +74,32 @@ export default class Signal extends Function {
62
74
  }
63
75
  }
64
76
 
65
- map (...args) {
77
+ [ARRAY_METHOD] (method, nonArrayReturnValue, ...args) {
66
78
  if (this[IS_QUERY]) {
67
79
  const collection = this[SEGMENTS][0]
68
80
  const hash = this[HASH]
69
81
  const ids = _get([QUERIES, hash, 'ids'])
70
- return ids.map(id => getSignal(getRoot(this), [collection, id])).map(...args)
82
+ return ids.map(
83
+ id => getSignal(getRoot(this), [collection, id])
84
+ )[method](...args)
71
85
  }
72
86
  const items = _get(this[SEGMENTS])
73
- if (!Array.isArray(items)) return []
74
- return Array(items.length)
75
- .fill()
76
- .map((_, index) => getSignal(getRoot(this), [...this[SEGMENTS], index]))
77
- .map(...args)
87
+ if (!Array.isArray(items)) return nonArrayReturnValue
88
+ return Array(items.length).fill().map(
89
+ (_, index) => getSignal(getRoot(this), [...this[SEGMENTS], index])
90
+ )[method](...args)
91
+ }
92
+
93
+ map (...args) {
94
+ return this[ARRAY_METHOD]('map', [], ...args)
95
+ }
96
+
97
+ reduce (...args) {
98
+ return this[ARRAY_METHOD]('reduce', undefined, ...args)
99
+ }
100
+
101
+ find (...args) {
102
+ return this[ARRAY_METHOD]('find', undefined, ...args)
78
103
  }
79
104
 
80
105
  async set (value) {
@@ -104,7 +129,9 @@ export default class Signal extends Function {
104
129
  if (this[IS_QUERY]) throw Error('Signal.pop() can\'t be used on a query signal')
105
130
  const array = this.get()
106
131
  if (!Array.isArray(array) || array.length === 0) return
132
+ const lastItem = array[array.length - 1]
107
133
  await this[array.length - 1].del()
134
+ return lastItem
108
135
  }
109
136
 
110
137
  // TODO: implement a json0 operation for unshift
@@ -138,6 +165,7 @@ export default class Signal extends Function {
138
165
  }
139
166
  id ??= uuid()
140
167
  await this[id].set(value)
168
+ return id
141
169
  }
142
170
 
143
171
  async del () {
@@ -178,7 +206,7 @@ export const regularBindings = {
178
206
  }
179
207
  }
180
208
 
181
- const QUERY_METHODS = ['map', 'get']
209
+ const QUERY_METHODS = ['map', 'reduce', 'find', 'get']
182
210
 
183
211
  // dot syntax always returns a child signal even if such method or property exists.
184
212
  // The method is only called when the signal is explicitly called as a function,
@@ -201,6 +229,7 @@ export const extremelyLateBindings = {
201
229
  if (typeof key === 'symbol') return Reflect.get(signal, key, receiver)
202
230
  if (key === 'then') return undefined // handle checks for whether the symbol is a Promise
203
231
  key = transformAlias(signal[SEGMENTS], key)
232
+ key = maybeTransformToArrayIndex(key)
204
233
  if (signal[IS_QUERY]) {
205
234
  if (key === 'ids') return getSignal(getRoot(signal), [QUERIES, signal[HASH], 'ids'])
206
235
  if (QUERY_METHODS.includes(key)) return Reflect.get(signal, key, receiver)
@@ -209,6 +238,14 @@ export const extremelyLateBindings = {
209
238
  }
210
239
  }
211
240
 
241
+ const REGEX_POSITIVE_INTEGER = /^(?:0|[1-9]\d*)$/
242
+ // Transform the key to a number if it's a positive integer.
243
+ // Otherwise the key must be a string.
244
+ function maybeTransformToArrayIndex (key) {
245
+ if (typeof key === 'string' && REGEX_POSITIVE_INTEGER.test(key)) return +key
246
+ return key
247
+ }
248
+
212
249
  const transformAlias = (({
213
250
  collectionsMapping = {
214
251
  session: '_session',
package/orm/dataTree.js CHANGED
@@ -23,7 +23,7 @@ export function getRaw (segments) {
23
23
 
24
24
  export function set (segments, value, tree = dataTree) {
25
25
  let dataNode = tree
26
- let dataNodeRaw = raw(dataTree)
26
+ let dataNodeRaw = raw(tree)
27
27
  for (let i = 0; i < segments.length - 1; i++) {
28
28
  const segment = segments[i]
29
29
  if (dataNode[segment] == null) {
package/orm/sub.js CHANGED
@@ -3,9 +3,16 @@ import { docSubscriptions } from './Doc.js'
3
3
  import { querySubscriptions, getQuerySignal } from './Query.js'
4
4
 
5
5
  export default function sub ($signal, params) {
6
+ if (Array.isArray($signal)) {
7
+ const res = $signal.map(args => Array.isArray(args) ? sub(...args) : sub(args))
8
+ if (res.some($s => $s.then)) return Promise.all(res)
9
+ return res
10
+ }
6
11
  if (isPublicDocumentSignal($signal)) {
12
+ if (arguments.length > 1) throw Error(ERRORS.subDocArguments(...arguments))
7
13
  return doc$($signal)
8
14
  } else if (isPublicCollectionSignal($signal)) {
15
+ if (arguments.length !== 2) throw Error(ERRORS.subQueryArguments(...arguments))
9
16
  return query$($signal, params)
10
17
  } else if (typeof $signal === 'function' && !($signal instanceof Signal)) {
11
18
  return api$($signal, params)
@@ -21,6 +28,7 @@ function doc$ ($doc) {
21
28
  }
22
29
 
23
30
  function query$ ($collection, params) {
31
+ if (typeof params !== 'object') throw Error(ERRORS.queryParamsObject($collection, params))
24
32
  const $query = getQuerySignal($collection[SEGMENTS], params)
25
33
  const promise = querySubscriptions.subscribe($query)
26
34
  if (!promise) return $query
@@ -30,3 +38,27 @@ function query$ ($collection, params) {
30
38
  function api$ (fn, args) {
31
39
  throw Error('sub() for async functions is not implemented yet')
32
40
  }
41
+
42
+ const ERRORS = {
43
+ subDocArguments: ($signal, ...args) => `
44
+ sub($doc) accepts only 1 argument - the document signal to subscribe to
45
+ Doc: ${$signal[SEGMENTS]}
46
+ Got args: ${[$signal, ...args]}
47
+ `,
48
+ subQueryArguments: ($signal, params, ...args) => `
49
+ sub($collection, params) accepts 2 arguments - the collection signal and an object with query params.
50
+ If you want to subscribe to all documents in a collection, pass an empty object: sub($collection, {}).
51
+ Collection: ${$signal[SEGMENTS]}
52
+ Params: ${params}
53
+ Got args: ${[$signal, params, ...args]}
54
+ `,
55
+ queryParamsObject: ($collection, params) => `
56
+ sub($collection, params):
57
+ Params must be an object.
58
+ If you want to subscribe to all documents in a collection, pass an empty object: sub($collection, {}).
59
+
60
+ Got:
61
+ $collection: ${$collection[SEGMENTS]}
62
+ params: ${params}
63
+ `
64
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "teamplay",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "Full-stack signals ORM with multiplayer",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -23,12 +23,12 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "@nx-js/observer-util": "^4.1.3",
26
- "@teamplay/backend": "^0.1.13",
27
- "@teamplay/cache": "^0.1.13",
28
- "@teamplay/channel": "^0.1.13",
29
- "@teamplay/debug": "^0.1.13",
30
- "@teamplay/schema": "^0.1.13",
31
- "@teamplay/utils": "^0.1.13",
26
+ "@teamplay/backend": "^0.1.15",
27
+ "@teamplay/cache": "^0.1.15",
28
+ "@teamplay/channel": "^0.1.15",
29
+ "@teamplay/debug": "^0.1.15",
30
+ "@teamplay/schema": "^0.1.15",
31
+ "@teamplay/utils": "^0.1.15",
32
32
  "diff-match-patch": "^1.0.5",
33
33
  "events": "^3.3.0",
34
34
  "json0-ot-diff": "^1.1.2",
@@ -63,5 +63,5 @@
63
63
  ]
64
64
  },
65
65
  "license": "MIT",
66
- "gitHead": "1abacbe2dd704f77dfa20d061edf89490ac65cee"
66
+ "gitHead": "fc145854b61d07a913f27db2b604e4a2bf855fa0"
67
67
  }