@3lineas/d1-orm 1.0.3 → 1.0.5

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/dist/index.mjs CHANGED
@@ -2,30 +2,73 @@ import "./chunk-X6BYQHVC.mjs";
2
2
 
3
3
  // src/core/connection.ts
4
4
  var Connection = class {
5
+ /**
6
+ * The underlying D1Database instance.
7
+ */
5
8
  db;
9
+ /**
10
+ * Create a new Connection instance.
11
+ *
12
+ * @param database - The D1Database instance.
13
+ */
6
14
  constructor(database) {
7
15
  this.db = database;
8
16
  }
17
+ /**
18
+ * Execute a SELECT statement.
19
+ *
20
+ * @param query - The SQL query string.
21
+ * @param bindings - The parameter bindings.
22
+ * @returns A promise that resolves to an array of results.
23
+ */
9
24
  async select(query, bindings = []) {
10
25
  const stmt = this.db.prepare(query).bind(...bindings);
11
26
  const result = await stmt.all();
12
27
  return result.results || [];
13
28
  }
29
+ /**
30
+ * Execute an INSERT statement.
31
+ *
32
+ * @param query - The SQL query string.
33
+ * @param bindings - The parameter bindings.
34
+ * @returns A promise that resolves to true on success.
35
+ */
14
36
  async insert(query, bindings = []) {
15
37
  const stmt = this.db.prepare(query).bind(...bindings);
16
38
  const result = await stmt.run();
17
39
  return result.success;
18
40
  }
41
+ /**
42
+ * Execute an UPDATE statement.
43
+ *
44
+ * @param query - The SQL query string.
45
+ * @param bindings - The parameter bindings.
46
+ * @returns A promise that resolves to true on success.
47
+ */
19
48
  async update(query, bindings = []) {
20
49
  const stmt = this.db.prepare(query).bind(...bindings);
21
50
  const result = await stmt.run();
22
51
  return result.success;
23
52
  }
53
+ /**
54
+ * Execute a DELETE statement.
55
+ *
56
+ * @param query - The SQL query string.
57
+ * @param bindings - The parameter bindings.
58
+ * @returns A promise that resolves to true on success.
59
+ */
24
60
  async delete(query, bindings = []) {
25
61
  const stmt = this.db.prepare(query).bind(...bindings);
26
62
  const result = await stmt.run();
27
63
  return result.success;
28
64
  }
65
+ /**
66
+ * Execute an arbitrary SQL statement.
67
+ *
68
+ * @param query - The SQL query string.
69
+ * @param bindings - The parameter bindings.
70
+ * @returns A promise that resolves to true on success.
71
+ */
29
72
  async statement(query, bindings = []) {
30
73
  const stmt = this.db.prepare(query).bind(...bindings);
31
74
  const result = await stmt.run();
@@ -35,22 +78,66 @@ var Connection = class {
35
78
 
36
79
  // src/core/query-builder.ts
37
80
  var QueryBuilder = class {
81
+ /**
82
+ * The database connection.
83
+ */
38
84
  connection;
85
+ /**
86
+ * The table to query.
87
+ */
39
88
  table;
89
+ /**
90
+ * The columns to select.
91
+ */
40
92
  columns = ["*"];
93
+ /**
94
+ * The where constraints for the query.
95
+ */
41
96
  wheres = [];
97
+ /**
98
+ * The bindings for the query.
99
+ */
42
100
  bindings = [];
101
+ /**
102
+ * The orderings for the query.
103
+ */
43
104
  orders = [];
105
+ /**
106
+ * The maximum number of records to return.
107
+ */
44
108
  limitValue = null;
109
+ /**
110
+ * The number of records to skip.
111
+ */
45
112
  offsetValue = null;
113
+ /**
114
+ * Create a new QueryBuilder instance.
115
+ *
116
+ * @param connection - The connection instance.
117
+ * @param table - The table name.
118
+ */
46
119
  constructor(connection, table) {
47
120
  this.connection = connection;
48
121
  this.table = table;
49
122
  }
123
+ /**
124
+ * Add a SELECT clause to the query.
125
+ *
126
+ * @param columns - The columns to select.
127
+ * @returns The QueryBuilder instance.
128
+ */
50
129
  select(...columns) {
51
130
  this.columns = columns.length > 0 ? columns : ["*"];
52
131
  return this;
53
132
  }
133
+ /**
134
+ * Add a basic WHERE clause to the query.
135
+ *
136
+ * @param column - The column name.
137
+ * @param operator - The operator or value.
138
+ * @param value - The value if operator is provided.
139
+ * @returns The QueryBuilder instance.
140
+ */
54
141
  where(column, operator, value) {
55
142
  if (value === void 0) {
56
143
  value = operator;
@@ -60,6 +147,14 @@ var QueryBuilder = class {
60
147
  this.bindings.push(value);
61
148
  return this;
62
149
  }
150
+ /**
151
+ * Add an OR WHERE clause to the query.
152
+ *
153
+ * @param column - The column name.
154
+ * @param operator - The operator or value.
155
+ * @param value - The value if operator is provided.
156
+ * @returns The QueryBuilder instance.
157
+ */
63
158
  orWhere(column, operator, value) {
64
159
  if (value === void 0) {
65
160
  value = operator;
@@ -69,18 +164,42 @@ var QueryBuilder = class {
69
164
  this.bindings.push(value);
70
165
  return this;
71
166
  }
167
+ /**
168
+ * Add an ORDER BY clause to the query.
169
+ *
170
+ * @param column - The column name.
171
+ * @param direction - The direction of the order.
172
+ * @returns The QueryBuilder instance.
173
+ */
72
174
  orderBy(column, direction = "asc") {
73
175
  this.orders.push(`${column} ${direction.toUpperCase()}`);
74
176
  return this;
75
177
  }
178
+ /**
179
+ * Add a LIMIT clause to the query.
180
+ *
181
+ * @param limit - The limit value.
182
+ * @returns The QueryBuilder instance.
183
+ */
76
184
  limit(limit) {
77
185
  this.limitValue = limit;
78
186
  return this;
79
187
  }
188
+ /**
189
+ * Add an OFFSET clause to the query.
190
+ *
191
+ * @param offset - The offset value.
192
+ * @returns The QueryBuilder instance.
193
+ */
80
194
  offset(offset) {
81
195
  this.offsetValue = offset;
82
196
  return this;
83
197
  }
198
+ /**
199
+ * Get the SQL representation of the query.
200
+ *
201
+ * @returns An object containing the SQL string and the bindings.
202
+ */
84
203
  toSql() {
85
204
  let sql = `SELECT ${this.columns.join(", ")} FROM ${this.table}`;
86
205
  if (this.wheres.length > 0) {
@@ -101,15 +220,31 @@ var QueryBuilder = class {
101
220
  }
102
221
  return { sql, bindings: this.bindings };
103
222
  }
223
+ /**
224
+ * Execute the query and get the results.
225
+ *
226
+ * @returns A promise that resolves to an array of records.
227
+ */
104
228
  async get() {
105
229
  const { sql, bindings } = this.toSql();
106
230
  return this.connection.select(sql, bindings);
107
231
  }
232
+ /**
233
+ * Execute the query and get the first result.
234
+ *
235
+ * @returns A promise that resolves to the first record or null.
236
+ */
108
237
  async first() {
109
238
  this.limit(1);
110
239
  const results = await this.get();
111
240
  return results.length > 0 ? results[0] : null;
112
241
  }
242
+ /**
243
+ * Insert a new record into the database.
244
+ *
245
+ * @param data - The data to insert.
246
+ * @returns A promise that resolves to true on success.
247
+ */
113
248
  async insert(data) {
114
249
  const columns = Object.keys(data);
115
250
  const values = Object.values(data);
@@ -117,6 +252,12 @@ var QueryBuilder = class {
117
252
  const sql = `INSERT INTO ${this.table} (${columns.join(", ")}) VALUES (${placeholders})`;
118
253
  return this.connection.insert(sql, values);
119
254
  }
255
+ /**
256
+ * Update records in the database.
257
+ *
258
+ * @param data - The data to update.
259
+ * @returns A promise that resolves to true on success.
260
+ */
120
261
  async update(data) {
121
262
  const columns = Object.keys(data);
122
263
  const values = Object.values(data);
@@ -128,10 +269,14 @@ var QueryBuilder = class {
128
269
  return w.startsWith("OR") ? w : `AND ${w}`;
129
270
  });
130
271
  sql += ` WHERE ${constraints.join(" ")}`;
131
- } else {
132
272
  }
133
273
  return this.connection.update(sql, [...values, ...this.bindings]);
134
274
  }
275
+ /**
276
+ * Delete records from the database.
277
+ *
278
+ * @returns A promise that resolves to true on success.
279
+ */
135
280
  async delete() {
136
281
  let sql = `DELETE FROM ${this.table}`;
137
282
  if (this.wheres.length > 0) {
@@ -147,11 +292,26 @@ var QueryBuilder = class {
147
292
 
148
293
  // src/core/model-query-builder.ts
149
294
  var ModelQueryBuilder = class extends QueryBuilder {
295
+ /**
296
+ * The class of the model being queried.
297
+ */
150
298
  modelClass;
299
+ /**
300
+ * Create a new ModelQueryBuilder instance.
301
+ *
302
+ * @param connection - The database connection.
303
+ * @param table - The table name.
304
+ * @param modelClass - The class constructor for the model.
305
+ */
151
306
  constructor(connection, table, modelClass) {
152
307
  super(connection, table);
153
308
  this.modelClass = modelClass;
154
309
  }
310
+ /**
311
+ * Execute the query and return model instances.
312
+ *
313
+ * @returns A promise that resolves to an array of model instances.
314
+ */
155
315
  async get() {
156
316
  const { sql, bindings } = this.toSql();
157
317
  const results = await this.connection.select(sql, bindings);
@@ -162,11 +322,21 @@ var ModelQueryBuilder = class extends QueryBuilder {
162
322
  return instance;
163
323
  });
164
324
  }
325
+ /**
326
+ * Execute the query and return the first matching model instance.
327
+ *
328
+ * @returns A promise that resolves to the model instance or null.
329
+ */
165
330
  async first() {
166
331
  this.limit(1);
167
332
  const results = await this.get();
168
333
  return results.length > 0 ? results[0] : null;
169
334
  }
335
+ /**
336
+ * Get the underlying model class.
337
+ *
338
+ * @returns The model class constructor.
339
+ */
170
340
  getModel() {
171
341
  return this.modelClass;
172
342
  }
@@ -174,14 +344,36 @@ var ModelQueryBuilder = class extends QueryBuilder {
174
344
 
175
345
  // src/core/database.ts
176
346
  var Database = class _Database {
347
+ /**
348
+ * The singleton instance of the Database.
349
+ */
177
350
  static instance;
351
+ /**
352
+ * The active database connection.
353
+ */
178
354
  connection;
355
+ /**
356
+ * Private constructor to enforce singleton pattern.
357
+ *
358
+ * @param d1 - The D1Database instance from Cloudflare.
359
+ */
179
360
  constructor(d1) {
180
361
  this.connection = new Connection(d1);
181
362
  }
363
+ /**
364
+ * Setup the database connection.
365
+ *
366
+ * @param d1 - The D1Database instance from Cloudflare environment (env.DB).
367
+ */
182
368
  static setup(d1) {
183
369
  _Database.instance = new _Database(d1);
184
370
  }
371
+ /**
372
+ * Get the singleton Database instance.
373
+ *
374
+ * @throws Error if setup() has not been called.
375
+ * @returns The Database instance.
376
+ */
185
377
  static getInstance() {
186
378
  if (!_Database.instance) {
187
379
  throw new Error(
@@ -266,43 +458,106 @@ var BelongsTo = class extends Relationship {
266
458
 
267
459
  // src/models/model.ts
268
460
  var Model = class {
461
+ /**
462
+ * The table associated with the model.
463
+ */
269
464
  static table;
465
+ /**
466
+ * Resolver function for the database connection.
467
+ */
270
468
  static connectionResolver;
469
+ /**
470
+ * The model's attributes.
471
+ */
271
472
  attributes = {};
473
+ /**
474
+ * The attributes that are mass assignable.
475
+ */
272
476
  fillable = [];
477
+ /**
478
+ * The attributes that should be hidden for serialization.
479
+ */
273
480
  hidden = [];
481
+ /**
482
+ * Indicates if the model exists in the database.
483
+ */
274
484
  exists = false;
485
+ /**
486
+ * The model's original attribute values.
487
+ */
275
488
  original = {};
489
+ /**
490
+ * Create a new Model instance.
491
+ *
492
+ * @param attributes - Initial attributes for the model.
493
+ */
276
494
  constructor(attributes = {}) {
277
495
  this.fill(attributes);
278
496
  }
279
- // Static Query Builder
497
+ /**
498
+ * Begin querying the model.
499
+ *
500
+ * @returns A new ModelQueryBuilder instance.
501
+ */
280
502
  static query() {
281
503
  const instance = new this();
282
504
  const table = instance.getTable();
283
505
  const connection = Database.getInstance().connection;
284
506
  return new ModelQueryBuilder(connection, table, this);
285
507
  }
508
+ /**
509
+ * Start a query on a specific connection (currently uses default).
510
+ *
511
+ * @param connectionName - The name of the connection.
512
+ * @returns A new ModelQueryBuilder instance.
513
+ */
286
514
  static on(connectionName) {
287
515
  return this.query();
288
516
  }
517
+ /**
518
+ * Retrieve all records for the model.
519
+ *
520
+ * @returns A promise that resolves to an array of model instances.
521
+ */
289
522
  static async all() {
290
523
  return this.query().get();
291
524
  }
525
+ /**
526
+ * Find a model by its primary key.
527
+ *
528
+ * @param id - The ID of the record.
529
+ * @returns A promise that resolves to the model instance or null if not found.
530
+ */
292
531
  static async find(id) {
293
532
  return this.query().where("id", "=", id).first();
294
533
  }
534
+ /**
535
+ * Save a new model and return the instance.
536
+ *
537
+ * @param attributes - Attributes for the new record.
538
+ * @returns A promise that resolves to the created model instance.
539
+ */
295
540
  static async create(attributes) {
296
541
  const instance = new this();
297
542
  instance.fill(attributes);
298
543
  await instance.save();
299
544
  return instance;
300
545
  }
301
- // Instance Methods
546
+ /**
547
+ * Fill the model with an array of attributes.
548
+ *
549
+ * @param attributes - Attributes to fill.
550
+ * @returns The model instance.
551
+ */
302
552
  fill(attributes) {
303
553
  Object.assign(this.attributes, attributes);
304
554
  return this;
305
555
  }
556
+ /**
557
+ * Save the model to the database.
558
+ *
559
+ * @returns A promise that resolves to true on success, false otherwise.
560
+ */
306
561
  async save() {
307
562
  const query = this.constructor.query();
308
563
  if (this.exists) {
@@ -322,6 +577,11 @@ var Model = class {
322
577
  return false;
323
578
  }
324
579
  }
580
+ /**
581
+ * Delete the model from the database.
582
+ *
583
+ * @returns A promise that resolves to true on success, false otherwise.
584
+ */
325
585
  async delete() {
326
586
  if (!this.exists) return false;
327
587
  const query = this.constructor.query();
@@ -330,12 +590,22 @@ var Model = class {
330
590
  this.exists = false;
331
591
  return true;
332
592
  }
593
+ /**
594
+ * Get the table associated with the model.
595
+ *
596
+ * @returns The table name.
597
+ */
333
598
  getTable() {
334
599
  if (this.constructor.table) {
335
600
  return this.constructor.table;
336
601
  }
337
602
  return this.constructor.name.toLowerCase() + "s";
338
603
  }
604
+ /**
605
+ * Get the attributes that have been changed since the last sync.
606
+ *
607
+ * @returns A record of dirty attributes.
608
+ */
339
609
  getDirty() {
340
610
  const dirty = {};
341
611
  for (const key in this.attributes) {
@@ -345,37 +615,122 @@ var Model = class {
345
615
  }
346
616
  return dirty;
347
617
  }
618
+ /**
619
+ * Sync the original attributes with the current attributes.
620
+ */
348
621
  syncOriginal() {
349
622
  this.original = { ...this.attributes };
350
623
  }
351
- // Relationships
624
+ /**
625
+ * Define a one-to-one relationship.
626
+ *
627
+ * @param related - The related model class.
628
+ * @param foreignKey - The foreign key on the related table.
629
+ * @param localKey - The local key on the current table.
630
+ * @returns A HasOne relationship instance.
631
+ */
352
632
  hasOne(related, foreignKey, localKey) {
353
633
  const instance = new related();
354
634
  const fk = foreignKey || this.getForeignKey();
355
635
  const lk = localKey || "id";
356
636
  return new HasOne(instance.newQuery(), this, fk, lk);
357
637
  }
638
+ /**
639
+ * Define a one-to-many relationship.
640
+ *
641
+ * @param related - The related model class.
642
+ * @param foreignKey - The foreign key on the related table.
643
+ * @param localKey - The local key on the current table.
644
+ * @returns A HasMany relationship instance.
645
+ */
358
646
  hasMany(related, foreignKey, localKey) {
359
647
  const instance = new related();
360
648
  const fk = foreignKey || this.getForeignKey();
361
649
  const lk = localKey || "id";
362
650
  return new HasMany(instance.newQuery(), this, fk, lk);
363
651
  }
652
+ /**
653
+ * Define an inverse one-to-one or many relationship.
654
+ *
655
+ * @param related - The related model class.
656
+ * @param foreignKey - The foreign key on the current table.
657
+ * @param ownerKey - The owner key on the related table.
658
+ * @returns A BelongsTo relationship instance.
659
+ */
364
660
  belongsTo(related, foreignKey, ownerKey) {
365
661
  const instance = new related();
366
662
  const fk = foreignKey || instance.getForeignKey();
367
663
  const ok = ownerKey || "id";
368
664
  return new BelongsTo(instance.newQuery(), this, fk, ok);
369
665
  }
666
+ /**
667
+ * Get the default foreign key name for the model.
668
+ *
669
+ * @returns The foreign key name.
670
+ */
370
671
  getForeignKey() {
371
672
  return this.getTable().slice(0, -1) + "_id";
372
673
  }
674
+ /**
675
+ * Get a new query builder for the model's table.
676
+ *
677
+ * @returns A ModelQueryBuilder instance.
678
+ */
373
679
  newQuery() {
374
680
  return this.constructor.query();
375
681
  }
376
682
  };
377
683
 
378
684
  // src/database/blueprint.ts
685
+ var Column = class {
686
+ name;
687
+ type;
688
+ isNullable = false;
689
+ isUnique = false;
690
+ defaultValue = null;
691
+ constructor(name, type) {
692
+ this.name = name;
693
+ this.type = type;
694
+ }
695
+ /**
696
+ * Set the column as nullable.
697
+ */
698
+ nullable() {
699
+ this.isNullable = true;
700
+ return this;
701
+ }
702
+ /**
703
+ * Set the column as unique.
704
+ */
705
+ unique() {
706
+ this.isUnique = true;
707
+ return this;
708
+ }
709
+ /**
710
+ * Set the default value for the column.
711
+ */
712
+ default(value) {
713
+ this.defaultValue = value;
714
+ return this;
715
+ }
716
+ /**
717
+ * Convert the column definition to SQL.
718
+ */
719
+ toSql() {
720
+ let sql = `${this.name} ${this.type}`;
721
+ if (this.isUnique) {
722
+ sql += " UNIQUE";
723
+ }
724
+ if (!this.isNullable) {
725
+ sql += " NOT NULL";
726
+ }
727
+ if (this.defaultValue !== null) {
728
+ const formattedValue = typeof this.defaultValue === "string" ? `'${this.defaultValue}'` : this.defaultValue;
729
+ sql += ` DEFAULT ${formattedValue}`;
730
+ }
731
+ return sql;
732
+ }
733
+ };
379
734
  var Blueprint = class {
380
735
  table;
381
736
  columns = [];
@@ -383,30 +738,55 @@ var Blueprint = class {
383
738
  constructor(table) {
384
739
  this.table = table;
385
740
  }
741
+ /**
742
+ * Add an auto-incrementing ID column.
743
+ */
386
744
  id() {
387
745
  this.columns.push("id INTEGER PRIMARY KEY AUTOINCREMENT");
388
746
  return this;
389
747
  }
390
- string(column, length) {
391
- this.columns.push(`${column} TEXT`);
392
- return this;
393
- }
748
+ /**
749
+ * Add a string (TEXT) column.
750
+ */
751
+ string(column) {
752
+ const col = new Column(column, "TEXT");
753
+ this.columns.push(col);
754
+ return col;
755
+ }
756
+ /**
757
+ * Add an integer column.
758
+ */
394
759
  integer(column) {
395
- this.columns.push(`${column} INTEGER`);
396
- return this;
760
+ const col = new Column(column, "INTEGER");
761
+ this.columns.push(col);
762
+ return col;
397
763
  }
764
+ /**
765
+ * Add a boolean column.
766
+ */
398
767
  boolean(column) {
399
- this.columns.push(`${column} BOOLEAN`);
400
- return this;
768
+ const col = new Column(column, "BOOLEAN");
769
+ this.columns.push(col);
770
+ return col;
401
771
  }
772
+ /**
773
+ * Add created_at and updated_at timestamp columns.
774
+ */
402
775
  timestamps() {
403
776
  this.columns.push("created_at DATETIME DEFAULT CURRENT_TIMESTAMP");
404
777
  this.columns.push("updated_at DATETIME DEFAULT CURRENT_TIMESTAMP");
405
778
  return this;
406
779
  }
780
+ /**
781
+ * Convert the blueprint to a set of SQL statements.
782
+ */
407
783
  toSql() {
408
784
  if (this.columns.length > 0) {
409
- const cols = this.columns.join(", ");
785
+ const colDefinitions = this.columns.map((col) => {
786
+ if (typeof col === "string") return col;
787
+ return col.toSql();
788
+ });
789
+ const cols = colDefinitions.join(", ");
410
790
  return [`CREATE TABLE IF NOT EXISTS ${this.table} (${cols})`];
411
791
  }
412
792
  return this.commands;
@@ -427,6 +807,7 @@ var Schema = class {
427
807
  export {
428
808
  BelongsTo,
429
809
  Blueprint,
810
+ Column,
430
811
  Connection,
431
812
  Database,
432
813
  HasMany,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@3lineas/d1-orm",
3
- "version": "1.0.3",
4
- "description": "",
3
+ "version": "1.0.5",
4
+ "description": "A lightweight and powerful ORM for Cloudflare D1, inspired by Laravel Eloquent.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
7
7
  "bin": {
@@ -13,8 +13,7 @@
13
13
  "scripts": {
14
14
  "build": "tsup src/index.ts src/cli/index.ts --format cjs,esm --dts --clean",
15
15
  "orm": "npx tsx src/cli/index.ts",
16
- "test": "echo \"Error: no test specified\" && exit 1",
17
- "postinstall": "node scripts/postinstall.js"
16
+ "test": "echo \"Error: no test specified\" && exit 1"
18
17
  },
19
18
  "keywords": [],
20
19
  "author": "",
@@ -34,5 +33,8 @@
34
33
  "sharp",
35
34
  "workerd"
36
35
  ]
36
+ },
37
+ "dependencies": {
38
+ "@clack/prompts": "^0.11.0"
37
39
  }
38
40
  }