json-rest-api 1.0.14 → 1.0.16

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 (118) hide show
  1. package/connectors_ideas/fastify.js +66 -68
  2. package/connectors_ideas/koa-plugin.js +50 -51
  3. package/eslint.config.js +11 -2
  4. package/examples/url-override-example.js +63 -63
  5. package/index.js +13 -13
  6. package/lib/enhanced-logger.js +51 -51
  7. package/lib/error-formatter.js +61 -61
  8. package/lib/rest-api-errors.js +28 -28
  9. package/package.json +1 -1
  10. package/plugins/core/bulk-operations-plugin.js +142 -145
  11. package/plugins/core/connectors/express-plugin.js +210 -217
  12. package/plugins/core/connectors/lib/busboy-detector.js +84 -84
  13. package/plugins/core/connectors/lib/formidable-detector.js +50 -50
  14. package/plugins/core/connectors/lib/request-helpers.js +74 -74
  15. package/plugins/core/file-handling-plugin.js +125 -125
  16. package/plugins/core/lib/anyapi/anyapi-registry.js +254 -254
  17. package/plugins/core/lib/anyapi/query/anyapi-query-adapter.js +287 -287
  18. package/plugins/core/lib/anyapi/schema-utils.js +101 -101
  19. package/plugins/core/lib/anyapi/utils/descriptor-helpers.js +41 -41
  20. package/plugins/core/lib/dbTablesOperations.js +134 -135
  21. package/plugins/core/lib/fractional-positioning.js +74 -76
  22. package/plugins/core/lib/querying/knex-cross-table-search.js +320 -320
  23. package/plugins/core/lib/querying/knex-json-api-transformers-querying.js +144 -144
  24. package/plugins/core/lib/querying/knex-pagination-helpers.js +164 -164
  25. package/plugins/core/lib/querying/knex-process-includes.js +50 -50
  26. package/plugins/core/lib/querying/knex-query-helpers-base.js +31 -31
  27. package/plugins/core/lib/querying/knex-query-helpers.js +451 -452
  28. package/plugins/core/lib/querying/knex-relationship-includes.js +1160 -1170
  29. package/plugins/core/lib/querying/knex-window-queries.js +89 -89
  30. package/plugins/core/lib/querying/url-helpers.js +35 -35
  31. package/plugins/core/lib/querying-writing/compile-schemas.js +99 -99
  32. package/plugins/core/lib/querying-writing/connectors-query-parser.js +31 -31
  33. package/plugins/core/lib/querying-writing/database-capabilities.js +94 -94
  34. package/plugins/core/lib/querying-writing/database-value-normalizers.js +76 -76
  35. package/plugins/core/lib/querying-writing/default-data-helpers.js +27 -27
  36. package/plugins/core/lib/querying-writing/field-utils.js +44 -42
  37. package/plugins/core/lib/querying-writing/knex-constants.js +15 -16
  38. package/plugins/core/lib/querying-writing/knex-field-helpers.js +117 -115
  39. package/plugins/core/lib/querying-writing/knex-json-api-transformers.js +41 -41
  40. package/plugins/core/lib/querying-writing/payload-validators.js +275 -275
  41. package/plugins/core/lib/querying-writing/schema-helpers.js +129 -129
  42. package/plugins/core/lib/querying-writing/scope-validations.js +143 -146
  43. package/plugins/core/lib/querying-writing/simplified-helpers.js +133 -129
  44. package/plugins/core/lib/storage/storage-adapter.js +68 -68
  45. package/plugins/core/lib/writing/knex-json-api-transformers-writing.js +31 -31
  46. package/plugins/core/lib/writing/many-to-many-manipulations.js +81 -81
  47. package/plugins/core/lib/writing/relationship-processor.js +58 -58
  48. package/plugins/core/rest-api-access.js +11 -15
  49. package/plugins/core/rest-api-anyapi-knex-plugin.js +920 -920
  50. package/plugins/core/rest-api-cors-plugin.js +170 -171
  51. package/plugins/core/rest-api-knex-plugin.js +482 -493
  52. package/plugins/core/rest-api-multihome-plugin.js +247 -251
  53. package/plugins/core/rest-api-plugin-hooks/compile-resource-schemas.js +5 -5
  54. package/plugins/core/rest-api-plugin-hooks/register-relationship-routes.js +20 -21
  55. package/plugins/core/rest-api-plugin-hooks/register-scope-routes.js +44 -44
  56. package/plugins/core/rest-api-plugin-hooks/turn-scope-init-into-vars.js +23 -23
  57. package/plugins/core/rest-api-plugin-hooks/validate-include-configurations.js +15 -15
  58. package/plugins/core/rest-api-plugin-methods/add-route.js +9 -9
  59. package/plugins/core/rest-api-plugin-methods/check-permissions.js +5 -6
  60. package/plugins/core/rest-api-plugin-methods/common.js +295 -297
  61. package/plugins/core/rest-api-plugin-methods/delete-relationship.js +35 -37
  62. package/plugins/core/rest-api-plugin-methods/delete.js +57 -59
  63. package/plugins/core/rest-api-plugin-methods/enrich-attributes.js +172 -171
  64. package/plugins/core/rest-api-plugin-methods/get-related.js +96 -96
  65. package/plugins/core/rest-api-plugin-methods/get-relationship.js +16 -18
  66. package/plugins/core/rest-api-plugin-methods/get.js +86 -86
  67. package/plugins/core/rest-api-plugin-methods/patch-relationship.js +16 -17
  68. package/plugins/core/rest-api-plugin-methods/patch.js +63 -64
  69. package/plugins/core/rest-api-plugin-methods/post-relationship.js +54 -55
  70. package/plugins/core/rest-api-plugin-methods/post.js +61 -62
  71. package/plugins/core/rest-api-plugin-methods/put.js +86 -87
  72. package/plugins/core/rest-api-plugin-methods/query.js +88 -88
  73. package/plugins/core/rest-api-plugin-methods/release.js +5 -6
  74. package/plugins/core/rest-api-plugin.js +76 -78
  75. package/plugins/core/rest-api-positioning-plugin.js +251 -252
  76. package/plugins/core/socketio-plugin.js +240 -236
  77. package/plugins/storage/local-storage.js +103 -103
  78. package/plugins/storage/s3-storage.js +41 -42
  79. package/quickTest.js +37 -37
  80. package/scripts/debug-anyapi-review-filter.mjs +18 -18
  81. package/scripts/inspect-anyapi-descriptor-country.mjs +10 -10
  82. package/scripts/inspect-anyapi-descriptor.mjs +10 -10
  83. package/scripts/run-docs.js +112 -113
  84. package/test-debug.js +28 -28
  85. package/tests/TEST_TEMPLATE.test.js +51 -51
  86. package/tests/anyapi-basic.test.js +42 -42
  87. package/tests/anyapi-cursor-pagination.test.js +48 -48
  88. package/tests/bulk-operations.test.js +208 -208
  89. package/tests/computed-fields.test.js +204 -204
  90. package/tests/cors.test.js +412 -413
  91. package/tests/curl.test.js +275 -276
  92. package/tests/custom-idproperty-relationships.test.js +266 -266
  93. package/tests/field-getters.test.js +132 -132
  94. package/tests/field-setters.test.js +110 -110
  95. package/tests/fixtures/api-configs.js +699 -699
  96. package/tests/helpers/storage-mode.js +32 -32
  97. package/tests/helpers/test-utils.js +76 -76
  98. package/tests/include-depth-validation.test.js +76 -76
  99. package/tests/includes.test.js +145 -145
  100. package/tests/multihome.test.js +175 -175
  101. package/tests/nested-includes.test.js +255 -255
  102. package/tests/pagination-cursor-multifield.test.js +164 -164
  103. package/tests/pagination-enhanced.test.js +225 -225
  104. package/tests/polymorphic-relationships.test.js +96 -96
  105. package/tests/polymorphic-simple.test.js +44 -44
  106. package/tests/positioning-advanced.test.js +226 -226
  107. package/tests/positioning-extended.test.js +399 -399
  108. package/tests/positioning-multifilter.test.js +204 -204
  109. package/tests/positioning.test.js +266 -266
  110. package/tests/queries.test.js +184 -184
  111. package/tests/query-limits.test.js +154 -155
  112. package/tests/relationship-endpoints.test.js +127 -127
  113. package/tests/relationships.test.js +178 -179
  114. package/tests/rest-api-access.test.js +86 -86
  115. package/tests/rest-api.test.js +103 -103
  116. package/tests/searchschema-merge.test.js +93 -93
  117. package/tests/socketio.test.js +326 -326
  118. package/tests/virtual-fields.test.js +164 -164
@@ -1,25 +1,25 @@
1
- import knexLib from 'knex';
2
- import { createCustomIdPropertyApi } from '../tests/fixtures/api-configs.js';
3
- import { createJsonApiDocument } from '../tests/helpers/test-utils.js';
1
+ import knexLib from 'knex'
2
+ import { createCustomIdPropertyApi } from '../tests/fixtures/api-configs.js'
3
+ import { createJsonApiDocument } from '../tests/helpers/test-utils.js'
4
4
 
5
- async function run() {
6
- const knex = knexLib({ client: 'better-sqlite3', connection: { filename: ':memory:' }, useNullAsDefault: true });
7
- const api = await createCustomIdPropertyApi(knex);
5
+ async function run () {
6
+ const knex = knexLib({ client: 'better-sqlite3', connection: { filename: ':memory:' }, useNullAsDefault: true })
7
+ const api = await createCustomIdPropertyApi(knex)
8
8
 
9
9
  const country = await api.resources.countries.post({
10
10
  inputRecord: createJsonApiDocument('countries', { name: 'USA', code: 'US' })
11
- });
11
+ })
12
12
 
13
13
  const book = await api.resources.books.post({
14
14
  inputRecord: createJsonApiDocument('books',
15
15
  { title: 'Test Book' },
16
16
  { country: { data: { type: 'countries', id: country.data.id } } }
17
17
  )
18
- });
18
+ })
19
19
 
20
20
  const author = await api.resources.authors.post({
21
21
  inputRecord: createJsonApiDocument('authors', { name: 'Author' })
22
- });
22
+ })
23
23
 
24
24
  await api.resources.reviews.post({
25
25
  inputRecord: createJsonApiDocument('reviews', {
@@ -30,7 +30,7 @@ async function run() {
30
30
  reviewable_type: 'books',
31
31
  reviewable_id: book.data.id
32
32
  })
33
- });
33
+ })
34
34
 
35
35
  await api.resources.reviews.post({
36
36
  inputRecord: createJsonApiDocument('reviews', {
@@ -41,23 +41,23 @@ async function run() {
41
41
  reviewable_type: 'authors',
42
42
  reviewable_id: author.data.id
43
43
  })
44
- });
44
+ })
45
45
 
46
46
  try {
47
47
  const res = await api.resources.reviews.query({
48
48
  queryParams: { filters: { reviewable_type: 'books' } }
49
- });
50
- console.log('Query succeeded with rows:', res.data.length);
49
+ })
50
+ console.log('Query succeeded with rows:', res.data.length)
51
51
  } catch (error) {
52
- console.error('Query failed:', error);
52
+ console.error('Query failed:', error)
53
53
  if (error?.sql) {
54
- console.error('SQL:', error.sql);
54
+ console.error('SQL:', error.sql)
55
55
  }
56
56
  }
57
57
 
58
- await knex.destroy();
58
+ await knex.destroy()
59
59
  }
60
60
 
61
61
  run().catch((err) => {
62
- console.error('Unexpected failure:', err);
63
- });
62
+ console.error('Unexpected failure:', err)
63
+ })
@@ -1,19 +1,19 @@
1
- import knexLib from 'knex';
2
- import { createCustomIdPropertyApi } from '../tests/fixtures/api-configs.js';
1
+ import knexLib from 'knex'
2
+ import { createCustomIdPropertyApi } from '../tests/fixtures/api-configs.js'
3
3
 
4
- async function run() {
5
- const knex = knexLib({ client: 'better-sqlite3', connection: { filename: ':memory:' }, useNullAsDefault: true });
6
- const api = await createCustomIdPropertyApi(knex);
7
- const descriptor = await api.anyapi.registry.getDescriptor('default', 'countries');
4
+ async function run () {
5
+ const knex = knexLib({ client: 'better-sqlite3', connection: { filename: ':memory:' }, useNullAsDefault: true })
6
+ const api = await createCustomIdPropertyApi(knex)
7
+ const descriptor = await api.anyapi.registry.getDescriptor('default', 'countries')
8
8
  console.log(JSON.stringify({
9
9
  idProperty: descriptor.idProperty,
10
10
  fields: descriptor.fields,
11
11
  canonicalFieldMap: descriptor.canonicalFieldMap,
12
12
  reverseAttributes: descriptor.reverseAttributes,
13
- }, null, 2));
14
- await knex.destroy();
13
+ }, null, 2))
14
+ await knex.destroy()
15
15
  }
16
16
 
17
17
  run().catch((err) => {
18
- console.error('Failed to inspect descriptor', err);
19
- });
18
+ console.error('Failed to inspect descriptor', err)
19
+ })
@@ -1,19 +1,19 @@
1
- import knexLib from 'knex';
2
- import { createCustomIdPropertyApi } from '../tests/fixtures/api-configs.js';
1
+ import knexLib from 'knex'
2
+ import { createCustomIdPropertyApi } from '../tests/fixtures/api-configs.js'
3
3
 
4
- async function run() {
5
- const knex = knexLib({ client: 'better-sqlite3', connection: { filename: ':memory:' }, useNullAsDefault: true });
6
- const api = await createCustomIdPropertyApi(knex);
7
- const descriptor = await api.anyapi.registry.getDescriptor('default', 'reviews');
4
+ async function run () {
5
+ const knex = knexLib({ client: 'better-sqlite3', connection: { filename: ':memory:' }, useNullAsDefault: true })
6
+ const api = await createCustomIdPropertyApi(knex)
7
+ const descriptor = await api.anyapi.registry.getDescriptor('default', 'reviews')
8
8
  console.log(JSON.stringify({
9
9
  idProperty: descriptor.idProperty,
10
10
  fields: descriptor.fields,
11
11
  canonicalFieldMap: descriptor.canonicalFieldMap,
12
12
  reverseAttributes: descriptor.reverseAttributes,
13
- }, null, 2));
14
- await knex.destroy();
13
+ }, null, 2))
14
+ await knex.destroy()
15
15
  }
16
16
 
17
17
  run().catch((err) => {
18
- console.error('Failed to inspect descriptor', err);
19
- });
18
+ console.error('Failed to inspect descriptor', err)
19
+ })
@@ -2,7 +2,7 @@
2
2
 
3
3
  /**
4
4
  * Run the documentation site
5
- *
5
+ *
6
6
  * This script:
7
7
  * 1. Syncs documentation files
8
8
  * 2. Builds the Jekyll site
@@ -10,129 +10,128 @@
10
10
  * 4. Opens the browser
11
11
  */
12
12
 
13
- import { spawn } from 'child_process';
14
- import { promises as fs } from 'fs';
15
- import path from 'path';
16
- import { fileURLToPath } from 'url';
13
+ import { spawn } from 'child_process'
14
+ import { promises as fs } from 'fs'
15
+ import path from 'path'
16
+ import { fileURLToPath } from 'url'
17
17
 
18
- const __filename = fileURLToPath(import.meta.url);
19
- const __dirname = path.dirname(__filename);
20
- const projectRoot = path.join(__dirname, '..');
18
+ const __filename = fileURLToPath(import.meta.url)
19
+ const __dirname = path.dirname(__filename)
20
+ const projectRoot = path.join(__dirname, '..')
21
21
 
22
22
  // Delay before opening browser (milliseconds)
23
- const BROWSER_DELAY = 3000;
23
+ const BROWSER_DELAY = 3000
24
24
 
25
25
  // Site URLs
26
- const LOCAL_URL = 'http://localhost:4000/json-rest-api/';
27
- const GITHUB_PAGES_URL = 'https://mobily-enterprises.github.io/json-rest-api/';
28
-
29
- async function runCommand(command, args, options = {}) {
30
- return new Promise((resolve, reject) => {
31
- const proc = spawn(command, args, {
32
- stdio: 'inherit',
33
- shell: true,
34
- ...options
35
- });
36
-
37
- proc.on('error', reject);
38
- proc.on('exit', (code) => {
39
- if (code === 0) {
40
- resolve();
41
- } else {
42
- reject(new Error(`Command failed with code ${code}`));
43
- }
44
- });
45
- });
26
+ const LOCAL_URL = 'http://localhost:4000/json-rest-api/'
27
+ const GITHUB_PAGES_URL = 'https://mobily-enterprises.github.io/json-rest-api/'
28
+
29
+ async function runCommand (command, args, options = {}) {
30
+ return new Promise((resolve, reject) => {
31
+ const proc = spawn(command, args, {
32
+ stdio: 'inherit',
33
+ shell: true,
34
+ ...options
35
+ })
36
+
37
+ proc.on('error', reject)
38
+ proc.on('exit', (code) => {
39
+ if (code === 0) {
40
+ resolve()
41
+ } else {
42
+ reject(new Error(`Command failed with code ${code}`))
43
+ }
44
+ })
45
+ })
46
46
  }
47
47
 
48
- async function openBrowser(url) {
49
- const platform = process.platform;
50
- let command;
51
-
52
- if (platform === 'darwin') {
53
- command = 'open';
54
- } else if (platform === 'win32') {
55
- command = 'start';
56
- } else {
57
- // Linux
58
- command = 'xdg-open';
59
- }
60
-
61
- try {
62
- await runCommand(command, [url]);
63
- console.log(`\n🌐 Opened browser at ${url}`);
64
- } catch (err) {
65
- console.log(`\n💡 Visit ${url} in your browser`);
66
- }
48
+ async function openBrowser (url) {
49
+ const platform = process.platform
50
+ let command
51
+
52
+ if (platform === 'darwin') {
53
+ command = 'open'
54
+ } else if (platform === 'win32') {
55
+ command = 'start'
56
+ } else {
57
+ // Linux
58
+ command = 'xdg-open'
59
+ }
60
+
61
+ try {
62
+ await runCommand(command, [url])
63
+ console.log(`\n🌐 Opened browser at ${url}`)
64
+ } catch (err) {
65
+ console.log(`\n💡 Visit ${url} in your browser`)
66
+ }
67
67
  }
68
68
 
69
- async function main() {
70
- console.log('📚 Starting documentation site...\n');
71
-
69
+ async function main () {
70
+ console.log('📚 Starting documentation site...\n')
71
+
72
+ try {
73
+ // Step 1: There is no step 1
74
+
75
+ // Step 2: Install Jekyll dependencies if needed
76
+ const bundleLockPath = path.join(projectRoot, 'docs', 'Gemfile.lock')
72
77
  try {
73
- // Step 1: There is no step 1
74
-
75
- // Step 2: Install Jekyll dependencies if needed
76
- const bundleLockPath = path.join(projectRoot, 'docs', 'Gemfile.lock');
77
- try {
78
- await fs.access(bundleLockPath);
79
- } catch {
80
- console.log('\n2️⃣ Installing Jekyll dependencies...');
81
- await runCommand('bundle', ['install'], {
82
- cwd: path.join(projectRoot, 'docs')
83
- });
84
- }
85
-
86
- // Step 3: Start Jekyll server in background
87
- console.log('\n3️⃣ Starting Jekyll server...');
88
- const jekyll = spawn('bundle', ['exec', 'jekyll', 'serve', '--watch'], {
89
- cwd: path.join(projectRoot, 'docs'),
90
- stdio: 'pipe',
91
- shell: true
92
- });
93
-
94
- // Handle server output
95
- jekyll.stdout.on('data', (data) => {
96
- const output = data.toString();
97
- process.stdout.write(output);
98
-
99
- // Open browser when server is ready
100
- if (output.includes('Server running') || output.includes('Server address:')) {
101
- setTimeout(() => openBrowser(LOCAL_URL), 1000);
102
- }
103
- });
104
-
105
- jekyll.stderr.on('data', (data) => {
106
- process.stderr.write(data);
107
- });
108
-
109
- // Handle shutdown
110
- process.on('SIGINT', () => {
111
- console.log('\n\n👋 Shutting down Jekyll server...');
112
- jekyll.kill();
113
- process.exit(0);
114
- });
115
-
116
- jekyll.on('error', (err) => {
117
- console.error('❌ Jekyll server error:', err);
118
- process.exit(1);
119
- });
120
-
121
- jekyll.on('exit', (code) => {
122
- if (code !== 0 && code !== null) {
123
- console.error(`❌ Jekyll server exited with code ${code}`);
124
- process.exit(code);
125
- }
126
- });
127
-
128
- // Wait a bit then try to open browser anyway (in case we missed the server ready message)
129
- setTimeout(() => openBrowser(LOCAL_URL), BROWSER_DELAY);
130
-
131
- } catch (error) {
132
- console.error('❌ Error:', error.message);
133
- process.exit(1);
78
+ await fs.access(bundleLockPath)
79
+ } catch {
80
+ console.log('\n2️⃣ Installing Jekyll dependencies...')
81
+ await runCommand('bundle', ['install'], {
82
+ cwd: path.join(projectRoot, 'docs')
83
+ })
134
84
  }
85
+
86
+ // Step 3: Start Jekyll server in background
87
+ console.log('\n3️⃣ Starting Jekyll server...')
88
+ const jekyll = spawn('bundle', ['exec', 'jekyll', 'serve', '--watch'], {
89
+ cwd: path.join(projectRoot, 'docs'),
90
+ stdio: 'pipe',
91
+ shell: true
92
+ })
93
+
94
+ // Handle server output
95
+ jekyll.stdout.on('data', (data) => {
96
+ const output = data.toString()
97
+ process.stdout.write(output)
98
+
99
+ // Open browser when server is ready
100
+ if (output.includes('Server running') || output.includes('Server address:')) {
101
+ setTimeout(() => openBrowser(LOCAL_URL), 1000)
102
+ }
103
+ })
104
+
105
+ jekyll.stderr.on('data', (data) => {
106
+ process.stderr.write(data)
107
+ })
108
+
109
+ // Handle shutdown
110
+ process.on('SIGINT', () => {
111
+ console.log('\n\n👋 Shutting down Jekyll server...')
112
+ jekyll.kill()
113
+ process.exit(0)
114
+ })
115
+
116
+ jekyll.on('error', (err) => {
117
+ console.error('❌ Jekyll server error:', err)
118
+ process.exit(1)
119
+ })
120
+
121
+ jekyll.on('exit', (code) => {
122
+ if (code !== 0 && code !== null) {
123
+ console.error(`❌ Jekyll server exited with code ${code}`)
124
+ process.exit(code)
125
+ }
126
+ })
127
+
128
+ // Wait a bit then try to open browser anyway (in case we missed the server ready message)
129
+ setTimeout(() => openBrowser(LOCAL_URL), BROWSER_DELAY)
130
+ } catch (error) {
131
+ console.error('❌ Error:', error.message)
132
+ process.exit(1)
133
+ }
135
134
  }
136
135
 
137
136
  // Run the script
138
- main();
137
+ main()
package/test-debug.js CHANGED
@@ -1,29 +1,29 @@
1
- import { createBasicApi } from './tests/fixtures/api-configs.js';
2
- import { cleanTables, createJsonApiDocument, createRelationship } from './tests/helpers/test-utils.js';
3
- import knex from 'knex';
1
+ import { createBasicApi } from './tests/fixtures/api-configs.js'
2
+ import { cleanTables, createJsonApiDocument, createRelationship } from './tests/helpers/test-utils.js'
3
+ import knex from 'knex'
4
4
 
5
5
  const dbConfig = {
6
6
  client: 'better-sqlite3',
7
7
  connection: { filename: ':memory:' },
8
8
  useNullAsDefault: true
9
- };
9
+ }
10
+
11
+ const db = knex(dbConfig)
10
12
 
11
- const db = knex(dbConfig);
13
+ async function test () {
14
+ const api = await createBasicApi(db)
12
15
 
13
- async function test() {
14
- const api = await createBasicApi(db);
15
-
16
16
  // Create test data
17
- await cleanTables(db, ['basic_countries', 'basic_publishers', 'basic_authors', 'basic_books', 'basic_book_authors']);
18
-
17
+ await cleanTables(db, ['basic_countries', 'basic_publishers', 'basic_authors', 'basic_books', 'basic_book_authors'])
18
+
19
19
  // Create a country first
20
- const countryDoc = createJsonApiDocument('countries', { name: 'Test Country', code: 'TC' });
21
- const country = await api.resources.countries.post({ inputRecord: countryDoc });
22
-
20
+ const countryDoc = createJsonApiDocument('countries', { name: 'Test Country', code: 'TC' })
21
+ const country = await api.resources.countries.post({ inputRecord: countryDoc })
22
+
23
23
  // Create an author
24
- const authorDoc = createJsonApiDocument('authors', { name: 'Test Author' });
25
- const author = await api.resources.authors.post({ inputRecord: authorDoc });
26
-
24
+ const authorDoc = createJsonApiDocument('authors', { name: 'Test Author' })
25
+ const author = await api.resources.authors.post({ inputRecord: authorDoc })
26
+
27
27
  // Create a book with proper relationships
28
28
  const bookDoc = {
29
29
  data: {
@@ -33,27 +33,27 @@ async function test() {
33
33
  country: { data: { type: 'countries', id: String(country.data.id) } }
34
34
  }
35
35
  }
36
- };
37
- const book = await api.resources.books.post({ inputRecord: bookDoc });
38
-
36
+ }
37
+ const book = await api.resources.books.post({ inputRecord: bookDoc })
38
+
39
39
  // Create the many-to-many relationship
40
40
  await db('basic_book_authors').insert({
41
41
  author_id: author.data.id,
42
42
  book_id: book.data.id
43
- });
44
-
43
+ })
44
+
45
45
  // Now try to query authors with books included
46
- console.log('Querying authors with books included...');
46
+ console.log('Querying authors with books included...')
47
47
  try {
48
48
  const result = await api.resources.authors.query({
49
49
  queryParams: { include: ['books'] }
50
- });
51
- console.log('Success!', JSON.stringify(result, null, 2));
50
+ })
51
+ console.log('Success!', JSON.stringify(result, null, 2))
52
52
  } catch (error) {
53
- console.error('Error:', error.message);
53
+ console.error('Error:', error.message)
54
54
  }
55
-
56
- await db.destroy();
55
+
56
+ await db.destroy()
57
57
  }
58
58
 
59
- test().catch(console.error);
59
+ test().catch(console.error)