-- Database schema and model definitions local M = {} local database = require('notex.database.init') -- Table definitions local SCHEMA = { documents = [[ CREATE TABLE IF NOT EXISTS documents ( id TEXT PRIMARY KEY, file_path TEXT UNIQUE NOT NULL, content_hash TEXT NOT NULL, last_modified INTEGER NOT NULL, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL ) ]], properties = [[ CREATE TABLE IF NOT EXISTS properties ( id TEXT PRIMARY KEY, document_id TEXT NOT NULL, key TEXT NOT NULL, value TEXT NOT NULL, value_type TEXT NOT NULL, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL, FOREIGN KEY (document_id) REFERENCES documents(id) ON DELETE CASCADE ) ]], queries = [[ CREATE TABLE IF NOT EXISTS queries ( id TEXT PRIMARY KEY, name TEXT NOT NULL, definition TEXT NOT NULL, created_at INTEGER NOT NULL, last_used INTEGER DEFAULT 0, use_count INTEGER DEFAULT 0 ) ]], schema_metadata = [[ CREATE TABLE IF NOT EXISTS schema_metadata ( property_key TEXT PRIMARY KEY, detected_type TEXT NOT NULL, validation_rules TEXT, document_count INTEGER DEFAULT 0, created_at INTEGER NOT NULL ) ]] } -- Index definitions local INDICES = { documents_file_path = "CREATE UNIQUE INDEX IF NOT EXISTS idx_documents_file_path ON documents(file_path)", properties_document_id = "CREATE INDEX IF NOT EXISTS idx_properties_document_id ON properties(document_id)", properties_key = "CREATE INDEX IF NOT EXISTS idx_properties_key ON properties(key)", queries_last_used = "CREATE INDEX IF NOT EXISTS idx_queries_last_used ON queries(last_used)", properties_composite = "CREATE INDEX IF NOT EXISTS idx_properties_composite ON properties(document_id, key)", properties_type = "CREATE INDEX IF NOT EXISTS idx_properties_type ON properties(key, value_type)" } -- Initialize schema function M.init() local ok, result = database.transaction({ { query = SCHEMA.documents }, { query = SCHEMA.properties }, { query = SCHEMA.queries }, { query = SCHEMA.schema_metadata }, { query = INDICES.documents_file_path }, { query = INDICES.properties_document_id }, { query = INDICES.properties_key }, { query = INDICES.queries_last_used }, { query = INDICES.properties_composite }, { query = INDICES.properties_type } }) if not ok then return false, result end return true, "Schema initialized successfully" end -- Document model functions M.documents = {} function M.documents.create(document_data) local query = [[ INSERT INTO documents (id, file_path, content_hash, last_modified, created_at, updated_at) VALUES (:id, :file_path, :content_hash, :last_modified, :created_at, :updated_at) ]] return database.execute(query, document_data) end function M.documents.get_by_id(id) local query = "SELECT * FROM documents WHERE id = :id" local ok, result = database.execute(query, { id = id }) if ok and #result > 0 then return true, result[1] end return ok, nil end function M.documents.get_by_path(file_path) local query = "SELECT * FROM documents WHERE file_path = :file_path" local ok, result = database.execute(query, { file_path = file_path }) if ok and #result > 0 then return true, result[1] end return ok, nil end function M.documents.update(document_data) local query = [[ UPDATE documents SET content_hash = :content_hash, last_modified = :last_modified, updated_at = :updated_at WHERE id = :id ]] return database.execute(query, document_data) end function M.documents.delete(id) local query = "DELETE FROM documents WHERE id = :id" return database.execute(query, { id = id }) end -- Property model functions M.properties = {} function M.properties.create(property_data) local query = [[ INSERT INTO properties (id, document_id, key, value, value_type, created_at, updated_at) VALUES (:id, :document_id, :key, :value, :value_type, :created_at, :updated_at) ]] return database.execute(query, property_data) end function M.properties.get_by_document(document_id) local query = "SELECT * FROM properties WHERE document_id = :document_id" local ok, result = database.execute(query, { document_id = document_id }) return ok, result or {} end function M.properties.get_by_key(key) local query = "SELECT * FROM properties WHERE key = :key" local ok, result = database.execute(query, { key = key }) return ok, result or {} end function M.properties.update(property_data) local query = [[ UPDATE properties SET value = :value, value_type = :value_type, updated_at = :updated_at WHERE id = :id ]] return database.execute(query, property_data) end function M.properties.delete(id) local query = "DELETE FROM properties WHERE id = :id" return database.execute(query, { id = id }) end function M.properties.delete_by_document(document_id) local query = "DELETE FROM properties WHERE document_id = :document_id" return database.execute(query, { document_id = document_id }) end -- Query model functions M.queries = {} function M.queries.create(query_data) local query = [[ INSERT INTO queries (id, name, definition, created_at) VALUES (:id, :name, :definition, :created_at) ]] return database.execute(query, query_data) end function M.queries.get_all() local query = "SELECT * FROM queries ORDER BY last_used DESC" return database.execute(query) end function M.queries.get_by_id(id) local query = "SELECT * FROM queries WHERE id = :id" local ok, result = database.execute(query, { id = id }) if ok and #result > 0 then return true, result[1] end return ok, nil end function M.queries.update_usage(id) local query = [[ UPDATE queries SET last_used = :last_used, use_count = use_count + 1 WHERE id = :id ]] return database.execute(query, { id = id, last_used = os.time() }) end function M.queries.delete(id) local query = "DELETE FROM queries WHERE id = :id" return database.execute(query, { id = id }) end -- Schema metadata functions M.schema = {} function M.schema.update_property(property_key, detected_type, validation_rules, document_count) local query = [[ INSERT OR REPLACE INTO schema_metadata (property_key, detected_type, validation_rules, document_count, created_at) VALUES (:property_key, :detected_type, :validation_rules, :document_count, :created_at) ]] return database.execute(query, { property_key = property_key, detected_type = detected_type, validation_rules = validation_rules, document_count = document_count, created_at = os.time() }) end function M.schema.get_all() local query = "SELECT * FROM schema_metadata ORDER BY document_count DESC" return database.execute(query) end function M.schema.get_by_key(property_key) local query = "SELECT * FROM schema_metadata WHERE property_key = :property_key" local ok, result = database.execute(query, { property_key = property_key }) if ok and #result > 0 then return true, result[1] end return ok, nil end return M