Add Backup and Restore
This commit is contained in:
parent
634be9b01d
commit
ec27ff9c04
57
README.md
57
README.md
@ -15,6 +15,10 @@ A schema-driven SQLite manager for [Bun](https://bun.sh), featuring automatic sc
|
||||
- [Configuration](#configuration)
|
||||
- [Schema Definition](#schema-definition)
|
||||
- [CLI Commands](#cli-commands)
|
||||
- [`schema`](#schema--sync-database-to-schema)
|
||||
- [`typedef`](#typedef--generate-typescript-types-only)
|
||||
- [`backup`](#backup--back-up-the-database)
|
||||
- [`restore`](#restore--restore-the-database-from-a-backup)
|
||||
- [CRUD API](#crud-api)
|
||||
- [Select](#select)
|
||||
- [Insert](#insert)
|
||||
@ -154,6 +158,7 @@ The config file must be named `bun-sqlite.config.ts` and placed at the root of y
|
||||
| `db_backup_dir` | `string` | Yes | Directory for database backups, relative to `db_dir` |
|
||||
| `db_dir` | `string` | No | Root directory for the database file and schema. Defaults to project root |
|
||||
| `typedef_file_path` | `string` | No | Output path for generated TypeScript types, relative to project root |
|
||||
| `max_backups` | `number` | No | Maximum number of backup files to keep. Oldest are deleted automatically. Defaults to `10` |
|
||||
|
||||
---
|
||||
|
||||
@ -274,6 +279,47 @@ Reads the schema and writes TypeScript type definitions to the path configured i
|
||||
|
||||
---
|
||||
|
||||
### `backup` — Back up the database
|
||||
|
||||
```bash
|
||||
bunx bun-sqlite backup
|
||||
```
|
||||
|
||||
Copies the current database file into `db_backup_dir` with a timestamped filename. After copying, the oldest backups are automatically pruned so the number of stored backups never exceeds `max_backups` (default: 10).
|
||||
|
||||
**Example:**
|
||||
|
||||
```bash
|
||||
bunx bun-sqlite backup
|
||||
# Backing up database ...
|
||||
# DB Backup Success!
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### `restore` — Restore the database from a backup
|
||||
|
||||
```bash
|
||||
bunx bun-sqlite restore
|
||||
```
|
||||
|
||||
Presents an interactive list of available backups sorted by date (newest first). Select a backup to overwrite the current database file with it.
|
||||
|
||||
**Example:**
|
||||
|
||||
```bash
|
||||
bunx bun-sqlite restore
|
||||
# Restoring up database ...
|
||||
# ? Select a backup: (Use arrow keys)
|
||||
# ❯ Backup #1: Mon Mar 02 2026 14:30:00
|
||||
# Backup #2: Sun Mar 01 2026 09:15:42
|
||||
# DB Restore Success!
|
||||
```
|
||||
|
||||
> If no backups exist, the command exits with an error and a reminder to run `backup` first.
|
||||
|
||||
---
|
||||
|
||||
## CRUD API
|
||||
|
||||
Import the default export:
|
||||
@ -695,7 +741,9 @@ bun-sqlite/
|
||||
│ ├── commands/
|
||||
│ │ ├── index.ts # CLI entry point
|
||||
│ │ ├── schema.ts # `schema` command
|
||||
│ │ └── typedef.ts # `typedef` command
|
||||
│ │ ├── typedef.ts # `typedef` command
|
||||
│ │ ├── backup.ts # `backup` command
|
||||
│ │ └── restore.ts # `restore` command
|
||||
│ ├── functions/
|
||||
│ │ └── init.ts # Config + schema loader
|
||||
│ ├── lib/sqlite/
|
||||
@ -715,7 +763,12 @@ bun-sqlite/
|
||||
│ ├── sql-insert-generator.ts # INSERT query builder
|
||||
│ ├── sql-gen-operator-gen.ts # Equality operator mapper
|
||||
│ ├── sql-equality-parser.ts # Equality string parser
|
||||
│ └── append-default-fields-to-db-schema.ts
|
||||
│ ├── append-default-fields-to-db-schema.ts
|
||||
│ ├── grab-db-dir.ts # Resolve db/backup directory paths
|
||||
│ ├── grab-db-backup-file-name.ts # Generate timestamped backup filename
|
||||
│ ├── grab-sorted-backups.ts # List backups sorted newest-first
|
||||
│ ├── grab-backup-data.ts # Parse metadata from a backup filename
|
||||
│ └── trim-backups.ts # Prune oldest backups over max_backups
|
||||
└── test/
|
||||
└── test-01/ # Example project using the library
|
||||
├── bun-sqlite.config.ts
|
||||
|
||||
63
bun.lock
63
bun.lock
@ -4,7 +4,10 @@
|
||||
"": {
|
||||
"name": "bun-sqlite",
|
||||
"dependencies": {
|
||||
"@inquirer/prompts": "^8.3.0",
|
||||
"chalk": "^5.6.2",
|
||||
"commander": "^14.0.3",
|
||||
"inquirer": "^13.3.0",
|
||||
"lodash": "^4.17.23",
|
||||
"mysql": "^2.18.1",
|
||||
"sqlite-vec": "^0.1.7-alpha.2",
|
||||
@ -21,6 +24,38 @@
|
||||
},
|
||||
},
|
||||
"packages": {
|
||||
"@inquirer/ansi": ["@inquirer/ansi@2.0.3", "", {}, "sha512-g44zhR3NIKVs0zUesa4iMzExmZpLUdTLRMCStqX3GE5NT6VkPcxQGJ+uC8tDgBUC/vB1rUhUd55cOf++4NZcmw=="],
|
||||
|
||||
"@inquirer/checkbox": ["@inquirer/checkbox@5.1.0", "", { "dependencies": { "@inquirer/ansi": "^2.0.3", "@inquirer/core": "^11.1.5", "@inquirer/figures": "^2.0.3", "@inquirer/type": "^4.0.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-/HjF1LN0a1h4/OFsbGKHNDtWICFU/dqXCdym719HFTyJo9IG7Otr+ziGWc9S0iQuohRZllh+WprSgd5UW5Fw0g=="],
|
||||
|
||||
"@inquirer/confirm": ["@inquirer/confirm@6.0.8", "", { "dependencies": { "@inquirer/core": "^11.1.5", "@inquirer/type": "^4.0.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-Di6dgmiZ9xCSUxWUReWTqDtbhXCuG2MQm2xmgSAIruzQzBqNf49b8E07/vbCYY506kDe8BiwJbegXweG8M1klw=="],
|
||||
|
||||
"@inquirer/core": ["@inquirer/core@11.1.5", "", { "dependencies": { "@inquirer/ansi": "^2.0.3", "@inquirer/figures": "^2.0.3", "@inquirer/type": "^4.0.3", "cli-width": "^4.1.0", "fast-wrap-ansi": "^0.2.0", "mute-stream": "^3.0.0", "signal-exit": "^4.1.0" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-QQPAX+lka8GyLcZ7u7Nb1h6q72iZ/oy0blilC3IB2nSt1Qqxp7akt94Jqhi/DzARuN3Eo9QwJRvtl4tmVe4T5A=="],
|
||||
|
||||
"@inquirer/editor": ["@inquirer/editor@5.0.8", "", { "dependencies": { "@inquirer/core": "^11.1.5", "@inquirer/external-editor": "^2.0.3", "@inquirer/type": "^4.0.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-sLcpbb9B3XqUEGrj1N66KwhDhEckzZ4nI/W6SvLXyBX8Wic3LDLENlWRvkOGpCPoserabe+MxQkpiMoI8irvyA=="],
|
||||
|
||||
"@inquirer/expand": ["@inquirer/expand@5.0.8", "", { "dependencies": { "@inquirer/core": "^11.1.5", "@inquirer/type": "^4.0.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-QieW3F1prNw3j+hxO7/NKkG1pk3oz7pOB6+5Upwu3OIwADfPX0oZVppsqlL+Vl/uBHHDSOBY0BirLctLnXwGGg=="],
|
||||
|
||||
"@inquirer/external-editor": ["@inquirer/external-editor@2.0.3", "", { "dependencies": { "chardet": "^2.1.1", "iconv-lite": "^0.7.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-LgyI7Agbda74/cL5MvA88iDpvdXI2KuMBCGRkbCl2Dg1vzHeOgs+s0SDcXV7b+WZJrv2+ERpWSM65Fpi9VfY3w=="],
|
||||
|
||||
"@inquirer/figures": ["@inquirer/figures@2.0.3", "", {}, "sha512-y09iGt3JKoOCBQ3w4YrSJdokcD8ciSlMIWsD+auPu+OZpfxLuyz+gICAQ6GCBOmJJt4KEQGHuZSVff2jiNOy7g=="],
|
||||
|
||||
"@inquirer/input": ["@inquirer/input@5.0.8", "", { "dependencies": { "@inquirer/core": "^11.1.5", "@inquirer/type": "^4.0.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-p0IJslw0AmedLEkOU+yrEX3Aj2RTpQq7ZOf8nc1DIhjzaxRWrrgeuE5Kyh39fVRgtcACaMXx/9WNo8+GjgBOfw=="],
|
||||
|
||||
"@inquirer/number": ["@inquirer/number@4.0.8", "", { "dependencies": { "@inquirer/core": "^11.1.5", "@inquirer/type": "^4.0.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-uGLiQah9A0F9UIvJBX52m0CnqtLaym0WpT9V4YZrjZ+YRDKZdwwoEPz06N6w8ChE2lrnsdyhY9sL+Y690Kh9gQ=="],
|
||||
|
||||
"@inquirer/password": ["@inquirer/password@5.0.8", "", { "dependencies": { "@inquirer/ansi": "^2.0.3", "@inquirer/core": "^11.1.5", "@inquirer/type": "^4.0.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-zt1sF4lYLdvPqvmvHdmjOzuUUjuCQ897pdUCO8RbXMUDKXJTTyOQgtn23le+jwcb+MpHl3VAFvzIdxRAf6aPlA=="],
|
||||
|
||||
"@inquirer/prompts": ["@inquirer/prompts@8.3.0", "", { "dependencies": { "@inquirer/checkbox": "^5.1.0", "@inquirer/confirm": "^6.0.8", "@inquirer/editor": "^5.0.8", "@inquirer/expand": "^5.0.8", "@inquirer/input": "^5.0.8", "@inquirer/number": "^4.0.8", "@inquirer/password": "^5.0.8", "@inquirer/rawlist": "^5.2.4", "@inquirer/search": "^4.1.4", "@inquirer/select": "^5.1.0" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-JAj66kjdH/F1+B7LCigjARbwstt3SNUOSzMdjpsvwJmzunK88gJeXmcm95L9nw1KynvFVuY4SzXh/3Y0lvtgSg=="],
|
||||
|
||||
"@inquirer/rawlist": ["@inquirer/rawlist@5.2.4", "", { "dependencies": { "@inquirer/core": "^11.1.5", "@inquirer/type": "^4.0.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-fTuJ5Cq9W286isLxwj6GGyfTjx1Zdk4qppVEPexFuA6yioCCXS4V1zfKroQqw7QdbDPN73xs2DiIAlo55+kBqg=="],
|
||||
|
||||
"@inquirer/search": ["@inquirer/search@4.1.4", "", { "dependencies": { "@inquirer/core": "^11.1.5", "@inquirer/figures": "^2.0.3", "@inquirer/type": "^4.0.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-9yPTxq7LPmYjrGn3DRuaPuPbmC6u3fiWcsE9ggfLcdgO/ICHYgxq7mEy1yJ39brVvgXhtOtvDVjDh9slJxE4LQ=="],
|
||||
|
||||
"@inquirer/select": ["@inquirer/select@5.1.0", "", { "dependencies": { "@inquirer/ansi": "^2.0.3", "@inquirer/core": "^11.1.5", "@inquirer/figures": "^2.0.3", "@inquirer/type": "^4.0.3" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-OyYbKnchS1u+zRe14LpYrN8S0wH1vD0p2yKISvSsJdH2TpI87fh4eZdWnpdbrGauCRWDph3NwxRmM4Pcm/hx1Q=="],
|
||||
|
||||
"@inquirer/type": ["@inquirer/type@4.0.3", "", { "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-cKZN7qcXOpj1h+1eTTcGDVLaBIHNMT1Rz9JqJP5MnEJ0JhgVWllx7H/tahUp5YEK1qaByH2Itb8wLG/iScD5kw=="],
|
||||
|
||||
"@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="],
|
||||
|
||||
"@types/lodash": ["@types/lodash@4.17.24", "", {}, "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ=="],
|
||||
@ -33,24 +68,50 @@
|
||||
|
||||
"bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="],
|
||||
|
||||
"chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
|
||||
|
||||
"chardet": ["chardet@2.1.1", "", {}, "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ=="],
|
||||
|
||||
"cli-width": ["cli-width@4.1.0", "", {}, "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ=="],
|
||||
|
||||
"commander": ["commander@14.0.3", "", {}, "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw=="],
|
||||
|
||||
"core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="],
|
||||
|
||||
"fast-string-truncated-width": ["fast-string-truncated-width@3.0.3", "", {}, "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g=="],
|
||||
|
||||
"fast-string-width": ["fast-string-width@3.0.2", "", { "dependencies": { "fast-string-truncated-width": "^3.0.2" } }, "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg=="],
|
||||
|
||||
"fast-wrap-ansi": ["fast-wrap-ansi@0.2.0", "", { "dependencies": { "fast-string-width": "^3.0.2" } }, "sha512-rLV8JHxTyhVmFYhBJuMujcrHqOT2cnO5Zxj37qROj23CP39GXubJRBUFF0z8KFK77Uc0SukZUf7JZhsVEQ6n8w=="],
|
||||
|
||||
"iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="],
|
||||
|
||||
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
||||
|
||||
"inquirer": ["inquirer@13.3.0", "", { "dependencies": { "@inquirer/ansi": "^2.0.3", "@inquirer/core": "^11.1.5", "@inquirer/prompts": "^8.3.0", "@inquirer/type": "^4.0.3", "mute-stream": "^3.0.0", "run-async": "^4.0.6", "rxjs": "^7.8.2" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-APTrZe9IhrsshL0u2PgmEMLP3CXDBjZ99xh5dR2+sryOt5R+JGL0KNuaTTT2lW54B9eNQDMutPR05UYTL7Xb1Q=="],
|
||||
|
||||
"isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="],
|
||||
|
||||
"lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="],
|
||||
|
||||
"mute-stream": ["mute-stream@3.0.0", "", {}, "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw=="],
|
||||
|
||||
"mysql": ["mysql@2.18.1", "", { "dependencies": { "bignumber.js": "9.0.0", "readable-stream": "2.3.7", "safe-buffer": "5.1.2", "sqlstring": "2.3.1" } }, "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig=="],
|
||||
|
||||
"process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="],
|
||||
|
||||
"readable-stream": ["readable-stream@2.3.7", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw=="],
|
||||
|
||||
"run-async": ["run-async@4.0.6", "", {}, "sha512-IoDlSLTs3Yq593mb3ZoKWKXMNu3UpObxhgA/Xuid5p4bbfi2jdY1Hj0m1K+0/tEuQTxIGMhQDqGjKb7RuxGpAQ=="],
|
||||
|
||||
"rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "^2.1.0" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="],
|
||||
|
||||
"safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="],
|
||||
|
||||
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
|
||||
|
||||
"signal-exit": ["signal-exit@4.1.0", "", {}, "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw=="],
|
||||
|
||||
"sqlite-vec": ["sqlite-vec@0.1.7-alpha.2", "", { "optionalDependencies": { "sqlite-vec-darwin-arm64": "0.1.7-alpha.2", "sqlite-vec-darwin-x64": "0.1.7-alpha.2", "sqlite-vec-linux-arm64": "0.1.7-alpha.2", "sqlite-vec-linux-x64": "0.1.7-alpha.2", "sqlite-vec-windows-x64": "0.1.7-alpha.2" } }, "sha512-rNgRCv+4V4Ed3yc33Qr+nNmjhtrMnnHzXfLVPeGb28Dx5mmDL3Ngw/Wk8vhCGjj76+oC6gnkmMG8y73BZWGBwQ=="],
|
||||
|
||||
"sqlite-vec-darwin-arm64": ["sqlite-vec-darwin-arm64@0.1.7-alpha.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-raIATOqFYkeCHhb/t3r7W7Cf2lVYdf4J3ogJ6GFc8PQEgHCPEsi+bYnm2JT84MzLfTlSTIdxr4/NKv+zF7oLPw=="],
|
||||
@ -67,6 +128,8 @@
|
||||
|
||||
"string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="],
|
||||
|
||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
||||
|
||||
"undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="],
|
||||
|
||||
2
dist/commands/backup.d.ts
vendored
Normal file
2
dist/commands/backup.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
import { Command } from "commander";
|
||||
export default function (): Command;
|
||||
22
dist/commands/backup.js
vendored
Normal file
22
dist/commands/backup.js
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
import { Command } from "commander";
|
||||
import init from "../functions/init";
|
||||
import path from "path";
|
||||
import grabDBDir from "../utils/grab-db-dir";
|
||||
import fs from "fs";
|
||||
import grabDBBackupFileName from "../utils/grab-db-backup-file-name";
|
||||
import chalk from "chalk";
|
||||
import trimBackups from "../utils/trim-backups";
|
||||
export default function () {
|
||||
return new Command("backup")
|
||||
.description("Backup Database")
|
||||
.action(async (opts) => {
|
||||
console.log(`Backing up database ...`);
|
||||
const { config } = await init();
|
||||
const { backup_dir, db_file_path } = grabDBDir({ config });
|
||||
const new_db_file_name = grabDBBackupFileName({ config });
|
||||
fs.cpSync(db_file_path, path.join(backup_dir, new_db_file_name));
|
||||
trimBackups({ config });
|
||||
console.log(`${chalk.bold(chalk.green(`DB Backup Success!`))}`);
|
||||
process.exit();
|
||||
});
|
||||
}
|
||||
4
dist/commands/index.js
vendored
4
dist/commands/index.js
vendored
@ -2,6 +2,8 @@
|
||||
import { program } from "commander";
|
||||
import schema from "./schema";
|
||||
import typedef from "./typedef";
|
||||
import backup from "./backup";
|
||||
import restore from "./restore";
|
||||
/**
|
||||
* # Describe Program
|
||||
*/
|
||||
@ -14,6 +16,8 @@ program
|
||||
*/
|
||||
program.addCommand(schema());
|
||||
program.addCommand(typedef());
|
||||
program.addCommand(backup());
|
||||
program.addCommand(restore());
|
||||
/**
|
||||
* # Handle Unavailable Commands
|
||||
*/
|
||||
|
||||
2
dist/commands/restore.d.ts
vendored
Normal file
2
dist/commands/restore.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
import { Command } from "commander";
|
||||
export default function (): Command;
|
||||
44
dist/commands/restore.js
vendored
Normal file
44
dist/commands/restore.js
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
import { Command } from "commander";
|
||||
import init from "../functions/init";
|
||||
import grabDBDir from "../utils/grab-db-dir";
|
||||
import fs from "fs";
|
||||
import chalk from "chalk";
|
||||
import grabSortedBackups from "../utils/grab-sorted-backups";
|
||||
import { select } from "@inquirer/prompts";
|
||||
import grabBackupData from "../utils/grab-backup-data";
|
||||
import path from "path";
|
||||
export default function () {
|
||||
return new Command("restore")
|
||||
.description("Restore Database")
|
||||
.action(async (opts) => {
|
||||
console.log(`Restoring up database ...`);
|
||||
const { config } = await init();
|
||||
const { backup_dir, db_file_path } = grabDBDir({ config });
|
||||
const backups = grabSortedBackups({ config });
|
||||
if (!backups?.[0]) {
|
||||
console.error(`No Backups to restore. Use the \`backup\` command to create a backup`);
|
||||
process.exit(1);
|
||||
}
|
||||
try {
|
||||
const selected_backup = await select({
|
||||
message: "Select a backup:",
|
||||
choices: backups.map((b, i) => {
|
||||
const { backup_date } = grabBackupData({
|
||||
backup_name: b,
|
||||
});
|
||||
return {
|
||||
name: `Backup #${i + 1}: ${backup_date.toDateString()} ${backup_date.getHours()}:${backup_date.getMinutes()}:${backup_date.getSeconds().toString().padStart(2, "0")}`,
|
||||
value: b,
|
||||
};
|
||||
}),
|
||||
});
|
||||
fs.cpSync(path.join(backup_dir, selected_backup), db_file_path);
|
||||
console.log(`${chalk.bold(chalk.green(`DB Restore Success!`))}`);
|
||||
process.exit();
|
||||
}
|
||||
catch (error) {
|
||||
console.error(`Backup Restore ERROR => ${error.message}`);
|
||||
process.exit();
|
||||
}
|
||||
});
|
||||
}
|
||||
2
dist/commands/schema.js
vendored
2
dist/commands/schema.js
vendored
@ -7,6 +7,7 @@ import dbSchemaToTypeDef from "../lib/sqlite/schema-to-typedef";
|
||||
import _ from "lodash";
|
||||
import { DefaultFields } from "../types";
|
||||
import appendDefaultFieldsToDbSchema from "../utils/append-default-fields-to-db-schema";
|
||||
import chalk from "chalk";
|
||||
export default function () {
|
||||
return new Command("schema")
|
||||
.description("Build DB From Schema")
|
||||
@ -32,6 +33,7 @@ export default function () {
|
||||
dst_file: out_file,
|
||||
});
|
||||
}
|
||||
console.log(`${chalk.bold(chalk.green(`DB Schema setup success!`))}`);
|
||||
process.exit();
|
||||
});
|
||||
}
|
||||
|
||||
2
dist/commands/typedef.js
vendored
2
dist/commands/typedef.js
vendored
@ -4,6 +4,7 @@ import dbSchemaToTypeDef from "../lib/sqlite/schema-to-typedef";
|
||||
import path from "path";
|
||||
import grabDirNames from "../data/grab-dir-names";
|
||||
import appendDefaultFieldsToDbSchema from "../utils/append-default-fields-to-db-schema";
|
||||
import chalk from "chalk";
|
||||
export default function () {
|
||||
return new Command("typedef")
|
||||
.description("Build DB From Schema")
|
||||
@ -23,6 +24,7 @@ export default function () {
|
||||
console.error(``);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(`${chalk.bold(chalk.green(`Typedef gen success!`))}`);
|
||||
process.exit();
|
||||
});
|
||||
}
|
||||
|
||||
1
dist/data/app-data.d.ts
vendored
1
dist/data/app-data.d.ts
vendored
@ -1,3 +1,4 @@
|
||||
export declare const AppData: {
|
||||
readonly ConfigFileName: "bun-sqlite.config.ts";
|
||||
readonly MaxBackups: 10;
|
||||
};
|
||||
|
||||
1
dist/data/app-data.js
vendored
1
dist/data/app-data.js
vendored
@ -1,3 +1,4 @@
|
||||
export const AppData = {
|
||||
ConfigFileName: "bun-sqlite.config.ts",
|
||||
MaxBackups: 10,
|
||||
};
|
||||
|
||||
6
dist/lib/sqlite/index.js
vendored
6
dist/lib/sqlite/index.js
vendored
@ -1,16 +1,16 @@
|
||||
import { Database } from "bun:sqlite";
|
||||
import path from "node:path";
|
||||
import * as sqliteVec from "sqlite-vec";
|
||||
import grabDirNames from "../../data/grab-dir-names";
|
||||
import init from "../../functions/init";
|
||||
import grabDBDir from "../../utils/grab-db-dir";
|
||||
const { ROOT_DIR } = grabDirNames();
|
||||
const { config } = await init();
|
||||
let db_dir = ROOT_DIR;
|
||||
if (config.db_dir) {
|
||||
db_dir = config.db_dir;
|
||||
}
|
||||
const DBFilePath = path.join(db_dir, config.db_name);
|
||||
const DbClient = new Database(DBFilePath, {
|
||||
const { db_file_path } = grabDBDir({ config });
|
||||
const DbClient = new Database(db_file_path, {
|
||||
create: true,
|
||||
});
|
||||
sqliteVec.load(DbClient);
|
||||
|
||||
1
dist/types/index.d.ts
vendored
1
dist/types/index.d.ts
vendored
@ -997,6 +997,7 @@ export type BunSQLiteConfig = {
|
||||
* The Directory for backups
|
||||
*/
|
||||
db_backup_dir: string;
|
||||
max_backups?: number;
|
||||
/**
|
||||
* The Root Directory for the DB file and schema
|
||||
*/
|
||||
|
||||
9
dist/utils/grab-backup-data.d.ts
vendored
Normal file
9
dist/utils/grab-backup-data.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
type Params = {
|
||||
backup_name: string;
|
||||
};
|
||||
export default function grabBackupData({ backup_name }: Params): {
|
||||
backup_date: Date;
|
||||
backup_date_timestamp: number;
|
||||
origin_backup_name: string;
|
||||
};
|
||||
export {};
|
||||
7
dist/utils/grab-backup-data.js
vendored
Normal file
7
dist/utils/grab-backup-data.js
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
export default function grabBackupData({ backup_name }) {
|
||||
const backup_parts = backup_name.split("-");
|
||||
const backup_date_timestamp = Number(backup_parts.pop());
|
||||
const origin_backup_name = backup_parts.join("-");
|
||||
const backup_date = new Date(backup_date_timestamp);
|
||||
return { backup_date, backup_date_timestamp, origin_backup_name };
|
||||
}
|
||||
6
dist/utils/grab-db-backup-file-name.d.ts
vendored
Normal file
6
dist/utils/grab-db-backup-file-name.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
import type { BunSQLiteConfig } from "../types";
|
||||
type Params = {
|
||||
config: BunSQLiteConfig;
|
||||
};
|
||||
export default function grabDBBackupFileName({ config }: Params): string;
|
||||
export {};
|
||||
4
dist/utils/grab-db-backup-file-name.js
vendored
Normal file
4
dist/utils/grab-db-backup-file-name.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
export default function grabDBBackupFileName({ config }) {
|
||||
const new_db_file_name = `${config.db_name}-${Date.now()}`;
|
||||
return new_db_file_name;
|
||||
}
|
||||
10
dist/utils/grab-db-dir.d.ts
vendored
Normal file
10
dist/utils/grab-db-dir.d.ts
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
import type { BunSQLiteConfig } from "../types";
|
||||
type Params = {
|
||||
config: BunSQLiteConfig;
|
||||
};
|
||||
export default function grabDBDir({ config }: Params): {
|
||||
db_dir: string;
|
||||
backup_dir: string;
|
||||
db_file_path: string;
|
||||
};
|
||||
export {};
|
||||
12
dist/utils/grab-db-dir.js
vendored
Normal file
12
dist/utils/grab-db-dir.js
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
import path from "path";
|
||||
import grabDirNames from "../data/grab-dir-names";
|
||||
export default function grabDBDir({ config }) {
|
||||
const { ROOT_DIR } = grabDirNames();
|
||||
let db_dir = ROOT_DIR;
|
||||
if (config.db_dir) {
|
||||
db_dir = config.db_dir;
|
||||
}
|
||||
const backup_dir = path.resolve(db_dir, config.db_backup_dir);
|
||||
const db_file_path = path.resolve(db_dir, config.db_name);
|
||||
return { db_dir, backup_dir, db_file_path };
|
||||
}
|
||||
6
dist/utils/grab-sorted-backups.d.ts
vendored
Normal file
6
dist/utils/grab-sorted-backups.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
import type { BunSQLiteConfig } from "../types";
|
||||
type Params = {
|
||||
config: BunSQLiteConfig;
|
||||
};
|
||||
export default function grabSortedBackups({ config }: Params): string[];
|
||||
export {};
|
||||
18
dist/utils/grab-sorted-backups.js
vendored
Normal file
18
dist/utils/grab-sorted-backups.js
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
import grabDBDir from "../utils/grab-db-dir";
|
||||
import fs from "fs";
|
||||
export default function grabSortedBackups({ config }) {
|
||||
const { backup_dir } = grabDBDir({ config });
|
||||
const backups = fs.readdirSync(backup_dir);
|
||||
/**
|
||||
* Order Backups. Most recent first.
|
||||
*/
|
||||
const ordered_backups = backups.sort((a, b) => {
|
||||
const a_date = Number(a.split("-").pop());
|
||||
const b_date = Number(b.split("-").pop());
|
||||
if (a_date > b_date) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
return ordered_backups;
|
||||
}
|
||||
6
dist/utils/trim-backups.d.ts
vendored
Normal file
6
dist/utils/trim-backups.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
import type { BunSQLiteConfig } from "../types";
|
||||
type Params = {
|
||||
config: BunSQLiteConfig;
|
||||
};
|
||||
export default function trimBackups({ config }: Params): void;
|
||||
export {};
|
||||
19
dist/utils/trim-backups.js
vendored
Normal file
19
dist/utils/trim-backups.js
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
import grabDBDir from "../utils/grab-db-dir";
|
||||
import fs from "fs";
|
||||
import grabSortedBackups from "./grab-sorted-backups";
|
||||
import { AppData } from "../data/app-data";
|
||||
import path from "path";
|
||||
export default function trimBackups({ config }) {
|
||||
const { backup_dir } = grabDBDir({ config });
|
||||
const backups = grabSortedBackups({ config });
|
||||
const max_backups = config.max_backups || AppData["MaxBackups"];
|
||||
for (let i = 0; i < backups.length; i++) {
|
||||
const backup_name = backups[i];
|
||||
if (!backup_name)
|
||||
continue;
|
||||
if (i > max_backups - 1) {
|
||||
const backup_file_to_unlink = path.join(backup_dir, backup_name);
|
||||
fs.unlinkSync(backup_file_to_unlink);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -30,7 +30,10 @@
|
||||
"url": "git+https://git.tben.me/Moduletrace/bun-sqlite.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"@inquirer/prompts": "^8.3.0",
|
||||
"chalk": "^5.6.2",
|
||||
"commander": "^14.0.3",
|
||||
"inquirer": "^13.3.0",
|
||||
"lodash": "^4.17.23",
|
||||
"mysql": "^2.18.1",
|
||||
"sqlite-vec": "^0.1.7-alpha.2"
|
||||
|
||||
29
src/commands/backup.ts
Normal file
29
src/commands/backup.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { Command } from "commander";
|
||||
import init from "../functions/init";
|
||||
import path from "path";
|
||||
import grabDBDir from "../utils/grab-db-dir";
|
||||
import fs from "fs";
|
||||
import grabDBBackupFileName from "../utils/grab-db-backup-file-name";
|
||||
import chalk from "chalk";
|
||||
import trimBackups from "../utils/trim-backups";
|
||||
|
||||
export default function () {
|
||||
return new Command("backup")
|
||||
.description("Backup Database")
|
||||
.action(async (opts) => {
|
||||
console.log(`Backing up database ...`);
|
||||
|
||||
const { config } = await init();
|
||||
|
||||
const { backup_dir, db_file_path } = grabDBDir({ config });
|
||||
|
||||
const new_db_file_name = grabDBBackupFileName({ config });
|
||||
|
||||
fs.cpSync(db_file_path, path.join(backup_dir, new_db_file_name));
|
||||
|
||||
trimBackups({ config });
|
||||
|
||||
console.log(`${chalk.bold(chalk.green(`DB Backup Success!`))}`);
|
||||
process.exit();
|
||||
});
|
||||
}
|
||||
@ -3,6 +3,8 @@
|
||||
import { program } from "commander";
|
||||
import schema from "./schema";
|
||||
import typedef from "./typedef";
|
||||
import backup from "./backup";
|
||||
import restore from "./restore";
|
||||
|
||||
/**
|
||||
* # Declare Global Variables
|
||||
@ -22,6 +24,8 @@ program
|
||||
*/
|
||||
program.addCommand(schema());
|
||||
program.addCommand(typedef());
|
||||
program.addCommand(backup());
|
||||
program.addCommand(restore());
|
||||
|
||||
/**
|
||||
* # Handle Unavailable Commands
|
||||
|
||||
56
src/commands/restore.ts
Normal file
56
src/commands/restore.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { Command } from "commander";
|
||||
import init from "../functions/init";
|
||||
import grabDBDir from "../utils/grab-db-dir";
|
||||
import fs from "fs";
|
||||
import chalk from "chalk";
|
||||
import grabSortedBackups from "../utils/grab-sorted-backups";
|
||||
import { select } from "@inquirer/prompts";
|
||||
import grabBackupData from "../utils/grab-backup-data";
|
||||
import path from "path";
|
||||
|
||||
export default function () {
|
||||
return new Command("restore")
|
||||
.description("Restore Database")
|
||||
.action(async (opts) => {
|
||||
console.log(`Restoring up database ...`);
|
||||
|
||||
const { config } = await init();
|
||||
|
||||
const { backup_dir, db_file_path } = grabDBDir({ config });
|
||||
|
||||
const backups = grabSortedBackups({ config });
|
||||
|
||||
if (!backups?.[0]) {
|
||||
console.error(
|
||||
`No Backups to restore. Use the \`backup\` command to create a backup`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
try {
|
||||
const selected_backup = await select({
|
||||
message: "Select a backup:",
|
||||
choices: backups.map((b, i) => {
|
||||
const { backup_date } = grabBackupData({
|
||||
backup_name: b,
|
||||
});
|
||||
return {
|
||||
name: `Backup #${i + 1}: ${backup_date.toDateString()} ${backup_date.getHours()}:${backup_date.getMinutes()}:${backup_date.getSeconds().toString().padStart(2, "0")}`,
|
||||
value: b,
|
||||
};
|
||||
}),
|
||||
});
|
||||
|
||||
fs.cpSync(path.join(backup_dir, selected_backup), db_file_path);
|
||||
|
||||
console.log(
|
||||
`${chalk.bold(chalk.green(`DB Restore Success!`))}`,
|
||||
);
|
||||
|
||||
process.exit();
|
||||
} catch (error: any) {
|
||||
console.error(`Backup Restore ERROR => ${error.message}`);
|
||||
process.exit();
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -7,6 +7,7 @@ import dbSchemaToTypeDef from "../lib/sqlite/schema-to-typedef";
|
||||
import _ from "lodash";
|
||||
import { DefaultFields } from "../types";
|
||||
import appendDefaultFieldsToDbSchema from "../utils/append-default-fields-to-db-schema";
|
||||
import chalk from "chalk";
|
||||
|
||||
export default function () {
|
||||
return new Command("schema")
|
||||
@ -47,6 +48,9 @@ export default function () {
|
||||
});
|
||||
}
|
||||
|
||||
console.log(
|
||||
`${chalk.bold(chalk.green(`DB Schema setup success!`))}`,
|
||||
);
|
||||
process.exit();
|
||||
});
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ import dbSchemaToTypeDef from "../lib/sqlite/schema-to-typedef";
|
||||
import path from "path";
|
||||
import grabDirNames from "../data/grab-dir-names";
|
||||
import appendDefaultFieldsToDbSchema from "../utils/append-default-fields-to-db-schema";
|
||||
import chalk from "chalk";
|
||||
|
||||
export default function () {
|
||||
return new Command("typedef")
|
||||
@ -30,6 +31,8 @@ export default function () {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`${chalk.bold(chalk.green(`Typedef gen success!`))}`);
|
||||
|
||||
process.exit();
|
||||
});
|
||||
}
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
export const AppData = {
|
||||
ConfigFileName: "bun-sqlite.config.ts",
|
||||
MaxBackups: 10,
|
||||
} as const;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { Database } from "bun:sqlite";
|
||||
import path from "node:path";
|
||||
import * as sqliteVec from "sqlite-vec";
|
||||
import grabDirNames from "../../data/grab-dir-names";
|
||||
import init from "../../functions/init";
|
||||
import grabDBDir from "../../utils/grab-db-dir";
|
||||
|
||||
const { ROOT_DIR } = grabDirNames();
|
||||
const { config } = await init();
|
||||
@ -13,9 +13,9 @@ if (config.db_dir) {
|
||||
db_dir = config.db_dir;
|
||||
}
|
||||
|
||||
const DBFilePath = path.join(db_dir, config.db_name);
|
||||
const { db_file_path } = grabDBDir({ config });
|
||||
|
||||
const DbClient = new Database(DBFilePath, {
|
||||
const DbClient = new Database(db_file_path, {
|
||||
create: true,
|
||||
});
|
||||
|
||||
|
||||
@ -1152,6 +1152,7 @@ export type BunSQLiteConfig = {
|
||||
* The Directory for backups
|
||||
*/
|
||||
db_backup_dir: string;
|
||||
max_backups?: number;
|
||||
/**
|
||||
* The Root Directory for the DB file and schema
|
||||
*/
|
||||
|
||||
13
src/utils/grab-backup-data.ts
Normal file
13
src/utils/grab-backup-data.ts
Normal file
@ -0,0 +1,13 @@
|
||||
type Params = {
|
||||
backup_name: string;
|
||||
};
|
||||
|
||||
export default function grabBackupData({ backup_name }: Params) {
|
||||
const backup_parts = backup_name.split("-");
|
||||
const backup_date_timestamp = Number(backup_parts.pop());
|
||||
const origin_backup_name = backup_parts.join("-");
|
||||
|
||||
const backup_date = new Date(backup_date_timestamp);
|
||||
|
||||
return { backup_date, backup_date_timestamp, origin_backup_name };
|
||||
}
|
||||
11
src/utils/grab-db-backup-file-name.ts
Normal file
11
src/utils/grab-db-backup-file-name.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import type { BunSQLiteConfig } from "../types";
|
||||
|
||||
type Params = {
|
||||
config: BunSQLiteConfig;
|
||||
};
|
||||
|
||||
export default function grabDBBackupFileName({ config }: Params) {
|
||||
const new_db_file_name = `${config.db_name}-${Date.now()}`;
|
||||
|
||||
return new_db_file_name;
|
||||
}
|
||||
22
src/utils/grab-db-dir.ts
Normal file
22
src/utils/grab-db-dir.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import path from "path";
|
||||
import grabDirNames from "../data/grab-dir-names";
|
||||
import type { BunSQLiteConfig } from "../types";
|
||||
|
||||
type Params = {
|
||||
config: BunSQLiteConfig;
|
||||
};
|
||||
|
||||
export default function grabDBDir({ config }: Params) {
|
||||
const { ROOT_DIR } = grabDirNames();
|
||||
|
||||
let db_dir = ROOT_DIR;
|
||||
|
||||
if (config.db_dir) {
|
||||
db_dir = config.db_dir;
|
||||
}
|
||||
|
||||
const backup_dir = path.resolve(db_dir, config.db_backup_dir);
|
||||
const db_file_path = path.resolve(db_dir, config.db_name);
|
||||
|
||||
return { db_dir, backup_dir, db_file_path };
|
||||
}
|
||||
29
src/utils/grab-sorted-backups.ts
Normal file
29
src/utils/grab-sorted-backups.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import grabDBDir from "../utils/grab-db-dir";
|
||||
import fs from "fs";
|
||||
import type { BunSQLiteConfig } from "../types";
|
||||
|
||||
type Params = {
|
||||
config: BunSQLiteConfig;
|
||||
};
|
||||
|
||||
export default function grabSortedBackups({ config }: Params) {
|
||||
const { backup_dir } = grabDBDir({ config });
|
||||
|
||||
const backups = fs.readdirSync(backup_dir);
|
||||
|
||||
/**
|
||||
* Order Backups. Most recent first.
|
||||
*/
|
||||
const ordered_backups = backups.sort((a, b) => {
|
||||
const a_date = Number(a.split("-").pop());
|
||||
const b_date = Number(b.split("-").pop());
|
||||
|
||||
if (a_date > b_date) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
});
|
||||
|
||||
return ordered_backups;
|
||||
}
|
||||
27
src/utils/trim-backups.ts
Normal file
27
src/utils/trim-backups.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import grabDBDir from "../utils/grab-db-dir";
|
||||
import fs from "fs";
|
||||
import type { BunSQLiteConfig } from "../types";
|
||||
import grabSortedBackups from "./grab-sorted-backups";
|
||||
import { AppData } from "../data/app-data";
|
||||
import path from "path";
|
||||
|
||||
type Params = {
|
||||
config: BunSQLiteConfig;
|
||||
};
|
||||
|
||||
export default function trimBackups({ config }: Params) {
|
||||
const { backup_dir } = grabDBDir({ config });
|
||||
|
||||
const backups = grabSortedBackups({ config });
|
||||
|
||||
const max_backups = config.max_backups || AppData["MaxBackups"];
|
||||
|
||||
for (let i = 0; i < backups.length; i++) {
|
||||
const backup_name = backups[i];
|
||||
if (!backup_name) continue;
|
||||
if (i > max_backups - 1) {
|
||||
const backup_file_to_unlink = path.join(backup_dir, backup_name);
|
||||
fs.unlinkSync(backup_file_to_unlink);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user