spindb 0.2.0 → 0.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/package.json +10 -2
- package/.claude/settings.local.json +0 -25
- package/.env.example +0 -1
- package/.prettierignore +0 -4
- package/.prettierrc +0 -6
- package/CLAUDE.md +0 -192
- package/TODO.md +0 -75
- package/eslint.config.js +0 -24
- package/seeds/mysql/sample-db.sql +0 -22
- package/seeds/postgres/sample-db.sql +0 -27
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spindb",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.01",
|
|
4
4
|
"description": "Spin up local database containers without Docker. A DBngin-like CLI for PostgreSQL.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -48,5 +48,13 @@
|
|
|
48
48
|
"prettier": "^3.6.2",
|
|
49
49
|
"typescript": "^5.3.0",
|
|
50
50
|
"typescript-eslint": "^8.48.0"
|
|
51
|
-
}
|
|
51
|
+
},
|
|
52
|
+
"tsx": {
|
|
53
|
+
"tsconfig": "./tsconfig.json"
|
|
54
|
+
},
|
|
55
|
+
"files": [
|
|
56
|
+
"bin/**/*",
|
|
57
|
+
"src/**/*",
|
|
58
|
+
"tsconfig.json"
|
|
59
|
+
]
|
|
52
60
|
}
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"permissions": {
|
|
3
|
-
"allow": [
|
|
4
|
-
"Bash(lsof:*)",
|
|
5
|
-
"Bash(npm view:*)",
|
|
6
|
-
"Bash(pnpm install:*)",
|
|
7
|
-
"Bash(pnpm run start --help:*)",
|
|
8
|
-
"Bash(pnpm run start:*)",
|
|
9
|
-
"Bash(curl:*)",
|
|
10
|
-
"Bash(psql:*)",
|
|
11
|
-
"Bash(chmod:*)",
|
|
12
|
-
"Bash(node bin/cli.js:*)",
|
|
13
|
-
"Bash(pnpm add:*)",
|
|
14
|
-
"Bash(pnpm run format:*)",
|
|
15
|
-
"Bash(pnpm run lint:*)",
|
|
16
|
-
"Bash(node /Users/bob/dev/db-container/bin/cli.js:*)",
|
|
17
|
-
"Bash(node -e \"\nconst { fetchAvailableVersions, SUPPORTED_MAJOR_VERSIONS } = require(''./src/engines/postgresql/binary-urls.ts'');\n\")",
|
|
18
|
-
"Bash(node --import tsx bin/cli.js:*)",
|
|
19
|
-
"Bash(node --import tsx:*)",
|
|
20
|
-
"Bash(cat:*)"
|
|
21
|
-
],
|
|
22
|
-
"deny": [],
|
|
23
|
-
"ask": []
|
|
24
|
-
}
|
|
25
|
-
}
|
package/.env.example
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
# No environment variables needed for this project
|
package/.prettierignore
DELETED
package/.prettierrc
DELETED
package/CLAUDE.md
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
# CLAUDE.md - Project Context for Claude Code
|
|
2
|
-
|
|
3
|
-
## Project Overview
|
|
4
|
-
|
|
5
|
-
SpinDB is a CLI tool for running local PostgreSQL databases without Docker. It's a lightweight alternative to DBngin, downloading and managing PostgreSQL binaries directly.
|
|
6
|
-
|
|
7
|
-
## Tech Stack
|
|
8
|
-
|
|
9
|
-
- **Runtime**: Node.js 18+ with TypeScript
|
|
10
|
-
- **Execution**: `tsx` for direct TypeScript execution (no build step for dev)
|
|
11
|
-
- **Package Manager**: pnpm (strictly - not npm/yarn)
|
|
12
|
-
- **CLI Framework**: Commander.js
|
|
13
|
-
- **Interactive UI**: Inquirer.js (prompts), Chalk (colors), Ora (spinners)
|
|
14
|
-
- **Module System**: ESM (`"type": "module"`)
|
|
15
|
-
- **Path Aliases**: `@/*` maps to `./src/*`
|
|
16
|
-
|
|
17
|
-
## Project Structure
|
|
18
|
-
|
|
19
|
-
```
|
|
20
|
-
src/
|
|
21
|
-
├── bin/cli.ts # Entry point (#!/usr/bin/env tsx)
|
|
22
|
-
├── cli/
|
|
23
|
-
│ ├── index.ts # Commander setup, routes to commands
|
|
24
|
-
│ ├── commands/ # CLI commands (create, start, stop, etc.)
|
|
25
|
-
│ │ ├── menu.ts # Interactive arrow-key menu (default when no args)
|
|
26
|
-
│ │ └── config.ts # Binary path configuration
|
|
27
|
-
│ └── ui/
|
|
28
|
-
│ ├── prompts.ts # Inquirer prompts
|
|
29
|
-
│ ├── spinner.ts # Ora spinner helpers
|
|
30
|
-
│ └── theme.ts # Chalk color theme
|
|
31
|
-
├── core/
|
|
32
|
-
│ ├── binary-manager.ts # Downloads PostgreSQL from zonky.io
|
|
33
|
-
│ ├── config-manager.ts # Manages ~/.spindb/config.json
|
|
34
|
-
│ ├── container-manager.ts # CRUD for containers
|
|
35
|
-
│ ├── port-manager.ts # Port availability checking
|
|
36
|
-
│ └── process-manager.ts # pg_ctl start/stop wrapper
|
|
37
|
-
├── config/
|
|
38
|
-
│ ├── paths.ts # ~/.spindb/ path definitions
|
|
39
|
-
│ └── defaults.ts # Default values, platform mappings
|
|
40
|
-
├── engines/
|
|
41
|
-
│ ├── base-engine.ts # Abstract base class
|
|
42
|
-
│ ├── index.ts # Engine registry
|
|
43
|
-
│ └── postgresql/
|
|
44
|
-
│ ├── index.ts # PostgreSQL engine implementation
|
|
45
|
-
│ ├── binary-urls.ts # Zonky.io URL builder
|
|
46
|
-
│ └── restore.ts # Backup detection and restore
|
|
47
|
-
└── types/index.ts # TypeScript interfaces
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Key Architecture Decisions
|
|
51
|
-
|
|
52
|
-
### Binary Source
|
|
53
|
-
PostgreSQL server binaries come from [zonky.io](https://github.com/zonkyio/embedded-postgres-binaries) (Maven Central). These only include server binaries (postgres, pg_ctl, initdb), NOT client tools (psql, pg_dump, pg_restore).
|
|
54
|
-
|
|
55
|
-
**Download flow:**
|
|
56
|
-
1. Download JAR from Maven Central
|
|
57
|
-
2. Unzip JAR (it's a ZIP file)
|
|
58
|
-
3. Extract `.txz` file inside
|
|
59
|
-
4. Extract tar.xz to `~/.spindb/bin/postgresql-{version}-{platform}-{arch}/`
|
|
60
|
-
|
|
61
|
-
### Client Tools
|
|
62
|
-
Client tools (psql, pg_restore) are detected from the system. The `config-manager.ts` handles:
|
|
63
|
-
- Auto-detection from PATH and common locations
|
|
64
|
-
- Caching paths in `~/.spindb/config.json`
|
|
65
|
-
- Manual override via `spindb config set`
|
|
66
|
-
|
|
67
|
-
### Data Storage
|
|
68
|
-
```
|
|
69
|
-
~/.spindb/
|
|
70
|
-
├── bin/ # Downloaded PostgreSQL binaries
|
|
71
|
-
├── containers/{name}/
|
|
72
|
-
│ ├── container.json # Container metadata
|
|
73
|
-
│ ├── data/ # PostgreSQL data directory
|
|
74
|
-
│ └── postgres.log # Server logs
|
|
75
|
-
└── config.json # Tool paths, settings
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
### Interactive Menu
|
|
79
|
-
When `spindb` is run with no arguments, it shows an interactive menu (`src/cli/commands/menu.ts`) using Inquirer's list prompt. Users navigate with arrow keys.
|
|
80
|
-
|
|
81
|
-
**Menu Navigation Rules:**
|
|
82
|
-
- Any submenu with a "Back" button that goes to a parent menu (not main menu) MUST also have a "Back to main menu" option
|
|
83
|
-
- Back buttons use blue color: `${chalk.blue('←')} Back to...`
|
|
84
|
-
- Main menu buttons use house emoji: `${chalk.blue('🏠')} Back to main menu`
|
|
85
|
-
|
|
86
|
-
### Container Config
|
|
87
|
-
Each container has a `container.json` with:
|
|
88
|
-
```typescript
|
|
89
|
-
type ContainerConfig = {
|
|
90
|
-
name: string
|
|
91
|
-
engine: string
|
|
92
|
-
version: string
|
|
93
|
-
port: number
|
|
94
|
-
database: string // User's database name (separate from container name)
|
|
95
|
-
created: string
|
|
96
|
-
status: 'created' | 'running' | 'stopped'
|
|
97
|
-
clonedFrom?: string
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
The `database` field allows users to specify a custom database name in the connection string (e.g., `postgresql://postgres@localhost:5432/my-app-db`).
|
|
102
|
-
|
|
103
|
-
## Common Tasks
|
|
104
|
-
|
|
105
|
-
### Running the CLI
|
|
106
|
-
```bash
|
|
107
|
-
pnpm run start # Opens interactive menu
|
|
108
|
-
pnpm run start create mydb # Run specific command
|
|
109
|
-
pnpm run start --help # Show help
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### Testing Changes
|
|
113
|
-
No test suite yet. Manual testing:
|
|
114
|
-
```bash
|
|
115
|
-
pnpm run start create testdb -p 5433
|
|
116
|
-
pnpm run start list
|
|
117
|
-
pnpm run start connect testdb
|
|
118
|
-
pnpm run start delete testdb --force --yes
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
### Adding a New Command
|
|
122
|
-
1. Create `src/cli/commands/{name}.ts`
|
|
123
|
-
2. Export a Commander `Command` instance
|
|
124
|
-
3. Import and add to `src/cli/index.ts`
|
|
125
|
-
4. Optionally add to interactive menu in `src/cli/commands/menu.ts`
|
|
126
|
-
|
|
127
|
-
## Important Implementation Details
|
|
128
|
-
|
|
129
|
-
### Platform Detection
|
|
130
|
-
```typescript
|
|
131
|
-
import { platform, arch } from 'os';
|
|
132
|
-
// platform() returns 'darwin' | 'linux'
|
|
133
|
-
// arch() returns 'arm64' | 'x64'
|
|
134
|
-
// Mapped to zonky.io names in defaults.ts platformMappings
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### Version Fetching
|
|
138
|
-
PostgreSQL versions are fetched dynamically from Maven Central with a 5-minute cache. Falls back to `FALLBACK_VERSION_MAP` if network fails. See `src/engines/postgresql/binary-urls.ts`:
|
|
139
|
-
|
|
140
|
-
```typescript
|
|
141
|
-
// Fallback versions (used when Maven is unreachable)
|
|
142
|
-
export const FALLBACK_VERSION_MAP: Record<string, string> = {
|
|
143
|
-
'14': '14.20.0',
|
|
144
|
-
'15': '15.15.0',
|
|
145
|
-
'16': '16.11.0',
|
|
146
|
-
'17': '17.7.0',
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
// Dynamic fetching from Maven
|
|
150
|
-
export async function fetchAvailableVersions(): Promise<Record<string, string[]>>
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
The create flow uses two-step version selection: first major version (14, 15, 16, 17), then specific minor version within that major.
|
|
154
|
-
|
|
155
|
-
### Port Management
|
|
156
|
-
- Default port: 5432
|
|
157
|
-
- If busy, scans 5432-5500 for available port
|
|
158
|
-
- Uses `net.createServer()` to test availability
|
|
159
|
-
|
|
160
|
-
### Process Management
|
|
161
|
-
Uses `pg_ctl` for start/stop:
|
|
162
|
-
```bash
|
|
163
|
-
pg_ctl start -D {dataDir} -l {logFile} -w -o "-p {port}"
|
|
164
|
-
pg_ctl stop -D {dataDir} -m fast -w
|
|
165
|
-
```
|
|
166
|
-
|
|
167
|
-
PID file location: `~/.spindb/containers/{name}/data/postmaster.pid`
|
|
168
|
-
|
|
169
|
-
## Known Limitations
|
|
170
|
-
|
|
171
|
-
1. **No client tools bundled** - psql/pg_restore must be installed separately
|
|
172
|
-
2. **macOS/Linux only** - No Windows support (zonky.io doesn't provide Windows binaries)
|
|
173
|
-
3. **No backup command** - pg_dump must be run manually with system tools
|
|
174
|
-
4. **Database names immutable** - Cannot rename database after creation (would require `ALTER DATABASE`)
|
|
175
|
-
|
|
176
|
-
## Future Improvements
|
|
177
|
-
|
|
178
|
-
See `TODO.md` for full list. Key items:
|
|
179
|
-
- [ ] Add `spindb backup` command (wrapper around pg_dump)
|
|
180
|
-
- [ ] Add `spindb logs` command to tail postgres.log
|
|
181
|
-
- [ ] Add `spindb exec` for running SQL files
|
|
182
|
-
- [ ] Database rename support
|
|
183
|
-
- [ ] Support MySQL/SQLite engines (architecture supports it)
|
|
184
|
-
- [ ] Windows support (would need different binary source)
|
|
185
|
-
|
|
186
|
-
## Code Style Notes
|
|
187
|
-
|
|
188
|
-
- No `.js` extensions in imports
|
|
189
|
-
- Use `@/` path alias for all internal imports
|
|
190
|
-
- Prefer `async/await` over callbacks
|
|
191
|
-
- Use Ora spinners for long-running operations
|
|
192
|
-
- Error messages should include actionable fix suggestions
|
package/TODO.md
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
# SpinDB TODO
|
|
2
|
-
|
|
3
|
-
## Monetization Model
|
|
4
|
-
|
|
5
|
-
Similar to ngrok - free tier for individual developers with core functionality, paid tiers for power users and teams.
|
|
6
|
-
|
|
7
|
-
- **Free**: Full local dev experience, unlimited containers, basic backup/restore
|
|
8
|
-
- **Pro** ($X/month): Security features, multi-engine support, advanced features
|
|
9
|
-
- **Team** ($X/user/month): Shared configs, team collaboration, priority support
|
|
10
|
-
|
|
11
|
-
## Free Features
|
|
12
|
-
|
|
13
|
-
### High Priority
|
|
14
|
-
- [ ] **Run SQL file** - Add menu option to run a `.sql` file against a container (wrapper around `psql -f`)
|
|
15
|
-
- [ ] **Backup command** - Add `spindb backup` to create dumps using `pg_dump`
|
|
16
|
-
- [ ] **Logs command** - Add `spindb logs <container>` to tail `postgres.log`
|
|
17
|
-
- [x] **Engine/binary management** - Menu to list installed PostgreSQL versions, install new versions, uninstall unused versions (free up disk space)
|
|
18
|
-
|
|
19
|
-
### Medium Priority
|
|
20
|
-
- [x] **Container rename** - Rename a container without cloning/deleting (via Edit menu)
|
|
21
|
-
- [ ] **Database rename** - Rename a database within a container (requires stopping container, running `ALTER DATABASE ... RENAME TO ...`, updating config)
|
|
22
|
-
- [x] **Export connection string** - Copy connection string to clipboard (via container submenu)
|
|
23
|
-
- [ ] **Multiple databases per container** - List/create/delete databases within a container
|
|
24
|
-
- [x] **Fetch available versions** - Query Maven Central API to show all available PostgreSQL versions instead of hardcoded list
|
|
25
|
-
|
|
26
|
-
### Low Priority
|
|
27
|
-
- [ ] **SQLite support** - Add SQLite engine
|
|
28
|
-
- [ ] **Health checks** - Periodic connection tests to verify containers are responsive
|
|
29
|
-
- [ ] **Offline Support** - Package binaries locally for offline installation
|
|
30
|
-
- [ ] **Binary caching** - Cache downloaded binaries locally to avoid re-downloading
|
|
31
|
-
- [ ] **Binary version management** - List, install, and remove different PostgreSQL versions
|
|
32
|
-
- [ ] **Binary verification** - Verify downloaded binaries with checksums
|
|
33
|
-
- [ ] **Binary cleanup** - Remove old cached binaries to free up disk space
|
|
34
|
-
- [ ] **Binary space monitoring** - Show disk usage of cached binaries
|
|
35
|
-
- [ ] **Binary auto-cleanup** - Automatically remove old versions after a retention period
|
|
36
|
-
|
|
37
|
-
---
|
|
38
|
-
|
|
39
|
-
## Paid Features (Pro)
|
|
40
|
-
|
|
41
|
-
### Security
|
|
42
|
-
- [ ] **Password support** - Set password on container creation, modify `pg_hba.conf` for password auth
|
|
43
|
-
- [ ] **Encrypted backups** - Encrypt dumps with password using gpg/openssl
|
|
44
|
-
|
|
45
|
-
### Multi-Engine Support
|
|
46
|
-
- [ ] **MySQL support** - Add MySQL engine (needs binary source)
|
|
47
|
-
- [ ] **MongoDB support** - Add MongoDB engine
|
|
48
|
-
|
|
49
|
-
### Advanced Features
|
|
50
|
-
- [ ] **Container templates** - Save container configs as reusable templates
|
|
51
|
-
- [ ] **Import from Docker** - Import data from Docker PostgreSQL containers
|
|
52
|
-
- [ ] **Automatic binary updates** - Check for and download newer PostgreSQL versions
|
|
53
|
-
- [ ] **Custom superuser name** - Allow changing from default `postgres` user
|
|
54
|
-
- [ ] **Scheduled backups** - Cron-like backup scheduling
|
|
55
|
-
- [ ] **Cloud backup sync** - Sync backups to S3/GCS/Azure
|
|
56
|
-
|
|
57
|
-
### Team Features
|
|
58
|
-
- [ ] **Shared configs** - Export/import container configs for team sharing
|
|
59
|
-
- [ ] **Config profiles** - Dev/staging/test profiles with different settings
|
|
60
|
-
|
|
61
|
-
---
|
|
62
|
-
|
|
63
|
-
## Stretch Goals
|
|
64
|
-
|
|
65
|
-
- [ ] **Terminal-based IDE** - Full TUI (terminal UI) for browsing tables, running queries, viewing results, editing data inline (think `lazygit` but for databases)
|
|
66
|
-
- Potential libraries: [blessed](https://github.com/chjj/blessed), [ink](https://github.com/vadimdemedes/ink), [terminal-kit](https://github.com/cronvel/terminal-kit)
|
|
67
|
-
- Inspiration: `lazygit`, `k9s`, `pgcli`
|
|
68
|
-
|
|
69
|
-
---
|
|
70
|
-
|
|
71
|
-
## Known Limitations
|
|
72
|
-
|
|
73
|
-
- **No Windows support** - zonky.io doesn't provide Windows binaries
|
|
74
|
-
- **Client tools required** - psql/pg_dump/pg_restore must be installed separately (not bundled)
|
|
75
|
-
- **Local only** - No remote connection support (binds to 127.0.0.1)
|
package/eslint.config.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import eslint from '@eslint/js'
|
|
2
|
-
import tseslint from 'typescript-eslint'
|
|
3
|
-
|
|
4
|
-
export default tseslint.config(
|
|
5
|
-
eslint.configs.recommended,
|
|
6
|
-
...tseslint.configs.recommended,
|
|
7
|
-
{
|
|
8
|
-
ignores: ['dist/', 'node_modules/', 'bin/', 'eslint.config.js'],
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
languageOptions: {
|
|
12
|
-
parserOptions: {
|
|
13
|
-
project: true,
|
|
14
|
-
tsconfigRootDir: import.meta.dirname,
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
rules: {
|
|
18
|
-
'@typescript-eslint/no-unused-vars': [
|
|
19
|
-
'error',
|
|
20
|
-
{ argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
|
|
21
|
-
],
|
|
22
|
-
},
|
|
23
|
-
},
|
|
24
|
-
)
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
-- Sample database schema for testing SpinDB
|
|
2
|
-
-- Creates a basic users table with common fields (MySQL syntax)
|
|
3
|
-
|
|
4
|
-
CREATE TABLE IF NOT EXISTS users (
|
|
5
|
-
id INT AUTO_INCREMENT PRIMARY KEY,
|
|
6
|
-
first_name VARCHAR(100) NOT NULL,
|
|
7
|
-
last_name VARCHAR(100) NOT NULL,
|
|
8
|
-
email VARCHAR(255) NOT NULL UNIQUE,
|
|
9
|
-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
10
|
-
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
|
11
|
-
deleted_at TIMESTAMP NULL,
|
|
12
|
-
INDEX idx_users_email (email),
|
|
13
|
-
INDEX idx_users_deleted_at (deleted_at)
|
|
14
|
-
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
15
|
-
|
|
16
|
-
-- Sample data
|
|
17
|
-
INSERT IGNORE INTO users (first_name, last_name, email) VALUES
|
|
18
|
-
('Alice', 'Johnson', 'alice@example.com'),
|
|
19
|
-
('Bob', 'Smith', 'bob@example.com'),
|
|
20
|
-
('Charlie', 'Williams', 'charlie@example.com'),
|
|
21
|
-
('Diana', 'Brown', 'diana@example.com'),
|
|
22
|
-
('Eve', 'Davis', 'eve@example.com');
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
-- Sample database schema for testing SpinDB
|
|
2
|
-
-- Creates a basic users table with common fields
|
|
3
|
-
|
|
4
|
-
CREATE TABLE IF NOT EXISTS users (
|
|
5
|
-
id SERIAL PRIMARY KEY,
|
|
6
|
-
first_name VARCHAR(100) NOT NULL,
|
|
7
|
-
last_name VARCHAR(100) NOT NULL,
|
|
8
|
-
email VARCHAR(255) NOT NULL UNIQUE,
|
|
9
|
-
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
10
|
-
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
|
|
11
|
-
deleted_at TIMESTAMP WITH TIME ZONE
|
|
12
|
-
);
|
|
13
|
-
|
|
14
|
-
-- Create an index on email for faster lookups
|
|
15
|
-
CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);
|
|
16
|
-
|
|
17
|
-
-- Create an index on deleted_at for soft delete queries
|
|
18
|
-
CREATE INDEX IF NOT EXISTS idx_users_deleted_at ON users(deleted_at);
|
|
19
|
-
|
|
20
|
-
-- Sample data
|
|
21
|
-
INSERT INTO users (first_name, last_name, email) VALUES
|
|
22
|
-
('Alice', 'Johnson', 'alice@example.com'),
|
|
23
|
-
('Bob', 'Smith', 'bob@example.com'),
|
|
24
|
-
('Charlie', 'Williams', 'charlie@example.com'),
|
|
25
|
-
('Diana', 'Brown', 'diana@example.com'),
|
|
26
|
-
('Eve', 'Davis', 'eve@example.com')
|
|
27
|
-
ON CONFLICT (email) DO NOTHING;
|