|
| 1 | +# Adonis Lucid Soft Deletes |
| 2 | + |
| 3 | +This is an experimental Lucid Addon which adds support for soft deletes. It's based on [PR #315](https://github.com/adonisjs/adonis-lucid/pull/315) created by me. |
| 4 | + |
| 5 | +This code should be treated as *experimental* and *likely unstable*. You're using it on your own responsibility. |
| 6 | + |
| 7 | +## Installation |
| 8 | + |
| 9 | +``` |
| 10 | +adonis install @radmen/adonis-lucid-soft-deletes |
| 11 | +
|
| 12 | +# for yarn users |
| 13 | +adonis install @radmen/adonis-lucid-soft-deletes --yarn |
| 14 | +``` |
| 15 | + |
| 16 | +Next, make sure to read the [instructions.md](https://github.com/radmen/adonis-lucid-soft-deletes/blob/master/instructions.md) file. |
| 17 | + |
| 18 | +## Usage |
| 19 | + |
| 20 | +### Removing model |
| 21 | + |
| 22 | +Default `delete()` method will mark model as soft-deleted (it will set current date in `deleted_at` attribute). |
| 23 | + |
| 24 | +If you'd like to _really_ remove the model pass `{ force: true }` as a first argument to the method. |
| 25 | + |
| 26 | +### Restoring model |
| 27 | + |
| 28 | +To restore deleted model use `restore()` method. Note that it will work **only** for soft-deleted models. |
| 29 | + |
| 30 | +### Scopes |
| 31 | + |
| 32 | +Trait will append global scope which includes only records with `deleted_at = NULL`. |
| 33 | + |
| 34 | +It's possible to query model with deleted records. To do so, use `withTrashed()` method. |
| 35 | + |
| 36 | +If you want to get _only_ deleted records, use `onlyTrashed()` method. |
| 37 | + |
| 38 | +### Getters |
| 39 | + |
| 40 | +Trait will append the following getters to the model: |
| 41 | + |
| 42 | +* `isTrashed` returns `TRUE` when model has `deleted_at !== NULL` |
| 43 | +* `wasTrashed` returns `TRUE` only when model _was_ deleted but it got `restore`'d. |
| 44 | + |
| 45 | +### Hooks |
| 46 | + |
| 47 | +For either soft or force delete, `beforeDelete`/`afterDelete` hooks will be triggered. |
| 48 | + |
| 49 | +When a model is being restored it will trigger `beforeRestore`/`afterRestore` hooks. |
| 50 | + |
| 51 | +## Hacks, workarounds |
| 52 | + |
| 53 | +### `isDeleted` |
| 54 | + |
| 55 | +By default, Adonis Models can't be updated if they've been deleted. When this happens `isDeleted` returns `TRUE` and no change is possible. This prevents from using soft deletes so the trait changes this behavior. `isDeleted` **will always return FALSE**. |
| 56 | + |
| 57 | +This may generate some unexpected problems, yet they didn't occur to me. |
| 58 | + |
| 59 | +## Known bugs |
| 60 | + |
| 61 | +### Global scope with `OR` statements |
| 62 | + |
| 63 | +It's possible to ignore global scope by mistake. This can happen when one uses `orWhere` methods (in general any `OR` statement): |
| 64 | + |
| 65 | +```js |
| 66 | +User.where('name', 'Jon').orWhere('name', 'Array') |
| 67 | +``` |
| 68 | + |
| 69 | +To avoid that you should group such statements: |
| 70 | + |
| 71 | +```js |
| 72 | +User.where(function () { |
| 73 | + this.where('name', 'Jon') |
| 74 | + .orWhere('name', 'Array') |
| 75 | +}) |
| 76 | +``` |
| 77 | + |
| 78 | +## Testing |
| 79 | + |
| 80 | +To run tests use `npm test`. By default, it will use `sqlite` as default database backend. |
| 81 | + |
| 82 | +It's possible to run tests against `postgres` or `mysql` database backends. This requires Docker to be installed. |
| 83 | + |
| 84 | +If you want to run tests using `mysql` driver: |
| 85 | + |
| 86 | +```bash |
| 87 | +NODE_ENV=mysql .travis/setUp.sh |
| 88 | +NODE_ENV=mysql npm test |
| 89 | + |
| 90 | +# remove the database |
| 91 | +.travis/tearDown.sh |
| 92 | +``` |
| 93 | + |
| 94 | +Available databases: |
| 95 | + |
| 96 | +* `mysql` will use the latest mysql |
| 97 | +* `mysql5` will use latest mysql 5.x |
| 98 | +* `postgres` will use latest postgres |
| 99 | +* `postgres9` will use latest postgres 9.x |
| 100 | + |
| 101 | +## Why separate package? |
| 102 | + |
| 103 | +I've created _hacky_, simple trait implementing basics for soft deletes. It was taken from a project of mine, where it was _good enough_ to be used. |
| 104 | + |
| 105 | +Since this feature is on Adonis roadmap I thought that it can be used as a baseline for official Adonis implementation. I've started a PR and left some questions. |
| 106 | +Some of them were answered, some of them not. This prevented me from further development. |
| 107 | + |
| 108 | +Since there's a high demand for this feature, I was asked to publish it as a separate package and allow the community to check it and leave feedback. |
| 109 | +After some consideration, I think that it's a good idea. |
| 110 | + |
| 111 | +The goal of this package is to test it, gather feedback, improve and eventually back-port to Adonis. |
| 112 | +I'm not an active Adonis user so community support is required. |
0 commit comments