@stacksjs/database 0.75.0 → 0.75.2

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.
@@ -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
@@ -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 the indexes below depend on, for tables that may predate them.
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
@@ -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.0",
5
+ "version": "0.75.2",
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.0",
70
- "@stacksjs/env": "0.75.0",
71
- "@stacksjs/error-handling": "0.75.0",
72
- "@stacksjs/faker": "^0.75.0",
73
- "@stacksjs/features": "0.75.0",
74
- "@stacksjs/logging": "0.75.0",
75
- "@stacksjs/model-meta": "0.75.0",
76
- "@stacksjs/path": "0.75.0",
77
- "@stacksjs/query-builder": "^0.75.0",
78
- "@stacksjs/security": "0.75.0",
79
- "@stacksjs/storage": "0.75.0",
80
- "@stacksjs/strings": "0.75.0",
69
+ "@stacksjs/config": "0.75.2",
70
+ "@stacksjs/env": "0.75.2",
71
+ "@stacksjs/error-handling": "0.75.2",
72
+ "@stacksjs/faker": "^0.75.2",
73
+ "@stacksjs/features": "0.75.2",
74
+ "@stacksjs/logging": "0.75.2",
75
+ "@stacksjs/model-meta": "0.75.2",
76
+ "@stacksjs/path": "0.75.2",
77
+ "@stacksjs/query-builder": "^0.75.2",
78
+ "@stacksjs/security": "0.75.2",
79
+ "@stacksjs/storage": "0.75.2",
80
+ "@stacksjs/strings": "0.75.2",
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.0",
87
- "@stacksjs/router": "0.75.0",
88
- "@stacksjs/utils": "0.75.0",
86
+ "@stacksjs/cli": "0.75.2",
87
+ "@stacksjs/router": "0.75.2",
88
+ "@stacksjs/utils": "0.75.2",
89
89
  "better-dx": "^0.2.24"
90
90
  }
91
91
  }