@stacksjs/commerce 0.75.141 → 0.75.143
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
import assert from"node:assert/strict";import{
|
|
1
|
+
import assert from"node:assert/strict";import{basename,dirname,join}from"node:path";import process from"node:process";const dialect=process.env.DB_CONNECTION;assert(dialect==="sqlite"||dialect==="postgres"||dialect==="mysql");const configPath=process.env.STACKS_COMMERCE_RETURNING_ALL_CONFIG;assert(configPath&&basename(dirname(configPath)).startsWith("stacks-commerce-returning-all-"));if(dialect==="sqlite")assert.equal(dirname(process.env.DB_DATABASE_PATH),dirname(configPath));else{assert.equal(process.env.DB_DATABASE_PATH,":memory:");assert(process.env.DB_DATABASE?.startsWith("stacks_commerce_returning_all_"));assert(["127.0.0.1","localhost","[::1]"].includes(process.env.DB_HOST))}const{overridesReady}=await import("@stacksjs/config");await overridesReady;const{db,ensureDatabaseConfigLoaded,initializeDbConfig,resetDatabaseConnection}=await import("@stacksjs/database");await ensureDatabaseConfigLoaded();initializeDbConfig({app:{env:"test"},database:{default:dialect,connections:dialect==="sqlite"?{sqlite:{database:process.env.DB_DATABASE_PATH}}:{[dialect]:{name:process.env.DB_DATABASE,host:process.env.DB_HOST,port:Number(process.env.DB_PORT),username:process.env.DB_USERNAME,password:process.env.DB_PASSWORD}},queryLogging:{enabled:!1}}});const TABLES=["carts","categories","product_units","product_variants","products","shipping_methods","shipping_rates","shipping_zones"],{buildMigrationPlan,generateSql,loadModels}=await import("bun-query-builder"),modelsDir=join(import.meta.dir,"../../../../../defaults/app/Models"),models={...await loadModels({modelsDir}),...await loadModels({modelsDir:join(modelsDir,"commerce")})},plan=buildMigrationPlan(models,{dialect});plan.tables=plan.tables.filter((table)=>TABLES.includes(table.table));assert.deepEqual(plan.tables.map((table)=>table.table).sort(),TABLES);for(const table of plan.tables)for(const column of table.columns)delete column.references;const statements=generateSql(plan),{update:updateCart}=await import("../../carts/update"),{update:updateItem}=await import("../../products/items/update"),{update:updateVariant}=await import("../../products/variants/update"),{update:updateUnit}=await import("../../products/units/update"),{update:updateRate}=await import("../../shippings/shipping-rates/update"),{store:storeCategory}=await import("../../products/categories/store");async function stored(table,id){return await db.selectFrom(table).selectAll().where("id","=",id).executeTakeFirst()}const failures=[];async function check(name,run){try{await run();console.log(`PASS ${name}`)}catch(error){failures.push(`${name}: ${error instanceof Error?error.message:String(error)}`)}}try{for(const statement of statements)await db.unsafe(statement).execute();await db.insertInto("carts").values({id:1,status:"active",expires_at:"2030-02-01 00:00:00",applied_coupon_id:"none"}).execute();await db.insertInto("products").values({id:1,name:"before",price:100,preparation_time:5}).execute();await db.insertInto("product_variants").values({id:1,variant:"Size",type:"dropdown",status:"active"}).execute();await db.insertInto("product_units").values({id:1,name:"gram",abbreviation:"g",type:"weight"}).execute();await db.insertInto("shipping_methods").values({id:1,name:"standard",base_rate:500,status:"active"}).execute();await db.insertInto("shipping_zones").values({id:1,name:"domestic",status:"active",shipping_method_id:1}).execute();await db.insertInto("shipping_rates").values({id:1,weight_from:0,weight_to:10,rate:100,shipping_method_id:1,shipping_zone_id:1}).execute();await check("carts update",async()=>{const row=await updateCart(1,{notes:"after"});assert.equal(row?.notes,"after",`${dialect}: the returned cart`);assert.equal((await stored("carts",1))?.notes,"after",`${dialect}: the stored cart`)});await check("product items update",async()=>{const row=await updateItem(1,{name:"after"});assert.equal(row?.name,"after",`${dialect}: the returned product`);assert.equal((await stored("products",1))?.name,"after",`${dialect}: the stored product`)});await check("product variants update",async()=>{const row=await updateVariant(1,{variant:"Colour"});assert.equal(row?.variant,"Colour",`${dialect}: the returned variant`);assert.equal((await stored("product_variants",1))?.variant,"Colour",`${dialect}: the stored variant`)});await check("product units update",async()=>{const row=await updateUnit(1,{name:"kilogram"});assert.equal(row?.name,"kilogram",`${dialect}: the returned unit`);assert.equal((await stored("product_units",1))?.name,"kilogram",`${dialect}: the stored unit`)});await check("shipping rates update",async()=>{const row=await updateRate(1,{rate:250});assert.equal(Number(row?.rate),250,`${dialect}: the returned rate`);assert.equal(Number((await stored("shipping_rates",1))?.rate),250,`${dialect}: the stored rate`)});await check("categories store",async()=>{const row=await storeCategory({name:"Shoes",slug:`shoes-${dialect}`,display_order:1});assert(row?.id,`${dialect}: the inserted category comes back with its id`);assert.equal(row.name,"Shoes");assert.equal((await stored("categories",row.id))?.slug,`shoes-${dialect}`,`${dialect}: the stored category`)});assert.deepEqual(failures,[],`${dialect}: every returningAll() write must apply and return its row`);console.log("commerce returningAll writes OK")}finally{resetDatabaseConnection()}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import assert from"node:assert/strict";import{
|
|
1
|
+
import assert from"node:assert/strict";import{basename,dirname,join}from"node:path";import process from"node:process";const dialect=process.env.DB_CONNECTION;assert(dialect==="sqlite"||dialect==="postgres"||dialect==="mysql");const configPath=process.env.STACKS_COMMERCE_SOFT_DELETE_CONFIG;assert(configPath&&basename(dirname(configPath)).startsWith("stacks-commerce-soft-delete-"));if(dialect==="sqlite")assert.equal(dirname(process.env.DB_DATABASE_PATH),dirname(configPath));else{assert.equal(process.env.DB_DATABASE_PATH,":memory:");assert(process.env.DB_DATABASE?.startsWith("stacks_commerce_soft_delete_"));assert(["127.0.0.1","localhost","[::1]"].includes(process.env.DB_HOST))}const{overridesReady}=await import("@stacksjs/config");await overridesReady;const{db,ensureDatabaseConfigLoaded,initializeDbConfig,resetDatabaseConnection}=await import("@stacksjs/database");await ensureDatabaseConfigLoaded();initializeDbConfig({app:{env:"test"},database:{default:dialect,connections:dialect==="sqlite"?{sqlite:{database:process.env.DB_DATABASE_PATH}}:{[dialect]:{name:process.env.DB_DATABASE,host:process.env.DB_HOST,port:Number(process.env.DB_PORT),username:process.env.DB_USERNAME,password:process.env.DB_PASSWORD}},queryLogging:{enabled:!1}}});const TABLES=["carts","digital_deliveries","gift_cards","license_keys","orders","product_units","product_variants","products","shipping_methods","shipping_rates","shipping_zones"],{buildMigrationPlan,generateSql,loadModels}=await import("bun-query-builder"),modelsDir=join(import.meta.dir,"../../../../../defaults/app/Models"),models={...await loadModels({modelsDir}),...await loadModels({modelsDir:join(modelsDir,"commerce")})},plan=buildMigrationPlan(models,{dialect});plan.tables=plan.tables.filter((table)=>TABLES.includes(table.table));assert.deepEqual(plan.tables.map((table)=>table.table).sort(),TABLES);for(const table of plan.tables)for(const column of table.columns)delete column.references;const statements=generateSql(plan),orders=await import("../../orders/destroy"),digitalDeliveries=await import("../../shippings/digital-deliveries/destroy"),licenseKeys=await import("../../shippings/license-keys/destroy"),shippingMethods=await import("../../shippings/shipping-methods/destroy"),shippingZones=await import("../../shippings/shipping-zones/destroy"),{deactivate:deactivateGiftCard}=await import("../../gift-cards/destroy"),{bulkUpdate:bulkUpdateVariants,updateStatus:updateVariantStatus}=await import("../../products/variants/update"),{bulkUpdate:bulkUpdateCarts}=await import("../../carts/update"),{updateByZone:updateRatesByZone}=await import("../../shippings/shipping-rates/update"),{bulkUpdate:bulkUpdateItems}=await import("../../products/items/update"),{bulkUpdate:bulkUpdateUnits}=await import("../../products/units/update"),MODULES=[{name:"orders",table:"orders",deleted:"CANCELED",module:orders,row:(id,status)=>({id,status,total_amount:1000,order_type:"DELIVERY"}),live:"PENDING"},{name:"shippings/digital-deliveries",table:"digital_deliveries",deleted:"inactive",module:digitalDeliveries,row:(id,status)=>({id,status,name:`delivery-${id}`,description:"seeded",expiry_days:7}),live:"active"},{name:"shippings/license-keys",table:"license_keys",deleted:"inactive",module:licenseKeys,row:(id,status)=>({id,status,key:`KEY-${id}`,template:"Standard License",expiry_date:"2030-01-01"}),live:"active"},{name:"shippings/shipping-methods",table:"shipping_methods",deleted:"inactive",module:shippingMethods,row:(id,status)=>({id,status,name:`method-${id}`,base_rate:500}),live:"active"},{name:"shippings/shipping-zones",table:"shipping_zones",deleted:"inactive",module:shippingZones,row:(id,status)=>({id,status,name:`zone-${id}`}),live:"active"}];async function statusOf(table,id){return(await db.selectFrom(table).selectAll().where("id","=",id).executeTakeFirst())?.status}const failures=[];async function check(name,run){try{await run();console.log(`PASS ${name}`)}catch(error){failures.push(`${name}: ${error instanceof Error?error.message:String(error)}`)}}try{for(const statement of statements)await db.unsafe(statement).execute();for(const{name,table,deleted,live,module,row}of MODULES)await check(`${name} soft delete counts rows already in the target state`,async()=>{for(const[id,status]of[[1,deleted],[2,live],[3,deleted],[4,live]])await db.insertInto(table).values(row(id,status)).execute();assert.equal(await module.softDelete(1),!0,`${dialect}: soft-deleting an already soft-deleted row must report success`);assert.equal(await statusOf(table,1),deleted,"the row is still there, still soft-deleted");assert.equal(await module.softDelete(2),!0,`${dialect}: soft-deleting a live row must report success`);assert.equal(await statusOf(table,2),deleted);assert.equal(await module.bulkSoftDelete([3,4]),2,`${dialect}: bulk soft delete must count rows already in the target state`);assert.equal(await statusOf(table,3),deleted);assert.equal(await statusOf(table,4),deleted);assert.equal(await module.softDelete(404),!1,`${dialect}: soft-deleting a row that does not exist must report failure`);assert.equal(await module.bulkSoftDelete([404,405]),0)});const{setSystemTime}=await import("bun:test");setSystemTime(new Date("2030-01-02T03:04:05.000Z"));try{await check("gift card deactivate is idempotent within one second",async()=>{await db.insertInto("gift_cards").values({id:1,code:"GC-1",initial_balance:5000,current_balance:5000,status:"ACTIVE"}).execute();assert.equal(await deactivateGiftCard(1),!0,`${dialect}: deactivating an active gift card must report success`);assert.equal(await deactivateGiftCard(1),!0,`${dialect}: deactivating an already deactivated gift card must report success`);assert.equal(await statusOf("gift_cards",1),"DEACTIVATED")});await check("variant updateStatus reports success for the status it already has",async()=>{await db.insertInto("product_variants").values({id:1,variant:"Size",type:"dropdown",status:"active"}).execute();await db.insertInto("product_variants").values({id:2,variant:"Colour",type:"dropdown",status:"draft"}).execute();assert.equal(await updateVariantStatus(1,"active"),!0,`${dialect}: re-applying a variant's current status must report success`);assert.equal(await updateVariantStatus(1,"active"),!0,`${dialect}: re-applying it again in the same second must report success`);assert.equal(await updateVariantStatus(2,"active"),!0,`${dialect}: changing a variant's status must report success`);assert.equal(await statusOf("product_variants",2),"active");assert.equal(await updateVariantStatus(404,"active"),!1,`${dialect}: a variant that does not exist must report failure`)});await check("variant bulkUpdate counts rows already holding the values",async()=>{const rows=await db.selectFrom("product_variants").selectAll().where("id","in",[1,2]).execute();assert.equal(rows.length,2);const resaved=await bulkUpdateVariants(rows.map((row)=>({id:row.id,status:row.status})));assert.equal(resaved,2,`${dialect}: bulk update must count rows that already hold the values written`)});await check("cart bulkUpdate counts rows already holding the values, inside a transaction",async()=>{for(const id of[1,2])await db.insertInto("carts").values({id,status:"active",expires_at:"2030-02-01 00:00:00",applied_coupon_id:"none"}).execute();const rows=[{id:1,status:"active"},{id:2,status:"active"}];assert.equal(await bulkUpdateCarts(rows),2);assert.equal(await bulkUpdateCarts(rows),2,`${dialect}: bulk update must count carts that already hold the values written`)});await check("shipping rate updateByZone counts rates already at that rate",async()=>{for(const id of[1,2])await db.insertInto("shipping_rates").values({id,weight_from:0,weight_to:10,rate:250,shipping_zone_id:7}).execute();assert.equal(await updateRatesByZone(7,{rate:250}),2);assert.equal(await updateRatesByZone(7,{rate:250}),2,`${dialect}: updateByZone must count rates already at the requested rate`)});await check("product bulkUpdate counts rows already holding the values",async()=>{for(const id of[1,2])await db.insertInto("products").values({id,name:`product-${id}`,price:100,preparation_time:5}).execute();const rows=[{id:1,name:"product-1"},{id:2,name:"product-2"}];assert.equal(await bulkUpdateItems(rows),2);assert.equal(await bulkUpdateItems(rows),2,`${dialect}: bulk update must count products that already hold the values written`)});await check("product unit bulkUpdate counts rows already holding the values",async()=>{for(const id of[1,2])await db.insertInto("product_units").values({id,name:`unit-${id}`,abbreviation:`u${id}`,type:"weight"}).execute();const rows=[{id:1,name:"unit-1"},{id:2,name:"unit-2"}];assert.equal(await bulkUpdateUnits(rows),2);assert.equal(await bulkUpdateUnits(rows),2,`${dialect}: bulk update must count units that already hold the values written`)})}finally{setSystemTime()}assert.deepEqual(failures,[],`${dialect}: every write must report the rows its predicate matched`);console.log("commerce soft delete counts OK")}finally{resetDatabaseConnection()}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import assert from"node:assert/strict";import{
|
|
1
|
+
import assert from"node:assert/strict";import{tmpdir}from"node:os";import{basename,dirname,join}from"node:path";import process from"node:process";const dialect=process.env.DB_CONNECTION;assert(dialect==="sqlite"||dialect==="postgres"||dialect==="mysql");const configPath=process.env.STACKS_COMMERCE_WRITE_COUNTS_CONFIG;assert(configPath&&basename(dirname(configPath)).startsWith("stacks-commerce-write-counts-"));if(dialect==="sqlite")assert.equal(dirname(process.env.DB_DATABASE_PATH),dirname(configPath));else{assert.equal(process.env.DB_DATABASE_PATH,":memory:");assert(process.env.DB_DATABASE?.startsWith("stacks_commerce_write_counts_"));assert(["127.0.0.1","localhost","[::1]"].includes(process.env.DB_HOST))}const{overridesReady}=await import("@stacksjs/config");await overridesReady;const{Database}=await import("bun:sqlite"),{db,ensureDatabaseConfigLoaded,initializeDbConfig,resetDatabaseConnection,sqlDateTime}=await import("@stacksjs/database");await ensureDatabaseConfigLoaded();initializeDbConfig({app:{env:"test"},database:{default:dialect,connections:dialect==="sqlite"?{sqlite:{database:process.env.DB_DATABASE_PATH}}:{[dialect]:{name:process.env.DB_DATABASE,host:process.env.DB_HOST,port:Number(process.env.DB_PORT),username:process.env.DB_USERNAME,password:process.env.DB_PASSWORD}},queryLogging:{enabled:!1}}});const TABLES=["carts","categories","coupons","gift_cards","payments","receipts"],{buildMigrationPlan,generateSql,loadModels}=await import("bun-query-builder"),modelsDir=join(import.meta.dir,"../../../../../defaults/app/Models"),models={...await loadModels({modelsDir}),...await loadModels({modelsDir:join(modelsDir,"commerce")})},plan=buildMigrationPlan(models,{dialect});plan.tables=plan.tables.filter((table)=>TABLES.includes(table.table));assert.deepEqual(plan.tables.map((table)=>table.table).sort(),TABLES);for(const table of plan.tables)for(const column of table.columns)delete column.references;const statements=generateSql(plan),{deactivate,deactivateChildCategories}=await import("../../products/categories/destroy"),{registerPersistentQueryHooks}=await import("@stacksjs/query-builder"),{redeem}=await import("../../coupons/update"),{store:storeCoupon}=await import("../../coupons/store"),{updateBalance}=await import("../../gift-cards/update"),{store:storeGiftCard}=await import("../../gift-cards/store"),{cleanupAbandonedCarts}=await import("../../orders/guards"),{recordRefund}=await import("../../payments/update"),{store:storePayment}=await import("../../payments/store"),{bulkStore}=await import("../../receipts/store");async function count(table){return(await db.selectFrom(table).selectAll().execute()).length}async function column(table,id,name){return(await db.selectFrom(table).selectAll().where("id","=",id).executeTakeFirst())?.[name]}function deleteOnAnotherConnection(id){if(dialect==="sqlite"){const handle=new Database(process.env.DB_DATABASE_PATH);try{handle.run("DELETE FROM categories WHERE id = ?",[id])}finally{handle.close()}return!0}const adapter=dialect==="postgres"?"postgres":"mysql",child=Bun.spawnSync([process.execPath,"-e",`
|
|
2
2
|
const db = new Bun.SQL({ adapter: '${adapter}', hostname: process.env.DB_HOST,
|
|
3
3
|
port: Number(process.env.DB_PORT), database: process.env.DB_DATABASE,
|
|
4
4
|
username: process.env.DB_USERNAME, password: process.env.DB_PASSWORD,
|
package/dist/tests/setup.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{existsSync,
|
|
1
|
+
import{existsSync,unlinkSync}from"node:fs";import{tmpdir}from"node:os";import{join}from"node:path";import process from"node:process";const DB_PATH=join(tmpdir(),`stacks-commerce-${process.pid}.sqlite`);process.env.DB_CONNECTION="sqlite";process.env.DB_DATABASE_PATH=DB_PATH;process.env.APP_ENV="test";const{acquireDbConfigLock,db,ensureDatabaseConfigLoaded,initializeDbConfig}=await import("@stacksjs/database"),{buildMigrationPlan,generateSql,loadModels}=await import("bun-query-builder"),defaultsModelsDir=join(import.meta.dir,"../../../../defaults/app/Models"),commerceModelsDir=join(defaultsModelsDir,"commerce");async function forceConfig(){const releaseDbConfigLock=await acquireDbConfigLock();try{await ensureDatabaseConfigLoaded();initializeDbConfig({app:{env:"test"},database:{default:"sqlite",connections:{sqlite:{database:DB_PATH,prefix:""}}}})}finally{releaseDbConfigLock()}}for(const suffix of["","-wal","-shm"])if(existsSync(`${DB_PATH}${suffix}`))unlinkSync(`${DB_PATH}${suffix}`);await forceConfig();const models={...await loadModels({modelsDir:defaultsModelsDir}),...await loadModels({modelsDir:commerceModelsDir})},plan=buildMigrationPlan(models,{dialect:"sqlite"});for(const table of plan.tables)for(const column of table.columns)delete column.references;const statements=generateSql(plan);for(const statement of statements)await db.unsafe(statement).execute();const tableNames=plan.tables.map((table)=>table.table);export async function refreshDatabase(){await forceConfig();for(const table of tableNames)await db.unsafe(`DELETE FROM ${table}`).execute()}process.on("exit",()=>{for(const suffix of["","-wal","-shm"])try{if(existsSync(`${DB_PATH}${suffix}`))unlinkSync(`${DB_PATH}${suffix}`)}catch{}});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/commerce",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.75.
|
|
4
|
+
"version": "0.75.143",
|
|
5
5
|
"description": "Stacks commerce utilities.",
|
|
6
6
|
"author": "Chris Breuer",
|
|
7
7
|
"contributors": [
|
|
@@ -57,18 +57,18 @@
|
|
|
57
57
|
"prepublishOnly": "bun run build"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@stacksjs/cache": "0.75.
|
|
61
|
-
"@stacksjs/config": "0.75.
|
|
62
|
-
"@stacksjs/database": "0.75.
|
|
63
|
-
"@stacksjs/env": "0.75.
|
|
64
|
-
"@stacksjs/error-handling": "0.75.
|
|
65
|
-
"@stacksjs/events": "0.75.
|
|
66
|
-
"@stacksjs/logging": "0.75.
|
|
67
|
-
"@stacksjs/orm": "0.75.
|
|
68
|
-
"@stacksjs/payments": "0.75.
|
|
69
|
-
"@stacksjs/realtime": "0.75.
|
|
70
|
-
"@stacksjs/strings": "0.75.
|
|
71
|
-
"@stacksjs/validation": "0.75.
|
|
60
|
+
"@stacksjs/cache": "0.75.143",
|
|
61
|
+
"@stacksjs/config": "0.75.143",
|
|
62
|
+
"@stacksjs/database": "0.75.143",
|
|
63
|
+
"@stacksjs/env": "0.75.143",
|
|
64
|
+
"@stacksjs/error-handling": "0.75.143",
|
|
65
|
+
"@stacksjs/events": "0.75.143",
|
|
66
|
+
"@stacksjs/logging": "0.75.143",
|
|
67
|
+
"@stacksjs/orm": "0.75.143",
|
|
68
|
+
"@stacksjs/payments": "0.75.143",
|
|
69
|
+
"@stacksjs/realtime": "0.75.143",
|
|
70
|
+
"@stacksjs/strings": "0.75.143",
|
|
71
|
+
"@stacksjs/validation": "0.75.143",
|
|
72
72
|
"ts-spreadsheets": "^0.2.0"
|
|
73
73
|
},
|
|
74
74
|
"devDependencies": {
|