manyfest 1.0.37 → 1.0.39

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/README.md CHANGED
@@ -42,15 +42,15 @@ const libManyfest = require('Manyfest');
42
42
 
43
43
  // Construct a Manyfest with a few defined columns
44
44
  let animalManyfest = new libManyfest(
45
- {
46
- "Scope": "Animal",
47
- "Descriptors":
48
- {
49
- "IDAnimal": { "Name":"Database ID", "Description":"The unique integer-based database identifier for an Animal record.", "DataType":"Integer", "Default":0 },
50
- "Name": { "Description":"The animal's colloquial species name (e.g. Rabbit, Dog, Bear, Mongoose)." },
51
- "Type": { "Description":"Whether or not the animal is wild, domesticated, agricultural, in a research lab or a part of a zoo.." }
52
- }
53
- });
45
+ {
46
+ "Scope": "Animal",
47
+ "Descriptors":
48
+ {
49
+ "IDAnimal": { "Name":"Database ID", "Description":"The unique integer-based database identifier for an Animal record.", "DataType":"Integer", "Default":0 },
50
+ "Name": { "Description":"The animal's colloquial species name (e.g. Rabbit, Dog, Bear, Mongoose)." },
51
+ "Type": { "Description":"Whether or not the animal is wild, domesticated, agricultural, in a research lab or a part of a zoo.." }
52
+ }
53
+ });
54
54
 
55
55
  // Make up a cute and furry test creature
56
56
  let testAnimal = {IDAnimal:8675309, Name:'BatBrains', Type:'Lab', Color:'Brown'};
@@ -93,29 +93,29 @@ Let's use our Animal schema and extend it a little bit. In this case, a new JSO
93
93
 
94
94
  ```javascript
95
95
  let animalManyfest = new libManyfest(
96
- {
97
- "Scope": "Animal",
98
- "Descriptors":
99
- {
100
- "IDAnimal": { "Name":"Database ID", "Description":"The unique integer-based database identifier for an Animal record.", "DataType":"Integer" },
101
- "Name": { "Description":"The animal's colloquial species name (e.g. Rabbit, Dog, Bear, Mongoose)." },
102
- "Type": { "Description":"Whether or not the animal is wild, domesticated, agricultural, in a research lab or a part of a zoo.." },
103
- "MedicalStats":
104
- {
105
- "Name":"Medical Statistics", "Description":"Basic medical statistics for this animal"
106
- },
107
- "MedicalStats.Temps.MinET": { "Name":"Minimum Environmental Temperature", "NameShort":"MinET", "Description":"Safest minimum temperature for this animal to survive in."},
108
- "MedicalStats.Temps.MaxET": { "Name":"Maximum Environmental Temperature", "NameShort":"MaxET", "Description":"Safest maximum temperature for this animal to survive in."},
109
- "MedicalStats.Temps.CET":
110
- {
111
- "Name":"Comfortable Environmental Temperature",
112
- "NameShort":"Comf Env Temp",
113
- "Hash":"ComfET",
114
- "DataType":"Float",
115
- "Description":"The most comfortable temperature for this animal to survive in."
116
- }
117
- }
118
- });
96
+ {
97
+ "Scope": "Animal",
98
+ "Descriptors":
99
+ {
100
+ "IDAnimal": { "Name":"Database ID", "Description":"The unique integer-based database identifier for an Animal record.", "DataType":"Integer" },
101
+ "Name": { "Description":"The animal's colloquial species name (e.g. Rabbit, Dog, Bear, Mongoose)." },
102
+ "Type": { "Description":"Whether or not the animal is wild, domesticated, agricultural, in a research lab or a part of a zoo.." },
103
+ "MedicalStats":
104
+ {
105
+ "Name":"Medical Statistics", "Description":"Basic medical statistics for this animal"
106
+ },
107
+ "MedicalStats.Temps.MinET": { "Name":"Minimum Environmental Temperature", "NameShort":"MinET", "Description":"Safest minimum temperature for this animal to survive in."},
108
+ "MedicalStats.Temps.MaxET": { "Name":"Maximum Environmental Temperature", "NameShort":"MaxET", "Description":"Safest maximum temperature for this animal to survive in."},
109
+ "MedicalStats.Temps.CET":
110
+ {
111
+ "Name":"Comfortable Environmental Temperature",
112
+ "NameShort":"Comf Env Temp",
113
+ "Hash":"ComfET",
114
+ "DataType":"Float",
115
+ "Description":"The most comfortable temperature for this animal to survive in."
116
+ }
117
+ }
118
+ });
119
119
  ```
120
120
 
121
121
  Notice in this example, the addresses are more complex. They have a dot syntax. This notifies Manyfest that they are nested values. Further, there is both a Name and a NameShort descriptor setup. This gives us a framework for consistently referring to the data element both internally and to the user. It is no longer a mystery what someAnimal.MedicalStats.Temps.CET means. Developers, user interface designers, database engineers, product managers and other folks who work on the software side don't have to maintain a third body of documentation about what the data means.
@@ -135,10 +135,15 @@ Boolean | A boolean value represented by the JSON true or false
135
135
  Binary | A boolean value represented as 1 or 0
136
136
  YesNo | A boolean value represented as Y or N
137
137
  DateTime | A javascript date
138
+ Key | A two-part Key with an Identifier and Globally Unique Identifier (ID and GUID)
138
139
  Array | A plain old javascript array
139
140
  Object | A plain old javascript object
140
141
  Null | A null value
141
142
 
143
+ #### Keys
144
+
145
+ Keys are a slightly more complex value type, in that they have configuration that defines cardinality. The address is meant to point to one of two of the values (either the GUID or the ID). There is a secondary parameter for the other.
146
+
142
147
  ## Reading and Writing Element Properties
143
148
 
144
149
  Lastly, when working with objects, Manyfest provides a set of functions to read and write from/to these element addresses. This can be useful for consistently accessing objects across boundaries as well as filling out element defaults without requiring a crazy amount of boilerplate code.
@@ -221,15 +226,15 @@ const libManyfest = require('Manyfest');
221
226
 
222
227
  // Construct a Manyfest with a few defined columns
223
228
  let animalManyfest = new libManyfest(
224
- {
225
- "Scope": "Animal",
226
- "Descriptors":
227
- {
228
- "IDAnimal": { "Name":"Database ID", "Description":"The unique integer-based database identifier for an Animal record.", "DataType":"Integer" },
229
- "Name": { "Description":"The animal's colloquial species name (e.g. Rabbit, Dog, Bear, Mongoose)." },
230
- "Type": { "Description":"Whether or not the animal is wild, domesticated, agricultural, in a research lab or a part of a zoo.." }
231
- }
232
- });
229
+ {
230
+ "Scope": "Animal",
231
+ "Descriptors":
232
+ {
233
+ "IDAnimal": { "Name":"Database ID", "Description":"The unique integer-based database identifier for an Animal record.", "DataType":"Integer" },
234
+ "Name": { "Description":"The animal's colloquial species name (e.g. Rabbit, Dog, Bear, Mongoose)." },
235
+ "Type": { "Description":"Whether or not the animal is wild, domesticated, agricultural, in a research lab or a part of a zoo.." }
236
+ }
237
+ });
233
238
  ```
234
239
 
235
240
  The programmatic equivalent is the following code:
@@ -269,250 +274,250 @@ There is an API to access their data. It's ... really messy, the data you get b
269
274
 
270
275
  ```JSON
271
276
  {
272
- "created": 1664830085,
273
- "d1": "ia600202.us.archive.org",
274
- "d2": "ia800202.us.archive.org",
275
- "dir": "/7/items/FrankenberryCountChoculaTevevisionCommercial1971",
276
- "files": [
277
- {
278
- "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000001.jpg",
279
- "source": "derivative",
280
- "format": "Thumbnail",
281
- "original": "frankerberry_countchockula_1971.0001.mpg",
282
- "mtime": "1296336956",
283
- "size": "838",
284
- "md5": "e47269cd5a82db9594f265a65785ec12",
285
- "crc32": "165c668b",
286
- "sha1": "383303d9546c381267569ad4e33aff691f0bb8c7"
287
- },
288
- {
289
- "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000004.jpg",
290
- "source": "derivative",
291
- "format": "Thumbnail",
292
- "original": "frankerberry_countchockula_1971.0001.mpg",
293
- "mtime": "1296336957",
294
- "size": "6843",
295
- "md5": "c93fa52000ab4665e69b25c403e11aff",
296
- "crc32": "9444e6f6",
297
- "sha1": "716b4f9950b8147f51d3265f9c62ff86451308d5"
298
- },
299
- {
300
- "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000009.jpg",
301
- "source": "derivative",
302
- "format": "Thumbnail",
303
- "original": "frankerberry_countchockula_1971.0001.mpg",
304
- "mtime": "1296336957",
305
- "size": "8388",
306
- "md5": "30eb3eb4cbbdfa08d531a0a74da7c000",
307
- "crc32": "be874a9e",
308
- "sha1": "0c392d777609e967b6022be27edad678c5ae74e2"
309
- },
310
- {
311
- "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000014.jpg",
312
- "source": "derivative",
313
- "format": "Thumbnail",
314
- "original": "frankerberry_countchockula_1971.0001.mpg",
315
- "mtime": "1296336958",
316
- "size": "5993",
317
- "md5": "4e9ebc3d076bec8cf7dfe76795f8c769",
318
- "crc32": "912ec98c",
319
- "sha1": "01dc49c852e1bbb421199450dd902935c62b06de"
320
- },
321
- {
322
- "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000019.jpg",
323
- "source": "derivative",
324
- "format": "Thumbnail",
325
- "original": "frankerberry_countchockula_1971.0001.mpg",
326
- "mtime": "1296336958",
327
- "size": "4951",
328
- "md5": "59f190f0c5b0a048415b26412860b6dd",
329
- "crc32": "a70a30b1",
330
- "sha1": "a284af9757cb24d28f96ec88ec1b1c23a8cea9fe"
331
- },
332
- {
333
- "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000024.jpg",
334
- "source": "derivative",
335
- "format": "Thumbnail",
336
- "original": "frankerberry_countchockula_1971.0001.mpg",
337
- "mtime": "1296336959",
338
- "size": "3383",
339
- "md5": "be2a908acd563b896e7758b598295148",
340
- "crc32": "ed467831",
341
- "sha1": "94c001e72ebc86d837a78c61a004db9ab9d597bd"
342
- },
343
- {
344
- "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000029.jpg",
345
- "source": "derivative",
346
- "format": "Thumbnail",
347
- "original": "frankerberry_countchockula_1971.0001.mpg",
348
- "mtime": "1296336960",
349
- "size": "3503",
350
- "md5": "c82199d09be07633000fd07b363dd8a3",
351
- "crc32": "a1fd79cb",
352
- "sha1": "2bc8e761edb24a441fa5906dda1c424e1f98a47a"
353
- },
354
- {
355
- "name": "FrankenberryCountChoculaTevevisionCommercial1971_archive.torrent",
356
- "source": "metadata",
357
- "btih": "de6b371e7cc3c83db1cc08150500753eae533409",
358
- "mtime": "1542761794",
359
- "size": "4093",
360
- "md5": "a275d3b4028cccb5bea8b47a88c838af",
361
- "crc32": "5ffa7334",
362
- "sha1": "af8222637b574cba1360d0ea77e231640ffd43c4",
363
- "format": "Archive BitTorrent"
364
- },
365
- {
366
- "name": "FrankenberryCountChoculaTevevisionCommercial1971_files.xml",
367
- "source": "metadata",
368
- "format": "Metadata",
369
- "md5": "3a7e87b08bed1e203a5858b31352c110"
370
- },
371
- {
372
- "name": "FrankenberryCountChoculaTevevisionCommercial1971_meta.xml",
373
- "source": "metadata",
374
- "format": "Metadata",
375
- "mtime": "1542761793",
376
- "size": "1371",
377
- "md5": "0b9c9bf21b9a26aea43a2f735b404624",
378
- "crc32": "41077288",
379
- "sha1": "22e6f2c73bf63072f671d846355da2785db51dbd"
380
- },
381
- {
382
- "name": "FrankenberryCountChoculaTevevisionCommercial1971_reviews.xml",
383
- "source": "original",
384
- "mtime": "1466898697",
385
- "size": "620",
386
- "md5": "260bfba5d696772445dcc7ff6e6d5bdb",
387
- "crc32": "25ea3229",
388
- "sha1": "7d541f18fcd5ad9c6e593afe5a80f18771f23b32",
389
- "format": "Metadata"
390
- },
391
- {
392
- "name": "__ia_thumb.jpg",
393
- "source": "original",
394
- "mtime": "1539115881",
395
- "size": "7481",
396
- "md5": "8cec324fa0016fd77cc04e6a4b2ebb00",
397
- "crc32": "d9e1b316",
398
- "sha1": "4dab42952fe0405a3b7f80146636b33d7b1bd01e",
399
- "format": "Item Tile",
400
- "rotation": "0"
401
- },
402
- {
403
- "name": "frankerberry_countchockula_1971.0001.gif",
404
- "source": "derivative",
405
- "format": "Animated GIF",
406
- "original": "frankerberry_countchockula_1971.0001.mpg",
407
- "mtime": "1296336965",
408
- "size": "101114",
409
- "md5": "b78a13094030f104900eb996bafe2b7d",
410
- "crc32": "6650cd8",
411
- "sha1": "669798c037205cac14f70592deef6f7831b3d4a1"
412
- },
413
- {
414
- "name": "frankerberry_countchockula_1971.0001.mpg",
415
- "source": "original",
416
- "format": "MPEG2",
417
- "mtime": "1296335803",
418
- "size": "31625216",
419
- "md5": "762ba18b026b85b3f074523e7fcb4db0",
420
- "crc32": "42347f78",
421
- "sha1": "41162dc2d1a91b618124c84628d0c231544a02be",
422
- "length": "31.14",
423
- "height": "480",
424
- "width": "640"
425
- },
426
- {
427
- "name": "frankerberry_countchockula_1971.0001.mpg.idx",
428
- "source": "derivative",
429
- "format": "Video Index",
430
- "original": "frankerberry_countchockula_1971.0001.mpg",
431
- "mtime": "1296336956",
432
- "size": "31141",
433
- "md5": "49423e072726e4ea3cdd8ebdd26c7dfc",
434
- "crc32": "ae969a68",
435
- "sha1": "805782cd2d0f9002555816daadf3b8607e621f79"
436
- },
437
- {
438
- "name": "frankerberry_countchockula_1971.0001.ogv",
439
- "source": "derivative",
440
- "format": "Ogg Video",
441
- "original": "frankerberry_countchockula_1971.0001.mpg",
442
- "mtime": "1296336994",
443
- "size": "2248166",
444
- "md5": "f1b933e97ce63594fb28a0a019ff3436",
445
- "crc32": "a2a0e5e9",
446
- "sha1": "a6bf0aec9f006baeca37c03f586686ebe685d59b",
447
- "length": "31.15",
448
- "height": "300",
449
- "width": "400"
450
- },
451
- {
452
- "name": "frankerberry_countchockula_1971.0001_512kb.mp4",
453
- "source": "derivative",
454
- "format": "512Kb MPEG4",
455
- "original": "frankerberry_countchockula_1971.0001.mpg",
456
- "mtime": "1296336977",
457
- "size": "2378677",
458
- "md5": "a7750839519c61ba3bb99fc66b32011d",
459
- "crc32": "4dbd37c8",
460
- "sha1": "3929314c192dec006fac2739bcb4730788e8c068",
461
- "length": "31.13",
462
- "height": "240",
463
- "width": "320"
464
- }
465
- ],
466
- "files_count": 17,
467
- "item_last_updated": 1542761794,
468
- "item_size": 36431778,
469
- "metadata": {
470
- "identifier": "FrankenberryCountChoculaTevevisionCommercial1971",
471
- "title": "Franken Berry / Count Chocula : Tevevision Commercial 1971",
472
- "creator": "General Mills",
473
- "mediatype": "movies",
474
- "collection": [
475
- "classic_tv_commercials",
476
- "television"
477
- ],
478
- "description": "Count Chocula and Franken Berry were both introduced in 1971. Boo Berry Cereal appeared in 1973 followed by Fruit Brute in 1974. Yummy Mummy appeared more than a decade later in 1988 - completing the the group known as the General Mills Monster Cereals.",
479
- "subject": "Third Eye Cinema; Classic Television Commercials; animation; cartoons;General Mills",
480
- "licenseurl": "http://creativecommons.org/publicdomain/mark/1.0/",
481
- "publicdate": "2011-01-29 21:36:42",
482
- "addeddate": "2011-01-29 21:35:38",
483
- "uploader": "bolexman@msn.com",
484
- "updater": [
485
- "Bolexman",
486
- "Bolexman",
487
- "Jeff Kaplan"
488
- ],
489
- "updatedate": [
490
- "2011-01-29 21:45:38",
491
- "2011-01-29 21:55:46",
492
- "2011-01-29 23:04:55"
493
- ],
494
- "sound": "sound",
495
- "color": "color",
496
- "runtime": "0:31",
497
- "backup_location": "ia903608_22",
498
- "ia_orig__runtime": "31 seconds"
499
- },
500
- "reviews": [
501
- {
502
- "reviewbody": "Sugar cereal cartoon Karloff and Lugosi argue self-importance pre Lorre ghost. Interesting how kids still know the voices without any idea of the origins.",
503
- "reviewtitle": "pre booberry",
504
- "reviewer": "outofthebox",
505
- "reviewdate": "2016-06-25 23:51:36",
506
- "createdate": "2016-06-25 23:51:36",
507
- "stars": "4"
508
- }
509
- ],
510
- "server": "ia800202.us.archive.org",
511
- "uniq": 1957612749,
512
- "workable_servers": [
513
- "ia800202.us.archive.org",
514
- "ia600202.us.archive.org"
515
- ]
277
+ "created": 1664830085,
278
+ "d1": "ia600202.us.archive.org",
279
+ "d2": "ia800202.us.archive.org",
280
+ "dir": "/7/items/FrankenberryCountChoculaTevevisionCommercial1971",
281
+ "files": [
282
+ {
283
+ "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000001.jpg",
284
+ "source": "derivative",
285
+ "format": "Thumbnail",
286
+ "original": "frankerberry_countchockula_1971.0001.mpg",
287
+ "mtime": "1296336956",
288
+ "size": "838",
289
+ "md5": "e47269cd5a82db9594f265a65785ec12",
290
+ "crc32": "165c668b",
291
+ "sha1": "383303d9546c381267569ad4e33aff691f0bb8c7"
292
+ },
293
+ {
294
+ "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000004.jpg",
295
+ "source": "derivative",
296
+ "format": "Thumbnail",
297
+ "original": "frankerberry_countchockula_1971.0001.mpg",
298
+ "mtime": "1296336957",
299
+ "size": "6843",
300
+ "md5": "c93fa52000ab4665e69b25c403e11aff",
301
+ "crc32": "9444e6f6",
302
+ "sha1": "716b4f9950b8147f51d3265f9c62ff86451308d5"
303
+ },
304
+ {
305
+ "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000009.jpg",
306
+ "source": "derivative",
307
+ "format": "Thumbnail",
308
+ "original": "frankerberry_countchockula_1971.0001.mpg",
309
+ "mtime": "1296336957",
310
+ "size": "8388",
311
+ "md5": "30eb3eb4cbbdfa08d531a0a74da7c000",
312
+ "crc32": "be874a9e",
313
+ "sha1": "0c392d777609e967b6022be27edad678c5ae74e2"
314
+ },
315
+ {
316
+ "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000014.jpg",
317
+ "source": "derivative",
318
+ "format": "Thumbnail",
319
+ "original": "frankerberry_countchockula_1971.0001.mpg",
320
+ "mtime": "1296336958",
321
+ "size": "5993",
322
+ "md5": "4e9ebc3d076bec8cf7dfe76795f8c769",
323
+ "crc32": "912ec98c",
324
+ "sha1": "01dc49c852e1bbb421199450dd902935c62b06de"
325
+ },
326
+ {
327
+ "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000019.jpg",
328
+ "source": "derivative",
329
+ "format": "Thumbnail",
330
+ "original": "frankerberry_countchockula_1971.0001.mpg",
331
+ "mtime": "1296336958",
332
+ "size": "4951",
333
+ "md5": "59f190f0c5b0a048415b26412860b6dd",
334
+ "crc32": "a70a30b1",
335
+ "sha1": "a284af9757cb24d28f96ec88ec1b1c23a8cea9fe"
336
+ },
337
+ {
338
+ "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000024.jpg",
339
+ "source": "derivative",
340
+ "format": "Thumbnail",
341
+ "original": "frankerberry_countchockula_1971.0001.mpg",
342
+ "mtime": "1296336959",
343
+ "size": "3383",
344
+ "md5": "be2a908acd563b896e7758b598295148",
345
+ "crc32": "ed467831",
346
+ "sha1": "94c001e72ebc86d837a78c61a004db9ab9d597bd"
347
+ },
348
+ {
349
+ "name": "FrankenberryCountChoculaTevevisionCommercial1971.thumbs/frankerberry_countchockula_1971.0001_000029.jpg",
350
+ "source": "derivative",
351
+ "format": "Thumbnail",
352
+ "original": "frankerberry_countchockula_1971.0001.mpg",
353
+ "mtime": "1296336960",
354
+ "size": "3503",
355
+ "md5": "c82199d09be07633000fd07b363dd8a3",
356
+ "crc32": "a1fd79cb",
357
+ "sha1": "2bc8e761edb24a441fa5906dda1c424e1f98a47a"
358
+ },
359
+ {
360
+ "name": "FrankenberryCountChoculaTevevisionCommercial1971_archive.torrent",
361
+ "source": "metadata",
362
+ "btih": "de6b371e7cc3c83db1cc08150500753eae533409",
363
+ "mtime": "1542761794",
364
+ "size": "4093",
365
+ "md5": "a275d3b4028cccb5bea8b47a88c838af",
366
+ "crc32": "5ffa7334",
367
+ "sha1": "af8222637b574cba1360d0ea77e231640ffd43c4",
368
+ "format": "Archive BitTorrent"
369
+ },
370
+ {
371
+ "name": "FrankenberryCountChoculaTevevisionCommercial1971_files.xml",
372
+ "source": "metadata",
373
+ "format": "Metadata",
374
+ "md5": "3a7e87b08bed1e203a5858b31352c110"
375
+ },
376
+ {
377
+ "name": "FrankenberryCountChoculaTevevisionCommercial1971_meta.xml",
378
+ "source": "metadata",
379
+ "format": "Metadata",
380
+ "mtime": "1542761793",
381
+ "size": "1371",
382
+ "md5": "0b9c9bf21b9a26aea43a2f735b404624",
383
+ "crc32": "41077288",
384
+ "sha1": "22e6f2c73bf63072f671d846355da2785db51dbd"
385
+ },
386
+ {
387
+ "name": "FrankenberryCountChoculaTevevisionCommercial1971_reviews.xml",
388
+ "source": "original",
389
+ "mtime": "1466898697",
390
+ "size": "620",
391
+ "md5": "260bfba5d696772445dcc7ff6e6d5bdb",
392
+ "crc32": "25ea3229",
393
+ "sha1": "7d541f18fcd5ad9c6e593afe5a80f18771f23b32",
394
+ "format": "Metadata"
395
+ },
396
+ {
397
+ "name": "__ia_thumb.jpg",
398
+ "source": "original",
399
+ "mtime": "1539115881",
400
+ "size": "7481",
401
+ "md5": "8cec324fa0016fd77cc04e6a4b2ebb00",
402
+ "crc32": "d9e1b316",
403
+ "sha1": "4dab42952fe0405a3b7f80146636b33d7b1bd01e",
404
+ "format": "Item Tile",
405
+ "rotation": "0"
406
+ },
407
+ {
408
+ "name": "frankerberry_countchockula_1971.0001.gif",
409
+ "source": "derivative",
410
+ "format": "Animated GIF",
411
+ "original": "frankerberry_countchockula_1971.0001.mpg",
412
+ "mtime": "1296336965",
413
+ "size": "101114",
414
+ "md5": "b78a13094030f104900eb996bafe2b7d",
415
+ "crc32": "6650cd8",
416
+ "sha1": "669798c037205cac14f70592deef6f7831b3d4a1"
417
+ },
418
+ {
419
+ "name": "frankerberry_countchockula_1971.0001.mpg",
420
+ "source": "original",
421
+ "format": "MPEG2",
422
+ "mtime": "1296335803",
423
+ "size": "31625216",
424
+ "md5": "762ba18b026b85b3f074523e7fcb4db0",
425
+ "crc32": "42347f78",
426
+ "sha1": "41162dc2d1a91b618124c84628d0c231544a02be",
427
+ "length": "31.14",
428
+ "height": "480",
429
+ "width": "640"
430
+ },
431
+ {
432
+ "name": "frankerberry_countchockula_1971.0001.mpg.idx",
433
+ "source": "derivative",
434
+ "format": "Video Index",
435
+ "original": "frankerberry_countchockula_1971.0001.mpg",
436
+ "mtime": "1296336956",
437
+ "size": "31141",
438
+ "md5": "49423e072726e4ea3cdd8ebdd26c7dfc",
439
+ "crc32": "ae969a68",
440
+ "sha1": "805782cd2d0f9002555816daadf3b8607e621f79"
441
+ },
442
+ {
443
+ "name": "frankerberry_countchockula_1971.0001.ogv",
444
+ "source": "derivative",
445
+ "format": "Ogg Video",
446
+ "original": "frankerberry_countchockula_1971.0001.mpg",
447
+ "mtime": "1296336994",
448
+ "size": "2248166",
449
+ "md5": "f1b933e97ce63594fb28a0a019ff3436",
450
+ "crc32": "a2a0e5e9",
451
+ "sha1": "a6bf0aec9f006baeca37c03f586686ebe685d59b",
452
+ "length": "31.15",
453
+ "height": "300",
454
+ "width": "400"
455
+ },
456
+ {
457
+ "name": "frankerberry_countchockula_1971.0001_512kb.mp4",
458
+ "source": "derivative",
459
+ "format": "512Kb MPEG4",
460
+ "original": "frankerberry_countchockula_1971.0001.mpg",
461
+ "mtime": "1296336977",
462
+ "size": "2378677",
463
+ "md5": "a7750839519c61ba3bb99fc66b32011d",
464
+ "crc32": "4dbd37c8",
465
+ "sha1": "3929314c192dec006fac2739bcb4730788e8c068",
466
+ "length": "31.13",
467
+ "height": "240",
468
+ "width": "320"
469
+ }
470
+ ],
471
+ "files_count": 17,
472
+ "item_last_updated": 1542761794,
473
+ "item_size": 36431778,
474
+ "metadata": {
475
+ "identifier": "FrankenberryCountChoculaTevevisionCommercial1971",
476
+ "title": "Franken Berry / Count Chocula : Tevevision Commercial 1971",
477
+ "creator": "General Mills",
478
+ "mediatype": "movies",
479
+ "collection": [
480
+ "classic_tv_commercials",
481
+ "television"
482
+ ],
483
+ "description": "Count Chocula and Franken Berry were both introduced in 1971. Boo Berry Cereal appeared in 1973 followed by Fruit Brute in 1974. Yummy Mummy appeared more than a decade later in 1988 - completing the the group known as the General Mills Monster Cereals.",
484
+ "subject": "Third Eye Cinema; Classic Television Commercials; animation; cartoons;General Mills",
485
+ "licenseurl": "http://creativecommons.org/publicdomain/mark/1.0/",
486
+ "publicdate": "2011-01-29 21:36:42",
487
+ "addeddate": "2011-01-29 21:35:38",
488
+ "uploader": "bolexman@msn.com",
489
+ "updater": [
490
+ "Bolexman",
491
+ "Bolexman",
492
+ "Jeff Kaplan"
493
+ ],
494
+ "updatedate": [
495
+ "2011-01-29 21:45:38",
496
+ "2011-01-29 21:55:46",
497
+ "2011-01-29 23:04:55"
498
+ ],
499
+ "sound": "sound",
500
+ "color": "color",
501
+ "runtime": "0:31",
502
+ "backup_location": "ia903608_22",
503
+ "ia_orig__runtime": "31 seconds"
504
+ },
505
+ "reviews": [
506
+ {
507
+ "reviewbody": "Sugar cereal cartoon Karloff and Lugosi argue self-importance pre Lorre ghost. Interesting how kids still know the voices without any idea of the origins.",
508
+ "reviewtitle": "pre booberry",
509
+ "reviewer": "outofthebox",
510
+ "reviewdate": "2016-06-25 23:51:36",
511
+ "createdate": "2016-06-25 23:51:36",
512
+ "stars": "4"
513
+ }
514
+ ],
515
+ "server": "ia800202.us.archive.org",
516
+ "uniq": 1957612749,
517
+ "workable_servers": [
518
+ "ia800202.us.archive.org",
519
+ "ia600202.us.archive.org"
520
+ ]
516
521
  }
517
522
  ```
518
523
 
@@ -522,51 +527,51 @@ With just a small number of element descriptors, we can make this huge blob of J
522
527
 
523
528
  ```JSON
524
529
  {
525
- "Scope": "Archive.org",
526
- "Descriptors": {
527
- "d1": {
528
- "Hash": "Server",
529
- "Name": "Server",
530
- "Description": "The primary server to download these files from.",
531
- "DataType": "String"
532
- },
533
- "d2": {
534
- "Hash": "ServerAlternate",
535
- "Name": "Alternate Server",
536
- "Description": "The alternate server to download these files from.",
537
- "DataType": "String"
538
- },
539
- "dir": {
540
- "Hash": "Path",
541
- "Name": "Server URL Path",
542
- "NameShort": "Path",
543
- "Description": "The path on the server where these files are located."
544
- },
545
- "metadata.identifier": {
546
- "Hash": "GUID",
547
- "Name": "Globally Unique Identifier",
548
- "NameShort": "GUID",
549
- "Description": "Archive.org unique identifier string."
550
- },
551
- "metadata.title": {
552
- "Hash": "Title",
553
- "Name": "Title",
554
- "NameShort": "Title",
555
- "Description": "The title of the media item."
556
- },
557
- "metadata.creator": {
558
- "Hash": "Creator",
559
- "Name": "Creator",
560
- "NameShort": "Creator",
561
- "Description": "The creator of the media item."
562
- },
563
- "metadata.mediatype": {
564
- "Hash": "Type",
565
- "Name": "Media Type",
566
- "NameShort": "Type",
567
- "Description": "The type of media item."
568
- }
569
- }
530
+ "Scope": "Archive.org",
531
+ "Descriptors": {
532
+ "d1": {
533
+ "Hash": "Server",
534
+ "Name": "Server",
535
+ "Description": "The primary server to download these files from.",
536
+ "DataType": "String"
537
+ },
538
+ "d2": {
539
+ "Hash": "ServerAlternate",
540
+ "Name": "Alternate Server",
541
+ "Description": "The alternate server to download these files from.",
542
+ "DataType": "String"
543
+ },
544
+ "dir": {
545
+ "Hash": "Path",
546
+ "Name": "Server URL Path",
547
+ "NameShort": "Path",
548
+ "Description": "The path on the server where these files are located."
549
+ },
550
+ "metadata.identifier": {
551
+ "Hash": "GUID",
552
+ "Name": "Globally Unique Identifier",
553
+ "NameShort": "GUID",
554
+ "Description": "Archive.org unique identifier string."
555
+ },
556
+ "metadata.title": {
557
+ "Hash": "Title",
558
+ "Name": "Title",
559
+ "NameShort": "Title",
560
+ "Description": "The title of the media item."
561
+ },
562
+ "metadata.creator": {
563
+ "Hash": "Creator",
564
+ "Name": "Creator",
565
+ "NameShort": "Creator",
566
+ "Description": "The creator of the media item."
567
+ },
568
+ "metadata.mediatype": {
569
+ "Hash": "Type",
570
+ "Name": "Media Type",
571
+ "NameShort": "Type",
572
+ "Description": "The type of media item."
573
+ }
574
+ }
570
575
  }
571
576
  ```
572
577
 
@@ -582,6 +587,102 @@ let _Schema = new libManyfest(schemaArchiveOrg);
582
587
 
583
588
  console.log(`The URL for "${_Schema.getValueByHash(dataArchiveOrg,'Title')}" is: ${_Schema.getValueByHash(dataArchiveOrg,'Server')}${_Schema.getValueByHash(dataArchiveOrg,'Path')}`);
584
589
  ```
585
- # Architectural TODO:
586
590
 
587
- Change the complex address resolution functions to leverage a single resolver that returns both `container` and `entry`.
591
+ ### A Manyfest Schema for Book records
592
+
593
+ This shows a book record with an Author Key as well.
594
+
595
+ ```JSON
596
+ {
597
+ "Scope": "Book",
598
+ "Descriptors": {
599
+ "GUIDBook": {
600
+ "Hash": "GUIDBook",
601
+ "Name": "Book GUID",
602
+ "DataType": "Key",
603
+ "KeyRepresentation": "GUID",
604
+ "GUIDAddress": "GUIDBook",
605
+ "IDAddress": "IDBook"
606
+ },
607
+ "IDBook": {
608
+ "Hash": "IDBook",
609
+ "Name": "Book Identifier",
610
+ "DataType": "Key",
611
+ "KeyRepresentation": "ID",
612
+ "GUIDAddress": "GUIDBook",
613
+ "IDAddress": "IDBook"
614
+ },
615
+ "Title": {
616
+ "Hash": "Title",
617
+ "Name": "Book Title",
618
+ "DataType": "String"
619
+ },
620
+ "IDAuthor": {
621
+ "Hash": "Book_IDAuthor",
622
+ "Name": "Book Primary Author",
623
+ "DataType": "Key",
624
+ "KeyRepresentation": "ID",
625
+ "GUIDAddress": "GUIDAuthor",
626
+ "IDAddress": "IDAuthor"
627
+ },
628
+ }
629
+ }
630
+ ```
631
+
632
+ Because we expect only one scope to be the controlling scope for a particular key pair, we can use the key pair presence as a mechnism for resolution of IDs to GUIDs when they aren't natural.
633
+
634
+ What does this mean in practice?
635
+
636
+ If we have the following Book record:
637
+
638
+ ```JSON
639
+ {
640
+ "GUIDBook": "SCIFI-000-Dune",
641
+ "Title": "Dune",
642
+ "GUIDAuthor": "AUTHOR-FRANK-HERBERT"
643
+ }
644
+ ```
645
+
646
+ And the following Author record:
647
+
648
+ ```JSON
649
+ {
650
+ "GUIDAuthor": "AUTHOR-FRANK-HERBERT",
651
+ "IDAuthor": 1001,
652
+ "Name": "Frank Herbert"
653
+ }
654
+ ```
655
+
656
+
657
+ #### This gives rise to the need for a "Key" data type which is a tuple
658
+
659
+ The tuple will be a GUID or ID, but will represent both. As long as only one entity in the controlling scope (the Book table for instance) to have *both* the ID and the GUID, this can be used to make that the source of record for the Key. This allows lookups back and forth between GUID and ID.
660
+
661
+ 1. Author is the cannonical source for finding the GUIDAuthor->IDAuthor connection, and vice versa. Because it is the only record shape in the model space that contains both.
662
+ 2. GUIDAuthor is not in the Descriptors as a secondary address, but IDAuthor is. GUIDAuthor is, though, resolvable from the IDAuthor GUIDAddress property.
663
+ 3. This means we want to treat the "GUIDAuthor"/"IDAuthor" pairing as a single entry in a manyfest, which is a departure from how the rest of them operate.
664
+
665
+ ## BELOW WILL BE IN Pict
666
+
667
+ ## Record "Sieve"s
668
+
669
+ Sometimes we want to take a record from a source shape, and translate it into a destination shape. This can be done with an implicit sieve or an explicit sieve.
670
+
671
+ ### Handy Assertions for Working with a Sieve
672
+
673
+ * A record is a single object without loops.
674
+ * A record is part of a RecordSet.
675
+ * A record has an RecordSet key (e.g. "Users", "Projects", "Books", etc.).
676
+ * A record may have an Entity key (e.g. "Users", "Projects", "Books", etc.).
677
+ * The difference between RecordSet and Entity is that an Entity is a Record associated with a Key is expected to be stored in an Entity Storage System of some kind whereas a RecordSet Record might be abstract.
678
+ * A Record has a Key which represents a GUID and Identifier.
679
+ * GUIDs are RecordSet scoped strings that are unique to a Record.
680
+ * Identifiers are RecordSet Storage scoped strings or numbers that are unique to a Record.
681
+ * There is only one cannonical provider of each Record Entity
682
+ * When creating a sieve instance, we are going to migrate sets of records from one schema to another.
683
+
684
+ ### Implicit Sieve
685
+
686
+ An implicit sieve embeds the configuration for Projection(s) within the current recordset. There is a Projection array, each of which has an entry for basic record projections. This should be good enough for simple transformation operations.
687
+
688
+ Each of these Projections come as a simple record shape with templated expressions.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "manyfest",
3
- "version": "1.0.37",
3
+ "version": "1.0.39",
4
4
  "description": "JSON Object Manifest for Data Description and Parsing",
5
5
  "main": "source/Manyfest.js",
6
6
  "scripts": {
@@ -44,10 +44,10 @@
44
44
  ]
45
45
  },
46
46
  "dependencies": {
47
- "fable-serviceproviderbase": "^3.0.13"
47
+ "fable-serviceproviderbase": "^3.0.15"
48
48
  },
49
49
  "devDependencies": {
50
- "quackage": "^1.0.30"
50
+ "quackage": "^1.0.41"
51
51
  },
52
52
  "author": "steven velozo <steven@velozo.com>",
53
53
  "license": "MIT",
@@ -47,9 +47,19 @@ class ManyfestObjectAddressResolverGetValue
47
47
  getValueAtAddress (pObject, pAddress, pParentAddress, pRootObject)
48
48
  {
49
49
  // Make sure pObject (the object we are meant to be recursing) is an object (which could be an array or object)
50
- if (typeof(pObject) != 'object') return undefined;
50
+ if (typeof(pObject) != 'object')
51
+ {
52
+ return undefined;
53
+ }
54
+ if (pObject === null)
55
+ {
56
+ return undefined;
57
+ }
51
58
  // Make sure pAddress (the address we are resolving) is a string
52
- if (typeof(pAddress) != 'string') return undefined;
59
+ if (typeof(pAddress) != 'string')
60
+ {
61
+ return undefined;
62
+ }
53
63
  // Stash the parent address for later resolution
54
64
  let tmpParentAddress = "";
55
65
  if (typeof(pParentAddress) == 'string')
@@ -335,7 +345,7 @@ class ManyfestObjectAddressResolverGetValue
335
345
  }
336
346
  else
337
347
  {
338
- return undefined;
348
+ return null;
339
349
  }
340
350
  }
341
351
  }
@@ -98,12 +98,24 @@ class ManyfestObjectAddressSetValue
98
98
  tmpBoxedPropertyReference = this.cleanWrapCharacters('`', tmpBoxedPropertyReference);
99
99
  tmpBoxedPropertyReference = this.cleanWrapCharacters("'", tmpBoxedPropertyReference);
100
100
 
101
+ if (!(tmpBoxedPropertyReference in pObject[tmpBoxedPropertyName]))
102
+ {
103
+ // If the subobject doesn't exist, create it
104
+ pObject[tmpBoxedPropertyName][tmpBoxedPropertyReference] = {};
105
+ }
106
+
101
107
  // Return the value in the property
102
108
  pObject[tmpBoxedPropertyName][tmpBoxedPropertyReference] = pValue;
103
109
  return true;
104
110
  }
105
111
  else
106
112
  {
113
+ while(pObject[tmpBoxedPropertyName].length < (tmpBoxedPropertyNumber + 1))
114
+ {
115
+ // If the subobject doesn't exist, create it
116
+ pObject[tmpBoxedPropertyName].push({});
117
+ }
118
+
107
119
  pObject[tmpBoxedPropertyName][tmpBoxedPropertyNumber] = pValue;
108
120
  return true;
109
121
  }
@@ -174,11 +186,23 @@ class ManyfestObjectAddressSetValue
174
186
  tmpBoxedPropertyReference = this.cleanWrapCharacters('`', tmpBoxedPropertyReference);
175
187
  tmpBoxedPropertyReference = this.cleanWrapCharacters("'", tmpBoxedPropertyReference);
176
188
 
189
+ if (!(tmpBoxedPropertyReference in pObject[tmpBoxedPropertyName]))
190
+ {
191
+ // If the subobject doesn't exist, create it
192
+ pObject[tmpBoxedPropertyName][tmpBoxedPropertyReference] = {};
193
+ }
194
+
177
195
  // Recurse directly into the subobject
178
196
  return this.setValueAtAddress(pObject[tmpBoxedPropertyName][tmpBoxedPropertyReference], tmpNewAddress, pValue);
179
197
  }
180
198
  else
181
199
  {
200
+ while(pObject[tmpBoxedPropertyName].length < (tmpBoxedPropertyNumber + 1))
201
+ {
202
+ // If the subobject doesn't exist, create it
203
+ pObject[tmpBoxedPropertyName].push({});
204
+ }
205
+
182
206
  // We parsed a valid number out of the boxed property name, so recurse into the array
183
207
  return this.setValueAtAddress(pObject[tmpBoxedPropertyName][tmpBoxedPropertyNumber], tmpNewAddress, pValue);
184
208
  }
@@ -227,6 +227,12 @@
227
227
  "color": "color",
228
228
  "runtime": "0:31",
229
229
  "backup_location": "ia903608_22",
230
+ "synthesizer": {
231
+ "name": "Manyfest",
232
+ "version": "1.0.38",
233
+ "description": "JSON Object Manifest for Data Description and Parsing",
234
+ "author": "The chocula himself"
235
+ },
230
236
  "ia_orig__runtime": "31 seconds"
231
237
  },
232
238
  "reviews": [
@@ -43,6 +43,27 @@ suite
43
43
  }
44
44
  );
45
45
  test
46
+ (
47
+ 'Javascript null values should not cause errors..',
48
+ (fTestComplete)=>
49
+ {
50
+ let _Manyfest = new libManyfest({ Scope:'Archive.org', Descriptors: {'metadata.creator': {Name:'Creator', Hash:'Creator'}}});
51
+ let tmpNullSampleData = JSON.parse(JSON.stringify(_SampleDataArchiveOrgFrankenberry));
52
+ tmpNullSampleData.Noel = null;
53
+ let tmpNullValue = _Manyfest.getValueAtAddress(tmpNullSampleData, 'Noel');
54
+ let tmpNullValueOneDeep = _Manyfest.getValueAtAddress(tmpNullSampleData, 'Noel.SomeChildValue');
55
+ let tmpNullValueTwoDeep = _Manyfest.getValueAtAddress(tmpNullSampleData, 'Noel.SomeChildValue.SecondTier');
56
+ let tmpNullValueTwoDeepObject = _Manyfest.getValueAtAddress(tmpNullSampleData, 'Noel.SomeChildValue[SecondTier]');
57
+ let tmpNullValueTwoDeepArray = _Manyfest.getValueAtAddress(tmpNullSampleData, 'Noel.SomeChildValue.SecondTier[0]');
58
+ Expect(tmpNullValue).to.equal(null);
59
+ Expect(tmpNullValueOneDeep).to.equal(undefined);
60
+ Expect(tmpNullValueTwoDeep).to.equal(undefined);
61
+ Expect(tmpNullValueTwoDeepObject).to.equal(undefined);
62
+ Expect(tmpNullValueTwoDeepArray).to.equal(undefined);
63
+ fTestComplete();
64
+ }
65
+ );
66
+ test
46
67
  (
47
68
  'It should be trivial to access subproperties with a schema by hash.',
48
69
  (fTestComplete)=>
@@ -117,6 +138,12 @@ suite
117
138
  // The .. means go back one level
118
139
  let tmpDir = _Manyfest.getValueAtAddress(_SampleDataArchiveOrgFrankenberry, 'files[0]..dir');
119
140
  Expect(tmpDir).to.equal("/7/items/FrankenberryCountChoculaTevevisionCommercial1971");
141
+ // Test a middle of address boxed object property
142
+ let tmpEmbeddedObjectBracket = _Manyfest.getValueAtAddress(_SampleDataArchiveOrgFrankenberry, 'metadata["synthesizer"].author');
143
+ Expect(tmpEmbeddedObjectBracket).to.equal('The chocula himself');
144
+ // Test a middle of address boxed object property where the boxed object is missing
145
+ let tmpEmbeddedObjectBracketMissingMidTierObject = _Manyfest.getValueAtAddress(_SampleDataArchiveOrgFrankenberry, 'metadata["chef"].author');
146
+ Expect(tmpEmbeddedObjectBracketMissingMidTierObject).to.be.undefined;
120
147
  fTestComplete();
121
148
  }
122
149
  );
@@ -131,7 +131,10 @@ suite
131
131
  (fTestComplete)=>
132
132
  {
133
133
  let _Manyfest = new libManyfest();
134
- let _Object = {Dogs:{RunnerUp:{Name:'Fido',Speed:100},Loser:{Name:'Spot'},Winner:{Name:'Trinity'}}};
134
+ let _Object = {RaceHeats: [
135
+ {HeatNumber:1, Dogs:{RunnerUp:'Fido',Loser:'Spot',Winner:'Trinity'}},
136
+ {HeatNumber:2, Dogs:{RunnerUp:'Rex',Loser:'Max',Winner:'Buddy'}}
137
+ ], Dogs:{RunnerUp:{Name:'Fido',Speed:100},Loser:{Name:'Spot'},Winner:{Name:'Trinity'}}};
135
138
  _Manyfest.setValueAtAddress(_Object, 'Dogs[`RunnerUp`].Speed', 300);
136
139
  Expect(_Object.Dogs.RunnerUp.Speed)
137
140
  .to.equal(300);
@@ -139,6 +142,13 @@ suite
139
142
  _Manyfest.setValueAtAddress(_Object, 'Dogs[`Loser`].Speed', 10);
140
143
  Expect(_Object.Dogs.Loser.Speed)
141
144
  .to.equal(10);
145
+ // Set a value for an address and boxed object property that doesn't exist.
146
+ _Manyfest.setValueAtAddress(_Object, 'Dogs[`CriterionCollection`].MovieRating', 10000);
147
+ Expect(_Object.Dogs.CriterionCollection.MovieRating)
148
+ .to.equal(10000);
149
+ _Manyfest.setValueAtAddress(_Object, 'RaceHeats[2].HeatNumber', 10001);
150
+ Expect(_Object.RaceHeats[2].HeatNumber)
151
+ .to.equal(10001);
142
152
  fTestComplete();
143
153
  }
144
154
  );