@storecraft/database-sql-base
Version:
Official SQL Database driver for storecraft
371 lines (335 loc) • 11.3 kB
JavaScript
/**
* @import { Database } from '../types.sql.tables.js'
*/
import { CreateTableBuilder, Kysely } from 'kysely'
/**
* @template {string} TB
* @template {string} B
* @param {CreateTableBuilder<TB, B>} tb
*/
export const add_base_columns = tb => {
return tb
.addColumn('id', 'varchar(255)', (col) =>
col.primaryKey()
)
.addColumn('handle', 'varchar(255)', (col) => col.unique())
.addColumn('created_at', 'varchar(32)')
.addColumn('updated_at', 'varchar(32)')
.addColumn('attributes', 'json')
.addColumn('description', 'text')
.addColumn('active', 'integer')
}
/**
* @param {Kysely<Database>} db
* @param {keyof Database} table_name
*/
export const create_entity_to_value_table = (db, table_name) => {
return db.schema
.createTable(table_name).ifNotExists()
.addColumn('id', 'integer',
(col) => col.autoIncrement().primaryKey()
)
.addColumn('entity_id', 'varchar(100)', col => col.notNull())
.addColumn('entity_handle', 'varchar(255)')
.addColumn('value', 'varchar(500)')
.addColumn('reporter', 'varchar(100)')
.addColumn('context', 'varchar(100)')
}
/**
*
* @param {Kysely<Database>} db
* @param {keyof Database} table_name
*/
export const create_safe_table = (db, table_name) => {
return db.schema.createTable(table_name).ifNotExists();
}
/**
*
* @param {Kysely<Database>} db
* @param {keyof Database} table_name
*/
export const drop_safe_table = (db, table_name) => {
return db.schema.dropTable(table_name).ifExists().execute();
}
/**
* @param {Kysely<Database>} db
* @param {keyof Database} table_name
* @param {boolean} [include_id=true]
* @param {boolean} [include_handle=true]
*/
export const create_base_indexes = async (db, table_name, include_id=true, include_handle=true) => {
if(include_id) {
await db.schema.createIndex(`index_${table_name}_id_updated_at_asc`)
.on(table_name)
.columns(['id', 'updated_at asc'])
.execute();
await db.schema.createIndex(`index_${table_name}_id_updated_at_desc`)
.on(table_name)
.columns(['id', 'updated_at desc'])
.execute();
}
if(include_handle) {
await db.schema.createIndex(`index_${table_name}_handle_updated_at_asc`)
.on(table_name)
.columns(['handle', 'updated_at asc'])
.execute();
await db.schema.createIndex(`index_${table_name}_handle_updated_at_desc`)
.on(table_name)
.columns(['handle', 'updated_at desc'])
.execute();
}
}
/**
* @param {Kysely<Database>} db
* @param {keyof Pick<Database, 'entity_to_media' |
* 'entity_to_search_terms' | 'entity_to_tags_projections' |
* 'products_to_collections' | 'products_to_discounts' |
* 'products_to_variants' | 'storefronts_to_other' | 'products_to_related_products'>} table_name
*/
export const create_entity_table_indexes = async (db, table_name) => {
await db.schema.createIndex(`index_${table_name}_entity_id`)
.on(table_name)
.column('entity_id')
.execute();
await db.schema.createIndex(`index_${table_name}_entity_handle`)
.on(table_name)
.column('entity_handle')
.execute();
await db.schema.createIndex(`index_${table_name}_value`)
.on(table_name)
.column('value')
.execute();
await db.schema.createIndex(`index_${table_name}_reporter`)
.on(table_name)
.column('reporter')
.execute();
await db.schema.createIndex(`index_${table_name}_context`)
.on(table_name)
.column('context')
.execute();
}
/**
*
* @param {Kysely<Database>} db
*/
export async function up(db) {
{ // auth_users
let tb = create_safe_table(db, 'auth_users');
tb = add_base_columns(tb);
tb = tb
.addColumn('email', 'varchar(255)', (col) => col.unique())
.addColumn('password', 'text')
.addColumn('roles', 'json')
.addColumn('confirmed_mail', 'integer');
await tb.execute();
await create_base_indexes(db, 'auth_users');
}
{ // tags
let tb = create_safe_table(db, 'tags');
tb = add_base_columns(tb);
tb = tb.addColumn('values', 'json');
await tb.execute();
await create_base_indexes(db, 'tags');
}
{ // templates
let tb = create_safe_table(db, 'templates');
tb = add_base_columns(tb);
tb = tb.addColumn('title', 'text');
tb = tb.addColumn('template_html', 'text');
tb = tb.addColumn('template_text', 'text');
tb = tb.addColumn('reference_example_input', 'json');
await tb.execute();
await create_base_indexes(db, 'templates');
}
{ // collections
let tb = create_safe_table(db, 'collections');
tb = add_base_columns(tb);
tb = tb
.addColumn('title', 'text')
.addColumn('published', 'text')
await tb.execute();
await create_base_indexes(db, 'collections');
}
{ // products
let tb = create_safe_table(db, 'products');
tb = add_base_columns(tb);
tb = tb
.addColumn('title', 'text')
.addColumn('video', 'text')
.addColumn('price', 'numeric')
.addColumn('isbn', 'varchar(255)', (col) => col.unique())
.addColumn('compare_at_price', 'numeric')
.addColumn('qty', 'integer')
.addColumn('variants_options', 'json')
.addColumn('parent_handle', 'varchar(255)')
.addColumn('parent_id', 'varchar(100)')
.addColumn('variant_hint', 'json')
await tb.execute();
await create_base_indexes(db, 'products');
}
{ // products_to_collections
await create_entity_to_value_table(db, 'products_to_collections').execute();
await create_entity_table_indexes(db, 'products_to_collections');
}
{ // products_to_discounts
await create_entity_to_value_table(db, 'products_to_discounts').execute();
await create_entity_table_indexes(db, 'products_to_discounts');
}
{ // products_to_variants
await create_entity_to_value_table(db, 'products_to_variants').execute();
await create_entity_table_indexes(db, 'products_to_variants');
}
{ // products_to_related_products
await create_entity_to_value_table(db, 'products_to_related_products').execute();
await create_entity_table_indexes(db, 'products_to_related_products');
}
{ // shipping_methods
let tb = create_safe_table(db, 'shipping_methods');
tb = add_base_columns(tb);
tb = tb.addColumn('title', 'text')
.addColumn('price', 'numeric')
await tb.execute();
await create_base_indexes(db, 'shipping_methods');
}
{ // posts
let tb = create_safe_table(db, 'posts');
tb = add_base_columns(tb);
tb = tb
.addColumn('title', 'text')
.addColumn('text', 'text')
await tb.execute();
await create_base_indexes(db, 'posts');
}
{ // customers
let tb = create_safe_table(db, 'customers');
tb = add_base_columns(tb);
tb = tb
.addColumn('email', 'varchar(255)', (col) => col.unique())
.addColumn('auth_id', 'varchar(255)', (col) => col.unique())
.addColumn('firstname', 'varchar(255)')
.addColumn('lastname', 'varchar(255)')
.addColumn('phone_number', 'varchar(255)')
.addColumn('address', 'json')
await tb.execute();
await create_base_indexes(db, 'customers');
}
{ // orders
let tb = create_safe_table(db, 'orders');
tb = add_base_columns(tb);
tb = tb
.addColumn('contact', 'json')
.addColumn('address', 'json')
.addColumn('line_items', 'json')
.addColumn('notes', 'text')
.addColumn('shipping_method', 'json')
.addColumn('status', 'json')
.addColumn('pricing', 'json')
.addColumn('validation', 'json')
.addColumn('payment_gateway', 'json')
.addColumn('coupons', 'json')
.addColumn('_customer_id', 'varchar(255)')
.addColumn('_customer_email', 'varchar(255)')
.addColumn('_status_payment_id', 'integer')
.addColumn('_status_checkout_id', 'integer')
.addColumn('_status_fulfillment_id', 'integer')
await tb.execute();
await create_base_indexes(db, 'orders');
}
{ // storefronts
let tb = create_safe_table(db, 'storefronts');
tb = add_base_columns(tb);
tb = tb
.addColumn('title', 'text')
.addColumn('video', 'text')
.addColumn('published', 'text')
await tb.execute();
await create_base_indexes(db, 'storefronts');
}
{ // storefronts_to_other
await create_entity_to_value_table(db, 'storefronts_to_other').execute();
await create_entity_table_indexes(db, 'storefronts_to_other');
}
{ // notifications
let tb = create_safe_table(db, 'notifications');
tb = add_base_columns(tb);
tb = tb
.addColumn('message', 'text')
.addColumn('author', 'text')
.addColumn('actions', 'json')
await tb.execute();
await create_base_indexes(db, 'notifications', true, false);
}
{ // images
let tb = create_safe_table(db, 'images');
tb = add_base_columns(tb);
tb = tb
.addColumn('name', 'text')
.addColumn('url', 'text')
await tb.execute();
await create_base_indexes(db, 'images');
}
{ // discounts
let tb = create_safe_table(db, 'discounts');
tb = add_base_columns(tb);
tb = tb
.addColumn('title', 'text')
.addColumn('published', 'text')
.addColumn('priority', 'integer')
.addColumn('info', 'json')
.addColumn('application', 'json')
.addColumn('_application_id', 'integer')
.addColumn('_discount_type_id', 'integer')
await tb.execute();
await create_base_indexes(db, 'discounts');
}
{ // entity_to_tags_projections
await create_entity_to_value_table(db, 'entity_to_tags_projections').execute();
await create_entity_table_indexes(db, 'entity_to_tags_projections');
}
{ // entity_to_search_terms
await create_entity_to_value_table(db, 'entity_to_search_terms').execute();
await create_entity_table_indexes(db, 'entity_to_search_terms');
}
{ // entity_to_media
await create_entity_to_value_table(db, 'entity_to_media').execute();
await create_entity_table_indexes(db, 'entity_to_media');
}
}
/**
*
* @param {Kysely<Database>} db
*/
export async function down(db) {
await drop_tables(db);
}
/**
*
* @param {Kysely<Database>} db
*/
const drop_tables = async (db) => {
try {
await Promise.all([
drop_safe_table(db, 'auth_users'),
drop_safe_table(db, 'tags'),
drop_safe_table(db, 'collections'),
drop_safe_table(db, 'customers'),
drop_safe_table(db, 'discounts'),
drop_safe_table(db, 'images'),
drop_safe_table(db, 'notifications'),
drop_safe_table(db, 'orders'),
drop_safe_table(db, 'posts'),
drop_safe_table(db, 'shipping_methods'),
drop_safe_table(db, 'products'),
drop_safe_table(db, 'products_to_collections'),
drop_safe_table(db, 'products_to_discounts'),
drop_safe_table(db, 'products_to_variants'),
drop_safe_table(db, 'storefronts'),
drop_safe_table(db, 'storefronts_to_other'),
drop_safe_table(db, 'entity_to_media'),
drop_safe_table(db, 'entity_to_search_terms'),
drop_safe_table(db, 'entity_to_tags_projections'),
]);
} catch (e) {
console.log(e)
}
}