stabilize-orm 1.1.1 → 1.1.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/.github/ISSUE_TEMPLATE/PULL_REQUEST_TEMPLATE.md +23 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +25 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +17 -0
- package/.github/workflows/ci-cd.yml +4 -55
- package/CHANGELOG.md +23 -0
- package/CODE_OF_CONDUCT.md +87 -0
- package/CONTRIBUTING.md +48 -0
- package/FUNDING.md +14 -0
- package/README.md +273 -32
- package/SECURITY.md +35 -0
- package/SUPPORT.md +18 -0
- package/bun.lock +6 -0
- package/cli/stabilize-cli.ts +290 -319
- package/client.ts +5 -30
- package/migrations.ts +76 -11
- package/package.json +5 -3
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Pull Request
|
|
2
|
+
|
|
3
|
+
## Description
|
|
4
|
+
|
|
5
|
+
Please include a summary of the change and which issue is fixed. List any dependencies required for this change.
|
|
6
|
+
|
|
7
|
+
## Type of change
|
|
8
|
+
|
|
9
|
+
- [ ] Bug fix
|
|
10
|
+
- [ ] New feature
|
|
11
|
+
- [ ] Breaking change
|
|
12
|
+
- [ ] Documentation update
|
|
13
|
+
|
|
14
|
+
## Checklist
|
|
15
|
+
|
|
16
|
+
- [ ] My code follows the style guidelines of this project
|
|
17
|
+
- [ ] I have performed a self-review of my code
|
|
18
|
+
- [ ] I have added tests that prove my fix is effective or that my feature works
|
|
19
|
+
- [ ] New and existing unit tests pass locally with my changes
|
|
20
|
+
|
|
21
|
+
## Related issues
|
|
22
|
+
|
|
23
|
+
Closes #[issue-number]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Create a report to help us improve
|
|
4
|
+
labels: bug
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Describe the bug**
|
|
8
|
+
A clear and concise description of what the bug is.
|
|
9
|
+
|
|
10
|
+
**To Reproduce**
|
|
11
|
+
Steps to reproduce the behavior:
|
|
12
|
+
|
|
13
|
+
**Expected behavior**
|
|
14
|
+
A clear and concise description of what you expected to happen.
|
|
15
|
+
|
|
16
|
+
**Screenshots**
|
|
17
|
+
If applicable, add screenshots to help explain your problem.
|
|
18
|
+
|
|
19
|
+
**Environment (please complete the following information):**
|
|
20
|
+
- OS: [e.g. macOS, Linux, Windows]
|
|
21
|
+
- Bun version
|
|
22
|
+
- Stabilize ORM version
|
|
23
|
+
|
|
24
|
+
**Additional context**
|
|
25
|
+
Add any other context about the problem here.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Suggest an idea for this project
|
|
4
|
+
labels: enhancement
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Is your feature request related to a problem? Please describe.**
|
|
8
|
+
A clear and concise description of what the problem is.
|
|
9
|
+
|
|
10
|
+
**Describe the solution you'd like**
|
|
11
|
+
A clear and concise description of what you want to happen.
|
|
12
|
+
|
|
13
|
+
**Describe alternatives you've considered**
|
|
14
|
+
A clear and concise description of any alternative solutions.
|
|
15
|
+
|
|
16
|
+
**Additional context**
|
|
17
|
+
Add any other context or screenshots about the feature request here.
|
|
@@ -1,23 +1,16 @@
|
|
|
1
|
-
name:
|
|
1
|
+
name: Stabilize ORM CI
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
5
|
branches:
|
|
6
6
|
- main
|
|
7
|
-
tags:
|
|
8
|
-
- "v*.*.*"
|
|
9
7
|
pull_request:
|
|
10
8
|
branches:
|
|
11
9
|
- main
|
|
12
10
|
|
|
13
11
|
jobs:
|
|
14
|
-
test:
|
|
12
|
+
simple-test:
|
|
15
13
|
runs-on: ubuntu-latest
|
|
16
|
-
services:
|
|
17
|
-
redis:
|
|
18
|
-
image: redis:latest
|
|
19
|
-
ports:
|
|
20
|
-
- 6379:6379
|
|
21
14
|
steps:
|
|
22
15
|
- name: Checkout code
|
|
23
16
|
uses: actions/checkout@v4
|
|
@@ -25,49 +18,5 @@ jobs:
|
|
|
25
18
|
uses: oven-sh/setup-bun@v2
|
|
26
19
|
with:
|
|
27
20
|
bun-version: "latest"
|
|
28
|
-
- name: Install dependencies
|
|
29
|
-
run: bun install
|
|
30
|
-
- name: Check formatting
|
|
31
|
-
run: bunx prettier --check .
|
|
32
|
-
- name: Lint code
|
|
33
|
-
run: bun run lint
|
|
34
|
-
- name: Run tests
|
|
35
|
-
run: bun run test
|
|
36
|
-
env:
|
|
37
|
-
REDIS_URL: redis://localhost:6379
|
|
38
|
-
- name: Build project
|
|
39
|
-
run: bun run build
|
|
40
|
-
- name: Test CLI
|
|
41
|
-
run: |
|
|
42
|
-
bun run dist/cli/stabilize-cli.js generate model TestModel
|
|
43
|
-
bun run dist/cli/stabilize-cli.js generate seed TestSeed
|
|
44
|
-
bun run dist/cli/stabilize-cli.js seed -c examples/config/database.ts
|
|
45
|
-
- name: Upload coverage
|
|
46
|
-
uses: codecov/codecov-action@v4
|
|
47
|
-
with:
|
|
48
|
-
token: ${{ secrets.CODECOV_TOKEN }}
|
|
49
|
-
|
|
50
|
-
publish:
|
|
51
|
-
needs: test
|
|
52
|
-
runs-on: ubuntu-latest
|
|
53
|
-
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
|
|
54
|
-
steps:
|
|
55
|
-
- name: Checkout code
|
|
56
|
-
uses: actions/checkout@v4
|
|
57
|
-
- name: Setup Bun
|
|
58
|
-
uses: oven-sh/setup-bun@v2
|
|
59
|
-
with:
|
|
60
|
-
bun-version: "latest"
|
|
61
|
-
- name: Install dependencies
|
|
62
|
-
run: bun install
|
|
63
|
-
- name: Build project
|
|
64
|
-
run: bun run build
|
|
65
|
-
- name: Setup Node.js
|
|
66
|
-
uses: actions/setup-node@v4
|
|
67
|
-
with:
|
|
68
|
-
node-version: "20"
|
|
69
|
-
registry-url: "https://registry.npmjs.org"
|
|
70
|
-
- name: Publish to npm
|
|
71
|
-
run: npm publish --access public
|
|
72
|
-
env:
|
|
73
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
21
|
+
- name: Install dependencies (bun install)
|
|
22
|
+
run: bun install
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
## [1.1.2] - 2025-10-14
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- Improved repository QueryBuilder with chainable joins, advanced where clauses, and cache support.
|
|
9
|
+
- Added support for model decorators and repository pattern.
|
|
10
|
+
- New CLI features for migrations, seeds, rollback, and status.
|
|
11
|
+
- Security, funding, conduct, and contributing markdowns.
|
|
12
|
+
- More expressive README and docs.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- Updated ORM configuration examples.
|
|
16
|
+
- Enhanced documentation for open source best practices.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
- Various bug fixes for connection handling and retry logic.
|
|
20
|
+
|
|
21
|
+
## [Unreleased]
|
|
22
|
+
|
|
23
|
+
- Further features and improvements coming soon.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# 📝 Contributor Covenant Code of Conduct
|
|
2
|
+
|
|
3
|
+
## 💚 Our Pledge
|
|
4
|
+
|
|
5
|
+
We as members, contributors, and leaders pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
|
6
|
+
|
|
7
|
+
We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 🌟 Our Standards
|
|
12
|
+
|
|
13
|
+
**Positive behaviors include:**
|
|
14
|
+
- Demonstrating empathy and kindness toward other people
|
|
15
|
+
- Being respectful of differing opinions, viewpoints, and experiences
|
|
16
|
+
- Giving and gracefully accepting constructive feedback
|
|
17
|
+
- Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience
|
|
18
|
+
- Focusing on what is best not just for us as individuals, but for the overall community
|
|
19
|
+
|
|
20
|
+
**Unacceptable behaviors include:**
|
|
21
|
+
- The use of sexualized language or imagery, and sexual attention or advances of any kind
|
|
22
|
+
- Trolling, insulting or derogatory comments, and personal or political attacks
|
|
23
|
+
- Public or private harassment
|
|
24
|
+
- Publishing others’ private information, such as a physical or email address, without their explicit permission
|
|
25
|
+
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 🛡️ Enforcement Responsibilities
|
|
30
|
+
|
|
31
|
+
Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
|
|
32
|
+
|
|
33
|
+
Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 🌍 Scope
|
|
38
|
+
|
|
39
|
+
This Code of Conduct applies within all community spaces and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 📣 Enforcement
|
|
44
|
+
|
|
45
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at **lwazicd@icloud.com**.
|
|
46
|
+
|
|
47
|
+
All complaints will be reviewed and investigated promptly and fairly.
|
|
48
|
+
|
|
49
|
+
All community leaders are obligated to respect the privacy and security of the reporter of any incident.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
## ⚖️ Enforcement Guidelines
|
|
54
|
+
|
|
55
|
+
Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
|
|
56
|
+
|
|
57
|
+
### 1. Correction
|
|
58
|
+
|
|
59
|
+
- **Community Impact:** Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
|
|
60
|
+
- **Consequence:** A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. May include a public apology.
|
|
61
|
+
|
|
62
|
+
### 2. Warning
|
|
63
|
+
|
|
64
|
+
- **Community Impact:** A violation through a single incident or series of actions.
|
|
65
|
+
- **Consequence:** A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
|
|
66
|
+
|
|
67
|
+
### 3. Temporary Ban
|
|
68
|
+
|
|
69
|
+
- **Community Impact:** A serious violation of community standards, including sustained inappropriate behavior.
|
|
70
|
+
- **Consequence:** A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
|
|
71
|
+
|
|
72
|
+
### 4. Permanent Ban
|
|
73
|
+
|
|
74
|
+
- **Community Impact:** Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
|
|
75
|
+
- **Consequence:** A permanent ban from any sort of public interaction within the community.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 📜 Attribution
|
|
80
|
+
|
|
81
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at
|
|
82
|
+
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html](https://www.contributor-covenant.org/version/2/1/code_of_conduct.html).
|
|
83
|
+
|
|
84
|
+
For answers to common questions about this code of conduct, see [https://www.contributor-covenant.org/faq](https://www.contributor-covenant.org/faq).
|
|
85
|
+
Translations are available at [https://www.contributor-covenant.org/translations](https://www.contributor-covenant.org/translations).
|
|
86
|
+
|
|
87
|
+
---
|
package/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# 🤝 Contributing to Stabilize ORM
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in making Stabilize ORM even better! Your ideas, code, and feedback help drive this project forward.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🚀 How to Contribute
|
|
8
|
+
|
|
9
|
+
1. **Fork the Repository:**
|
|
10
|
+
Click "Fork" to make your own copy.
|
|
11
|
+
2. **Create Your Branch:**
|
|
12
|
+
Branch off `main` for your feature or fix.
|
|
13
|
+
3. **Write Code:**
|
|
14
|
+
- Use TypeScript.
|
|
15
|
+
- Follow established formatting and naming conventions.
|
|
16
|
+
4. **Test Your Changes:**
|
|
17
|
+
Ensure your code passes all tests.
|
|
18
|
+
5. **Update Documentation:**
|
|
19
|
+
If you change APIs, update the docs and README.
|
|
20
|
+
6. **Open a Pull Request:**
|
|
21
|
+
- Fill out the PR template.
|
|
22
|
+
- Describe your changes clearly.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 💡 Code Style
|
|
27
|
+
|
|
28
|
+
- **Language:** TypeScript only
|
|
29
|
+
- **Formatting:** Use project conventions (Prettier, ESLint, etc.)
|
|
30
|
+
- **Naming:** Be descriptive and consistent
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 🐞 Reporting Issues
|
|
35
|
+
|
|
36
|
+
- For bugs, use the [Bug Report Issue Template](.github/ISSUE_TEMPLATE/bug_report.md).
|
|
37
|
+
- For feature ideas, use the [Feature Request Template](.github/ISSUE_TEMPLATE/feature_request.md).
|
|
38
|
+
|
|
39
|
+
If in doubt, ask or open a discussion!
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 🙏 Thank You
|
|
44
|
+
|
|
45
|
+
Your contributions make Stabilize ORM stable, expressive, and truly open source.
|
|
46
|
+
Happy coding!
|
|
47
|
+
|
|
48
|
+
---
|
package/FUNDING.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# ❤️ Support Stabilize ORM
|
|
2
|
+
|
|
3
|
+
If you love Stabilize ORM and want to help it grow, you can support ongoing development in a few ways:
|
|
4
|
+
|
|
5
|
+
- **GitHub Sponsors:**
|
|
6
|
+
[Sponsor ElectronSz on GitHub](https://github.com/sponsors/ElectronSz)
|
|
7
|
+
|
|
8
|
+
- **Patreon:**
|
|
9
|
+
[Become a Patron](https://patreon.com/ElectronSz)
|
|
10
|
+
|
|
11
|
+
- **Ko-fi:**
|
|
12
|
+
[Buy ElectronSz a coffee](https://ko-fi.com/ElectronSz)
|
|
13
|
+
|
|
14
|
+
Your support helps with maintenance, new features, and keeping Stabilize ORM open source for everyone. Thank you! 🙏
|
package/README.md
CHANGED
|
@@ -1,52 +1,293 @@
|
|
|
1
1
|
# Stabilize ORM
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
_Stable, Fast, and Expressive ORM for Bun_
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
---
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
- **Retry Logic**: Automatic exponential backoff retries for queries and transactions.
|
|
9
|
-
- **Connection Management**: Pooling, switching connections, and metrics.
|
|
10
|
-
- **Transactions & Savepoints**: Built-in support with retry handling.
|
|
11
|
-
- **Prepared Statements**: Cached for SQLite to improve performance.
|
|
12
|
-
- **Logging**: Pluggable logger (default: ConsoleLogger).
|
|
13
|
-
- **Error Handling**: Custom `StabilizeError` with database-specific codes.
|
|
14
|
-
- **CLI**: Simple command-line tool for database operations (e.g., migrations, queries).
|
|
7
|
+
**Stabilize** is a lightweight, retry-aware ORM built on Bun’s native SQL API. It provides a unified interface for SQLite, MySQL, and PostgreSQL with connection pooling, automatic retries, transactions, savepoints, and robust logging. Designed for simplicity, performance, and reliability in Bun applications.
|
|
15
8
|
|
|
16
|
-
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## 🚀 Features
|
|
12
|
+
|
|
13
|
+
- **Unified API**: Supports SQLite, MySQL, and PostgreSQL
|
|
14
|
+
- **Retry Logic**: Automatic exponential backoff for queries & transactions
|
|
15
|
+
- **Connection Management**: Pooling, connection switching, live metrics
|
|
16
|
+
- **Transactions & Savepoints**: Built-in support with retry handling
|
|
17
|
+
- **Prepared Statements**: Cached for SQLite to maximize performance
|
|
18
|
+
- **Pluggable Logging**: Default ConsoleLogger, extensible for files or services
|
|
19
|
+
- **Custom Errors**: `StabilizeError` with clear, database-specific codes
|
|
20
|
+
- **CLI Tool**: Migrate, seed, and query from the command line
|
|
21
|
+
- **Model & Repository Pattern**: Clean, scalable code with decorators
|
|
22
|
+
- **Relationships & Joins**: Model relationships and flexible SQL joins
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 📦 Installation
|
|
17
27
|
|
|
18
28
|
Stabilize requires Bun (v1.0+).
|
|
19
29
|
|
|
20
30
|
```bash
|
|
21
|
-
# Install via bun
|
|
22
31
|
bun add stabilize-orm
|
|
23
32
|
```
|
|
24
|
-
## Usage
|
|
25
33
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
import { DBConfig } from 'stabilize-orm/src/types';
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 📃 Documentation & Community
|
|
30
37
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
38
|
+
- [Changelog](./CHANGELOG.md)
|
|
39
|
+
- [License](./LICENSE.md)
|
|
40
|
+
- [Code of Conduct](./CODE_OF_CONDUCT.md)
|
|
41
|
+
- [Contributing Guide](./CONTRIBUTING.md)
|
|
42
|
+
- [Security Policy](./SECURITY.md)
|
|
43
|
+
- [Support](./SUPPORT.md)
|
|
44
|
+
- [Funding](./FUNDING.md)
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## ⚙️ ORM Configuration
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// config/database.ts
|
|
52
|
+
import { DBType, Stabilize, type CacheConfig, type DBConfig } from "stabilize-orm";
|
|
53
|
+
|
|
54
|
+
export const dbConfig: DBConfig = {
|
|
55
|
+
type: DBType.Postgres, // or DBType.SQLite, DBType.MySQL
|
|
56
|
+
connectionString: process.env.DB_CONNECTION_STRING || "postgres://admin:P@ssw0rd@localhost:5432/db",
|
|
57
|
+
poolSize: Number(process.env.DB_POOL_SIZE) || 10,
|
|
58
|
+
retryAttempts: Number(process.env.DB_RETRY_ATTEMPTS) || 3,
|
|
59
|
+
retryDelay: Number(process.env.DB_RETRY_DELAY) || 1000,
|
|
60
|
+
maxJitter: Number(process.env.DB_MAX_JITTER) || 100,
|
|
36
61
|
};
|
|
37
62
|
|
|
38
|
-
const
|
|
63
|
+
export const cacheConfig: CacheConfig = {
|
|
64
|
+
enabled: process.env.CACHE_ENABLED === "true",
|
|
65
|
+
ttl: Number(process.env.CACHE_TTL) || 60,
|
|
66
|
+
redisUrl: process.env.REDIS_URL || "redis://localhost:6379",
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export const orm = new Stabilize(dbConfig, cacheConfig);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## 🏗️ Models, Relationships & Repositories
|
|
75
|
+
|
|
76
|
+
Define models with decorators, express relationships, and interact using repositories:
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
// models/User.ts
|
|
80
|
+
import "reflect-metadata";
|
|
81
|
+
import { Model, Column, Required } from "stabilize-orm";
|
|
82
|
+
|
|
83
|
+
@Model("users")
|
|
84
|
+
export class User {
|
|
85
|
+
@Column("id", "TEXT") @Required()
|
|
86
|
+
id: string = crypto.randomUUID();
|
|
87
|
+
|
|
88
|
+
@Column("name", "TEXT") @Required()
|
|
89
|
+
name?: string;
|
|
90
|
+
|
|
91
|
+
@Column("email", "TEXT") @Required()
|
|
92
|
+
email?: string;
|
|
93
|
+
|
|
94
|
+
@Column("active", "BOOLEAN") @Required()
|
|
95
|
+
active?: boolean;
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// models/Role.ts
|
|
101
|
+
import "reflect-metadata";
|
|
102
|
+
import { Model, Column, Required } from "stabilize-orm";
|
|
103
|
+
|
|
104
|
+
@Model("roles")
|
|
105
|
+
export class Role {
|
|
106
|
+
@Column("id", "TEXT") @Required()
|
|
107
|
+
id: string = crypto.randomUUID();
|
|
108
|
+
|
|
109
|
+
@Column("name", "TEXT") @Required()
|
|
110
|
+
name?: string;
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
// models/UserRole.ts
|
|
116
|
+
import "reflect-metadata";
|
|
117
|
+
import { Model, Column, Required, ManyToOne } from "stabilize-orm";
|
|
118
|
+
import { User } from "./User";
|
|
119
|
+
import { Role } from "./Role";
|
|
120
|
+
|
|
121
|
+
@Model("userroles")
|
|
122
|
+
export class UserRole {
|
|
123
|
+
@Column("id", "TEXT") @Required()
|
|
124
|
+
id: string = crypto.randomUUID();
|
|
125
|
+
|
|
126
|
+
@Column("user_id", "TEXT") @Required()
|
|
127
|
+
user_id!: string;
|
|
128
|
+
|
|
129
|
+
@Column("role_id", "TEXT") @Required()
|
|
130
|
+
role_id!: string;
|
|
131
|
+
|
|
132
|
+
// Relationships
|
|
133
|
+
@ManyToOne(() => User, "user_id")
|
|
134
|
+
user?: User;
|
|
135
|
+
|
|
136
|
+
@ManyToOne(() => Role, "role_id")
|
|
137
|
+
role?: Role;
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
// repository/userRepository.ts
|
|
143
|
+
import { orm } from "../config/database";
|
|
144
|
+
import { User } from "../models/User";
|
|
145
|
+
export const userRepository = orm.getRepository(User);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
---
|
|
39
149
|
|
|
40
|
-
|
|
41
|
-
const users = await db.query<{ id: number; name: string }>('SELECT * FROM users');
|
|
42
|
-
console.log(users);
|
|
150
|
+
## 🔀 Table Joins & Relationships
|
|
43
151
|
|
|
44
|
-
|
|
45
|
-
await db.query('INSERT INTO users (name) VALUES (?)', ['Alice']);
|
|
46
|
-
});
|
|
152
|
+
Stabilize ORM supports relationships and flexible SQL joins to help you write advanced queries.
|
|
47
153
|
|
|
48
|
-
|
|
154
|
+
**Relationship Decorators Example:**
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
@Model("user_roles")
|
|
158
|
+
export class UserRole {
|
|
159
|
+
// ...columns...
|
|
160
|
+
@ManyToOne(() => User, "user_id")
|
|
161
|
+
user?: User;
|
|
162
|
+
@ManyToOne(() => Role, "role_id")
|
|
163
|
+
role?: Role;
|
|
49
164
|
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
**Join Example:**
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
const adminUsers = await orm.getRepository(UserRole)
|
|
171
|
+
.find()
|
|
172
|
+
.join("users", "user_roles.user_id = users.id")
|
|
173
|
+
.join("roles", "use_rroles.role_id = roles.id")
|
|
174
|
+
.select("users.id", "users.name", "roles.name AS role")
|
|
175
|
+
.where("roles.name = ?", "Admin")
|
|
176
|
+
.orderBy("users.name ASC")
|
|
177
|
+
.execute(orm["client"]);
|
|
178
|
+
```
|
|
179
|
+
- Use `.join(table, condition)` to add joins, then combine with `.select`, `.where`, `.orderBy`, etc.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
## 🧑💻 Query Builder
|
|
184
|
+
|
|
185
|
+
The repository `.find()` method returns a chainable query builder:
|
|
186
|
+
|
|
187
|
+
```typescript
|
|
188
|
+
const qb = userRepository.find()
|
|
189
|
+
.where("active = ?", true)
|
|
190
|
+
.orderBy("created_at DESC")
|
|
191
|
+
.limit(10)
|
|
192
|
+
.offset(20)
|
|
193
|
+
.select("id", "name", "email");
|
|
194
|
+
|
|
195
|
+
const { query, params } = qb.build();
|
|
196
|
+
console.log(query, params);
|
|
197
|
+
|
|
198
|
+
const users = await qb.execute(orm["client"]);
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**API:**
|
|
202
|
+
|
|
203
|
+
```typescript
|
|
204
|
+
{
|
|
205
|
+
select(...fields: string[]): QueryBuilder<User>;
|
|
206
|
+
where(condition: string, ...params: any[]): QueryBuilder<User>;
|
|
207
|
+
join(table: string, condition: string): QueryBuilder<User>;
|
|
208
|
+
orderBy(clause: string): QueryBuilder<User>;
|
|
209
|
+
limit(limit: number): QueryBuilder<User>;
|
|
210
|
+
offset(offset: number): QueryBuilder<User>;
|
|
211
|
+
build(): { query: string; params: any[] };
|
|
212
|
+
execute(client: DBClient, cache?: Cache, cacheKey?: string): Promise<User[]>;
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## 📚 More Usage Examples
|
|
219
|
+
|
|
220
|
+
```typescript
|
|
221
|
+
// Get all users
|
|
222
|
+
export const getAll = async () => userRepository.find().execute(orm["client"]);
|
|
223
|
+
|
|
224
|
+
// Get active users, ordered by name
|
|
225
|
+
export const getActiveUsers = async () =>
|
|
226
|
+
userRepository.find().where("active = ?", true).orderBy("name ASC").execute(orm["client"]);
|
|
227
|
+
|
|
228
|
+
// Paginated query
|
|
229
|
+
export const getPaginatedUsers = async (limit: number, offset: number) =>
|
|
230
|
+
userRepository.find().orderBy("created_at DESC").limit(limit).offset(offset).execute(orm["client"]);
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
## 🌐 ExpressJS Integration
|
|
236
|
+
|
|
237
|
+
```typescript
|
|
238
|
+
import express from "express";
|
|
239
|
+
import { userRepository } from "./repository/userRepository";
|
|
240
|
+
import { orm } from "./config/database";
|
|
241
|
+
|
|
242
|
+
const app = express();
|
|
243
|
+
app.use(express.json());
|
|
244
|
+
|
|
245
|
+
app.get("/users", async (req, res) => {
|
|
246
|
+
try {
|
|
247
|
+
const users = await userRepository.find().execute(orm["client"]);
|
|
248
|
+
res.json(users);
|
|
249
|
+
} catch {
|
|
250
|
+
res.status(500).json({ error: "Failed to fetch users." });
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
app.get("/users/active", async (req, res) => {
|
|
255
|
+
try {
|
|
256
|
+
const users = await userRepository.find()
|
|
257
|
+
.where("active = ?", true)
|
|
258
|
+
.orderBy("name ASC")
|
|
259
|
+
.execute(orm["client"]);
|
|
260
|
+
res.json(users);
|
|
261
|
+
} catch {
|
|
262
|
+
res.status(500).json({ error: "Failed to fetch active users." });
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
app.post("/users", async (req, res) => {
|
|
267
|
+
try {
|
|
268
|
+
const user = await userRepository.create(req.body);
|
|
269
|
+
res.status(201).json(user);
|
|
270
|
+
} catch {
|
|
271
|
+
res.status(500).json({ error: "User creation failed." });
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
app.listen(3000, () => {
|
|
276
|
+
console.log("Express server listening on port 3000");
|
|
277
|
+
});
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
---
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
## 📑 License
|
|
284
|
+
|
|
285
|
+
See [LICENSE.md](./LICENSE.md)
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
<div align="center">
|
|
290
|
+
|
|
291
|
+
Created with ❤️ in Eswatini by ElectronSz
|
|
50
292
|
|
|
51
|
-
|
|
52
|
-
```
|
|
293
|
+
</div>
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# 🛡️ Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
We encourage responsible disclosure of security vulnerabilities for all actively maintained versions of Stabilize ORM.
|
|
6
|
+
|
|
7
|
+
| Version | Supported |
|
|
8
|
+
|--------------|------------------|
|
|
9
|
+
| Latest (main)| ✅ Yes |
|
|
10
|
+
| Older (< 6mo)| ✅ Yes |
|
|
11
|
+
| Unmaintained | ❌ No |
|
|
12
|
+
|
|
13
|
+
## Reporting a Vulnerability
|
|
14
|
+
|
|
15
|
+
If you discover a security vulnerability, please **do not disclose it publicly**.
|
|
16
|
+
|
|
17
|
+
### Secure Reporting Steps
|
|
18
|
+
|
|
19
|
+
1. **Email:**
|
|
20
|
+
Contact ElectronSz directly at [lwazicd@icloud.com](mailto:lwazicd@icloud.com) with full details.
|
|
21
|
+
|
|
22
|
+
2. **GitHub Security Advisory:**
|
|
23
|
+
Alternatively, open a [GitHub security advisory](https://github.com/ElectronSz/stabilize-orm/security/advisories) (private by default).
|
|
24
|
+
|
|
25
|
+
3. **Wait for Response:**
|
|
26
|
+
Please allow up to 72 hours for a first response. We may request more details or verification.
|
|
27
|
+
|
|
28
|
+
4. **Coordinated Disclosure:**
|
|
29
|
+
We will work with you to verify, patch, and coordinate public disclosure.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
> **Please do NOT post vulnerabilities in GitHub issues, discussions, or any public forum until a fix is released.**
|
|
34
|
+
|
|
35
|
+
Thank you for helping keep Stabilize ORM and its users safe!
|