CRUD completo#75
Conversation
CRUD completo + filtros
WalkthroughAdds AdonisJS Lucid integration: DB config, migration, Task model, validators, controllers, REST routes, CLI/ace updates and manifest entries, environment example changes, dependency updates, and README replacement for a Tasks API. Config namespace and providers updated. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor Client
participant Routes as start/routes.ts
participant Controller as TasksController
participant Validator as Create/Update Validator
participant Model as Task (Lucid)
participant DB as PostgreSQL
Client->>Routes: HTTP GET /tasks?q=&favorite=
Routes->>Controller: index()
Controller->>Model: query().if(q).if(favorite).orderBy(created_at)
Model->>DB: SELECT ...
DB-->>Model: rows
Model-->>Controller: Task[]
Controller-->>Client: 200 JSON
Client->>Routes: HTTP POST /tasks {title,...}
Routes->>Controller: store()
Controller->>Validator: validate(payload)
Validator-->>Controller: validated data
Controller->>Model: create(validated)
Model->>DB: INSERT ...
DB-->>Model: inserted row
Model-->>Controller: Task
Controller-->>Client: 201 JSON
Client->>Routes: HTTP PATCH /tasks/:id {partial}
Routes->>Controller: update()
Controller->>Validator: validate(partial)
Validator-->>Controller: validated data
Controller->>Model: findOrFail(id) -> merge + save
Model->>DB: SELECT/UPDATE
DB-->>Model: ok
Controller-->>Client: 200 JSON
Client->>Routes: HTTP DELETE /tasks/:id
Routes->>Controller: destroy()
Controller->>Model: findOrFail(id) -> delete
Model->>DB: DELETE
DB-->>Model: ok
Controller-->>Client: 204
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
Tip 🔌 Remote MCP (Model Context Protocol) integration is now available!Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats. ✨ Finishing Touches🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 15
🧹 Nitpick comments (14)
.env.example (1)
7-15: Sort PG_ keys to satisfy dotenv-linter and reduce churn*Reorder and keep one key per line without inline comments.
Apply:
-DB_CONNECTION=pg -PG_HOST=127.0.0.1 -PG_PORT=5432 -PG_USER=corelab -PG_PASSWORD=corelab -PG_DB_NAME=corelab +DB_CONNECTION=pg +PG_DB_NAME=corelab +PG_HOST=127.0.0.1 +PG_PASSWORD=corelab +PG_PORT=5432 +PG_USER=corelabconfig/database.ts (1)
7-19: Add connection pool and timeouts to harden DB accessPrevent resource exhaustion and long-hanging queries.
pg: { client: 'pg', connection: { host: Env.get('PG_HOST', '127.0.0.1') as string, port: Number(Env.get('PG_PORT', 5432)), user: Env.get('PG_USER', 'postgres') as string, password: Env.get('PG_PASSWORD', '') as string, database: Env.get('PG_DB_NAME', '') as string, + // Optional hardening (supported by node-postgres) + connectionTimeoutMillis: 6000, + statement_timeout: 8000, }, + pool: { min: 0, max: 10, acquireTimeoutMillis: 10000 }, migrations: { naturalSort: true }, healthCheck: true, debug: Env.get('DB_DEBUG', 'false') === 'true',.adonisrc.json (1)
17-21: Remove stale duplicate TasksController.ts
No imports referenceApp/Controllers/TasksController; deleteapp/Controllers/TasksController.tsto avoid ambiguity. Optionally verify tests and configurations don’t reference it.app/Models/Task.ts (1)
15-22: Ensure DB defaults and indexes align with expected filters
- If
isFavoritedefaults to false at DB level, declare it in the migration to avoid nulls.- If you’ll filter by
is_favoriteand/orcoloroften, consider indexing accordingly.Example migration tweak:
this.schema.alterTable('tasks', (table) => { table.boolean('is_favorite').notNullable().defaultTo(false).index() table.index(['color']) })app/Validators/CreateTaskValidator.ts (1)
4-12: Add custom validation messages (DX/i18n).Return clear, localizable errors instead of defaults.
export default class CreateTaskValidator { constructor(protected ctx: HttpContextContract) {} public schema = schema.create({ title: schema.string({}, [rules.trim(), rules.minLength(1), rules.maxLength(120)]), description: schema.string.optional({}, [rules.trim(), rules.maxLength(2000)]), - color: schema.enum.optional(['yellow', 'blue', 'green', 'peach'] as const), + color: schema.enum.optional(TASK_COLORS), isFavorite: schema.boolean.optional(), }) + + public messages = { + 'title.required': 'title is required', + 'title.minLength': 'title must have at least 1 character', + 'title.maxLength': 'title must have at most 120 characters', + 'description.maxLength': 'description must have at most 2000 characters', + 'color.enum': 'color must be one of: yellow, blue, green, peach', + } }app/Validators/UpdateTaskValidator.ts (1)
4-12: Add custom messages for consistency with Create validator.export default class UpdateTaskValidator { constructor(protected ctx: HttpContextContract) {} @@ public schema = schema.create({ title: schema.string.optional({}, [rules.trim(), rules.minLength(1), rules.maxLength(120)]), description: schema.string.optional({}, [rules.trim(), rules.maxLength(2000)]), color: schema.enum.optional(TASK_COLORS), isFavorite: schema.boolean.optional(), }) + + public messages = { + 'title.minLength': 'title must have at least 1 character', + 'title.maxLength': 'title must have at most 120 characters', + 'description.maxLength': 'description must have at most 2000 characters', + 'color.enum': 'color must be one of: yellow, blue, green, peach', + } }database/migrations/0000000000000_create_tasks_table.ts (1)
15-23: Add indexes to support filters.If the API lists/filter by color/is_favorite/created_at, add indexes.
this.schema.createTable(this.tableName, (table) => { table.increments('id') table.string('title', 120).notNullable() table.text('description').nullable() table.specificType('color', this.enumName).notNullable().defaultTo(this.schema.raw(`'yellow'::${this.enumName}`)) table.boolean('is_favorite').notNullable().defaultTo(false) table.timestamp('created_at', { useTz: true }).notNullable().defaultTo(this.now()) table.timestamp('updated_at', { useTz: true }).notNullable().defaultTo(this.now()) + table.index(['color'], 'tasks_color_idx') + table.index(['is_favorite'], 'tasks_is_favorite_idx') + table.index(['created_at'], 'tasks_created_at_idx') })package.json (1)
5-13: Add DB/migration scripts for DX."scripts": { "dev": "node ace serve --watch", "build": "node ace build --production", "start": "node server.js", + "migrate": "node ace migration:run", + "migrate:rollback": "node ace migration:rollback", + "db:refresh": "node ace migration:refresh", "lint": "eslint . --ext=.ts", "format": "prettier --write .", "test": "node ace test", "test:watch": "npm test --watch" },start/routes.ts (2)
3-9: Prefer Route.resource with id constraint.Cleaner, consistent REST mapping and numeric id guard.
-Route.get('/tasks', 'TasksController.index') -Route.get('/tasks/:id', 'TasksController.show') -Route.post('/tasks', 'TasksController.store') -Route.patch('/tasks/:id', 'TasksController.update') -Route.delete('/tasks/:id', 'TasksController.destroy') +Route.resource('tasks', 'TasksController').apiOnly() +Route.where('id', /^[0-9]+$/)
3-3: Avoid non-ASCII keys in health payload.JSON key with accent can be awkward for clients; prefer ascii snakeCase/camelCase.
-Route.get('/', async () => ({ Rota_Está_Funcionando: true })) +Route.get('/', async () => ({ route_is_working: true }))app/Controllers/Http/TasksController.ts (2)
23-24: Consider pagination to avoid unbounded result sets.Add simple page/perPage with sane caps.
- return query.orderBy('created_at', 'desc') + const page = Number(request.input('page', 1)) || 1 + const perPage = Math.min(Number(request.input('perPage', 20)) || 20, 100) + return query.orderBy('created_at', 'desc').paginate(page, perPage)
32-38: Leverage Adonis validators instead of manual checks.Prefer CreateTaskValidator/UpdateTaskValidator for consistent schema and messages.
Add import at top of file:
import CreateTaskValidator from 'App/Validators/CreateTaskValidator'Then replace request.only + manual checks with:
const payload = await request.validate(CreateTaskValidator)Similarly in update():
import UpdateTaskValidator from 'App/Validators/UpdateTaskValidator' const payload = await request.validate(UpdateTaskValidator)app/Controllers/TasksController.ts (2)
14-17: Trim q before applying filters.Prevents executing LIKE on whitespace.
- if (q && q.trim()) { + if (q && q.trim()) { + const qTrim = q.trim() - query.where((b) => b.whereILike('title', `%${q}%`).orWhereILike('description', `%${q}%`)) + query.where((b) => b.whereILike('title', `%${qTrim}%`).orWhereILike('description', `%${qTrim}%`)) }
40-42: Standardize error messages (locale and field casing).Use a consistent language and casing across endpoints, e.g., “title is required”.
- return response.badRequest({ message: 'title é obrigatório' }) + return response.badRequest({ error: 'title is required' })
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (13)
.adonisrc.json(2 hunks).env.example(1 hunks)ace(1 hunks)ace-manifest.json(1 hunks)app/Controllers/Http/TasksController.ts(1 hunks)app/Controllers/TasksController.ts(1 hunks)app/Models/Task.ts(1 hunks)app/Validators/CreateTaskValidator.ts(1 hunks)app/Validators/UpdateTaskValidator.ts(1 hunks)config/database.ts(1 hunks)database/migrations/0000000000000_create_tasks_table.ts(1 hunks)package.json(2 hunks)start/routes.ts(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
app/Controllers/Http/TasksController.ts (2)
app/Controllers/TasksController.ts (1)
TasksController(4-75)app/Models/Task.ts (1)
Task(6-29)
app/Controllers/TasksController.ts (2)
app/Controllers/Http/TasksController.ts (1)
TasksController(7-84)app/Models/Task.ts (1)
Task(6-29)
🪛 dotenv-linter (3.3.0)
.env.example
[warning] 3-3: [UnorderedKey] The HOST key should go before the PORT key
(UnorderedKey)
[warning] 4-4: [UnorderedKey] The NODE_ENV key should go before the PORT key
(UnorderedKey)
[warning] 5-5: [SpaceCharacter] The line has spaces around equal sign
(SpaceCharacter)
[warning] 5-5: [UnorderedKey] The APP_KEY key should go before the HOST key
(UnorderedKey)
[warning] 5-5: [ValueWithoutQuotes] This value needs to be surrounded in quotes
(ValueWithoutQuotes)
[warning] 12-12: [UnorderedKey] The PG_PASSWORD key should go before the PG_PORT key
(UnorderedKey)
[warning] 13-13: [UnorderedKey] The PG_DB_NAME key should go before the PG_HOST key
(UnorderedKey)
🔇 Additional comments (5)
ace (1)
3-3: Confirm source‑map behavior after switching to register()Previously
install({ handleUncaughtExceptions: false })avoided double handling;registeruses defaults. Please run a failing command (e.g., unknown ace command) and confirm stack traces map to TS and output is clean..adonisrc.json (1)
17-18: Restore or remove custom AppProvider registration
The fileproviders/AppProvider.tsstill exists but is no longer listed under"providers"in.adonisrc.json(lines 17–18). Either re-add"./providers/AppProvider"to the providers array or remove the unused file.app/Models/Task.ts (1)
6-29: Model mapping looks solid and consistent with typical Lucid conventionsFields, casing, and timestamps are correctly mapped.
app/Validators/UpdateTaskValidator.ts (1)
8-9: Confirm update semantics for empty strings.title is optional but cannot be ''. With trim + minLength(1), sending "" will 422. Ensure this is intended for PATCH.
ace-manifest.json (1)
98-572: Lucid commands manifest additions look correct.All expected migration/seeder commands are present; no action needed.
| HOST=0.0.0.0 | ||
| NODE_ENV=development | ||
| APP_KEY=73rHnSEgVPLfFLpTk8omwzBrMk-c75rX | ||
| APP_KEY= # preencha com uma chave |
There was a problem hiding this comment.
Fix APP_KEY line: parsing will break and key is missing
Inline comment plus spaces around "=" will be parsed as a value; Adonis will fail to boot if copied as-is. Move the comment to its own line and provide a proper placeholder/generated key.
Apply:
-APP_KEY= # preencha com uma chave
+# Gere uma chave com: node ace generate:key
+APP_KEY=changeme📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| APP_KEY= # preencha com uma chave | |
| # Gere uma chave com: node ace generate:key | |
| APP_KEY=changeme |
🧰 Tools
🪛 dotenv-linter (3.3.0)
[warning] 5-5: [SpaceCharacter] The line has spaces around equal sign
(SpaceCharacter)
[warning] 5-5: [UnorderedKey] The APP_KEY key should go before the HOST key
(UnorderedKey)
[warning] 5-5: [ValueWithoutQuotes] This value needs to be surrounded in quotes
(ValueWithoutQuotes)
🤖 Prompt for AI Agents
.env.example around line 5: the APP_KEY line contains an inline comment and
extra spaces which will be parsed as the value and break Adonis boot; change it
to a valid placeholder without spaces around "=", e.g.
APP_KEY=base64:REPLACE_WITH_GENERATED_KEY, and move the explanatory comment to
its own line above (e.g. "# Fill with your app key; generate with `node ace
generate:key`") so parsing and boot succeed.
| .handle(process.argv.slice(2)) | ||
| require('source-map-support/register') | ||
| const { Ignitor } = require('@adonisjs/core/build/src/Ignitor') | ||
| new Ignitor(__dirname).ace().handle(process.argv.slice(2)) |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Handle promise rejection to set a non‑zero exit code on CLI failure
Uncaught rejections may not set exit code consistently. Add a catch and set exit code.
-new Ignitor(__dirname).ace().handle(process.argv.slice(2))
+new Ignitor(__dirname)
+ .ace()
+ .handle(process.argv.slice(2))
+ .catch((err) => {
+ console.error(err)
+ process.exitCode = 1
+ })📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| new Ignitor(__dirname).ace().handle(process.argv.slice(2)) | |
| new Ignitor(__dirname) | |
| .ace() | |
| .handle(process.argv.slice(2)) | |
| .catch((err) => { | |
| console.error(err) | |
| process.exitCode = 1 | |
| }) |
🤖 Prompt for AI Agents
In ace around line 5, the promise returned by new
Ignitor(__dirname).ace().handle(process.argv.slice(2)) is not handled for
rejections; update the call to attach a catch handler that logs the error (or
sends it to your logger) and sets a non-zero exit code (e.g., process.exitCode =
1 or process.exit(1)) so CLI failures result in a failing process; keep the rest
of the call chain intact.
| const ALLOWED_COLORS = ['yellow', 'blue', 'green', 'peach'] as const | ||
| type AllowedColor = typeof ALLOWED_COLORS[number] | ||
|
|
There was a problem hiding this comment.
Add a robust boolean parser to prevent Boolean('false') bugs.
Introduce a helper and reuse it across index/store/update.
const ALLOWED_COLORS = ['yellow', 'blue', 'green', 'peach'] as const
type AllowedColor = typeof ALLOWED_COLORS[number]
+function parseBoolean(v: unknown): boolean | undefined {
+ if (v === undefined || v === null) return undefined
+ if (typeof v === 'boolean') return v
+ const s = String(v).trim().toLowerCase()
+ if (['true', '1', 'yes', 'y'].includes(s)) return true
+ if (['false', '0', 'no', 'n'].includes(s)) return false
+ return undefined
+}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const ALLOWED_COLORS = ['yellow', 'blue', 'green', 'peach'] as const | |
| type AllowedColor = typeof ALLOWED_COLORS[number] | |
| const ALLOWED_COLORS = ['yellow', 'blue', 'green', 'peach'] as const | |
| type AllowedColor = typeof ALLOWED_COLORS[number] | |
| function parseBoolean(v: unknown): boolean | undefined { | |
| if (v === undefined || v === null) return undefined | |
| if (typeof v === 'boolean') return v | |
| const s = String(v).trim().toLowerCase() | |
| if (['true', '1', 'yes', 'y'].includes(s)) return true | |
| if (['false', '0', 'no', 'n'].includes(s)) return false | |
| return undefined | |
| } |
🤖 Prompt for AI Agents
In app/Controllers/Http/TasksController.ts around lines 4–6, add a robust
boolean parser helper (e.g., parseBoolean(value): boolean) that treats
true/1/"true"/"1"/true as true and false/0/"false"/"0"/null/undefined/"" as
false to avoid JavaScript's Boolean('false') pitfall, export or place it at top
of the file, then replace any direct Boolean(...) or truthy checks in index,
store and update handlers with parseBoolean for incoming params (query/body)
that represent boolean flags (e.g., completed, archived), and update
imports/type annotations as needed so all three methods reuse the new helper.
| const q = request.input('q') as string | undefined | ||
| const favorite = request.input('favorite') | ||
|
|
There was a problem hiding this comment.
🛠️ Refactor suggestion
Harden query parsing: trim q and correctly parse favorite.
Avoid false positives/negatives on booleans and ignore empty q.
- const q = request.input('q') as string | undefined
- const favorite = request.input('favorite')
+ const qRaw = request.input('q')
+ const q = typeof qRaw === 'string' ? qRaw.trim() : undefined
+ const favParam = request.input('favorite')
@@
- if (q && q.trim()) {
+ if (q) {
query.where((b) => b.whereILike('title', `%${q}%`).orWhereILike('description', `%${q}%`))
}
@@
- if (favorite !== undefined) {
- const fav = String(favorite).toLowerCase() === 'true'
- query.where('is_favorite', fav)
- }
+ const fav = parseBoolean(favParam)
+ if (fav !== undefined) {
+ query.where('is_favorite', fav)
+ }Also applies to: 14-16, 18-21
🤖 Prompt for AI Agents
In app/Controllers/Http/TasksController.ts around lines 9-11 (and similarly
update 14-16, 18-21), trim and normalize the 'q' input and robustly parse the
'favorite' input: read raw values (const qRaw = request.input('q')), set q =
typeof qRaw === 'string' ? qRaw.trim() || undefined : undefined to ignore empty
queries, and parse favorite by inspecting the raw type (if boolean use as-is; if
string normalize to lower-case and map 'true','1','yes' => true and
'false','0','no' => false; if number treat 1 as true and 0 as false; otherwise
undefined). Replace direct casts with this normalization so downstream logic
sees either undefined, a trimmed non-empty q, or a boolean favorite.
| if (!title || !String(title).trim()) return response.badRequest({ error: 'title is required' }) | ||
| if (!ALLOWED_COLORS.includes(color as AllowedColor)) { | ||
| return response.badRequest({ error: `color must be one of ${ALLOWED_COLORS.join(', ')}` }) | ||
| } |
There was a problem hiding this comment.
Color is unintentionally required; default to 'yellow' when omitted and then validate.
Prevents unnecessary 400s when color isn’t sent.
- if (!title || !String(title).trim()) return response.badRequest({ error: 'title is required' })
- if (!ALLOWED_COLORS.includes(color as AllowedColor)) {
+ if (!title || !String(title).trim()) return response.badRequest({ error: 'title is required' })
+ const normalizedColor = (color ?? 'yellow') as AllowedColor
+ if (!ALLOWED_COLORS.includes(normalizedColor)) {
return response.badRequest({ error: `color must be one of ${ALLOWED_COLORS.join(', ')}` })
}
@@
title: String(title).trim(),
description: description ?? null,
- color: color as AllowedColor,
- isFavorite: Boolean(isFavorite),
+ color: normalizedColor,
+ isFavorite: parseBoolean(isFavorite) ?? false,
})Also applies to: 45-50
🤖 Prompt for AI Agents
In app/Controllers/Http/TasksController.ts around lines 40-43 (and also apply
the same change to lines 45-50), the controller currently rejects requests when
color is missing; instead, if color is undefined or empty, default it to
'yellow' before validation, then validate that the resulting value is in
ALLOWED_COLORS and return a 400 only if the final value is invalid; implement
this by assigning color = color ?? 'yellow' (or similar) prior to the
ALLOWED_COLORS.includes check for both create and update flows so missing color
no longer causes a 400.
| }, | ||
| migrations: { naturalSort: true }, | ||
| healthCheck: true, | ||
| debug: (Env.get('DB_DEBUG', false) as boolean) || false, |
There was a problem hiding this comment.
DB_DEBUG is coerced incorrectly; likely always truthy when set
Env.get returns strings unless validated; casting to boolean doesn't convert at runtime. "false" is truthy.
Apply:
- debug: (Env.get('DB_DEBUG', false) as boolean) || false,
+ // Accept "true"/"false" strings without relying on env.ts coercion
+ debug: Env.get('DB_DEBUG', 'false') === 'true',📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| debug: (Env.get('DB_DEBUG', false) as boolean) || false, | |
| // Accept "true"/"false" strings without relying on env.ts coercion | |
| debug: Env.get('DB_DEBUG', 'false') === 'true', |
🤖 Prompt for AI Agents
In config/database.ts around line 18, the debug flag is set by casting
Env.get(...) to boolean which doesn't convert string values (so "false" is
truthy); change the assignment to parse the string properly (for example use
Env.get('DB_DEBUG', 'false') === 'true' or implement a small helper that accepts
'true'/'1'/'yes' as true and defaults to false) so debug ends up a real boolean
with a safe default.
| this.schema.raw(`DO $$ | ||
| BEGIN | ||
| IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = '${this.enumName}') THEN | ||
| CREATE TYPE ${this.enumName} AS ENUM ('yellow', 'blue', 'green', 'peach'); | ||
| END IF; | ||
| END$$;`) |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Be explicit about PL/pgSQL language in DO blocks.
Some PG setups require LANGUAGE; add it to avoid failures.
- END$$;`)
+ END$$ LANGUAGE plpgsql;`)Apply the same to the down() DO block.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| this.schema.raw(`DO $$ | |
| BEGIN | |
| IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = '${this.enumName}') THEN | |
| CREATE TYPE ${this.enumName} AS ENUM ('yellow', 'blue', 'green', 'peach'); | |
| END IF; | |
| END$$;`) | |
| this.schema.raw(`DO $$ | |
| BEGIN | |
| IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = '${this.enumName}') THEN | |
| CREATE TYPE ${this.enumName} AS ENUM ('yellow', 'blue', 'green', 'peach'); | |
| END IF; | |
| END$$ LANGUAGE plpgsql;`) |
🤖 Prompt for AI Agents
In database/migrations/0000000000000_create_tasks_table.ts around lines 8 to 13,
the DO $$ ... $$ blocks are missing an explicit LANGUAGE declaration which can
cause failures on some PostgreSQL setups; update both the up() and down() DO
blocks to append "LANGUAGE plpgsql;" after the closing $$ (i.e. DO $$ ... $$
LANGUAGE plpgsql;) so the block is explicitly executed as PL/pgSQL and ensure
the same change is applied to the down() block that drops or alters the enum.
| table.specificType('color', this.enumName).notNullable().defaultTo('yellow') | ||
| table.boolean('is_favorite').notNullable().defaultTo(false) | ||
| table.timestamp('created_at', { useTz: true }).notNullable() | ||
| table.timestamp('updated_at', { useTz: true }).notNullable() |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Defaults: cast enum and timestamp defaults.
- Default enum literal should be cast to the enum type to avoid “type mismatch” in some PG versions.
- created_at/updated_at are NOT NULL but lack defaults; add now() to avoid insert errors outside Lucid.
- table.specificType('color', this.enumName).notNullable().defaultTo('yellow')
+ table.specificType('color', this.enumName).notNullable().defaultTo(this.schema.raw(`'yellow'::${this.enumName}`))
- table.boolean('is_favorite').notNullable().defaultTo(false)
- table.timestamp('created_at', { useTz: true }).notNullable()
- table.timestamp('updated_at', { useTz: true }).notNullable()
+ table.boolean('is_favorite').notNullable().defaultTo(false)
+ table.timestamp('created_at', { useTz: true }).notNullable().defaultTo(this.now())
+ table.timestamp('updated_at', { useTz: true }).notNullable().defaultTo(this.now())📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| table.specificType('color', this.enumName).notNullable().defaultTo('yellow') | |
| table.boolean('is_favorite').notNullable().defaultTo(false) | |
| table.timestamp('created_at', { useTz: true }).notNullable() | |
| table.timestamp('updated_at', { useTz: true }).notNullable() | |
| table.specificType('color', this.enumName) | |
| .notNullable() | |
| .defaultTo(this.schema.raw(`'yellow'::${this.enumName}`)) | |
| table.boolean('is_favorite') | |
| .notNullable() | |
| .defaultTo(false) | |
| table.timestamp('created_at', { useTz: true }) | |
| .notNullable() | |
| .defaultTo(this.now()) | |
| table.timestamp('updated_at', { useTz: true }) | |
| .notNullable() | |
| .defaultTo(this.now()) |
🤖 Prompt for AI Agents
In database/migrations/0000000000000_create_tasks_table.ts around lines 19 to
22, the enum default should be explicitly cast to the enum type and the
created_at/updated_at timestamps need defaults to avoid NOT NULL insertion
errors; update the color default to use a casted enum literal (e.g. use a
raw/default expression that casts 'yellow' to the enum type) and set created_at
and updated_at to default to now() (while keeping notNullable).
| this.schema.raw(`DO $$ | ||
| BEGIN | ||
| IF EXISTS (SELECT 1 FROM pg_type WHERE typname = '${this.enumName}') THEN | ||
| DROP TYPE ${this.enumName}; | ||
| END IF; | ||
| END$$;`) |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Same fix for down() DO block.
- END$$;`)
+ END$$ LANGUAGE plpgsql;`)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| this.schema.raw(`DO $$ | |
| BEGIN | |
| IF EXISTS (SELECT 1 FROM pg_type WHERE typname = '${this.enumName}') THEN | |
| DROP TYPE ${this.enumName}; | |
| END IF; | |
| END$$;`) | |
| this.schema.raw(`DO $$ | |
| BEGIN | |
| IF EXISTS (SELECT 1 FROM pg_type WHERE typname = '${this.enumName}') THEN | |
| DROP TYPE ${this.enumName}; | |
| END IF; | |
| END$$ LANGUAGE plpgsql;`) |
🤖 Prompt for AI Agents
In database/migrations/0000000000000_create_tasks_table.ts around lines 28 to
33, the down() migration still lacks the safe DO $$ block used in up() that
checks for the enum type's existence before dropping it; update the down()
method to run the same DO $$ BEGIN IF EXISTS (SELECT 1 FROM pg_type WHERE
typname = 'this.enumName') THEN DROP TYPE this.enumName; END IF; END $$; pattern
(using the same this.enumName interpolation/variable) so the enum is only
dropped if it exists and matches the fix applied in up().
| "@adonisjs/core": "5.9.0", | ||
| "@adonisjs/lucid": "18.4.2", | ||
| "@adonisjs/repl": "^3.1.10", | ||
| "luxon": "3.7.1", | ||
| "pg": "8.16.3", | ||
| "proxy-addr": "^2.0.7", | ||
| "reflect-metadata": "^0.1.13", | ||
| "source-map-support": "^0.5.21" | ||
| "reflect-metadata": "0.1.14", | ||
| "source-map-support": "0.5.21" | ||
| }, |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Check Node engine compatibility with pinned Adonis/Lucid versions.
Pinned deps are strict; ensure Node 16.15.x satisfies all engine ranges.
🏁 Script executed:
#!/bin/bash
# Validate engines and peer deps
node -v
npm -v
# Dry-run install to surface engine/version conflicts
npm i --package-lock-only --ignore-scripts
# Show resolved versions
npm ls @adonisjs/core @adonisjs/lucid pg luxonLength of output: 785
Fix Node.js engine version mismatch in package.json. The current engines.node range ^16.15.0 triggers EBADENGINE warnings on Node v24.3.0; either lock dev/CI to Node 16.15.x or broaden the range (e.g. >=16 <25) to cover your target versions.
🤖 Prompt for AI Agents
In package.json around lines 57 to 65 the current engines.node range (^16.15.0)
causes EBADENGINE warnings on Node 24.3.0; update the engines.node field to
either lock CI/dev to Node 16.15.x (e.g., exact 16.15.0 in toolchains) or
broaden the semver range to cover your target runtime (for example ">=16 <25")
so Node 24 is accepted, then run npm install/ci to verify no engine warnings
remain.
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (5)
README.md (5)
17-17: Corrigir termo: “autoincremento”Em PT-BR, recomenda-se “autoincremento” (uma palavra), não “auto-increment”.
Aplicar:
- - `id` (PK, auto-increment) + - `id` (PK, autoincremento)
71-74: Ajuste de gramática em pré-requisitosTrocar “um database criado” por “um banco de dados criado”.
- - **PostgreSQL** rodando e com um database criado + - **PostgreSQL** em execução e com um banco de dados criado
46-66: Especificar linguagem no bloco de código da estruturaFalta a linguagem no fenced code (MD040). Use “text” para evitar lint warnings.
-``` +```text app/ Controllers/ Http/ TasksController.ts Models/ Task.ts ... -``` +```
154-166: Documentar paginação e ordenação da listagemA rota aceita filtros; faltam paginação (page/perPage) e ordem padrão. Adicione agora ao README, mesmo que simples, para guiar consumo.
**Query params:** - `q` — busca parcial em `title` e `description` -- `favorite` — `true` | `false` +- `favorite` — `true` | `false` +- `page` — página (padrão `1`) +- `perPage` — itens por página (padrão `10`) +- `orderBy` — campo de ordenação (padrão `created_at`) +- `order` — `asc` | `desc` (padrão `desc`) **Exemplos:** ```bash curl -s http://127.0.0.1:3333/tasks | jq . -curl -s "http://127.0.0.1:3333/tasks?q=Adonis&favorite=true" | jq . +curl -s "http://127.0.0.1:3333/tasks?q=Adonis&favorite=true&page=1&perPage=10&orderBy=created_at&order=desc" | jq .--- `195-202`: **Clarificar “correções conhecidas” e versões Lucid/Decorators** A nota sobre `@column.dateTime()` é útil; recomendo apontar versão mínima do Lucid que exige isso para evitar confusão. ```diff - - Decorators de data → usar `@column.dateTime()` (Lucid 18) no lugar do legado `DateTimeColumn`. + - Decorators de data → usar `@column.dateTime()` (Lucid ≥18) no lugar do legado `DateTimeColumn`.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
README.md(1 hunks)
🧰 Additional context used
🪛 LanguageTool
README.md
[misspelling] ~17-~17: Esta é uma palavra só.
Context: ... Domínio Task Campos: - id (PK, auto-increment) - title (string, obrigatório) - `des...
(AUTO)
[grammar] ~73-~73: Possível erro de concordância.
Context: ...essário) - PostgreSQL rodando e com um database criado Selecionar Node 16: ```bash...
(GENERAL_GENDER_AGREEMENT_ERRORS)
[style] ~197-~197: Se for linguagem de Internet, considere escrever “que” por extenso. Se quis dizer “q”, coloque entre aspas.
Context: ...egura de color. - Busca simples via q em title/description e **filtro ...
(INTERNET_ABBREVIATIONS)
🪛 markdownlint-cli2 (0.17.2)
README.md
46-46: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (2)
README.md (2)
24-27: Nota sobre reversão de enum Postgres na migration (down)Ao remover, é preciso dropar a tabela que usa o tipo e só então o enum (
DROP TYPE task_color). Documente esse detalhe para evitar falhas em rollback.- Cria **tipo enum nativo** no Postgres (`task_color`) - Cria tabela `tasks` com as colunas acima + - Observação: no `down()`, remova a tabela antes e depois o tipo: + 1) `DROP TABLE tasks` + 2) `DROP TYPE task_color`
139-145: Documentar naming de isFavorite vs favorite no README.md
O modelo mapeiais_favorite→isFavoritee os controllers filtram por query paramfavorite. Atualize a seção de query params (linhas 139–145):- `favorite` — `true` | `false` + `favorite` — `true` | `false` (filtro via query string)Adicione logo abaixo:
O payload JSON envia
isFavorite, o filtro por query usafavorite, e no banco o campo éis_favorite(mapeado emapp/Models/Task.tsvia@column({ columnName: 'is_favorite', serializeAs: 'isFavorite' })).Exemplo de uso:
curl -s "http://127.0.0.1:3333/tasks?q=Adonis&favorite=true" | jq .Código não requer alterações.
| - **Node 16.x** (use `nvm` se necessário) | ||
| - **PostgreSQL** rodando e com um database criado | ||
|
|
||
| **Selecionar Node 16:** | ||
| ```bash | ||
| nvm install 16 | ||
| nvm use 16 | ||
| ``` |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
Node 16 está EOL — verificar suporte para LTS atual (18/20) e engines
Confirme compatibilidade do projeto e do Adonis v5 com Node LTS atual e ajuste README e package.json (“engines”) se aplicável.
Also applies to: 198-199
🏁 Script executed:
#!/bin/bash
set -e
echo "Engines em package.json:"
jq -r '.engines // {}' package.json 2>/dev/null || echo "package.json não encontrado"
echo -e "\nDependências Adonis/Lucid:"
jq -r '.dependencies, .devDependencies' package.json 2>/dev/null | rg -nP 'adonis|@adonisjs|lucid' || true
echo -e "\nVerifique também no CHANGELOG do AdonisJS v5 suporte a Node 18/20."Length of output: 703
Atualizar Node.js em README e engines para LTS atual
Node 16 está EOL desde abril 30, 2024 (eol.support); Adonis v5 requer Node ≥ 14.15.4 (v5-docs.adonisjs.com), então atualize package.json.engines.node para algo como ^20.0.0 (ou >=18.0.0) e ajuste o README para usar nvm install 20 / nvm use 20.
🧰 Tools
🪛 LanguageTool
[grammar] ~73-~73: Possível erro de concordância.
Context: ...essário) - PostgreSQL rodando e com um database criado Selecionar Node 16: ```bash...
(GENERAL_GENDER_AGREEMENT_ERRORS)
🤖 Prompt for AI Agents
In README.md around lines 72 to 79, the docs still reference Node 16 which is
EOL; update the README instructions and any nvm commands to recommend the
current LTS (e.g., Node 20) and change examples from `nvm install 16` / `nvm use
16` to `nvm install 20` / `nvm use 20`; additionally update
package.json.engines.node to require a modern LTS (for example set to `^20.0.0`
or a minimum of `>=18.0.0`) so the project enforces the supported Node version.
| **Configurar `.env`:** | ||
| ```dotenv | ||
| # App | ||
| PORT=3333 | ||
| HOST=0.0.0.0 | ||
| NODE_ENV=development | ||
| APP_KEY=alguma-chave-secreta | ||
|
|
||
| # Banco | ||
| DB_CONNECTION=pg | ||
| PG_HOST=127.0.0.1 | ||
| PG_PORT=5432 | ||
| PG_USER=corelab | ||
| PG_PASSWORD=corelab | ||
| PG_DB_NAME=corelab | ||
|
|
||
| # Necessário para o validador de env do Adonis | ||
| DRIVE_DISK=local | ||
| ``` |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Gerar APP_KEY em vez de placeholder no .env
APP_KEY deve ser gerado via Ace. Inclua instrução explícita.
APP_KEY=alguma-chave-secreta
+
+# Gere uma chave válida:
+# node ace generate:key
+# Copie o valor gerado para APP_KEY📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| **Configurar `.env`:** | |
| ```dotenv | |
| # App | |
| PORT=3333 | |
| HOST=0.0.0.0 | |
| NODE_ENV=development | |
| APP_KEY=alguma-chave-secreta | |
| # Banco | |
| DB_CONNECTION=pg | |
| PG_HOST=127.0.0.1 | |
| PG_PORT=5432 | |
| PG_USER=corelab | |
| PG_PASSWORD=corelab | |
| PG_DB_NAME=corelab | |
| # Necessário para o validador de env do Adonis | |
| DRIVE_DISK=local | |
| ``` | |
| **Configurar `.env`:** |
🤖 Prompt for AI Agents
In README.md around lines 86 to 104, the .env snippet uses a placeholder APP_KEY
value; update the instructions to tell users to generate a real key via Ace
(e.g., run the Adonis command to generate an app key) and paste it into the
APP_KEY field instead of using a static placeholder; include the exact Ace
command to run and a short note to keep the key secret.
| ```json | ||
| { Rota_Está_Funcionando: true } | ||
| ``` |
There was a problem hiding this comment.
Exemplo de resposta inválido (JSON malformado)
Chave sem aspas invalidará o JSON. Sugiro chave simples e válida.
-```json
-{ Rota_Está_Funcionando: true }
-```
+```json
+{ "ok": true }
+```🤖 Prompt for AI Agents
In README.md around lines 129 to 131 the example JSON block is malformed because
the key lacks quotes and the fenced block markers are inconsistent; replace the
invalid example with a valid JSON object and proper fenced code block markers —
e.g. use a triple-backtick JSON fence and the object {"ok": true} as the content
so the snippet is syntactically valid JSON.
CRUD completo + filtros
Summary by CodeRabbit