mevn-orm 3.0.0 → 3.2.1

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2021 StanoJs
3
+ Copyright (c) 2021 Stanley Masinde
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,29 +1,63 @@
1
- # Mevn-orm
2
- ![npm](https://img.shields.io/npm/v/mevn-orm?style=for-the-badge)
3
- [![GitHub license](https://img.shields.io/github/license/stanleymasinde/mevn-orm?style=for-the-badge)](https://github.com/StanleyMasinde/mevn-orm/blob/master/LICENSE)
4
- ![GitHub issues](https://img.shields.io/github/issues/stanleymasinde/mevn-orm?style=for-the-badge)
1
+ # Mevn ORM
2
+
3
+ ![npm](https://img.shields.io/npm/v/mevn-orm?style=for-the-badge) [![GitHub license](https://img.shields.io/github/license/stanleymasinde/mevn-orm?style=for-the-badge)](https://github.com/StanleyMasinde/mevn-orm/blob/master/LICENSE) ![GitHub issues](https://img.shields.io/github/issues/stanleymasinde/mevn-orm?style=for-the-badge)
4
+
5
+ ### Do not use This
6
+ When I started this, I had so much intertest in the JS ecosytem and ORMs. I still have some intertest in javascript
7
+ bit not ORMs.
8
+
9
+ **Mevn ORM** is a lightweight ORM for Express.js and MySQL that provides a clean, fluent interface for building queries and managing models.
10
+ It is under maintenance mode and receives security updates. Development is paused, but the core ORM functionality is complete and usable.
11
+
12
+ ## Getting Started
5
13
 
6
14
  ```javascript
7
- const { Model } = require('mevn-orm')
8
-
9
- class User extends Model {}
10
-
11
- let columns = {
12
- name: 'John Doe',
13
- email: 'john@example.com',
14
- password: secret // remember to hash the password
15
- }
16
- User()
17
- .create(columns)
18
- .then(created => {
19
- // Do something after the creation
20
- })
21
- .catch(err => {
22
- // Handle the error
23
- })
24
-
25
- // With aync await
26
- const userId = await User.create(columns)
15
+ const { Model } = require('mevn-orm')
16
+
17
+ class User extends Model {}
18
+
19
+ const user = await User.create({
20
+ name: 'John Doe',
21
+ email: 'john@example.com',
22
+ password: 'secret' // hash before storing
23
+ })
24
+ ````
25
+
26
+ ## Features
27
+
28
+ * Model-based abstraction
29
+ * Create, Read, Update, Delete support
30
+ * Chainable query builder (`where`, `first`, `all`)
31
+ * Timestamps
32
+ * Soft deletes
33
+ * SQLite support for testing
34
+ * Knex-based migration support
35
+
36
+ ## ORM Basics Checklist
37
+
38
+ * [x] `Model` base class
39
+ * [x] `.create`, `.find`, `.update`, `.delete`
40
+ * [x] `.where()`, `.first()`, `.all()` chaining
41
+ * [x] Table name inference
42
+ * [x] Timestamps
43
+ * [x] Soft deletes
44
+ * [x] Basic relationship hooks (`hasOne`, `hasMany`, `belongsTo`)
45
+ * [x] Raw queries
46
+ * [x] Knex passthrough
47
+ * [x] SQLite3 test DB
48
+ * [x] Uses `mysql2` for production
49
+ * [x] `dotenv` support
50
+
51
+ ## Testing
52
+
53
+ This project uses [Vitest](https://vitest.dev/) for testing.
54
+
55
+ ```bash
56
+ npm install
57
+ npm run migrate
58
+ npm run test
27
59
  ```
28
60
 
29
- _Still under development hence not ready for production_
61
+ ## License
62
+
63
+ [MIT](./LICENSE)
package/changelog.md ADDED
@@ -0,0 +1,135 @@
1
+ ## [unreleased]
2
+
3
+ ### 💼 Other
4
+
5
+ - Use Node 16 until I figure out what is going on
6
+ ## [3.2.0] - 2025-09-29
7
+
8
+ ### 🐛 Bug Fixes
9
+
10
+ - *(deps)* Bump actions/checkout from 4 to 5
11
+ - *(deps)* Bump actions/setup-node from 4 to 5
12
+
13
+ ### 💼 Other
14
+
15
+ - Support the latest versions of node
16
+ - Only use Node 20 for tests
17
+
18
+ ### ⚙️ Miscellaneous Tasks
19
+
20
+ - Upgrade deps
21
+ ## [3.0.0] - 2025-07-02
22
+
23
+ ### 🐛 Bug Fixes
24
+
25
+ - *(deps)* Bump actions/checkout from 3 to 4
26
+ - *(deps)* Bump actions/setup-node from 3 to 4
27
+
28
+ ### ⚙️ Miscellaneous Tasks
29
+
30
+ - Upgrade deps
31
+ ## [2.4.7-1] - 2023-03-08
32
+
33
+ ### ⚙️ Miscellaneous Tasks
34
+
35
+ - Update the default peer dep
36
+ ## [2.4.6] - 2023-03-08
37
+
38
+ ### ⚙️ Miscellaneous Tasks
39
+
40
+ - Add auto publish to npm
41
+ ## [2.4.5] - 2023-03-06
42
+
43
+ ### 💼 Other
44
+
45
+ - Update npm dependencies
46
+
47
+ ### ⚙️ Miscellaneous Tasks
48
+
49
+ - *(ci)* Drop support for node 14
50
+ - *(version)* Release patch version 2.4.5
51
+ ## [2.4.4] - 2023-01-04
52
+
53
+ ### ⚙️ Miscellaneous Tasks
54
+
55
+ - *(version)* Release patch version 2.4.4
56
+ ## [2.4.3] - 2023-01-04
57
+
58
+ ### ⚙️ Miscellaneous Tasks
59
+
60
+ - *(version)* Release patch version 2.4.3
61
+ ## [2.4.2] - 2023-01-03
62
+
63
+ ### 🐛 Bug Fixes
64
+
65
+ - *(deps)* Bump actions/checkout from 2 to 3 (#60)
66
+
67
+ ### ⚙️ Miscellaneous Tasks
68
+
69
+ - *(version)* Release patch version 2.4.2
70
+ ## [2.4.1] - 2022-07-21
71
+
72
+ ### ⚙️ Miscellaneous Tasks
73
+
74
+ - *(version)* Release patch version 2.4.1
75
+ ## [2.4.0] - 2022-07-20
76
+
77
+ ### ⚙️ Miscellaneous Tasks
78
+
79
+ - *(version)* Release minor version 2.4.0
80
+ ## [2.3.7] - 2022-07-20
81
+
82
+ ### 🐛 Bug Fixes
83
+
84
+ - *(deps)* Bump actions/setup-node from 2 to 3 (#59)
85
+ - *(dev)* Throwing error in the init db command that is used for setup
86
+
87
+ ### ⚙️ Miscellaneous Tasks
88
+
89
+ - *(dev)* The default database in .env.example is now mysql
90
+ - *(dev)* Using sqlite 3 instead of @vscode/sqlite3
91
+ - *(version)* Release patch version 2.3.7
92
+ ## [2.3.6] - 2022-02-03
93
+
94
+ ### 🐛 Bug Fixes
95
+
96
+ - *(config)* Error when reolving config from the user defined config. file not found
97
+ - *(knexfile)* The path of the knex file was still not updated to use either of the 2 .js or .cjs
98
+
99
+ ### ⚙️ Miscellaneous Tasks
100
+
101
+ - *(version)* Release patch version 2.3.2
102
+ - *(version)* Release patch version 2.3.3
103
+ - *(version)* Release patch version 2.3.4
104
+ - *(version)* Release patch version 2.3.5
105
+ - *(version)* Release patch version 2.3.6
106
+ ## [2.3.1] - 2022-02-01
107
+
108
+ ### ⚙️ Miscellaneous Tasks
109
+
110
+ - *(version)* Release minor version 2.3.1
111
+ ## [2.3.0] - 2022-02-01
112
+
113
+ ### 🚀 Features
114
+
115
+ - *(find)* Added the static find method
116
+ - *(model)* Added the create method
117
+ - *(update)* Added the instance update method
118
+ - *(delete)* Added a delete method
119
+
120
+ ### 🐛 Bug Fixes
121
+
122
+ - *(deps)* Bump knex from 0.21.17 to 0.95.11 (#12)
123
+ - *(exports)* Breaking changes were pushed with the previous change. the changes has been fixed
124
+ - *(tableName)* Not hiding the table by default
125
+ - *(first)* Fixed the first method
126
+ - *(knexfile)* Loading knexfile from the current working dir instead of the root of the package
127
+ - *(deps)* The latest knex version removed as a peer dep.
128
+
129
+ ### ⚙️ Miscellaneous Tasks
130
+
131
+ - *(package)* Updated package.json
132
+ - *(es6)* Using .cjs for knexfile
133
+ - *(version)* Release 2.2.13
134
+ - *(version)* Release minor version 2.2.14
135
+ - *(version)* Release minor version 2.3.0
package/lib/model.js CHANGED
@@ -1,5 +1,15 @@
1
+ const fs = require('fs')
1
2
  const knex = require('knex').knex
2
- const { development, staging, production } = require(process.cwd() + '/knexfile.cjs')
3
+
4
+ let fileName
5
+
6
+ if (fs.existsSync(process.cwd() + '/knexfile.js')) {
7
+ fileName = process.cwd() + '/knexfile.js'
8
+ } else {
9
+ fileName = process.cwd() + '/knexfile.cjs'
10
+ }
11
+ const { development, staging, production } = require(fileName)
12
+
3
13
  const pluralize = require('pluralize')
4
14
  let config
5
15
  switch (process.env.NODE_ENV) {
@@ -41,12 +51,13 @@ class Model {
41
51
  this.fillable.forEach((f) => {
42
52
  rows[f] = this[f]
43
53
  })
44
- const id = await DB(this.table)
54
+ const [id] = await DB(this.table)
45
55
  .insert(rows)
46
56
  const fields = await DB(this.table).where({ id }).first()
47
57
  for (const f in fields) {
48
58
  this[f] = fields[f]
49
59
  }
60
+ this['id'] = id
50
61
  return this.stripColumns(this)
51
62
  } catch (error) {
52
63
  throw new Error(error)
@@ -176,10 +187,13 @@ class Model {
176
187
  if (!foreignKey) {
177
188
  foreignKey = `${this.modelName}_id`
178
189
  }
179
- relation[foreignKey] = localKey
180
- const res = await DB(table).where(relation).first()
181
- if (res) {
182
- return this.stripColumns(new Related(res))
190
+
191
+ if (localKey) {
192
+ relation[foreignKey] = localKey
193
+ const res = await DB(table).where(relation).first()
194
+ if (res) {
195
+ return this.stripColumns(new Related(res))
196
+ }
183
197
  }
184
198
  return null
185
199
  }
@@ -227,11 +241,11 @@ class Model {
227
241
  * Delete columns that are not needed
228
242
  *
229
243
  */
230
- stripColumns(Model) {
244
+ stripColumns(model) {
231
245
  this.#private.concat(this.hidden).forEach((h) => {
232
- delete Model[h]
246
+ delete model[h]
233
247
  })
234
- return Model
248
+ return model
235
249
  }
236
250
 
237
251
  }
package/package.json CHANGED
@@ -1,56 +1,68 @@
1
1
  {
2
2
  "name": "mevn-orm",
3
- "version": "3.0.0",
3
+ "version": "3.2.1",
4
4
  "description": "simple ORM for express js",
5
5
  "type": "commonjs",
6
6
  "scripts": {
7
7
  "pretest": "node initDb",
8
- "test": "mocha --exit",
8
+ "test": "mocha --exit",
9
9
  "init:db": "node initDb",
10
10
  "migrate": "knex migrate:latest",
11
11
  "lint": "eslint --ext .js ./"
12
12
  },
13
13
  "peerDependencies": {
14
- "knex": "^0.95",
15
- "dotenv": "^10.0.0",
16
- "mysql": "^2.18.0"
14
+ "dotenv": "^17.0.1",
15
+ "knex": "^3.0.0",
16
+ "mysql2": "^3.9.3"
17
+ },
18
+ "peerDependenciesMeta": {
19
+ "dotenv": {
20
+ "optional": false
21
+ },
22
+ "knex": {
23
+ "optional": false
24
+ }
17
25
  },
18
26
  "keywords": [
19
27
  "ORM",
20
28
  "express",
21
29
  "Mysql",
22
- "mevn"
30
+ "mevn",
31
+ "database",
32
+ "orm",
33
+ "orm-express",
34
+ "orm-mysql"
35
+ ],
36
+ "author": "Stanley Masinde <stanmasinde@gmail.com> (https://stanleymasinde.github.io)",
37
+ "contributors": [
38
+ "Stanley Masinde <stanmasinde@gmail.com>"
23
39
  ],
24
- "author": "Stanley Masinde",
25
40
  "license": "MIT",
26
41
  "dependencies": {
27
42
  "pluralize": "^8.0.0"
28
43
  },
29
44
  "devDependencies": {
30
- "@babel/cli": "^7.13.16",
31
- "@babel/core": "^7.15.8",
32
- "@babel/eslint-parser": "^7.13.14",
33
- "@babel/eslint-plugin": "^7.13.16",
34
- "@babel/plugin-proposal-class-properties": "^7.14.5",
35
- "chai": "^4.2.0",
36
- "dotenv": "^8.6.0",
37
- "eslint": "^7.25.0",
38
- "faker": "^5.5.3",
39
- "knex": "^0.95.11",
40
- "mocha": "^9.1.2",
41
- "mysql2": "^2.3.0",
42
- "sqlite3": "^5.0.0"
45
+ "@babel/cli": "^7.24.5",
46
+ "@babel/core": "^7.24.5",
47
+ "@babel/eslint-parser": "^7.24.3",
48
+ "@babel/eslint-plugin": "^7.24.0",
49
+ "@faker-js/faker": "^9.8.0",
50
+ "chai": "^4.4.1",
51
+ "dotenv": "^17.0.1",
52
+ "knex": "^3.0.0",
53
+ "mocha": "^10.4.0",
54
+ "mysql": "^2.18.1",
55
+ "sqlite3": "^5.1.7"
43
56
  },
44
57
  "directories": {
58
+ "lib": "lib",
45
59
  "test": "test"
46
60
  },
47
61
  "private": false,
48
- "repository": {
49
- "type": "git",
50
- "url": "git+https://github.com/StanleyMasinde/mevn-orm.git"
51
- },
62
+ "repository": "git+https://github.com/StanleyMasinde/mevn-orm.git",
52
63
  "bugs": {
53
- "url": "https://github.com/StanleyMasinde/mevn-orm/issues"
64
+ "url": "https://github.com/StanleyMasinde/mevn-orm/issues",
65
+ "email": "stanleymasinde1@gmail.com"
54
66
  },
55
67
  "homepage": "https://github.com/StanleyMasinde/mevn-orm#readme",
56
68
  "main": "index.js"
package/.babelrc DELETED
@@ -1,3 +0,0 @@
1
- {
2
- "plugins": ["@babel/plugin-proposal-class-properties"]
3
- }
@@ -1,38 +0,0 @@
1
- ---
2
- name: Bug report
3
- about: Create a report to help us improve
4
- title: ''
5
- labels: ''
6
- assignees: ''
7
-
8
- ---
9
-
10
- **Describe the bug**
11
- A clear and concise description of what the bug is.
12
-
13
- **To Reproduce**
14
- Steps to reproduce the behavior:
15
- 1. Go to '...'
16
- 2. Click on '....'
17
- 3. Scroll down to '....'
18
- 4. See error
19
-
20
- **Expected behavior**
21
- A clear and concise description of what you expected to happen.
22
-
23
- **Screenshots**
24
- If applicable, add screenshots to help explain your problem.
25
-
26
- **Desktop (please complete the following information):**
27
- - OS: [e.g. iOS]
28
- - Browser [e.g. chrome, safari]
29
- - Version [e.g. 22]
30
-
31
- **Smartphone (please complete the following information):**
32
- - Device: [e.g. iPhone6]
33
- - OS: [e.g. iOS8.1]
34
- - Browser [e.g. stock browser, safari]
35
- - Version [e.g. 22]
36
-
37
- **Additional context**
38
- Add any other context about the problem here.
@@ -1,20 +0,0 @@
1
- ---
2
- name: Feature request
3
- about: Suggest an idea for this project
4
- title: ''
5
- labels: ''
6
- assignees: ''
7
-
8
- ---
9
-
10
- **Is your feature request related to a problem? Please describe.**
11
- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12
-
13
- **Describe the solution you'd like**
14
- A clear and concise description of what you want to happen.
15
-
16
- **Describe alternatives you've considered**
17
- A clear and concise description of any alternative solutions or features you've considered.
18
-
19
- **Additional context**
20
- Add any other context or screenshots about the feature request here.
@@ -1,30 +0,0 @@
1
- version: 2
2
- updates:
3
- - package-ecosystem: npm
4
- directory: '/'
5
- schedule:
6
- interval: daily
7
- time: '00:00'
8
- open-pull-requests-limit: 10
9
- reviewers:
10
- - stanleymasinde
11
- assignees:
12
- - stanleymasinde
13
- commit-message:
14
- prefix: fix
15
- prefix-development: chore
16
- include: scope
17
- - package-ecosystem: github-actions
18
- directory: '/'
19
- schedule:
20
- interval: daily
21
- time: '00:00'
22
- open-pull-requests-limit: 10
23
- reviewers:
24
- - stanleymasinde
25
- assignees:
26
- - stanleymasinde
27
- commit-message:
28
- prefix: fix
29
- prefix-development: chore
30
- include: scope
@@ -1,31 +0,0 @@
1
- # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
2
- # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
3
-
4
- name: Node.js CI
5
-
6
- on:
7
- push:
8
- branches: [ main ]
9
- pull_request:
10
- branches: [ main ]
11
-
12
- jobs:
13
- build:
14
-
15
- runs-on: ubuntu-latest
16
-
17
- strategy:
18
- matrix:
19
- node-version: [12.x, 14.x, 15.x]
20
- # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
21
-
22
- steps:
23
- - uses: actions/checkout@v2
24
- - name: Use Node.js ${{ matrix.node-version }}
25
- uses: actions/setup-node@v2
26
- with:
27
- node-version: ${{ matrix.node-version }}
28
- - run: cp .env.example .env
29
- - run: npm ci
30
- - run: npm run build --if-present
31
- - run: npm test
package/initDb DELETED
@@ -1,104 +0,0 @@
1
- #!/bin/env node
2
- require('dotenv').config()
3
- const Knex = require('knex')
4
- const { development, staging, production } = require('./knexfile.cjs')
5
- let config
6
-
7
- switch (process.env.NODE_ENV) {
8
- case 'testing':
9
- config = development
10
- break
11
- case 'development':
12
- config = development
13
- break
14
- case 'staging':
15
- config = staging
16
- break
17
- default:
18
- config = production
19
- break
20
- }
21
- async function initDatabase() {
22
- const DB = Knex(config)
23
- await DB.schema.dropTableIfExists('farmers')
24
- await DB.schema.dropTableIfExists('farms')
25
- await DB.schema.dropTableIfExists('profiles')
26
- await DB.schema.dropTableIfExists('articles')
27
- await DB.schema.createTable('farmers', (table) => {
28
- table.bigIncrements('id')
29
- table.string('name')
30
- table.string('email').unique()
31
- table.string('password')
32
- })
33
- await DB.schema.createTable('farms', (table) => {
34
- table.bigIncrements('id')
35
- table.bigInteger('farmer_id')
36
- table.string('name')
37
- })
38
-
39
- await DB.schema.createTable('profiles', (table) => {
40
- table.bigIncrements('id')
41
- table.bigInteger('farmer_id')
42
- table.string('bio')
43
- })
44
-
45
- await DB.schema.createTable('articles', (table) => {
46
- table.bigIncrements('id')
47
- table.string('title')
48
- table.text('body')
49
- table.bigInteger('postable_id')
50
- table.string('postable_type')
51
- })
52
-
53
- await DB.table('Farmers').insert([
54
- {
55
- name: 'Jane Doe',
56
- email: 'jane@mail.com',
57
- password: 'pasword'
58
- },
59
- {
60
- name: 'Ashley Doe',
61
- email: 'ashley@mail.com',
62
- password: 'pasword'
63
- },
64
- {
65
- name: 'Alice Doe',
66
- email: 'alice@mail.com',
67
- password: 'pasword'
68
- }
69
- ])
70
-
71
- await DB.table('farms').insert([
72
- {
73
- farmer_id: 1,
74
- name: 'Awesome Farm'
75
- },
76
- {
77
- farmer_id: 1,
78
- name: 'Awesome Farm two'
79
- },
80
- {
81
- farmer_id: 1,
82
- name: 'Awesome Farm three'
83
- }
84
- ])
85
-
86
- await DB.table('profiles').insert([
87
- {
88
- farmer_id: 1,
89
- bio: 'Profile for farmer one'
90
- }
91
- ])
92
-
93
- await DB.table('articles').insert([
94
- {
95
- title: 'Awesome Post',
96
- body: 'fffgjdfjdbdb something #1',
97
- postable_id: 1,
98
- postable_type: 'Farmer'
99
- }
100
- ])
101
-
102
- process.exit(0)
103
- }
104
- initDatabase()
@@ -1,86 +0,0 @@
1
- /* eslint-disable no-undef */
2
- const { Model, DB } = require('../index')
3
- const faker = require('faker')
4
- const { expect } = require('chai')
5
- class Profile extends Model {
6
- fillable = ['farmer_id', 'bio']
7
- }
8
- class Farmer extends Model {
9
- fillable = ['name', 'email', 'password']
10
- hidden = ['password']
11
-
12
- profile() {
13
- return this.hasOne(Profile)
14
- }
15
- }
16
-
17
- DB(Farmer)
18
-
19
- describe('#Model tests', () => {
20
- it('#Model instance', async () => {
21
- const farmer = new Farmer({
22
- name: faker.name.findName(),
23
- email: faker.internet.email(),
24
- password: faker.internet.password()
25
- })
26
- await farmer.save()
27
- expect(farmer).to.an('Object')
28
- })
29
-
30
- it('#find a model', async () => {
31
- const farmer = await Farmer.find(1)
32
- expect(farmer).to.an('Object')
33
- })
34
-
35
- it('#create a model', async () => {
36
- const farmer = await Farmer.create({
37
- name: faker.name.findName(),
38
- email: faker.internet.email(),
39
- password: faker.internet.password()
40
- })
41
- expect(farmer).to.an('Object')
42
- expect(farmer.id).to.be.a('number')
43
- })
44
-
45
- it('#Update a model with a new instance', async () => {
46
- const farmer = await Farmer.find(1)
47
- await farmer.update({
48
- name: 'new name',
49
- email: faker.internet.email(),
50
- password: faker.internet.password()
51
- })
52
- expect(farmer).to.an('Object')
53
- })
54
-
55
- it('#chain where and first', async () => {
56
- const farmer = await Farmer.where({ id: 1 }).first()
57
- expect(farmer).to.an('Object')
58
- })
59
-
60
- it('#Return null when not found', async () => {
61
- const farmer = await Farmer.where({ id: 'ggggggg' }).first()
62
- expect(farmer).to.be.null
63
- })
64
-
65
- it('#Delete a model', async () => {
66
- const farmer = await Farmer.find(1)
67
- await farmer.delete()
68
- expect(await Farmer.find(1)).to.be.null
69
- })
70
-
71
- it('#Has one relationship', async () => {
72
- const farmer = new Farmer({
73
- name: faker.name.findName(),
74
- email: faker.internet.email(),
75
- password: faker.internet.password()
76
- })
77
- await farmer.save()
78
- await new Profile({
79
- farmer_id: farmer.id,
80
- bio: faker.lorem.sentence()
81
- }).save()
82
- expect(farmer).to.an('Object')
83
- const farmerProfile = await farmer.profile()
84
- expect(farmerProfile).to.haveOwnProperty('farmer_id', farmer.id)
85
- })
86
- })
File without changes