This commit is contained in:
seb
2026-07-31 00:08:50 +02:00
parent 93e52cd513
commit 6bdac7e543
17 changed files with 520 additions and 24 deletions

80
package-lock.json generated
View File

@@ -1,15 +1,17 @@
{ {
"name": "dashdbschema", "name": "libdashstore",
"version": "1.0.0", "version": "0.1.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "dashdbschema", "name": "libdashstore",
"version": "1.0.0", "version": "0.1.0",
"license": "ISC", "license": "ISC",
"dependencies": { "dependencies": {
"@clack/prompts": "^1.7.0",
"@hpcc-js/wasm-graphviz": "^1.28.0", "@hpcc-js/wasm-graphviz": "^1.28.0",
"chalk": "^6.0.0",
"dotenv": "^17.4.2", "dotenv": "^17.4.2",
"mssql": "^12.7.0" "mssql": "^12.7.0"
} }
@@ -256,6 +258,34 @@
"node": ">=20" "node": ">=20"
} }
}, },
"node_modules/@clack/core": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/@clack/core/-/core-1.4.3.tgz",
"integrity": "sha512-/kr3UWNtdJfxZtPgDqUOmG2pvwlmcLGheex5yiZKdwbzZJxhV+HMNR9QNmyY5cGwTNV6LrR7Jtp+KjhUAP1qBQ==",
"license": "MIT",
"dependencies": {
"fast-wrap-ansi": "^0.2.0",
"sisteransi": "^1.0.5"
},
"engines": {
"node": ">= 20.12.0"
}
},
"node_modules/@clack/prompts": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-1.7.0.tgz",
"integrity": "sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==",
"license": "MIT",
"dependencies": {
"@clack/core": "1.4.3",
"fast-string-width": "^3.0.2",
"fast-wrap-ansi": "^0.2.0",
"sisteransi": "^1.0.5"
},
"engines": {
"node": ">= 20.12.0"
}
},
"node_modules/@hpcc-js/wasm-graphviz": { "node_modules/@hpcc-js/wasm-graphviz": {
"version": "1.28.0", "version": "1.28.0",
"resolved": "https://registry.npmjs.org/@hpcc-js/wasm-graphviz/-/wasm-graphviz-1.28.0.tgz", "resolved": "https://registry.npmjs.org/@hpcc-js/wasm-graphviz/-/wasm-graphviz-1.28.0.tgz",
@@ -404,6 +434,18 @@
"url": "https://github.com/sponsors/sindresorhus" "url": "https://github.com/sponsors/sindresorhus"
} }
}, },
"node_modules/chalk": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-6.0.0.tgz",
"integrity": "sha512-2uNTXIuTTxk7ciZgAU1BQcgnchcG0xXnrs6jzkQfj9SsRa9M2s5zE8WT96hS6KmG4MzWHSrvH43DF1m4XRkrFg==",
"license": "MIT",
"engines": {
"node": ">=22"
},
"funding": {
"url": "https://github.com/chalk/chalk?sponsor=1"
}
},
"node_modules/commander": { "node_modules/commander": {
"version": "11.1.0", "version": "11.1.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
@@ -509,6 +551,30 @@
"node": ">=0.8.x" "node": ">=0.8.x"
} }
}, },
"node_modules/fast-string-truncated-width": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz",
"integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==",
"license": "MIT"
},
"node_modules/fast-string-width": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz",
"integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==",
"license": "MIT",
"dependencies": {
"fast-string-truncated-width": "^3.0.2"
}
},
"node_modules/fast-wrap-ansi": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz",
"integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==",
"license": "MIT",
"dependencies": {
"fast-string-width": "^3.0.2"
}
},
"node_modules/http-proxy-agent": { "node_modules/http-proxy-agent": {
"version": "7.0.2", "version": "7.0.2",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
@@ -840,6 +906,12 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/sisteransi": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
"license": "MIT"
},
"node_modules/sprintf-js": { "node_modules/sprintf-js": {
"version": "1.1.3", "version": "1.1.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",

View File

@@ -11,10 +11,13 @@
}, },
"scripts": { "scripts": {
"schema-graph": "node generate-schema-graph.js", "schema-graph": "node generate-schema-graph.js",
"init-schema": "node scripts/init-schema.js" "init-schema": "node scripts/init-schema.js",
"test:api": "node scripts/test-api.js"
}, },
"dependencies": { "dependencies": {
"@clack/prompts": "^1.7.0",
"@hpcc-js/wasm-graphviz": "^1.28.0", "@hpcc-js/wasm-graphviz": "^1.28.0",
"chalk": "^6.0.0",
"dotenv": "^17.4.2", "dotenv": "^17.4.2",
"mssql": "^12.7.0" "mssql": "^12.7.0"
} }

View File

@@ -14,7 +14,7 @@ digraph schema {
company [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in1" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in2" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="3" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>company</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="default_language_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>default_language_id</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="root_category_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>root_category_id</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="name" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">name</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR></TABLE>>]; company [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in1" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD><TD PORT="in2" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="3" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>company</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="default_language_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>default_language_id</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="root_category_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>root_category_id</B>?</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="name" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">name</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
numbers [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>numbers</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="company_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>company_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="type" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">type</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(100)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="prefix" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">prefix</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="padding" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">padding</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="next" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">next</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR></TABLE>>]; numbers [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>numbers</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="company_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>company_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="type" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">type</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(100)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="prefix" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">prefix</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(50)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="padding" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">padding</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="next" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">next</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
entity [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>entity</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="customergroup_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>customergroup_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="firstname" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">firstname</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="lastname" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">lastname</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR></TABLE>>]; entity [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>entity</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="customergroup_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>customergroup_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="firstname" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">firstname</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="lastname" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">lastname</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(255)</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
companyuser [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>companyuser</B></FONT></TD></TR><TR><TD PORT="company_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>company_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="google_auth_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>google_auth_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR></TABLE>>]; companyuser [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="4" BORDER="1"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>companyuser</B></FONT></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="company_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>company_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="google_auth_id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>google_auth_id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>FK</B></FONT></TD></TR></TABLE></TD></TR></TABLE>>];
google_auth [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="1" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>google_auth</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="email" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">email</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(320)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="created_at" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">created_at</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">DATETIME2</FONT></TD></TR></TABLE></TD></TR></TABLE>>]; google_auth [label=<<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="4" COLOR="#a0aec0"><TR><TD COLSPAN="2" BGCOLOR="#bee3f8" ALIGN="CENTER" CELLPADDING="1" BORDER="1"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD PORT="in0" BGCOLOR="#bee3f8" BORDER="0" WIDTH="10" HEIGHT="4" CELLPADDING="0"></TD></TR><TR><TD COLSPAN="1" ALIGN="CENTER" CELLPADDING="3"><FONT COLOR="#1a365d" POINT-SIZE="12"><B>google_auth</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="id" COLSPAN="2" BGCOLOR="#ebf8ff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748"><B>id</B></FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">INT <B>PK</B></FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="email" COLSPAN="2" BGCOLOR="#f7fafc" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">email</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">NVARCHAR(320)</FONT></TD></TR></TABLE></TD></TR><TR><TD PORT="created_at" COLSPAN="2" BGCOLOR="#ffffff" BORDER="1" CELLPADDING="0"><TABLE BORDER="0" CELLBORDER="0" CELLSPACING="0" FIXEDSIZE="FALSE"><TR><TD ALIGN="LEFT" CELLPADDING="4"><FONT COLOR="#2d3748">created_at</FONT></TD><TD ALIGN="RIGHT" CELLPADDING="4"><FONT COLOR="#718096" POINT-SIZE="9">DATETIME2</FONT></TD></TR></TABLE></TD></TR></TABLE>>];
} }
subgraph cluster_i18n { subgraph cluster_i18n {

View File

@@ -261,26 +261,31 @@
<!-- companyuser --> <!-- companyuser -->
<g id="node6" class="node"> <g id="node6" class="node">
<title>companyuser</title> <title>companyuser</title>
<polygon fill="#bee3f8" stroke="none" points="399.78,-979.8 399.78,-1004.2 550.22,-1004.2 550.22,-979.8 399.78,-979.8"/> <polygon fill="#bee3f8" stroke="none" points="399.78,-993.2 399.78,-1017.6 550.22,-1017.6 550.22,-993.2 399.78,-993.2"/>
<polygon fill="none" stroke="#a0aec0" points="399.78,-979.8 399.78,-1004.2 550.22,-1004.2 550.22,-979.8 399.78,-979.8"/> <polygon fill="none" stroke="#a0aec0" points="399.78,-993.2 399.78,-1017.6 550.22,-1017.6 550.22,-993.2 399.78,-993.2"/>
<text xml:space="preserve" text-anchor="start" x="435.99" y="-989.4" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="12.00" fill="#1a365d">companyuser</text> <text xml:space="preserve" text-anchor="start" x="435.99" y="-1002.8" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="12.00" fill="#1a365d">companyuser</text>
<polygon fill="#ebf8ff" stroke="none" points="399.78,-953 399.78,-979.8 550.22,-979.8 550.22,-953 399.78,-953"/> <polygon fill="#ebf8ff" stroke="none" points="399.78,-966.4 399.78,-993.2 550.22,-993.2 550.22,-966.4 399.78,-966.4"/>
<polygon fill="none" stroke="#a0aec0" points="399.78,-953 399.78,-979.8 550.22,-979.8 550.22,-953 399.78,-953"/> <polygon fill="none" stroke="#a0aec0" points="399.78,-966.4 399.78,-993.2 550.22,-993.2 550.22,-966.4 399.78,-966.4"/>
<text xml:space="preserve" text-anchor="start" x="404.78" y="-963.2" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00" fill="#2d3748">company_id</text> <text xml:space="preserve" text-anchor="start" x="404.78" y="-976.6" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00" fill="#2d3748">id</text>
<text xml:space="preserve" text-anchor="start" x="516.23" y="-964.7" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">INT </text> <text xml:space="preserve" text-anchor="start" x="515.72" y="-978.1" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">INT </text>
<text xml:space="preserve" text-anchor="start" x="533.22" y="-964.7" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="9.00" fill="#718096">FK</text> <text xml:space="preserve" text-anchor="start" x="532.72" y="-978.1" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="9.00" fill="#718096">PK</text>
<polygon fill="#ebf8ff" stroke="none" points="399.78,-926.2 399.78,-953 550.22,-953 550.22,-926.2 399.78,-926.2"/> <polygon fill="#ebf8ff" stroke="none" points="399.78,-939.6 399.78,-966.4 550.22,-966.4 550.22,-939.6 399.78,-939.6"/>
<polygon fill="none" stroke="#a0aec0" points="399.78,-926.2 399.78,-953 550.22,-953 550.22,-926.2 399.78,-926.2"/> <polygon fill="none" stroke="#a0aec0" points="399.78,-939.6 399.78,-966.4 550.22,-966.4 550.22,-939.6 399.78,-939.6"/>
<text xml:space="preserve" text-anchor="start" x="404.78" y="-936.4" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00" fill="#2d3748">google_auth_id</text> <text xml:space="preserve" text-anchor="start" x="404.78" y="-949.8" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00" fill="#2d3748">company_id</text>
<text xml:space="preserve" text-anchor="start" x="516.23" y="-937.9" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">INT </text> <text xml:space="preserve" text-anchor="start" x="516.23" y="-951.3" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">INT </text>
<text xml:space="preserve" text-anchor="start" x="533.22" y="-937.9" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="9.00" fill="#718096">FK</text> <text xml:space="preserve" text-anchor="start" x="533.22" y="-951.3" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="9.00" fill="#718096">FK</text>
<polygon fill="#ebf8ff" stroke="none" points="399.78,-912.8 399.78,-939.6 550.22,-939.6 550.22,-912.8 399.78,-912.8"/>
<polygon fill="none" stroke="#a0aec0" points="399.78,-912.8 399.78,-939.6 550.22,-939.6 550.22,-912.8 399.78,-912.8"/>
<text xml:space="preserve" text-anchor="start" x="404.78" y="-923" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="14.00" fill="#2d3748">google_auth_id</text>
<text xml:space="preserve" text-anchor="start" x="516.23" y="-924.5" font-family="Helvetica,sans-Serif" font-size="9.00" fill="#718096">INT </text>
<text xml:space="preserve" text-anchor="start" x="533.22" y="-924.5" font-family="Helvetica,sans-Serif" font-weight="bold" font-size="9.00" fill="#718096">FK</text>
</g> </g>
<!-- companyuser&#45;&gt;company --> <!-- companyuser&#45;&gt;company -->
<g id="edge39" class="edge"> <g id="edge39" class="edge">
<title>companyuser:sw&#45;&gt;company:n</title> <title>companyuser:sw&#45;&gt;company:n</title>
<g id="a_edge39"><a xlink:title="FK_companyuser_company"> <g id="a_edge39"><a xlink:title="FK_companyuser_company">
<path fill="none" stroke="#22543d" stroke-width="1.4" d="M398.78,-953C358.66,-912.88 383.86,-883.66 371,-828.4 351.21,-743.39 324.92,-722.56 323.14,-639.82"/> <path fill="none" stroke="#22543d" stroke-width="1.4" d="M398.78,-939.6C398.08,-938.9 337.24,-690.01 325.13,-639.63"/>
<polygon fill="#22543d" stroke="#22543d" stroke-width="1.4" points="325.59,-639.89 323.07,-632.92 320.69,-639.94 325.59,-639.89"/> <polygon fill="#22543d" stroke="#22543d" stroke-width="1.4" points="327.53,-639.11 323.53,-632.86 322.76,-640.24 327.53,-639.11"/>
</a> </a>
</g> </g>
</g> </g>
@@ -309,8 +314,8 @@
<g id="edge38" class="edge"> <g id="edge38" class="edge">
<title>companyuser:se&#45;&gt;google_auth:n</title> <title>companyuser:se&#45;&gt;google_auth:n</title>
<g id="a_edge38"><a xlink:title="FK_companyuser_google_auth"> <g id="a_edge38"><a xlink:title="FK_companyuser_google_auth">
<path fill="none" stroke="#742a2a" stroke-width="1.4" d="M550.22,-925.2C597.93,-877.5 488.18,-702.08 479.54,-626.15"/> <path fill="none" stroke="#742a2a" stroke-width="1.4" d="M550.22,-911.8C595.86,-866.16 488.47,-699.21 479.58,-626.23"/>
<polygon fill="#742a2a" stroke="#742a2a" stroke-width="1.4" points="482,-626.35 479.13,-619.51 477.11,-626.65 482,-626.35"/> <polygon fill="#742a2a" stroke="#742a2a" stroke-width="1.4" points="482.04,-626.34 479.14,-619.51 477.15,-626.66 482.04,-626.34"/>
</a> </a>
</g> </g>
</g> </g>

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 129 KiB

25
scripts/init-schema.js Normal file
View File

@@ -0,0 +1,25 @@
import 'dotenv/config';
import sql from 'mssql';
import { SCHEMA_SCRIPTS } from '../src/schema.js';
const config = {
server: process.env.MSSQL_SERVER,
database: process.env.MSSQL_DATABASE,
user: process.env.MSSQL_USER,
password: process.env.MSSQL_PASSWORD,
options: {
encrypt: false,
trustServerCertificate: true,
},
};
const pool = await sql.connect(config);
try {
for (const script of SCHEMA_SCRIPTS) {
await pool.request().query(script);
}
console.log(`Schema init OK (${SCHEMA_SCRIPTS.length} scripts)`);
} finally {
await pool.close();
}

193
scripts/test-api.js Normal file
View File

@@ -0,0 +1,193 @@
import 'dotenv/config';
import sql from 'mssql';
import chalk from 'chalk';
import * as p from '@clack/prompts';
import LibDashStore from '../src/index.js';
const config = {
server: process.env.MSSQL_SERVER,
database: process.env.MSSQL_DATABASE,
user: process.env.MSSQL_USER,
password: process.env.MSSQL_PASSWORD,
options: {
encrypt: false,
trustServerCertificate: true,
},
};
function printResult(label, value) {
p.log.step(chalk.cyan(label));
const text =
value === undefined
? chalk.dim('undefined')
: typeof value === 'string'
? value
: JSON.stringify(value, null, 2);
console.log(chalk.white(text));
console.log();
}
async function shutdown(pool, code = 0) {
try {
await pool.close();
} catch {
// ignore
}
process.exit(code);
}
async function main() {
console.clear();
p.intro(chalk.bgMagenta.black(' libdashstore ') + chalk.dim(' api tester'));
const spin = p.spinner();
spin.start('Connecting to MSSQL…');
let pool;
try {
pool = await sql.connect(config);
} catch (err) {
spin.stop(chalk.red('Connection failed'));
p.log.error(err.message);
p.outro(chalk.red('Aborted'));
process.exit(1);
}
spin.message('Initializing schema…');
let client;
try {
client = await new LibDashStore(pool);
spin.stop(chalk.green('Ready'));
} catch (err) {
spin.stop(chalk.red('Initialize failed'));
p.log.error(err.message);
await shutdown(pool, 1);
}
p.note(
[
chalk.dim(`${config.server} / ${config.database}`),
chalk.dim('purge ends the session'),
].join('\n'),
'Connected',
);
while (true) {
const action = await p.select({
message: 'API method',
options: [
{
value: 'companyuser.getByEmail',
label: 'companyuser.getByEmail',
hint: 'email → id',
},
{
value: 'company.getByCompanyUserId',
label: 'company.getByCompanyUserId',
hint: 'id → [id, lang, root, name]',
},
{
value: 'category.getTree',
label: 'category.getTree',
hint: 'rootId → tree',
},
{
value: 'initialize',
label: 'initialize',
hint: 'purge + recreate schema',
},
{
value: 'purge',
label: chalk.red('purge'),
hint: 'drop all · exit',
},
{ value: 'exit', label: 'exit', hint: 'quit without purge' },
],
});
if (p.isCancel(action) || action === 'exit') {
p.outro(chalk.dim('Bye'));
await shutdown(pool, 0);
}
try {
if (action === 'companyuser.getByEmail') {
const email = await p.text({
message: 'Email',
placeholder: 'user@example.com',
validate: (v) => (!v?.trim() ? 'Required' : undefined),
});
if (p.isCancel(email)) continue;
const run = p.spinner();
run.start('Running…');
const id = await client.companyuser.getByEmail(email.trim());
run.stop(chalk.green('companyuser.getByEmail'));
printResult('id', id);
continue;
}
if (action === 'company.getByCompanyUserId') {
const raw = await p.text({
message: 'Company user id',
placeholder: '1',
validate: (v) =>
!/^\d+$/.test(v?.trim() ?? '') ? 'Integer required' : undefined,
});
if (p.isCancel(raw)) continue;
const run = p.spinner();
run.start('Running…');
const row = await client.company.getByCompanyUserId(Number(raw.trim()));
run.stop(chalk.green('company.getByCompanyUserId'));
printResult('[id, defaultLangId, rootCategoryId, name]', row);
continue;
}
if (action === 'category.getTree') {
const raw = await p.text({
message: 'Root category id',
placeholder: '1',
validate: (v) =>
!/^\d+$/.test(v?.trim() ?? '') ? 'Integer required' : undefined,
});
if (p.isCancel(raw)) continue;
const run = p.spinner();
run.start('Running…');
const tree = await client.category.getTree(Number(raw.trim()));
run.stop(chalk.green('category.getTree'));
printResult('tree', tree);
continue;
}
if (action === 'initialize') {
const run = p.spinner();
run.start('Initializing…');
await client.initialize();
run.stop(chalk.green('initialize'));
p.log.success('Schema purged and recreated');
console.log();
continue;
}
if (action === 'purge') {
const run = p.spinner();
run.start('Purging…');
await client.purge();
run.stop(chalk.green('purge'));
p.outro(chalk.red('Database purged — exiting'));
await shutdown(pool, 0);
}
} catch (err) {
p.log.error(err.message);
console.log(chalk.dim(err.stack?.split('\n').slice(1, 4).join('\n') ?? ''));
console.log();
}
}
}
main().catch(async (err) => {
console.error(chalk.red(err.stack ?? err.message));
process.exit(1);
});

30
src/index.js Normal file
View File

@@ -0,0 +1,30 @@
import companyuserGetByEmail from './store/companyuser/getByEmail.js';
import companyGetByCompanyUserId from './store/company/getByCompanyUserId.js';
import categoryGetTree from './store/category/getTree.js';
import storePurge from './store/purge.js';
import storeInitialize from './store/initialize.js';
export default class LibDashStore {
constructor(pool) {
this.pool = pool;
this.companyuser = {
getByEmail: companyuserGetByEmail(pool),
};
this.company = {
getByCompanyUserId: companyGetByCompanyUserId(pool),
};
this.category = {
getTree: categoryGetTree(pool),
};
this.purge = storePurge(pool);
this.initialize = storeInitialize(pool);
return this.initialize().then(() => this);
}
}
export { SCHEMA_SCRIPTS } from './schema.js';

View File

@@ -487,9 +487,10 @@ export const INIT_COMPANYUSER = `
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'companyuser') IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'companyuser')
BEGIN BEGIN
CREATE TABLE companyuser ( CREATE TABLE companyuser (
id INT IDENTITY(1,1) PRIMARY KEY,
google_auth_id INT NOT NULL, google_auth_id INT NOT NULL,
company_id INT NOT NULL, company_id INT NOT NULL,
CONSTRAINT PK_companyuser PRIMARY KEY (google_auth_id, company_id), CONSTRAINT UQ_companyuser_google_auth_company UNIQUE (google_auth_id, company_id),
CONSTRAINT FK_companyuser_google_auth FOREIGN KEY (google_auth_id) REFERENCES google_auth(id) ON DELETE CASCADE, CONSTRAINT FK_companyuser_google_auth FOREIGN KEY (google_auth_id) REFERENCES google_auth(id) ON DELETE CASCADE,
CONSTRAINT FK_companyuser_company FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE CONSTRAINT FK_companyuser_company FOREIGN KEY (company_id) REFERENCES company(id) ON DELETE CASCADE
); );

16
src/sql/category.js Normal file
View File

@@ -0,0 +1,16 @@
export const GET_TREE = `
WITH tree AS (
SELECT id, parent_id, sort
FROM category
WHERE id = @rootId
UNION ALL
SELECT c.id, c.parent_id, c.sort
FROM category c
INNER JOIN tree t ON c.parent_id = t.id
)
SELECT id, parent_id, sort
FROM tree
ORDER BY sort, id
`;

10
src/sql/company.js Normal file
View File

@@ -0,0 +1,10 @@
export const GET_BY_COMPANY_USER_ID = `
SELECT
c.id,
c.default_language_id,
c.root_category_id,
c.name
FROM company c
INNER JOIN companyuser cu ON cu.company_id = c.id
WHERE cu.id = @companyUserId
`;

6
src/sql/companyuser.js Normal file
View File

@@ -0,0 +1,6 @@
export const GET_BY_EMAIL = `
SELECT cu.id
FROM companyuser cu
INNER JOIN google_auth ga ON ga.id = cu.google_auth_id
WHERE ga.email = @email
`;

49
src/sql/purge.js Normal file
View File

@@ -0,0 +1,49 @@
/** Drop order = reverse of schema create dependency order. */
export const TABLES = [
'companyuser',
'numbers',
'manifestarticle',
'manifest',
'price',
'articletext',
'categorytext',
'categorypic',
'categoryarticle',
'optionslistarticle',
'articlelistarticle',
'brandpic',
'articlepic',
'articleean',
'articlehistory',
'article',
'brand',
'articlelist',
'optionslist',
'unittext',
'unit',
'entity',
'customergroup',
'company',
'pic',
'category',
'tax',
'language',
'google_auth',
'meta',
];
export const PROCEDURES = ['getnextnumberwithprefixandpadding'];
export function buildPurgeSql() {
const drops = [
...PROCEDURES.map(
(name) =>
`IF OBJECT_ID(N'dbo.${name}', N'P') IS NOT NULL DROP PROCEDURE dbo.[${name}];`,
),
...TABLES.map(
(name) =>
`IF OBJECT_ID(N'dbo.${name}', N'U') IS NOT NULL DROP TABLE dbo.[${name}];`,
),
];
return drops.join('\n');
}

View File

@@ -0,0 +1,38 @@
import sql from 'mssql';
import { GET_TREE } from '../../sql/category.js';
function buildTree(rows, rootId) {
const byId = new Map();
for (const row of rows) {
byId.set(row.id, {
id: row.id,
parent_id: row.parent_id,
sort: row.sort,
children: [],
});
}
let root = null;
for (const node of byId.values()) {
if (node.id === rootId) {
root = node;
continue;
}
const parent = byId.get(node.parent_id);
if (parent) parent.children.push(node);
}
return root;
}
export default function getTree(pool) {
return async (rootId) => {
const result = await pool
.request()
.input('rootId', sql.Int, rootId)
.query(GET_TREE);
if (result.recordset.length === 0) return null;
return buildTree(result.recordset, rootId);
};
}

View File

@@ -0,0 +1,16 @@
import sql from 'mssql';
import { GET_BY_COMPANY_USER_ID } from '../../sql/company.js';
export default function getByCompanyUserId(pool) {
return async (companyUserId) => {
const result = await pool
.request()
.input('companyUserId', sql.Int, companyUserId)
.query(GET_BY_COMPANY_USER_ID);
const row = result.recordset[0];
if (!row) return null;
return [row.id, row.default_language_id, row.root_category_id, row.name];
};
}

View File

@@ -0,0 +1,13 @@
import sql from 'mssql';
import { GET_BY_EMAIL } from '../../sql/companyuser.js';
export default function getByEmail(pool) {
return async (email) => {
const result = await pool
.request()
.input('email', sql.NVarChar(320), email)
.query(GET_BY_EMAIL);
return result.recordset[0]?.id ?? null;
};
}

12
src/store/initialize.js Normal file
View File

@@ -0,0 +1,12 @@
import { SCHEMA_SCRIPTS } from '../schema.js';
import purge from './purge.js';
export default function initialize(pool) {
const doPurge = purge(pool);
return async () => {
await doPurge();
for (const script of SCHEMA_SCRIPTS) {
await pool.request().query(script);
}
};
}

7
src/store/purge.js Normal file
View File

@@ -0,0 +1,7 @@
import { buildPurgeSql } from '../sql/purge.js';
export default function purge(pool) {
return async () => {
await pool.request().query(buildPurgeSql());
};
}