postlight / lux

Build scalable, Node.js-powered REST JSON APIs with almost no code.
https://lux.postlight.com
MIT License
571 stars 60 forks source link

Updating hasMany => through relationships #720

Closed willviles closed 6 years ago

willviles commented 7 years ago

Platform: Darwin Kernel Version 16.7.0 Database: Tested w/SQLite3 & pg (assumed present on all dbs) Lux Version: 1.2.1 Node Version: 6.10

To replicate this error, use the Lux test app inside the Lux repo.

1) Add reactions and tags to app/controllers/posts.js params. 2) Ensure the database is migrated and seeded. Run lux serve inside test/test-app 3) Send a PATCH to /posts/1 with the following body to confirm reactions update properly:

{
    "data": {
        "id": "1",
        "type": "posts",
        "attributes": {
        },
        "relationships": {
            "reactions": {
                "data": [{
                    "id": "1",
                    "type": "reactions"
                }]
            }
        }
    }
}

4) Send a PATCH to /posts/1 with the following body:

{
    "data": {
        "id": "1",
        "type": "posts",
        "attributes": {
        },
        "relationships": {
            "tags": {
                "data": [{
                    "id": "1",
                    "type": "tags"
                }]
            }
        }
    }
}

5) The following error should be logged: Error: SQLITE_ERROR: no such column: post_id.

It appears Lux is trying to update the relationship as though there's no joining categorization resource.

willviles commented 7 years ago

Also, to get lux seed to work in the test app, I had to make a slight amendment to /test/test-app/db/seed.js. It appears connection is undefined, so connection.batchInsert() throws the following error:

TypeError: Cannot read property 'batchInsert' of undefined
    at Object.keys.map.reduce (/Users/will/Code/lux/test/test-app/dist/bundle.js:1402:33)
    at Array.reduce (native)
    at seed (/Users/will/Code/lux/test/test-app/dist/bundle.js:1401:9)
    at /Users/will/Code/lux/test/test-app/node_modules/knex/lib/transaction.js:81:20
    at runCallback (timers.js:651:20)
    at tryOnImmediate (timers.js:624:5)
    at processImmediate [as _immediateCallback] (timers.js:596:5)
From previous event:
    at /Users/will/Code/lux/test/test-app/node_modules/knex/lib/transaction.js:75:10
    at runCallback (timers.js:651:20)
    at tryOnImmediate (timers.js:624:5)
From previous event:
    at new Transaction (/Users/will/Code/lux/test/test-app/node_modules/knex/lib/transaction.js:68:41)
    at Client_SQLite3.transaction (/Users/will/Code/lux/test/test-app/node_modules/knex/lib/client.js:158:12)
    at Function.transaction (/Users/will/Code/lux/test/test-app/node_modules/knex/lib/util/make-knex.js:75:21)
    at Database.then.store (/Users/will/.nvm/versions/node/v6.10.0/lib/node_modules/lux-framework/src/packages/cli/commands/dbseed.js:23:22)

The following code ran the seeds successfully:

import __fixtures__ from './__fixtures__.json'

const CHUNK_SIZE = 100

export default async function seed(trx) {
  const promises = Object
    .keys(__fixtures__)
    .map(key => [
      key,
      __fixtures__[key].map(row => (
        Object.assign(row, {
          created_at: new Date(row.created_at),
          updated_at: new Date(row.updated_at),
        })
      ))
    ])
    .reduce((arr, [table, rows]) => {
      arr[arr.length] = trx
        .batchInsert(table, rows, CHUNK_SIZE)
        .transacting(trx)
      return arr
    }, [])

  return Promise.all(promises)
}
zacharygolba commented 7 years ago

@willviles I was able to reproduce your issue regarding updating has many through relationships. I'm going to look into this a bit deeper and see if there is an easy fix.

In the mean time, could you expose the through model's controller and modify the relationships from there? I confirmed that it is working in the in v1.2.1.

Add Relationship

POST /friendships HTTP/1.1
Content-Type: application/vnd.api+json
Content-Length: 282

{
  "data": {
    "type": "friendships",
    "relationships": {
      "follower": {
        "data": {
          "id": ":id",
          "type": "users"
        }
      },
      "followee": {
        "data": {
          "id": ":id",
          "type": "users"
        }
      }
    }
  }
}

Remove Relationship

DELETE /friendships/:id HTTP/1.1