@stacksjs/database 0.75.0 → 0.75.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/dist/framework-schema.d.ts +2 -0
- package/dist/trait-tables.d.ts +8 -1
- package/dist/trait-tables.js +3 -1
- package/package.json +16 -16
|
@@ -364,6 +364,8 @@ export declare interface FrameworkSchema {
|
|
|
364
364
|
commentables_id: number
|
|
365
365
|
commentables_type: string
|
|
366
366
|
user_id: number | null
|
|
367
|
+
author_name: string | null
|
|
368
|
+
author_email: string | null
|
|
367
369
|
is_active: number | null
|
|
368
370
|
created_at: string
|
|
369
371
|
updated_at: string | null
|
package/dist/trait-tables.d.ts
CHANGED
|
@@ -19,6 +19,11 @@ export declare function traitTableNames(): TraitTableName[];
|
|
|
19
19
|
* 32-bit INTEGER on Postgres and MySQL — hence BIGINT. SQLite gives every
|
|
20
20
|
* INTEGER 64 bits, so the same declaration is correct there too.
|
|
21
21
|
*
|
|
22
|
+
* `author_name` / `author_email` carry a guest commenter, someone who left a
|
|
23
|
+
* name on a public form without an account. A signed-in commenter is
|
|
24
|
+
* `user_id` instead, so both are nullable. They were missing entirely, which
|
|
25
|
+
* left a public blog nowhere to record who wrote a comment.
|
|
26
|
+
*
|
|
22
27
|
* This is a distinct table from `comments`: `comments` is a model-backed
|
|
23
28
|
* table, `commentables` is the polymorphic trait table.
|
|
24
29
|
*/
|
|
@@ -88,7 +93,9 @@ export declare function commentableUpvotesTableSql(sql: SqlHelpers): string;
|
|
|
88
93
|
* duplicate-index error on replay instead.
|
|
89
94
|
*/
|
|
90
95
|
/**
|
|
91
|
-
* Columns
|
|
96
|
+
* Columns added after a table first shipped, for databases that predate them:
|
|
97
|
+
* the ones the indexes below depend on, and the guest-author columns on
|
|
98
|
+
* `commentables`.
|
|
92
99
|
*
|
|
93
100
|
* Only additive: a column that is missing gets added with a default, and one
|
|
94
101
|
* that is present is left alone. Nothing here drops or retypes, so replaying
|
package/dist/trait-tables.js
CHANGED
|
@@ -8,6 +8,8 @@ import{log}from"@stacksjs/logging";import{env as envVars}from"@stacksjs/env";imp
|
|
|
8
8
|
commentables_id INTEGER NOT NULL,
|
|
9
9
|
commentables_type VARCHAR(255) NOT NULL,
|
|
10
10
|
user_id INTEGER,
|
|
11
|
+
author_name VARCHAR(255),
|
|
12
|
+
author_email VARCHAR(255),
|
|
11
13
|
is_active BOOLEAN NOT NULL DEFAULT ${boolTrue},
|
|
12
14
|
${createdAt(sql)},
|
|
13
15
|
${updatedAt(sql)}
|
|
@@ -58,4 +60,4 @@ import{log}from"@stacksjs/logging";import{env as envVars}from"@stacksjs/env";imp
|
|
|
58
60
|
upvoteable_id INTEGER NOT NULL,
|
|
59
61
|
upvoteable_type VARCHAR(255) NOT NULL,
|
|
60
62
|
${createdAt(sql)}
|
|
61
|
-
)`}export function traitTableColumnGuarantees(sql){return[{table:"taggables",column:"taggable_id",definition:`INTEGER NOT NULL DEFAULT ${UNSCOPED_OWNER_ID}`},{table:"categorizables",column:"categorizable_id",definition:`INTEGER NOT NULL DEFAULT ${UNSCOPED_OWNER_ID}`}]}export function traitTableIndexSql(){return["CREATE INDEX IF NOT EXISTS commentables_owner_index ON commentables (commentables_type, commentables_id)","CREATE INDEX IF NOT EXISTS commentables_status_index ON commentables (status)","CREATE UNIQUE INDEX IF NOT EXISTS taggables_owner_slug_unique ON taggables (taggable_type, taggable_id, slug)","CREATE UNIQUE INDEX IF NOT EXISTS categorizables_owner_slug_unique ON categorizables (categorizable_type, categorizable_id, slug)","CREATE INDEX IF NOT EXISTS commentable_upvotes_target_index ON commentable_upvotes (upvoteable_type, upvoteable_id)","CREATE UNIQUE INDEX IF NOT EXISTS commentable_upvotes_user_unique ON commentable_upvotes (upvoteable_type, upvoteable_id, user_id)","CREATE UNIQUE INDEX IF NOT EXISTS taggable_models_unique ON taggable_models (tag_id, taggable_id, taggable_type)","CREATE UNIQUE INDEX IF NOT EXISTS categorizable_models_unique ON categorizable_models (category_id, categorizable_id, categorizable_type)"]}export async function likeableTargets(){const{path}=await import("@stacksjs/path"),{globSync}=await import("@stacksjs/storage"),{getTableName}=await import("@stacksjs/model-meta"),{getLikeableForeignKey,getUpvoteTableName}=await import("./drivers/helpers"),modelFiles=globSync([path.userModelsPath("*.ts"),path.storagePath("framework/defaults/app/Models/**/*.ts")],{absolute:!0}),targets=new Map;for(const modelFile of modelFiles){let model;try{model=(await import(modelFile)).default}catch{continue}if(!model?.traits?.likeable)continue;const tableName=await getTableName(model,modelFile);if(!tableName)continue;const table=getUpvoteTableName(model,tableName);if(!table||!/^[a-z_]\w*$/i.test(table))continue;const foreignKey=getLikeableForeignKey(model,tableName);if(!/^[a-z_]\w*$/i.test(foreignKey))continue;targets.set(table,{table,foreignKey})}return[...targets.values()]}export async function migrateTraitTables(options={}){const dbDriver=getDbDriver(),sql=sqlHelpers(dbDriver);if(options.verbose)log.info(`Creating polymorphic trait tables for ${dbDriver}...`);try{if(options.verbose)log.info("Creating commentables table...");await db.unsafe(commentablesTableSql(sql)).execute();if(options.verbose)log.info("Creating taggables table...");await db.unsafe(taggablesTableSql(sql)).execute();if(options.verbose)log.info("Creating categorizables table...");await db.unsafe(categorizablesTableSql(sql)).execute();if(options.verbose)log.info("Creating commentable_upvotes table...");await db.unsafe(commentableUpvotesTableSql(sql)).execute();if(options.verbose)log.info("Creating taggable_models pivot...");await db.unsafe(taggableModelsTableSql(sql)).execute();if(options.verbose)log.info("Creating categorizable_models pivot...");await db.unsafe(categorizableModelsTableSql(sql)).execute();try{for(const{table,foreignKey}of await likeableTargets()){if(options.verbose)log.info(`Creating ${table} table...`);await db.unsafe(likesTableSql(sql,table,foreignKey)).execute()}}catch(error){log.debug(`[trait-tables] Skipped likeable tables: ${error instanceof Error?error.message:String(error)}`)}for(const{table,column,definition}of traitTableColumnGuarantees(sql))try{await db.unsafe(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`).execute();if(options.verbose)log.info(`Added missing ${table}.${column}`)}catch(error){if(!isDuplicateColumnError(error))throw error}for(const statement of traitTableIndexSql())try{await db.unsafe(indexSqlForDialect(statement,dbDriver)).execute()}catch(error){if(!isDuplicateIndexError(error))throw error}if(options.verbose)log.success("Polymorphic trait tables created");return{success:!0}}catch(error){const message=error instanceof Error?error.message:String(error);log.error(`Failed to create polymorphic trait tables: ${message}`);return{success:!1,error:message}}}
|
|
63
|
+
)`}export function traitTableColumnGuarantees(sql){return[{table:"taggables",column:"taggable_id",definition:`INTEGER NOT NULL DEFAULT ${UNSCOPED_OWNER_ID}`},{table:"categorizables",column:"categorizable_id",definition:`INTEGER NOT NULL DEFAULT ${UNSCOPED_OWNER_ID}`},{table:"commentables",column:"author_name",definition:"VARCHAR(255)"},{table:"commentables",column:"author_email",definition:"VARCHAR(255)"}]}export function traitTableIndexSql(){return["CREATE INDEX IF NOT EXISTS commentables_owner_index ON commentables (commentables_type, commentables_id)","CREATE INDEX IF NOT EXISTS commentables_status_index ON commentables (status)","CREATE UNIQUE INDEX IF NOT EXISTS taggables_owner_slug_unique ON taggables (taggable_type, taggable_id, slug)","CREATE UNIQUE INDEX IF NOT EXISTS categorizables_owner_slug_unique ON categorizables (categorizable_type, categorizable_id, slug)","CREATE INDEX IF NOT EXISTS commentable_upvotes_target_index ON commentable_upvotes (upvoteable_type, upvoteable_id)","CREATE UNIQUE INDEX IF NOT EXISTS commentable_upvotes_user_unique ON commentable_upvotes (upvoteable_type, upvoteable_id, user_id)","CREATE UNIQUE INDEX IF NOT EXISTS taggable_models_unique ON taggable_models (tag_id, taggable_id, taggable_type)","CREATE UNIQUE INDEX IF NOT EXISTS categorizable_models_unique ON categorizable_models (category_id, categorizable_id, categorizable_type)"]}export async function likeableTargets(){const{path}=await import("@stacksjs/path"),{globSync}=await import("@stacksjs/storage"),{getTableName}=await import("@stacksjs/model-meta"),{getLikeableForeignKey,getUpvoteTableName}=await import("./drivers/helpers"),modelFiles=globSync([path.userModelsPath("*.ts"),path.storagePath("framework/defaults/app/Models/**/*.ts")],{absolute:!0}),targets=new Map;for(const modelFile of modelFiles){let model;try{model=(await import(modelFile)).default}catch{continue}if(!model?.traits?.likeable)continue;const tableName=await getTableName(model,modelFile);if(!tableName)continue;const table=getUpvoteTableName(model,tableName);if(!table||!/^[a-z_]\w*$/i.test(table))continue;const foreignKey=getLikeableForeignKey(model,tableName);if(!/^[a-z_]\w*$/i.test(foreignKey))continue;targets.set(table,{table,foreignKey})}return[...targets.values()]}export async function migrateTraitTables(options={}){const dbDriver=getDbDriver(),sql=sqlHelpers(dbDriver);if(options.verbose)log.info(`Creating polymorphic trait tables for ${dbDriver}...`);try{if(options.verbose)log.info("Creating commentables table...");await db.unsafe(commentablesTableSql(sql)).execute();if(options.verbose)log.info("Creating taggables table...");await db.unsafe(taggablesTableSql(sql)).execute();if(options.verbose)log.info("Creating categorizables table...");await db.unsafe(categorizablesTableSql(sql)).execute();if(options.verbose)log.info("Creating commentable_upvotes table...");await db.unsafe(commentableUpvotesTableSql(sql)).execute();if(options.verbose)log.info("Creating taggable_models pivot...");await db.unsafe(taggableModelsTableSql(sql)).execute();if(options.verbose)log.info("Creating categorizable_models pivot...");await db.unsafe(categorizableModelsTableSql(sql)).execute();try{for(const{table,foreignKey}of await likeableTargets()){if(options.verbose)log.info(`Creating ${table} table...`);await db.unsafe(likesTableSql(sql,table,foreignKey)).execute()}}catch(error){log.debug(`[trait-tables] Skipped likeable tables: ${error instanceof Error?error.message:String(error)}`)}for(const{table,column,definition}of traitTableColumnGuarantees(sql))try{await db.unsafe(`ALTER TABLE ${table} ADD COLUMN ${column} ${definition}`).execute();if(options.verbose)log.info(`Added missing ${table}.${column}`)}catch(error){if(!isDuplicateColumnError(error))throw error}for(const statement of traitTableIndexSql())try{await db.unsafe(indexSqlForDialect(statement,dbDriver)).execute()}catch(error){if(!isDuplicateIndexError(error))throw error}if(options.verbose)log.success("Polymorphic trait tables created");return{success:!0}}catch(error){const message=error instanceof Error?error.message:String(error);log.error(`Failed to create polymorphic trait tables: ${message}`);return{success:!1,error:message}}}
|
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.
|
|
5
|
+
"version": "0.75.1",
|
|
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.
|
|
70
|
-
"@stacksjs/env": "0.75.
|
|
71
|
-
"@stacksjs/error-handling": "0.75.
|
|
72
|
-
"@stacksjs/faker": "^0.75.
|
|
73
|
-
"@stacksjs/features": "0.75.
|
|
74
|
-
"@stacksjs/logging": "0.75.
|
|
75
|
-
"@stacksjs/model-meta": "0.75.
|
|
76
|
-
"@stacksjs/path": "0.75.
|
|
77
|
-
"@stacksjs/query-builder": "^0.75.
|
|
78
|
-
"@stacksjs/security": "0.75.
|
|
79
|
-
"@stacksjs/storage": "0.75.
|
|
80
|
-
"@stacksjs/strings": "0.75.
|
|
69
|
+
"@stacksjs/config": "0.75.1",
|
|
70
|
+
"@stacksjs/env": "0.75.1",
|
|
71
|
+
"@stacksjs/error-handling": "0.75.1",
|
|
72
|
+
"@stacksjs/faker": "^0.75.1",
|
|
73
|
+
"@stacksjs/features": "0.75.1",
|
|
74
|
+
"@stacksjs/logging": "0.75.1",
|
|
75
|
+
"@stacksjs/model-meta": "0.75.1",
|
|
76
|
+
"@stacksjs/path": "0.75.1",
|
|
77
|
+
"@stacksjs/query-builder": "^0.75.1",
|
|
78
|
+
"@stacksjs/security": "0.75.1",
|
|
79
|
+
"@stacksjs/storage": "0.75.1",
|
|
80
|
+
"@stacksjs/strings": "0.75.1",
|
|
81
81
|
"@stacksjs/ts-validation": "^0.5.6",
|
|
82
82
|
"bun-query-builder": "^0.2.70",
|
|
83
83
|
"dynamodb-tooling": "^0.3.2"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
|
-
"@stacksjs/cli": "0.75.
|
|
87
|
-
"@stacksjs/router": "0.75.
|
|
88
|
-
"@stacksjs/utils": "0.75.
|
|
86
|
+
"@stacksjs/cli": "0.75.1",
|
|
87
|
+
"@stacksjs/router": "0.75.1",
|
|
88
|
+
"@stacksjs/utils": "0.75.1",
|
|
89
89
|
"better-dx": "^0.2.24"
|
|
90
90
|
}
|
|
91
91
|
}
|