@3lineas/d1-orm 1.0.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/README.md ADDED
@@ -0,0 +1,207 @@
1
+ # D1 ORM
2
+
3
+ Un ORM ligero y potente dise帽ado espec铆ficamente para Cloudflare D1, inspirado en Eloquent de Laravel.
4
+
5
+ ## Caracter铆sticas
6
+
7
+ - 馃殌 **Ligero y R谩pido**: Optimizado para Cloudflare Workers.
8
+ - 馃洜 **Basado en Eloquent**: Sintaxis familiar para desarrolladores de Laravel.
9
+ - 馃摝 **TypeScript**: Tipado est谩tico completo para mayor seguridad.
10
+ - relations **Relaciones**: Soporte para `hasOne`, `hasMany` y `belongsTo`.
11
+ - 鈱笍 **CLI Integrado**: Herramientas para migraciones y generaci贸n de modelos.
12
+
13
+ ## Instalaci贸n
14
+
15
+ ```bash
16
+ npm install @3lineas/d1-orm
17
+ # O usando pnpm
18
+ pnpm add @3lineas/d1-orm
19
+ ```
20
+
21
+ ## Configuraci贸n Inicial
22
+
23
+ Para comenzar, debes configurar la conexi贸n a tu base de datos D1 en tu Worker. Normalmente esto se hace en el punto de entrada de tu aplicaci贸n (por ejemplo, `index.ts` o `server.ts`).
24
+
25
+ ```typescript
26
+ import { Database } from "@3lineas/d1-orm";
27
+
28
+ export default {
29
+ async fetch(request, env, ctx) {
30
+ // Inicializa la conexi贸n con tu base de datos D1 (asumiendo que se llama DB en wrangler.toml)
31
+ Database.setup(env.DB);
32
+
33
+ // ... tu c贸digo de manejo de rutas
34
+ },
35
+ };
36
+ ```
37
+
38
+ ## Definici贸n de Modelos
39
+
40
+ Los modelos se definen extendiendo la clase `Model`. Por defecto, el ORM asumir谩 que la tabla es el nombre de la clase en plural y min煤sculas (ej: `User` -> `users`).
41
+
42
+ ```typescript
43
+ import { Model } from "@3lineas/d1-orm";
44
+
45
+ export class User extends Model {
46
+ // Opcional: Definir tabla personalizada
47
+ // protected static table = 'my_users';
48
+
49
+ // Opcional: Definir atributos para tipado (recomendado)
50
+ declare id: number;
51
+ declare name: string;
52
+ declare email: string;
53
+ declare created_at: string;
54
+ }
55
+ ```
56
+
57
+ ## Operaciones CRUD
58
+
59
+ ### Crear
60
+
61
+ ```typescript
62
+ const user = await User.create({
63
+ name: "Juan Perez",
64
+ email: "juan@example.com",
65
+ });
66
+ ```
67
+
68
+ ### Leer
69
+
70
+ ```typescript
71
+ // Obtener todos los registros
72
+ const users = await User.all();
73
+
74
+ // Encontrar por ID
75
+ const user = await User.find(1);
76
+
77
+ // Consultas personalizadas
78
+ const activeUsers = await User.where("status", "=", "active")
79
+ .orderBy("created_at", "desc")
80
+ .get();
81
+
82
+ // Obtener el primer resultado
83
+ const firstUser = await User.where("email", "juan@example.com").first();
84
+ ```
85
+
86
+ ### Actualizar
87
+
88
+ ```typescript
89
+ const user = await User.find(1);
90
+ if (user) {
91
+ user.fill({ name: "Juan Actualizado" });
92
+ await user.save();
93
+ }
94
+
95
+ // O actualizar directamente desde una consulta
96
+ await User.where("status", "inactive").update({ status: "active" });
97
+ ```
98
+
99
+ ### Eliminar
100
+
101
+ ```typescript
102
+ const user = await User.find(1);
103
+ if (user) {
104
+ await user.delete();
105
+ }
106
+
107
+ // O eliminar directamente desde una consulta
108
+ await User.where("status", "banned").delete();
109
+ ```
110
+
111
+ ## Relaciones
112
+
113
+ El ORM soporta relaciones b谩sicas para estructurar tus datos.
114
+
115
+ ### Uno a Uno (HasOne)
116
+
117
+ ```typescript
118
+ // Modelo User
119
+ hasOne(Profile) {
120
+ return this.hasOne(Profile);
121
+ }
122
+
123
+ // Uso
124
+ const profile = await user.hasOne(Profile).get();
125
+ ```
126
+
127
+ ### Uno a Muchos (HasMany)
128
+
129
+ ```typescript
130
+ // Modelo User
131
+ posts() {
132
+ return this.hasMany(Post);
133
+ }
134
+
135
+ // Uso
136
+ const posts = await user.posts().get();
137
+ ```
138
+
139
+ ### Pertenece A (BelongsTo)
140
+
141
+ ```typescript
142
+ // Modelo Post
143
+ user() {
144
+ return this.belongsTo(User);
145
+ }
146
+
147
+ // Uso
148
+ const author = await post.user().get();
149
+ ```
150
+
151
+ ## CLI y Migraciones
152
+
153
+ El ORM incluye una CLI para facilitar la gesti贸n de la base de datos.
154
+
155
+ ### Scripts Recomendados
156
+
157
+ Agrega este script a tu `package.json` para facilitar el uso:
158
+
159
+ ```json
160
+ "scripts": {
161
+ "orm": "npx tsx src/cli/index.ts"
162
+ }
163
+ ```
164
+
165
+ ### Comandos Disponibles
166
+
167
+ #### Inicializar Proyecto
168
+
169
+ Crea las carpetas necesarias (`models`, `database/migrations`).
170
+
171
+ ```bash
172
+ pnpm orm init
173
+ ```
174
+
175
+ #### Crear un Modelo
176
+
177
+ Genera un archivo de modelo en `src/models`.
178
+
179
+ ```bash
180
+ pnpm orm make:model NombreModelo
181
+ ```
182
+
183
+ #### Crear una Migraci贸n
184
+
185
+ Genera un archivo de migraci贸n en `database/migrations`.
186
+
187
+ ```bash
188
+ pnpm orm make:migration create_users_table
189
+ ```
190
+
191
+ #### Ejecutar Migraciones
192
+
193
+ Ejecuta las migraciones pendientes.
194
+
195
+ ```bash
196
+ # Local (por defecto)
197
+ pnpm orm migrate
198
+
199
+ # Remoto (Producci贸n)
200
+ pnpm orm migrate -- --remote
201
+ ```
202
+
203
+ > **Nota:** Las migraciones locales requieren que `wrangler` est茅 configurado y funcionando correctamente en tu entorno.
204
+
205
+ ---
206
+
207
+ Desarrollado con 鉂わ笍 por **3Lineas**.
@@ -0,0 +1,12 @@
1
+ var __getOwnPropNames = Object.getOwnPropertyNames;
2
+ var __esm = (fn, res) => function __init() {
3
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
+ };
5
+ var __commonJS = (cb, mod) => function __require() {
6
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
7
+ };
8
+
9
+ export {
10
+ __esm,
11
+ __commonJS
12
+ };
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,250 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/cli/commands/init.ts
27
+ var fs = __toESM(require("fs"));
28
+ var path = __toESM(require("path"));
29
+ var readline = __toESM(require("readline"));
30
+ async function init() {
31
+ const rl = readline.createInterface({
32
+ input: process.stdin,
33
+ output: process.stdout
34
+ });
35
+ const question = (query) => {
36
+ return new Promise((resolve) => {
37
+ rl.question(query, resolve);
38
+ });
39
+ };
40
+ console.log("Initializing D1 ORM...");
41
+ const defaultModelsPath = "src/models";
42
+ const userModelsPath = await question(
43
+ `Where would you like to install your models? (default: ${defaultModelsPath}): `
44
+ ) || defaultModelsPath;
45
+ rl.close();
46
+ const folders = [userModelsPath, "database/migrations", "database/seeders"];
47
+ folders.forEach((folder) => {
48
+ const fullPath = path.join(process.cwd(), folder);
49
+ if (!fs.existsSync(fullPath)) {
50
+ fs.mkdirSync(fullPath, { recursive: true });
51
+ console.log(`Created directory: ${folder}`);
52
+ } else {
53
+ console.log(`Directory already exists: ${folder}`);
54
+ }
55
+ });
56
+ const userModelContent = `import { Model } from 'd1-orm';
57
+
58
+ export class User extends Model {
59
+ // protected static table = 'users';
60
+
61
+ declare id: number;
62
+ declare name: string;
63
+ declare email: string;
64
+ declare password?: string;
65
+ declare created_at: string;
66
+ declare updated_at: string;
67
+ }
68
+ `;
69
+ const userModelPath = path.join(process.cwd(), userModelsPath, "User.ts");
70
+ if (!fs.existsSync(userModelPath)) {
71
+ fs.writeFileSync(userModelPath, userModelContent);
72
+ console.log(`Created model: ${userModelPath}`);
73
+ }
74
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").split(".")[0].replace("T", "_");
75
+ const migrationName = `${timestamp}_create_users_table.ts`;
76
+ const migrationContent = `import { Blueprint, Schema } from 'd1-orm';
77
+
78
+ export const up = async () => {
79
+ return Schema.create('users', (table: Blueprint) => {
80
+ table.id();
81
+ table.string('name');
82
+ table.string('email').unique();
83
+ table.string('password').nullable();
84
+ table.timestamps();
85
+ });
86
+ };
87
+
88
+ export const down = async () => {
89
+ return Schema.dropIfExists('users');
90
+ };
91
+ `;
92
+ const migrationPath = path.join(
93
+ process.cwd(),
94
+ "database/migrations",
95
+ migrationName
96
+ );
97
+ if (!fs.existsSync(migrationPath)) {
98
+ fs.writeFileSync(migrationPath, migrationContent);
99
+ console.log(`Created migration: ${migrationPath}`);
100
+ }
101
+ const seederContent = `import { User } from '${path.relative(
102
+ path.join(process.cwd(), "database/seeders"),
103
+ path.join(process.cwd(), userModelsPath, "User")
104
+ ).replace(/\\/g, "/")}';
105
+
106
+ export const seed = async () => {
107
+ await User.create({
108
+ name: 'Juan Perez',
109
+ email: 'juan@perez.com',
110
+ password: 'password'
111
+ });
112
+ };
113
+ `;
114
+ const seederPath = path.join(
115
+ process.cwd(),
116
+ "database/seeders",
117
+ "UserSeeder.ts"
118
+ );
119
+ if (!fs.existsSync(seederPath)) {
120
+ fs.writeFileSync(seederPath, seederContent);
121
+ console.log(`Created seeder: ${seederPath}`);
122
+ }
123
+ }
124
+
125
+ // src/cli/commands/make-model.ts
126
+ var fs2 = __toESM(require("fs"));
127
+ var path2 = __toESM(require("path"));
128
+ function makeModel(name) {
129
+ const filename = `${name}.ts`;
130
+ const targetPath = path2.join(process.cwd(), "models", filename);
131
+ const template = `import { Model } from 'd1-orm';
132
+
133
+ export class ${name} extends Model {
134
+ // protected static table = '${name.toLowerCase()}s';
135
+
136
+ // Define attributes explicitly for type safety if desired
137
+ // declare id: number;
138
+ // declare created_at: string;
139
+ // declare updated_at: string;
140
+ }
141
+ `;
142
+ if (fs2.existsSync(targetPath)) {
143
+ console.error(`Model ${filename} already exists.`);
144
+ process.exit(1);
145
+ }
146
+ fs2.writeFileSync(targetPath, template);
147
+ console.log(`Created model: models/${filename}`);
148
+ }
149
+
150
+ // src/cli/commands/make-migration.ts
151
+ var fs3 = __toESM(require("fs"));
152
+ var path3 = __toESM(require("path"));
153
+ function makeMigration(name) {
154
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").split(".")[0].replace("T", "_");
155
+ const filename = `${timestamp}_${name}.ts`;
156
+ const targetPath = path3.join(process.cwd(), "database/migrations", filename);
157
+ const template = `import { Blueprint, Schema } from 'd1-orm';
158
+
159
+ export const up = async () => {
160
+ return Schema.create('${name}', (table: Blueprint) => {
161
+ table.id();
162
+ table.timestamps();
163
+ });
164
+ };
165
+
166
+ export const down = async () => {
167
+ return Schema.dropIfExists('${name}');
168
+ };
169
+ `;
170
+ if (fs3.existsSync(targetPath)) {
171
+ console.error(`Migration ${filename} already exists.`);
172
+ process.exit(1);
173
+ }
174
+ fs3.writeFileSync(targetPath, template);
175
+ console.log(`Created migration: database/migrations/${filename}`);
176
+ }
177
+
178
+ // src/cli/commands/migrate.ts
179
+ var fs4 = __toESM(require("fs"));
180
+ var path4 = __toESM(require("path"));
181
+ var import_child_process = require("child_process");
182
+ async function migrate(args2) {
183
+ console.log("Running migrations...");
184
+ const migrationsDir = path4.join(process.cwd(), "database/migrations");
185
+ if (!fs4.existsSync(migrationsDir)) {
186
+ console.log("No migrations directory found.");
187
+ return;
188
+ }
189
+ const files = fs4.readdirSync(migrationsDir).filter((f) => f.endsWith(".ts") || f.endsWith(".js")).sort();
190
+ for (const file of files) {
191
+ console.log(`Processing ${file}...`);
192
+ const filePath = path4.join(migrationsDir, file);
193
+ try {
194
+ const migration = await import(filePath);
195
+ if (migration.up) {
196
+ const sql = await migration.up();
197
+ if (sql) {
198
+ console.log(`Executing SQL: ${sql}`);
199
+ const isRemote = args2.includes("--remote");
200
+ const dbName = "DB";
201
+ const command2 = isRemote ? "--remote" : "--local";
202
+ try {
203
+ const execCmd = `npx wrangler d1 execute ${dbName} --command "${sql.replace(/"/g, '\\"')}" ${command2}`;
204
+ console.log(`Running: ${execCmd}`);
205
+ (0, import_child_process.execSync)(execCmd, { stdio: "inherit" });
206
+ } catch (e) {
207
+ console.error(`Failed to execute migration ${file}.`);
208
+ throw e;
209
+ }
210
+ }
211
+ }
212
+ } catch (error) {
213
+ console.error(`Error processing migration ${file}:`, error);
214
+ }
215
+ }
216
+ }
217
+
218
+ // src/cli/index.ts
219
+ var args = process.argv.slice(2);
220
+ var command = args[0];
221
+ var param = args[1];
222
+ switch (command) {
223
+ case "init":
224
+ init();
225
+ break;
226
+ case "make:model":
227
+ if (!param) {
228
+ console.error("Usage: d1-orm make:model <Name>");
229
+ process.exit(1);
230
+ }
231
+ makeModel(param);
232
+ break;
233
+ case "make:migration":
234
+ if (!param) {
235
+ console.error("Usage: d1-orm make:migration <Name>");
236
+ process.exit(1);
237
+ }
238
+ makeMigration(param);
239
+ break;
240
+ case "migrate":
241
+ const isLocal = args.includes("--local");
242
+ const isRemote = args.includes("--remote");
243
+ migrate(args);
244
+ break;
245
+ default:
246
+ console.log(
247
+ "Available commands: init, make:model, make:migration, migrate"
248
+ );
249
+ break;
250
+ }