@stacksjs/database 0.75.233 → 0.75.237

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.
@@ -6,8 +6,10 @@ export declare function migrationNameOrdinal(file: string): number | undefined;
6
6
  * Renames are read as a delete plus an add (`--no-renames`), because a
7
7
  * renumbered file's OLD name is the one an older ledger recorded. A file
8
8
  * deleted and later put back exactly as it was (a reverted commit, restored)
9
- * is the same migration under its own name, not a reuse of it, so it is not
10
- * retired. Outside a git checkout, without git, or in a shallow clone that
9
+ * is the same migration only when every historical deletion carried those
10
+ * exact bytes. An older different migration may still be in a production
11
+ * ledger, even if the latest deletion was restored identically. Outside a git
12
+ * checkout, without git, or in a shallow clone that
11
13
  * has no history, this answers with whatever git can see, which may be
12
14
  * nothing.
13
15
  */
@@ -1,2 +1 @@
1
- import{spawnSync}from"node:child_process";import{readdirSync,readFileSync}from"node:fs";import{basename,join}from"node:path";import{carriesGeneratedMarker}from"./hand-written-migrations";import{isPackageMigration}from"./package-migrations";export function migrationNameOrdinal(file){const match=/^(\d+)[-_]/.exec(file);return match?Number.parseInt(match[1],10):void 0}export function retiredMigrationNames(dir,options={}){const git=(args)=>spawnSync("git",args,{cwd:dir,encoding:"utf8",timeout:options.timeoutMs??1e4,maxBuffer:67108864});try{const result=git(["log","--no-renames","--diff-filter=D","--name-only","--pretty=format:commit %H","--","."]);if(result.status!==0||typeof result.stdout!=="string")return[];const deletedAt=new Map;let commit="";for(const raw of result.stdout.split(`
2
- `)){const line=raw.trim();if(line.startsWith("commit ")){commit=line.slice(7);continue}const name=basename(line);if(name.toLowerCase().endsWith(".sql")&&!deletedAt.has(name))deletedAt.set(name,{commit,path:line})}const names=[];for(const[name,deletion]of deletedAt){let current;try{current=readFileSync(join(dir,name),"utf8")}catch{current=void 0}if(current!==void 0&&deletion.commit){const before=git(["show",`${deletion.commit}^:${deletion.path}`]);if(before.status===0&&before.stdout===current)continue}names.push(name)}return names.sort()}catch{return[]}}export const TIMESTAMP_MIGRATION_ORDINAL=1e9;export function nextMigrationOrdinal(diskFiles,claimed=[]){let max=0;for(const file of diskFiles){if(isPackageMigration(file))continue;const ordinal=migrationNameOrdinal(file);if(ordinal!==void 0)max=Math.max(max,ordinal)}const reserved=reservedMigrationOrdinals(claimed);for(const ordinal of reserved)if(ordinal<TIMESTAMP_MIGRATION_ORDINAL)max=Math.max(max,ordinal);return nextFreeMigrationOrdinal(max+1,reserved)}export function reservedMigrationOrdinals(claimed){const reserved=new Set;for(const name of claimed){if(isPackageMigration(name))continue;const ordinal=migrationNameOrdinal(name);if(ordinal!==void 0)reserved.add(ordinal)}return reserved}export function nextFreeMigrationOrdinal(from,reserved){let cursor=from;while(reserved.has(cursor))cursor+=1;return cursor}export function duplicateMigrationOrdinals(files){const byOrdinal=new Map;for(const file of files){if(!file.toLowerCase().endsWith(".sql"))continue;const ordinal=/^(\d+)[-_]/.exec(file)?.[1];if(ordinal===void 0)continue;const key=String(Number.parseInt(ordinal,10));if(!byOrdinal.has(key))byOrdinal.set(key,[]);byOrdinal.get(key).push(file)}return[...byOrdinal.values()].filter((group)=>group.length>1).map((group)=>{const sorted=[...group].sort();return{ordinal:/^(\d+)/.exec(sorted[0])[1],files:sorted}}).sort((a,b)=>a.files[0].localeCompare(b.files[0]))}export function duplicateMigrationOrdinalsIn(dir){let files;try{files=readdirSync(dir)}catch{return[]}return duplicateMigrationOrdinals(files).map((group)=>({...group,generated:group.files.some((file)=>{try{return carriesGeneratedMarker(readFileSync(join(dir,file),"utf8"))}catch{return!1}})}))}
1
+ import{spawnSync}from"node:child_process";import{createHash}from"node:crypto";import{readdirSync,readFileSync}from"node:fs";import{basename,join}from"node:path";import{carriesGeneratedMarker}from"./hand-written-migrations";import{isPackageMigration}from"./package-migrations";export function migrationNameOrdinal(file){const match=/^(\d+)[-_]/.exec(file);return match?Number.parseInt(match[1],10):void 0}export function retiredMigrationNames(dir,options={}){const git=(args)=>spawnSync("git",args,{cwd:dir,encoding:"utf8",timeout:options.timeoutMs??1e4,maxBuffer:67108864});try{const result=git(["log","--no-renames","--diff-filter=D","--raw","--no-abbrev","-z","--pretty=format:","--","."]);if(result.status!==0||typeof result.stdout!=="string")return[];const deletedObjects=new Map,records=result.stdout.split("\x00");for(let index=0;index<records.length;index++){const deletion=/^:[0-7]{6} [0-7]{6} ([a-f0-9]{40}|[a-f0-9]{64}) 0+ D$/.exec(records[index].trim());if(!deletion)continue;const path=records[++index];if(!path)continue;const name=basename(path);if(!name.toLowerCase().endsWith(".sql"))continue;const objects=deletedObjects.get(name)??new Set;objects.add(deletion[1]);deletedObjects.set(name,objects)}const names=[];for(const[name,objects]of deletedObjects){if(objects.size===1)try{const current=readFileSync(join(dir,name)),previous=objects.values().next().value;if(createHash(previous.length===64?"sha256":"sha1").update(`blob ${current.byteLength}\x00`).update(current).digest("hex")===previous)continue}catch{}names.push(name)}return names.sort()}catch{return[]}}export const TIMESTAMP_MIGRATION_ORDINAL=1e9;export function nextMigrationOrdinal(diskFiles,claimed=[]){let max=0;for(const file of diskFiles){if(isPackageMigration(file))continue;const ordinal=migrationNameOrdinal(file);if(ordinal!==void 0)max=Math.max(max,ordinal)}const reserved=reservedMigrationOrdinals(claimed);for(const ordinal of reserved)if(ordinal<TIMESTAMP_MIGRATION_ORDINAL)max=Math.max(max,ordinal);return nextFreeMigrationOrdinal(max+1,reserved)}export function reservedMigrationOrdinals(claimed){const reserved=new Set;for(const name of claimed){if(isPackageMigration(name))continue;const ordinal=migrationNameOrdinal(name);if(ordinal!==void 0)reserved.add(ordinal)}return reserved}export function nextFreeMigrationOrdinal(from,reserved){let cursor=from;while(reserved.has(cursor))cursor+=1;return cursor}export function duplicateMigrationOrdinals(files){const byOrdinal=new Map;for(const file of files){if(!file.toLowerCase().endsWith(".sql"))continue;const ordinal=/^(\d+)[-_]/.exec(file)?.[1];if(ordinal===void 0)continue;const key=String(Number.parseInt(ordinal,10));if(!byOrdinal.has(key))byOrdinal.set(key,[]);byOrdinal.get(key).push(file)}return[...byOrdinal.values()].filter((group)=>group.length>1).map((group)=>{const sorted=[...group].sort();return{ordinal:/^(\d+)/.exec(sorted[0])[1],files:sorted}}).sort((a,b)=>a.files[0].localeCompare(b.files[0]))}export function duplicateMigrationOrdinalsIn(dir){let files;try{files=readdirSync(dir)}catch{return[]}return duplicateMigrationOrdinals(files).map((group)=>({...group,generated:group.files.some((file)=>{try{return carriesGeneratedMarker(readFileSync(join(dir,file),"utf8"))}catch{return!1}})}))}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/database",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.75.233",
5
+ "version": "0.75.237",
6
6
  "description": "The Stacks database integration.",
7
7
  "author": "Chris Breuer",
8
8
  "contributors": [
@@ -66,26 +66,26 @@
66
66
  "prepublishOnly": "bun run build"
67
67
  },
68
68
  "dependencies": {
69
- "@stacksjs/config": "0.75.233",
70
- "@stacksjs/env": "0.75.233",
71
- "@stacksjs/error-handling": "0.75.233",
72
- "@stacksjs/faker": "0.75.233",
73
- "@stacksjs/features": "0.75.233",
74
- "@stacksjs/logging": "0.75.233",
75
- "@stacksjs/model-meta": "0.75.233",
76
- "@stacksjs/path": "0.75.233",
77
- "@stacksjs/query-builder": "0.75.233",
78
- "@stacksjs/security": "0.75.233",
79
- "@stacksjs/storage": "0.75.233",
80
- "@stacksjs/strings": "0.75.233",
69
+ "@stacksjs/config": "0.75.237",
70
+ "@stacksjs/env": "0.75.237",
71
+ "@stacksjs/error-handling": "0.75.237",
72
+ "@stacksjs/faker": "0.75.237",
73
+ "@stacksjs/features": "0.75.237",
74
+ "@stacksjs/logging": "0.75.237",
75
+ "@stacksjs/model-meta": "0.75.237",
76
+ "@stacksjs/path": "0.75.237",
77
+ "@stacksjs/query-builder": "0.75.237",
78
+ "@stacksjs/security": "0.75.237",
79
+ "@stacksjs/storage": "0.75.237",
80
+ "@stacksjs/strings": "0.75.237",
81
81
  "@stacksjs/ts-validation": "^0.5.6",
82
82
  "bun-query-builder": "^0.3.9",
83
83
  "dynamodb-tooling": "^0.3.6"
84
84
  },
85
85
  "devDependencies": {
86
- "@stacksjs/cli": "0.75.233",
87
- "@stacksjs/router": "0.75.233",
88
- "@stacksjs/utils": "0.75.233",
86
+ "@stacksjs/cli": "0.75.237",
87
+ "@stacksjs/router": "0.75.237",
88
+ "@stacksjs/utils": "0.75.237",
89
89
  "better-dx": "^0.2.24"
90
90
  }
91
91
  }