@nitronjs/framework 0.2.2 → 0.2.3

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.
package/cli/njs.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  const COLORS = {
4
4
  reset: "\x1b[0m",
@@ -32,10 +32,8 @@ ${COLORS.bold}Database:${COLORS.reset}
32
32
  ${COLORS.cyan}njs migrate:status${COLORS.reset} Show the status of each migration
33
33
  ${COLORS.cyan}njs migrate:fresh${COLORS.reset} Drop all tables and re-migrate
34
34
  ${COLORS.cyan}njs migrate:fresh --seed${COLORS.reset} Fresh migrate with seeders
35
- ${COLORS.cyan}njs seed${COLORS.reset} Run prod seeders
36
- ${COLORS.cyan}njs seed --dev${COLORS.reset} Run dev seeders
37
- ${COLORS.cyan}njs seed --all${COLORS.reset} Run all seeders (prod + dev)
38
- ${COLORS.cyan}njs seed --status${COLORS.reset} Show the status of each seeder
35
+ ${COLORS.cyan}njs seed${COLORS.reset} Run all seeders
36
+ ${COLORS.cyan}njs seed <Name>${COLORS.reset} Run a specific seeder
39
37
 
40
38
  ${COLORS.bold}Generators:${COLORS.reset}
41
39
  ${COLORS.cyan}njs make:controller${COLORS.reset} Create a new controller
@@ -137,15 +135,8 @@ async function run() {
137
135
 
138
136
  case "seed": {
139
137
  const { default: Seed } = await import("../lib/Console/Commands/SeedCommand.js");
140
- const showStatus = additionalArgs.includes('--status');
141
- const isDev = additionalArgs.includes('--dev');
142
- const isAll = additionalArgs.includes('--all');
143
-
144
- let environment = 'prod';
145
- if (isDev) environment = 'dev';
146
- if (isAll) environment = 'all';
147
-
148
- await Seed({ environment, status: showStatus });
138
+ const seederName = additionalArgs.find(a => !a.startsWith('--')) || null;
139
+ await Seed(seederName);
149
140
  break;
150
141
  }
151
142
 
@@ -12,7 +12,8 @@ export default async function migrate(options = {}) {
12
12
 
13
13
  try {
14
14
  await DB.setup();
15
- } catch (error) {
15
+ }
16
+ catch (error) {
16
17
  console.error('❌ Database setup failed:', error.message);
17
18
  console.error('Check your .env file and ensure the database exists and is accessible');
18
19
  return false;
@@ -34,7 +35,8 @@ export default async function migrate(options = {}) {
34
35
  await DB.close();
35
36
  return true;
36
37
 
37
- } catch (error) {
38
+ }
39
+ catch (error) {
38
40
  console.error('❌ Migration error:', error.message);
39
41
  await DB.close();
40
42
  return false;
@@ -20,7 +20,8 @@ export default async function migrateFresh(options = {}) {
20
20
 
21
21
  try {
22
22
  await DB.setup();
23
- } catch (error) {
23
+ }
24
+ catch (error) {
24
25
  console.error('❌ Database setup failed:', error.message);
25
26
  console.error('Check your .env file and ensure the database exists and is accessible');
26
27
  return false;
@@ -59,7 +60,8 @@ export default async function migrateFresh(options = {}) {
59
60
  await DB.close();
60
61
  return true;
61
62
 
62
- } catch (error) {
63
+ }
64
+ catch (error) {
63
65
  console.error('❌ Fresh migration error:', error.message);
64
66
  await DB.close();
65
67
  return false;
@@ -11,7 +11,8 @@ export default async function rollback(options = {}) {
11
11
 
12
12
  try {
13
13
  await DB.setup();
14
- } catch (error) {
14
+ }
15
+ catch (error) {
15
16
  console.error('❌ Database setup failed:', error.message);
16
17
  console.error('Check your .env file and ensure the database exists and is accessible');
17
18
  return false;
@@ -9,7 +9,8 @@ export default async function status() {
9
9
 
10
10
  try {
11
11
  await DB.setup();
12
- } catch (error) {
12
+ }
13
+ catch (error) {
13
14
  console.error('❌ Database setup failed:', error.message);
14
15
  console.error('Check your .env file and ensure the database exists and is accessible');
15
16
  return false;
@@ -3,9 +3,7 @@ import DB from '../../Database/DB.js';
3
3
  import Config from '../../Core/Config.js';
4
4
  import SeederRunner from '../../Database/Seeder/SeederRunner.js';
5
5
 
6
- export default async function seed(options = {}) {
7
- const { environment = 'prod', status = false } = options;
8
-
6
+ export default async function seed(seederName = null) {
9
7
  dotenv.config({ quiet: true });
10
8
  await Config.initialize();
11
9
 
@@ -18,20 +16,7 @@ export default async function seed(options = {}) {
18
16
  }
19
17
 
20
18
  try {
21
- if (status) {
22
- await SeederRunner.printStatus();
23
- await DB.close();
24
- return true;
25
- }
26
-
27
- let result;
28
-
29
- if (environment === 'all') {
30
- result = await SeederRunner.runAll();
31
- } else {
32
- result = await SeederRunner.run(environment);
33
- }
34
-
19
+ const result = await SeederRunner.run(seederName);
35
20
  await DB.close();
36
21
  return result.success;
37
22
 
@@ -45,16 +30,9 @@ export default async function seed(options = {}) {
45
30
  const isMain = process.argv[1]?.endsWith("SeedCommand.js");
46
31
  if (isMain) {
47
32
  const args = process.argv.slice(2);
33
+ const seederName = args.find(a => !a.startsWith('--')) || null;
48
34
 
49
- const showStatus = args.includes('--status');
50
- const isDev = args.includes('--dev');
51
- const isAll = args.includes('--all');
52
-
53
- let environment = 'prod';
54
- if (isDev) environment = 'dev';
55
- if (isAll) environment = 'all';
56
-
57
- seed({ environment, status: showStatus })
35
+ seed(seederName)
58
36
  .then(success => process.exit(success ? 0 : 1))
59
37
  .catch(err => {
60
38
  console.error(err);
package/lib/Core/Paths.js CHANGED
@@ -92,14 +92,6 @@ class Paths {
92
92
  return path.join(this.#project, "database/seeders");
93
93
  }
94
94
 
95
- static get seedersProd() {
96
- return path.join(this.#project, "database/seeders/prod");
97
- }
98
-
99
- static get seedersDev() {
100
- return path.join(this.#project, "database/seeders/dev");
101
- }
102
-
103
95
  static get storage() {
104
96
  return path.join(this.#project, "storage");
105
97
  }
@@ -3,7 +3,6 @@ import path from 'path';
3
3
  import { pathToFileURL, fileURLToPath } from 'url';
4
4
  import Checksum from './Checksum.js';
5
5
  import MigrationRepository from './MigrationRepository.js';
6
- import SeederRepository from '../Seeder/SeederRepository.js';
7
6
  import Paths from '../../Core/Paths.js';
8
7
 
9
8
  const __filename = fileURLToPath(import.meta.url);
@@ -39,10 +38,7 @@ class MigrationRunner {
39
38
  const ran = [];
40
39
 
41
40
  for (const file of files) {
42
- const isMigrationsTable = file.includes('migrations');
43
- const tableExists = isMigrationsTable
44
- ? await MigrationRepository.tableExists()
45
- : await SeederRepository.tableExists();
41
+ const tableExists = await MigrationRepository.tableExists();
46
42
 
47
43
  if (tableExists) continue;
48
44
 
@@ -147,7 +143,8 @@ class MigrationRunner {
147
143
  console.log(`${COLORS.green}${COLORS.bold}✅ All migrations completed successfully.${COLORS.reset}`);
148
144
  return { success: true, ran: executedInBatch.map(e => e.file) };
149
145
 
150
- } catch (error) {
146
+ }
147
+ catch (error) {
151
148
  console.error(`\n${COLORS.red}❌ Migration failed: ${error.message}${COLORS.reset}`);
152
149
 
153
150
  if (executedInBatch.length > 0) {
@@ -98,6 +98,22 @@ class Model {
98
98
  return DB.table(this.table, null, this).select(...columns);
99
99
  }
100
100
 
101
+ static orderBy(column, direction = 'ASC') {
102
+ if (!this.table) {
103
+ throw new Error(`Model ${this.name} must define a static 'table' property`);
104
+ }
105
+
106
+ return DB.table(this.table, null, this).orderBy(column, direction);
107
+ }
108
+
109
+ static limit(value) {
110
+ if (!this.table) {
111
+ throw new Error(`Model ${this.name} must define a static 'table' property`);
112
+ }
113
+
114
+ return DB.table(this.table, null, this).limit(value);
115
+ }
116
+
101
117
  static async first() {
102
118
  if (!this.table) {
103
119
  throw new Error(`Model ${this.name} must define a static 'table' property`);
@@ -159,6 +159,18 @@ class QueryBuilder {
159
159
  }
160
160
 
161
161
  where(column, operator, value) {
162
+ if (typeof column === 'object' && column !== null && !Array.isArray(column)) {
163
+ for (const [key, val] of Object.entries(column)) {
164
+ if (Array.isArray(val) && val.length === 2) {
165
+ this.where(key, val[0], val[1]);
166
+ }
167
+ else {
168
+ this.where(key, '=', val);
169
+ }
170
+ }
171
+ return this;
172
+ }
173
+
162
174
  if (arguments.length === 2) {
163
175
  value = operator;
164
176
  operator = '=';
@@ -1,3 +1,24 @@
1
+ const RESERVED_KEYWORDS = new Set([
2
+ 'order', 'key', 'group', 'index', 'table', 'column', 'select', 'insert',
3
+ 'update', 'delete', 'from', 'where', 'join', 'left', 'right', 'inner',
4
+ 'outer', 'on', 'and', 'or', 'not', 'null', 'true', 'false', 'like',
5
+ 'in', 'between', 'is', 'as', 'by', 'asc', 'desc', 'limit', 'offset',
6
+ 'having', 'distinct', 'all', 'any', 'exists', 'case', 'when', 'then',
7
+ 'else', 'end', 'if', 'into', 'values', 'set', 'create', 'drop', 'alter',
8
+ 'add', 'primary', 'foreign', 'references', 'constraint', 'default',
9
+ 'unique', 'check', 'view', 'trigger', 'procedure', 'function', 'database',
10
+ 'schema', 'use', 'show', 'describe', 'explain', 'grant', 'revoke',
11
+ 'commit', 'rollback', 'transaction', 'lock', 'unlock', 'read', 'write',
12
+ 'range', 'rows', 'rank', 'row', 'status', 'type', 'level', 'value', 'name'
13
+ ]);
14
+
15
+ function escapeIdentifier(identifier) {
16
+ if (RESERVED_KEYWORDS.has(identifier.toLowerCase())) {
17
+ return `\`${identifier}\``;
18
+ }
19
+ return identifier;
20
+ }
21
+
1
22
  export function validateIdentifier(identifier) {
2
23
  if (typeof identifier !== 'string' || identifier.length === 0) {
3
24
  throw new Error('Identifier must be a non-empty string');
@@ -27,7 +48,15 @@ export function validateIdentifier(identifier) {
27
48
  throw new Error(`Invalid identifier: "${identifier}". Must be alphanumeric with underscores, optionally qualified with table name.`);
28
49
  }
29
50
 
30
- return identifier;
51
+ if (identifier.includes('.')) {
52
+ const [table, column] = identifier.split('.');
53
+ if (column === '*') {
54
+ return `${escapeIdentifier(table)}.*`;
55
+ }
56
+ return `${escapeIdentifier(table)}.${escapeIdentifier(column)}`;
57
+ }
58
+
59
+ return escapeIdentifier(identifier);
31
60
  }
32
61
 
33
62
  export function validateWhereOperator(operator) {
@@ -1,8 +1,6 @@
1
1
  import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { pathToFileURL } from 'url';
4
- import Checksum from '../Migration/Checksum.js';
5
- import SeederRepository from './SeederRepository.js';
6
4
  import Paths from '../../Core/Paths.js';
7
5
 
8
6
  const COLORS = {
@@ -17,167 +15,67 @@ const COLORS = {
17
15
 
18
16
  class SeederRunner {
19
17
 
20
- static async run(environment = 'prod') {
21
- const seedersDir = environment === 'dev' ? Paths.seedersDev : Paths.seedersProd;
18
+ static async run(seederName = null) {
19
+ const seedersDir = Paths.seeders;
22
20
 
23
21
  if (!fs.existsSync(seedersDir)) {
24
- console.log(`${COLORS.yellow}⚠️ No seeders directory found for ${environment}${COLORS.reset}`);
22
+ console.log(`${COLORS.yellow}⚠️ No seeders directory found${COLORS.reset}`);
25
23
  return { success: true, ran: [] };
26
24
  }
27
25
 
28
- const files = fs.readdirSync(seedersDir)
26
+ let files = fs.readdirSync(seedersDir)
29
27
  .filter(f => f.endsWith('.js'))
30
28
  .sort();
31
29
 
32
30
  if (files.length === 0) {
33
- console.log(`${COLORS.yellow}⚠️ No seeder files found in ${environment}${COLORS.reset}`);
31
+ console.log(`${COLORS.yellow}⚠️ No seeder files found${COLORS.reset}`);
34
32
  return { success: true, ran: [] };
35
33
  }
36
34
 
37
- const executedNames = await SeederRepository.getExecutedNames();
38
-
39
- for (const file of files) {
40
- const fullName = `${environment}/${file}`;
41
- if (executedNames.has(fullName)) {
42
- const filePath = path.join(seedersDir, file);
43
- const currentChecksum = Checksum.fromFile(filePath);
44
- const storedChecksum = await SeederRepository.getChecksum(fullName);
45
-
46
- if (currentChecksum !== storedChecksum) {
47
- console.error(`${COLORS.red}❌ CHECKSUM MISMATCH: ${fullName}${COLORS.reset}`);
48
- console.error(`${COLORS.dim} Stored: ${storedChecksum}${COLORS.reset}`);
49
- console.error(`${COLORS.dim} Current: ${currentChecksum}${COLORS.reset}`);
50
- console.error(`${COLORS.red} Seeder files must NEVER be modified after execution.${COLORS.reset}`);
51
- console.error(`${COLORS.red} Create a NEW seeder for any data changes.${COLORS.reset}`);
52
- return {
53
- success: false,
54
- ran: [],
55
- error: new Error(`Checksum mismatch for seeder: ${fullName}`)
56
- };
57
- }
35
+ // If specific seeder name provided, filter to only that one
36
+ if (seederName) {
37
+ const targetFile = seederName.endsWith('.js') ? seederName : `${seederName}.js`;
38
+ files = files.filter(f => f === targetFile);
39
+
40
+ if (files.length === 0) {
41
+ console.log(`${COLORS.red}❌ Seeder not found: ${seederName}${COLORS.reset}`);
42
+ return { success: false, ran: [], error: new Error(`Seeder not found: ${seederName}`) };
58
43
  }
59
44
  }
60
45
 
61
- const pending = files.filter(f => !executedNames.has(`${environment}/${f}`));
62
-
63
- if (pending.length === 0) {
64
- console.log(`${COLORS.green}✅ Nothing to seed. All ${environment} seeders are up to date.${COLORS.reset}`);
65
- return { success: true, ran: [] };
66
- }
67
-
68
- console.log(`${COLORS.cyan}🌱 Running ${environment} seeders${COLORS.reset}\n`);
46
+ console.log(`${COLORS.cyan}🌱 Running seeders${COLORS.reset}\n`);
69
47
 
70
48
  const executed = [];
71
49
 
72
50
  try {
73
- for (const file of pending) {
51
+ for (const file of files) {
74
52
  const filePath = path.join(seedersDir, file);
75
53
  const fileUrl = pathToFileURL(filePath).href;
76
- const checksum = Checksum.fromFile(filePath);
77
- const fullName = `${environment}/${file}`;
78
54
 
79
- console.log(`${COLORS.dim}Seeding:${COLORS.reset} ${COLORS.cyan}${fullName}${COLORS.reset}`);
55
+ console.log(`${COLORS.dim}Seeding:${COLORS.reset} ${COLORS.cyan}${file}${COLORS.reset}`);
80
56
 
81
- const { default: seeder } = await import(fileUrl);
57
+ const { default: seeder } = await import(`${fileUrl}?t=${Date.now()}`);
82
58
 
83
59
  if (typeof seeder.run !== 'function') {
84
60
  throw new Error(`Seeder ${file} does not have a run() method`);
85
61
  }
86
62
 
87
63
  await seeder.run();
88
- await SeederRepository.log(fullName, checksum);
89
- executed.push(fullName);
64
+ executed.push(file);
90
65
 
91
- console.log(`${COLORS.green}✅ Seeded:${COLORS.reset} ${COLORS.cyan}${fullName}${COLORS.reset}\n`);
66
+ console.log(`${COLORS.green}✅ Seeded:${COLORS.reset} ${COLORS.cyan}${file}${COLORS.reset}\n`);
92
67
  }
93
68
 
94
- console.log(`${COLORS.green}${COLORS.bold}✅ All ${environment} seeders completed successfully.${COLORS.reset}`);
69
+ console.log(`${COLORS.green}${COLORS.bold}✅ All seeders completed successfully.${COLORS.reset}`);
95
70
  return { success: true, ran: executed };
96
71
 
97
- } catch (error) {
72
+ }
73
+ catch (error) {
98
74
  console.error(`\n${COLORS.red}❌ Seeding failed: ${error.message}${COLORS.reset}`);
99
75
  return { success: false, ran: executed, error };
100
76
  }
101
77
  }
102
78
 
103
- static async runAll() {
104
- console.log(`${COLORS.bold}Running prod seeders...${COLORS.reset}\n`);
105
- const prodResult = await this.run('prod');
106
-
107
- if (!prodResult.success) {
108
- return prodResult;
109
- }
110
-
111
- console.log(`\n${COLORS.bold}Running dev seeders...${COLORS.reset}\n`);
112
- const devResult = await this.run('dev');
113
-
114
- return {
115
- success: devResult.success,
116
- ran: [...prodResult.ran, ...devResult.ran],
117
- error: devResult.error
118
- };
119
- }
120
-
121
- static async status() {
122
- const prodDir = Paths.seedersProd;
123
- const devDir = Paths.seedersDev;
124
-
125
- const status = [];
126
-
127
- if (fs.existsSync(prodDir)) {
128
- const prodFiles = fs.readdirSync(prodDir).filter(f => f.endsWith('.js')).sort();
129
- for (const file of prodFiles) {
130
- const fullName = `prod/${file}`;
131
- const record = await SeederRepository.find(fullName);
132
- status.push({
133
- name: fullName,
134
- status: record ? 'Ran' : 'Pending',
135
- executedAt: record?.executed_at || null
136
- });
137
- }
138
- }
139
-
140
- if (fs.existsSync(devDir)) {
141
- const devFiles = fs.readdirSync(devDir).filter(f => f.endsWith('.js')).sort();
142
- for (const file of devFiles) {
143
- const fullName = `dev/${file}`;
144
- const record = await SeederRepository.find(fullName);
145
- status.push({
146
- name: fullName,
147
- status: record ? 'Ran' : 'Pending',
148
- executedAt: record?.executed_at || null
149
- });
150
- }
151
- }
152
-
153
- return status;
154
- }
155
-
156
- static async printStatus() {
157
- const status = await this.status();
158
-
159
- if (status.length === 0) {
160
- console.log(`${COLORS.yellow}⚠️ No seeders found.${COLORS.reset}`);
161
- return;
162
- }
163
-
164
- console.log(`\n${COLORS.bold}Seeder Status${COLORS.reset}\n`);
165
- console.log(`${COLORS.dim}${'─'.repeat(80)}${COLORS.reset}`);
166
-
167
- for (const seeder of status) {
168
- const statusColor = seeder.status === 'Ran' ? COLORS.green : COLORS.yellow;
169
- const statusIcon = seeder.status === 'Ran' ? '✅' : '⏳';
170
-
171
- console.log(`${statusIcon} ${statusColor}${seeder.status.padEnd(7)}${COLORS.reset} ${seeder.name}`);
172
- }
173
-
174
- console.log(`${COLORS.dim}${'─'.repeat(80)}${COLORS.reset}\n`);
175
-
176
- const ran = status.filter(s => s.status === 'Ran').length;
177
- const pending = status.filter(s => s.status === 'Pending').length;
178
- console.log(`${COLORS.dim}Total: ${status.length} | Ran: ${ran} | Pending: ${pending}${COLORS.reset}\n`);
179
- }
180
-
181
79
  }
182
80
 
183
81
  export default SeederRunner;
@@ -7,6 +7,7 @@ import fastifyStatic from "@fastify/static";
7
7
  import fastifyCookie from "@fastify/cookie";
8
8
  import fastifyHelmet from "@fastify/helmet";
9
9
  import fastifyMultipart from "@fastify/multipart";
10
+ import fastifyFormbody from "@fastify/formbody";
10
11
  import Paths from "../Core/Paths.js";
11
12
  import Config from "../Core/Config.js";
12
13
  import Environment from "../Core/Environment.js";
@@ -111,6 +112,8 @@ class Server {
111
112
  },
112
113
  attachFieldsToBody: this.#serverConfigs.web_server.multipart.attachFieldsToBody
113
114
  });
115
+
116
+ this.#server.register(fastifyFormbody);
114
117
  }
115
118
 
116
119
  static #getCorsOrigin(requestOrigin, cb) {
package/lib/index.d.ts CHANGED
@@ -187,24 +187,13 @@ export class Lang {
187
187
  }
188
188
 
189
189
  export class DateTime {
190
- static now(): DateTime;
191
- static parse(date: string | Date): DateTime;
192
- static create(year: number, month: number, day: number, hour?: number, minute?: number, second?: number): DateTime;
193
- format(format: string): string;
194
- toDate(): Date;
195
- toISO(): string;
196
- addDays(days: number): DateTime;
197
- addMonths(months: number): DateTime;
198
- addYears(years: number): DateTime;
199
- subDays(days: number): DateTime;
200
- subMonths(months: number): DateTime;
201
- subYears(years: number): DateTime;
202
- diffInDays(other: DateTime): number;
203
- diffInMonths(other: DateTime): number;
204
- diffInYears(other: DateTime): number;
205
- isBefore(other: DateTime): boolean;
206
- isAfter(other: DateTime): boolean;
207
- isSame(other: DateTime): boolean;
190
+ static toSQL(timestamp?: number | null): string;
191
+ static getTime(sqlDateTime?: string | null): number;
192
+ static getDate(timestamp?: number | null, format?: string): string;
193
+ static addDays(days: number): string;
194
+ static addHours(hours: number): string;
195
+ static subDays(days: number): string;
196
+ static subHours(hours: number): string;
208
197
  }
209
198
 
210
199
  export class Str {
@@ -396,7 +385,6 @@ export class View {
396
385
  export const MigrationRunner: any;
397
386
  export const MigrationRepository: any;
398
387
  export const SeederRunner: any;
399
- export const SeederRepository: any;
400
388
  export const Checksum: any;
401
389
  export const DatabaseManager: any;
402
390
  export const SessionManager: any;
package/lib/index.js CHANGED
@@ -23,7 +23,6 @@ export { default as Checksum } from "./Database/Migration/Checksum.js";
23
23
 
24
24
  // Seeder
25
25
  export { default as SeederRunner } from "./Database/Seeder/SeederRunner.js";
26
- export { default as SeederRepository } from "./Database/Seeder/SeederRepository.js";
27
26
 
28
27
  // Authentication
29
28
  export { default as Auth } from "./Auth/Manager.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nitronjs/framework",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "NitronJS is a modern and extensible Node.js MVC framework built on Fastify. It focuses on clean architecture, modular structure, and developer productivity, offering built-in routing, middleware, configuration management, CLI tooling, and native React integration for scalable full-stack applications.",
5
5
  "bin": {
6
6
  "njs": "./cli/njs.js"
@@ -10,6 +10,8 @@
10
10
  "migrate:seed": "njs migrate --seed",
11
11
  "migrate:fresh": "njs migrate:fresh",
12
12
  "migrate:fresh:seed": "njs migrate:fresh --seed",
13
+ "migrate:status": "njs migrate:status",
14
+ "migrate:rollback": "njs migrate:rollback",
13
15
  "seed": "njs seed",
14
16
  "storage:link": "njs storage:link",
15
17
  "make:controller": "njs make:controller",
@@ -1,20 +0,0 @@
1
- import Schema from "../../Schema/Manager.js";
2
-
3
- class CreateSeedersTable {
4
-
5
- static async up() {
6
- await Schema.create("seeders", (table) => {
7
- table.id();
8
- table.string("name").unique();
9
- table.string("checksum", 64);
10
- table.timestamp("executed_at");
11
- });
12
- }
13
-
14
- static async down() {
15
- await Schema.dropIfExists("seeders");
16
- }
17
-
18
- }
19
-
20
- export default CreateSeedersTable;
@@ -1,45 +0,0 @@
1
- import DB from "../DB.js";
2
-
3
- class SeederRepository {
4
-
5
- static table = 'seeders';
6
-
7
- static async tableExists() {
8
- const [rows] = await DB.rawQuery(`SHOW TABLES LIKE '${this.table}'`);
9
- return rows.length > 0;
10
- }
11
-
12
- static async getExecuted() {
13
- if (!await this.tableExists()) return [];
14
- return await DB.table(this.table).orderBy("id", "asc").get();
15
- }
16
-
17
- static async getExecutedNames() {
18
- const seeders = await this.getExecuted();
19
- return new Set(seeders.map(s => s.name));
20
- }
21
-
22
- static async log(name, checksum) {
23
- await DB.table(this.table).insert({
24
- name,
25
- checksum,
26
- executed_at: new Date()
27
- });
28
- }
29
-
30
- static async find(name) {
31
- return await DB.table(this.table).where("name", name).first();
32
- }
33
-
34
- static async exists(name) {
35
- return (await this.find(name)) !== null;
36
- }
37
-
38
- static async getChecksum(name) {
39
- const seeder = await this.find(name);
40
- return seeder?.checksum || null;
41
- }
42
-
43
- }
44
-
45
- export default SeederRepository;