mythix-orm 1.11.6 → 1.12.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.
@@ -4,27 +4,27 @@
4
4
 
5
5
  'use strict';
6
6
 
7
- const APPLY = Symbol.for('@_apply');
8
- const CALLABLE = Symbol.for('@_callable');
9
- const CONSTRUCT = Symbol.for('@_construct');
10
- const DEFINE_PROPERTY = Symbol.for('@_defineProperty');
11
- const DELETE_PROPERTY = Symbol.for('@_deleteProperty');
12
- const GET = Symbol.for('@_get');
13
- const GET_OWN_PROPERTY_DESCRIPTOR = Symbol.for('@_getOwnPropertyDescriptor');
14
- const GET_PROTOTYPEOF = Symbol.for('@_getPrototypeOf');
15
- const HAS = Symbol.for('@_has');
16
- const IS_EXTENSIBLE = Symbol.for('@_isExtensible');
17
- const MISSING = Symbol.for('@_missing');
18
- const OWN_KEYS = Symbol.for('@_ownKeys');
19
- const PREVENT_EXTENSIONS = Symbol.for('@_preventExtensions');
20
- const SET = Symbol.for('@_set');
21
- const SET_PROTOTYPEOF = Symbol.for('@_setPrototypeOf');
22
- const PROXY = Symbol.for('@__proxy');
23
- const TARGET = Symbol.for('@__target');
24
- const SELF = Symbol.for('@__rootInstance');
25
- const AUTO_CALL_CALLER = Symbol.for('@__autoCallCaller');
26
- const AUTO_CALL_CALLED = Symbol.for('@__autoCallCalled');
27
- const AUTO_CALL = Symbol.for('@__autoCall');
7
+ const APPLY = Symbol.for('@_mythix/orm/ProxyClass/apply');
8
+ const CALLABLE = Symbol.for('@_mythix/orm/ProxyClass/callable');
9
+ const CONSTRUCT = Symbol.for('@_mythix/orm/ProxyClass/construct');
10
+ const DEFINE_PROPERTY = Symbol.for('@_mythix/orm/ProxyClass/defineProperty');
11
+ const DELETE_PROPERTY = Symbol.for('@_mythix/orm/ProxyClass/deleteProperty');
12
+ const GET = Symbol.for('@_mythix/orm/ProxyClass/get');
13
+ const GET_OWN_PROPERTY_DESCRIPTOR = Symbol.for('@_mythix/orm/ProxyClass/getOwnPropertyDescriptor');
14
+ const GET_PROTOTYPEOF = Symbol.for('@_mythix/orm/ProxyClass/getPrototypeOf');
15
+ const HAS = Symbol.for('@_mythix/orm/ProxyClass/has');
16
+ const IS_EXTENSIBLE = Symbol.for('@_mythix/orm/ProxyClass/isExtensible');
17
+ const MISSING = Symbol.for('@_mythix/orm/ProxyClass/missing');
18
+ const OWN_KEYS = Symbol.for('@_mythix/orm/ProxyClass/ownKeys');
19
+ const PREVENT_EXTENSIONS = Symbol.for('@_mythix/orm/ProxyClass/preventExtensions');
20
+ const SET = Symbol.for('@_mythix/orm/ProxyClass/set');
21
+ const SET_PROTOTYPEOF = Symbol.for('@_mythix/orm/ProxyClass/setPrototypeOf');
22
+ const PROXY = Symbol.for('@__mythix/orm/ProxyClass/proxy');
23
+ const TARGET = Symbol.for('@__mythix/orm/ProxyClass/target');
24
+ const SELF = Symbol.for('@__mythix/orm/ProxyClass/rootInstance');
25
+ const AUTO_CALL_CALLER = Symbol.for('@__mythix/orm/ProxyClass/autoCallCaller');
26
+ const AUTO_CALL_CALLED = Symbol.for('@__mythix/orm/ProxyClass/autoCallCalled');
27
+ const AUTO_CALL = Symbol.for('@__mythix/orm/ProxyClass/autoCall');
28
28
 
29
29
  function shouldSkipProxy(prop) {
30
30
  if (prop === 'bind' || prop === 'call' || prop === 'apply')
@@ -39,6 +39,26 @@ function shouldSkipProxy(prop) {
39
39
  return false;
40
40
  }
41
41
 
42
+ /// This is essentially a [Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy)
43
+ /// converted into class form. What that means is that instead of defining a
44
+ /// proxy by passing it a "handlers" object to it, this instead *is* the handler
45
+ /// for all classes that inherit from it. Just like a `Proxy`, inheriting from
46
+ /// this class will allow the child-class to intercept property gets and sets,
47
+ /// intercept method calls, property deletion, etc...
48
+ ///
49
+ /// It works by returning `this` inside the `constructor` wrapped in a
50
+ /// `Proxy`. The `Proxy` it creates is then managed by the class instance itself.
51
+ /// For example, during key access, if a key the user is requesting is not found,
52
+ /// the proxy will call the instance method `MISSING` on the class. This allows
53
+ /// the child class to provide a method for `MISSING`, and then respond to key
54
+ /// access for keys that don't actually exist on the instance.
55
+ ///
56
+ /// That is just one example of many. This class provides full `Proxy` support,
57
+ /// and so has methods (or stubs) for every feature available natively to a `Proxy`.
58
+ /// Instance methods are keyed by symbols. This is to try and reduce the chance
59
+ /// of a name collision... keeping this class useful for many scenarios. For example,
60
+ /// the `MISSING` method above is actually `Symbol.for('@_mythix/orm/ProxyClass/missing')`,
61
+ /// that is assigned to the constant <see>ProxyClass.MISSING</see>.
42
62
  class ProxyClass {
43
63
  static APPLY = APPLY;
44
64
  static CALLABLE = CALLABLE;
@@ -175,6 +195,8 @@ class ProxyClass {
175
195
  return proxy;
176
196
  }
177
197
 
198
+ /// Construct the class instance, with
199
+ /// `this` returned wrapped in a `Proxy`.
178
200
  constructor() {
179
201
  Object.defineProperties(this, {
180
202
  [AUTO_CALL_CALLER]: {
@@ -195,6 +217,65 @@ class ProxyClass {
195
217
  return proxy;
196
218
  }
197
219
 
220
+ /// Any method of the instance wrapped in an
221
+ /// `__autoCall` factory will be automatically
222
+ /// called by the engine if not called by the user.
223
+ ///
224
+ /// This works by the `ProxyClass` pushing the auto-call
225
+ /// into a queue when the method key is accessed. If another
226
+ /// key is accessed (any other key), then the `ProxyClass` will
227
+ /// check if the auto-call method has been called yet. If it
228
+ /// hasn't, then the `ProxyClass` will call it, providing no
229
+ /// arguments, and using the return value of the call for the
230
+ /// pending key access. If the auto-call method is simply called,
231
+ /// then the queue is cleared, and the return value simply returned
232
+ /// to the user.
233
+ ///
234
+ /// Example:
235
+ /// class Greeter extends ProxyClass {
236
+ /// greet = this.__autoCall((name) => {
237
+ /// if (arguments.length === 0) {
238
+ /// // An auto-call, or the user didn't
239
+ /// // provide any arguments.
240
+ /// console.log('Hello whoever you are!');
241
+ /// } else {
242
+ /// // Was definitely called by the user
243
+ /// console.log(`Hello ${name}!`);
244
+ /// }
245
+ /// });
246
+ ///
247
+ /// finish() {
248
+ /// // finish operation
249
+ /// }
250
+ /// }
251
+ ///
252
+ /// // Example 1
253
+ /// let greeter = new Greeter();
254
+ /// greeter.greet.finish();
255
+ /// // ^---- Auto call happens here
256
+ /// // output: Hello whoever you are!
257
+ ///
258
+ /// // Example 2
259
+ /// greeter.greet('Wyatt Greenway').finish();
260
+ /// // No auto-call happens... this is a manual call.
261
+ /// // output: Hello Wyatt Greenway!
262
+ ///
263
+ /// Note:
264
+ /// For an auto-call to work, a key access attempt must happen
265
+ /// after the auto-call method is accessed. This is almost always
266
+ /// the case, because in interacting with the object you are almost
267
+ /// guaranteed to access a key again, i.e. `.toString` if converting
268
+ /// to a string, `.toJSON` if converting to JSON, iterator access,
269
+ /// or even debugging the object.
270
+ ///
271
+ /// Arguments:
272
+ /// caller: Function
273
+ /// The method implementation for the class. This method will
274
+ /// be used by the factory to create an auto-call method for
275
+ /// the class.
276
+ ///
277
+ /// Return: Function
278
+ /// The `caller` method provided, wrapped into an auto-call factory method.
198
279
  __autoCall(caller) {
199
280
  this[AUTO_CALL_CALLER] = caller;
200
281
  this[AUTO_CALL_CALLED] = false;
@@ -202,6 +283,60 @@ class ProxyClass {
202
283
  return this;
203
284
  }
204
285
 
286
+ /// This is a factory much like <see>ProxyClass.__autoCall</see>
287
+ /// for creating instance methods. It differs however in that
288
+ /// the method returned by this factory isn't auto-called, but
289
+ /// instead an *optional* call.
290
+ ///
291
+ /// The way it works is that the method provided is returned,
292
+ /// itself wrapped in a `Proxy`. If it is called, then the
293
+ /// `Proxy` will pass the call through to the method, and return
294
+ /// the result. Being a `Proxy`, it passes all key access back
295
+ /// to the original class instance, allowing the method itself
296
+ /// to mimic the class instance. This allows for instance methods
297
+ /// that can *optionally* be called, but if they aren't called,
298
+ /// will act as though you are still interacting with the instance
299
+ /// of the class itself.
300
+ ///
301
+ /// Example:
302
+ /// class Greeter extends ProxyClass {
303
+ /// constructor() {
304
+ /// super();
305
+ ///
306
+ /// this.greetName = undefined;
307
+ /// }
308
+ ///
309
+ /// name = this.__call((name) => {
310
+ /// this.greetName = name;
311
+ /// });
312
+ ///
313
+ /// greet() {
314
+ /// if (this.greetName) {
315
+ /// console.log(`Hello ${this.greetName}!`);
316
+ /// } else {
317
+ /// console.log('Hello whoever you are!');
318
+ /// }
319
+ /// }
320
+ /// }
321
+ ///
322
+ /// // Example 1
323
+ /// let greeter = new Greeter();
324
+ /// greeter.name.greet();
325
+ /// // ^---- optional call here
326
+ /// // output: Hello whoever you are!
327
+ ///
328
+ /// // Example 2
329
+ /// greeter.name('Wyatt Greenway').greet();
330
+ /// // output: Hello Wyatt Greenway!
331
+ ///
332
+ /// Arguments:
333
+ /// caller: Function
334
+ /// The method implementation for the class. This method will
335
+ /// be used by the factory to create an optional call method for
336
+ /// the class.
337
+ ///
338
+ /// Return: Function
339
+ /// The `caller` method provided, wrapped into an optional call factory method.
205
340
  __call(caller) {
206
341
  return ProxyClass.createProxy.call(this, caller.bind(this[PROXY]));
207
342
  }