json-rest-api 1.0.24 → 1.0.26

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.
Files changed (84) hide show
  1. package/README.md +2 -1
  2. package/docs/API.md +12 -9
  3. package/docs/GUIDE/GUIDE_1_Initial_Setup.md +5 -2
  4. package/docs/GUIDE/GUIDE_2_1_The_Starting_Point.md +3 -3
  5. package/docs/GUIDE/GUIDE_3_Field_Transformations.md +2 -0
  6. package/docs/GUIDE/GUIDE_7_Hooks_Data_Management_And_Plugins.md +1 -1
  7. package/docs/GUIDE/GUIDE_X_Autofiltering.md +63 -0
  8. package/docs/GUIDE/GUIDE_X_File_Uploads.md +17 -12
  9. package/docs/GUIDE/GUIDE_X_Row_Policies.md +605 -0
  10. package/docs/GUIDE/GUIDE_X_SocketIO.md +15 -10
  11. package/docs/GUIDE/GUIDE_X_URL_Management.md +93 -254
  12. package/docs/GUIDE/GUIDE_X_Writing_Plugins.md +2 -0
  13. package/docs/GUIDE/index.md +4 -1
  14. package/fixing_plan.md +112 -0
  15. package/index.js +2 -0
  16. package/package.json +1 -1
  17. package/plugins/core/bulk-operations-plugin.js +5 -4
  18. package/plugins/core/connectors/express-plugin.js +6 -1
  19. package/plugins/core/connectors/fastify-plugin.js +5 -1
  20. package/plugins/core/connectors/lib/connector-core.js +17 -11
  21. package/plugins/core/connectors/lib/transport-route-schemas.js +12 -60
  22. package/plugins/core/file-handling-plugin.js +126 -96
  23. package/plugins/core/lib/anyapi/anyapi-registry.js +21 -3
  24. package/plugins/core/lib/anyapi/query/anyapi-query-adapter.js +36 -26
  25. package/plugins/core/lib/anyapi/schema-utils.js +1 -0
  26. package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +7 -1
  27. package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +20 -15
  28. package/plugins/core/lib/querying/knex-pagination-helpers.js +38 -84
  29. package/plugins/core/lib/querying/knex-relationship-includes.js +29 -28
  30. package/plugins/core/lib/querying/knex-window-queries.js +10 -77
  31. package/plugins/core/lib/querying/storage-adapter-utils.js +8 -8
  32. package/plugins/core/lib/querying/url-helpers.js +9 -21
  33. package/plugins/core/lib/querying-writing/connectors-query-parser.js +51 -0
  34. package/plugins/core/lib/querying-writing/database-capabilities.js +1 -1
  35. package/plugins/core/lib/querying-writing/database-value-normalizers.js +18 -9
  36. package/plugins/core/lib/querying-writing/knex-field-helpers.js +6 -1
  37. package/plugins/core/lib/querying-writing/relationship-contracts.js +56 -0
  38. package/plugins/core/lib/querying-writing/request-contracts.js +53 -4
  39. package/plugins/core/lib/querying-writing/return-record-settings.js +47 -0
  40. package/plugins/core/lib/querying-writing/schema-helpers.js +34 -41
  41. package/plugins/core/lib/storage/canonical-storage-mapping.js +2 -1
  42. package/plugins/core/lib/storage/storage-adapter.js +74 -13
  43. package/plugins/core/lib/writing/many-to-many-manipulations.js +4 -3
  44. package/plugins/core/lib/writing/relationship-processor.js +10 -1
  45. package/plugins/core/rest-api-anyapi-knex-plugin.js +210 -97
  46. package/plugins/core/rest-api-knex-plugin.js +70 -60
  47. package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +8 -2
  48. package/plugins/core/rest-api-plugin-methods/common.js +85 -63
  49. package/plugins/core/rest-api-plugin-methods/delete-relationship.js +23 -13
  50. package/plugins/core/rest-api-plugin-methods/delete.js +2 -6
  51. package/plugins/core/rest-api-plugin-methods/get-related.js +15 -13
  52. package/plugins/core/rest-api-plugin-methods/get-relationship.js +1 -1
  53. package/plugins/core/rest-api-plugin-methods/patch-relationship.js +17 -6
  54. package/plugins/core/rest-api-plugin-methods/patch.js +3 -6
  55. package/plugins/core/rest-api-plugin-methods/post-relationship.js +24 -14
  56. package/plugins/core/rest-api-plugin-methods/post.js +4 -7
  57. package/plugins/core/rest-api-plugin-methods/put.js +4 -7
  58. package/plugins/core/rest-api-plugin.js +6 -36
  59. package/plugins/core/rest-api-row-policy-plugin.js +157 -0
  60. package/plugins/storage/local-storage.js +44 -19
  61. package/plugins/storage/s3-storage.js +21 -55
  62. package/tests/README.md +1 -1
  63. package/tests/anyapi-cursor-pagination.test.js +7 -1
  64. package/tests/anyapi-custom-idproperty.test.js +163 -0
  65. package/tests/fastify-plugin.test.js +28 -0
  66. package/tests/field-setters.test.js +10 -10
  67. package/tests/file-handling.test.js +118 -0
  68. package/tests/fixtures/api-configs.js +383 -4
  69. package/tests/full-jsonapi-belongsto-linkage.test.js +150 -0
  70. package/tests/http-connectors-parity.test.js +165 -5
  71. package/tests/local-storage.test.js +96 -0
  72. package/tests/pagination-cursor-multifield.test.js +121 -0
  73. package/tests/pagination-enhanced.test.js +66 -15
  74. package/tests/post-commit-hooks.test.js +120 -0
  75. package/tests/public-exports.test.js +15 -0
  76. package/tests/put-create-parity.test.js +216 -0
  77. package/tests/relationship-endpoints.test.js +259 -0
  78. package/tests/return-record-settings.test.js +184 -0
  79. package/tests/row-policy.test.js +489 -0
  80. package/tests/s3-storage.test.js +38 -0
  81. package/tests/searchschema-merge.test.js +17 -0
  82. package/tests/socketio.test.js +62 -0
  83. package/tests/storage-mapping.test.js +1 -0
  84. package/tests/test-development-guide.md +5 -5
@@ -5,6 +5,7 @@ import {
5
5
  cleanTables,
6
6
  } from './helpers/test-utils.js'
7
7
  import { createSearchSchemaMergeApi } from './fixtures/api-configs.js'
8
+ import { generateSearchSchemaFromSchema } from '../plugins/core/lib/querying-writing/schema-helpers.js'
8
9
 
9
10
  // Create Knex instance for tests - always use SQLite in-memory
10
11
  const knex = knexLib({
@@ -131,4 +132,20 @@ describe('SearchSchema Merge Behavior', () => {
131
132
  'Should reject fields that are not defined in searchSchema'
132
133
  )
133
134
  })
135
+
136
+ it('should keep canonical belongsTo field keys searchable alongside relationship aliases', () => {
137
+ const searchSchema = generateSearchSchemaFromSchema({
138
+ petId: {
139
+ type: 'id',
140
+ belongsTo: 'pets',
141
+ as: 'pet',
142
+ search: true
143
+ }
144
+ }, null)
145
+
146
+ assert.ok(searchSchema.pet, 'relationship alias should stay searchable')
147
+ assert.equal(searchSchema.pet.actualField, 'petId')
148
+ assert.ok(searchSchema.petId, 'canonical field key should stay searchable for parent filters')
149
+ assert.equal(searchSchema.petId.actualField, 'petId')
150
+ })
134
151
  })
@@ -453,6 +453,68 @@ describe('WebSocket/Socket.IO Plugin', () => {
453
453
  socket.close()
454
454
  }
455
455
  })
456
+
457
+ it('should broadcast deferred patch notifications from relationship PATCH', async () => {
458
+ const token = await createToken({ userId: 'test-user', role: 'user' }, 'test-secret-key')
459
+
460
+ const socket = ioClient(`http://localhost:${server.address().port}`, {
461
+ path: '/api/socket.io',
462
+ auth: { token }
463
+ })
464
+
465
+ try {
466
+ await new Promise((resolve, reject) => {
467
+ socket.on('connect', resolve)
468
+ socket.on('connect_error', reject)
469
+ setTimeout(() => reject(new Error('Connection timeout')), 5000)
470
+ })
471
+
472
+ const country = await api.resources.countries.post({
473
+ inputRecord: createJsonApiDocument('countries', {
474
+ name: 'Original Country',
475
+ code: 'OC'
476
+ }),
477
+ simplified: false
478
+ })
479
+
480
+ const nextCountry = await api.resources.countries.post({
481
+ inputRecord: createJsonApiDocument('countries', {
482
+ name: 'Next Country',
483
+ code: 'NC'
484
+ }),
485
+ simplified: false
486
+ })
487
+
488
+ const book = await api.resources.books.post({
489
+ inputRecord: createJsonApiDocument(
490
+ 'books',
491
+ { title: 'Relationship Patch Broadcast' },
492
+ { country: createRelationship(resourceIdentifier('countries', country.data.id)) }
493
+ ),
494
+ simplified: false
495
+ })
496
+
497
+ await new Promise((resolve) => {
498
+ socket.emit('subscribe', { resource: 'books' }, resolve)
499
+ })
500
+
501
+ const updatePromise = waitForSocketEvent(socket, 'subscription.update', 1000)
502
+
503
+ await api.resources.books.patchRelationship({
504
+ id: book.data.id,
505
+ relationshipName: 'country',
506
+ relationshipData: resourceIdentifier('countries', nextCountry.data.id)
507
+ })
508
+
509
+ const notification = await updatePromise
510
+ assert.equal(notification.type, 'resource.patchd')
511
+ assert.equal(notification.resource, 'books')
512
+ assert.equal(String(notification.id), String(book.data.id))
513
+ assert.equal(notification.action, 'patch')
514
+ } finally {
515
+ socket.close()
516
+ }
517
+ })
456
518
  })
457
519
 
458
520
  describe('Multiple Subscriptions', () => {
@@ -42,6 +42,7 @@ describe('Storage mapping', () => {
42
42
  await api.use(RestApiPlugin, {
43
43
  simplifiedApi: false,
44
44
  simplifiedTransport: false,
45
+ sortableFields: ['id', 'displayName', 'loginCount', 'lastSeenAt', 'countryId', 'externalRef'],
45
46
  returnRecordApi: {
46
47
  post: 'full',
47
48
  put: 'full',
@@ -64,9 +64,9 @@ Control what methods return:
64
64
  ```javascript
65
65
  // In API configuration
66
66
  returnFullRecord: {
67
- post: true, // Return created record (needed to get ID)
68
- put: false, // Don't return after replacement
69
- patch: false // Don't return after update
67
+ post: 'full', // Return created record (needed to get ID)
68
+ put: 'no', // Don't return after replacement
69
+ patch: 'no' // Don't return after update
70
70
  }
71
71
 
72
72
  // Override per call if needed
@@ -74,7 +74,7 @@ const result = await api.resources.books.put({
74
74
  id: bookId,
75
75
  inputRecord: putDoc,
76
76
  simplified: false,
77
- returnFullRecord: false // Override to not return
77
+ returnFullRecord: 'no' // Override to not return
78
78
  });
79
79
  ```
80
80
 
@@ -367,4 +367,4 @@ npm test -- tests/relationships.test.js
367
367
  4. **validation.test.js** - Schema validation edge cases
368
368
  5. **polymorphic.test.js** - Polymorphic relationship tests
369
369
 
370
- Each should follow the patterns established in existing tests.
370
+ Each should follow the patterns established in existing tests.