From a45e33f94bf84ac496c122e687c6e5d0a96465bb Mon Sep 17 00:00:00 2001 From: LIm1tZz7 <36764786+TheBadRoger@users.noreply.github.com> Date: Tue, 13 Oct 2026 14:09:36 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B4=E7=90=86=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .agents/context/design-decisions.txt | 2 +- .agents/context/progress.txt | 2 +- .agents/skills/chusql-type-system/SKILL.md | 2 +- README.md | 1 - chusql-core/engine/src/ChuSQL/Core/Engine.hs | 4 - .../src/ChuSQL/Core/Engine/Algebra/Planner.hs | 22 +-- .../Core/Engine/Runtime/Dependencies.hs | 3 +- .../engine/src/ChuSQL/Core/Engine/Semantic.hs | 64 ++----- .../src/ChuSQL/Core/Engine/Syntax/AST.hs | 15 +- .../src/ChuSQL/Core/Engine/Syntax/Parser.hs | 27 +-- chusql-core/engine/test/RuntimeSpec.hs | 2 +- chusql-core/engine/test/Spec.hs | 50 +++--- .../src/ChuSQL/Interface/Config.hs | 3 - .../src/ChuSQL/Interface/Settings.hs | 2 - chusql-server/src/ChuSQL/Server/Backend.hs | 6 +- chusql-server/src/ChuSQL/Server/Privileges.hs | 3 +- chusql-server/src/ChuSQL/Server/Session.hs | 1 - chusql-web/app/Main.hs | 34 ---- chusql-web/chusql-web.cabal | 1 - chusql-web/src/ChuSQL/Web/API.hs | 20 --- chusql-web/src/ChuSQL/Web/Demo.hs | 166 ----------------- chusql-web/static/api.js | 5 - chusql-web/static/app.js | 15 +- docs/architecture.md | 150 ++++------------ docs/bootstrap.md | 9 +- docs/commands.md | 51 ++++-- docs/config.md | 10 +- docs/course-defense.md | 8 - docs/install.md | 23 ++- docs/normalization.md | 168 ------------------ docs/performance.md | 75 +++----- docs/release-signing.md | 31 ---- docs/release-v26.10.1.md | 15 -- docs/runtime-types.md | 88 --------- docs/syntax.md | 8 +- docs/types.md | 69 +++++-- docs/users-and-roles.md | 22 ++- resources/settings.toml.linux | 2 - resources/settings.toml.windows | 2 - 39 files changed, 264 insertions(+), 917 deletions(-) delete mode 100644 chusql-web/src/ChuSQL/Web/Demo.hs delete mode 100644 docs/course-defense.md delete mode 100644 docs/normalization.md delete mode 100644 docs/release-signing.md delete mode 100644 docs/release-v26.10.1.md delete mode 100644 docs/runtime-types.md diff --git a/.agents/context/design-decisions.txt b/.agents/context/design-decisions.txt index a1ae042..e375e2d 100644 --- a/.agents/context/design-decisions.txt +++ b/.agents/context/design-decisions.txt @@ -2,7 +2,7 @@ 进度见 progress.txt,限制见 known-issues.txt,用户操作见 docs/。 ## 架构与接口 -- 后续设计按领域记录于 docs/normalization.md、docs/types.md、docs/architecture.md 和 docs/release-signing.md;只读范式入口已提供;后续实施 bound IR / DOMAIN,再推进物化、递归、MVCC、compact 和并行写。各文档的设计章节定义拟议能力,现有运行语义不变。 +- 用户文档按主题记录于 docs/commands.md、docs/types.md、docs/architecture.md 和 docs/install.md;只读范式入口已提供。后续实施 bound IR / DOMAIN,再推进物化、递归、MVCC、compact 和并行写;规划不代表现有能力。 - 范式迁移首版保留来源,拒绝 NULL、重复行与依赖不保持;发布目标须验证约束、完整重建并使用独立原子结构 WAL 组,不能复用禁止 DDL 的会话事务拼接执行。 - 发布真实性采用 TUF 元数据链与 Ed25519,初始 root 必须可信取得;离线验证不证明最新版本,操作系统原生代码签名另行接入。 - Web / CLI → server TCP → Haskell 引擎 → FFI → Rust 存储;server 独占数据目录,Haskell 库静态链接,存储为 cdylib。 diff --git a/.agents/context/progress.txt b/.agents/context/progress.txt index b6e0011..8252725 100644 --- a/.agents/context/progress.txt +++ b/.agents/context/progress.txt @@ -39,7 +39,7 @@ ChuSQL 能力与进展摘要 - SQL 复合列声明、LIST / MAYBE / TUPLE、嵌套构造器、INSERT / UPDATE / CHECK / 子查询接入;CLI / Web 显示及 SQL 生成。 - 兼容边界:旧 ColumnType 和 RelOp 保留,日期 / 时间戳 / Blob 明确使用 CompatibilityType;完整 capability / operator / cast / 用户 ADT / Extension 不在本阶段。 - 本批已验证:Engine 466 / Server 141 / Web 75 / CLI 17 全部通过;前端运行时值 9 条断言及事务 10 项通过,改动文件注释检查无问题,git diff --check 通过。 -- 使用说明:docs/runtime-types.md;本批日志:logs/runtime-engine.log、logs/runtime-web.log、logs/runtime-web-final.log、logs/runtime-cli.log。Server 最终回归亦通过;Web 最终日志由单独重跑生成。 +- 使用说明:docs/types.md;本批日志:logs/runtime-engine.log、logs/runtime-web.log、logs/runtime-web-final.log、logs/runtime-cli.log。Server 最终回归亦通过;Web 最终日志由单独重跑生成。 ## 既有模块验证 diff --git a/.agents/skills/chusql-type-system/SKILL.md b/.agents/skills/chusql-type-system/SKILL.md index 666632c..6aff395 100644 --- a/.agents/skills/chusql-type-system/SKILL.md +++ b/.agents/skills/chusql-type-system/SKILL.md @@ -45,4 +45,4 @@ DECIMAL 是有限浮点表示,采用 ties-to-even 舍入与舍入后溢出检 ## References -按需读 `docs/runtime-types.md`;`docs/types.md` 含未来设计,必须与实现区分。以上源码模块是契约核对入口。 +按需读 `docs/types.md`,区分当前类型用法与未来约束设计。以上源码模块是契约核对入口。 diff --git a/README.md b/README.md index 844fb46..83b1ad5 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,6 @@ csql-web ## 更多参考文档 -- [数据库原理学习与答辩文档](learnning/README.md) - [安装与卸载](docs/install.md) - [配置选项](docs/config.md) - [命令与选项](docs/commands.md) diff --git a/chusql-core/engine/src/ChuSQL/Core/Engine.hs b/chusql-core/engine/src/ChuSQL/Core/Engine.hs index 556bb27..9ad562f 100644 --- a/chusql-core/engine/src/ChuSQL/Core/Engine.hs +++ b/chusql-core/engine/src/ChuSQL/Core/Engine.hs @@ -47,10 +47,6 @@ runStatementUncheckedM db q@Select{} = case bindQuery db q of Left e -> pure (Left e) Right bound -> executeQueryM bound -runStatementUncheckedM db q@SelectExpr{} = - case bindQuery db q of - Left e -> pure (Left e) - Right bound -> executeQueryM bound runStatementUncheckedM db (Insert tbl cols rows) = case lookupTable db tbl of Left e -> pure (Left e) diff --git a/chusql-core/engine/src/ChuSQL/Core/Engine/Algebra/Planner.hs b/chusql-core/engine/src/ChuSQL/Core/Engine/Algebra/Planner.hs index 354087b..2e0a1fd 100644 --- a/chusql-core/engine/src/ChuSQL/Core/Engine/Algebra/Planner.hs +++ b/chusql-core/engine/src/ChuSQL/Core/Engine/Algebra/Planner.hs @@ -86,26 +86,16 @@ translate q = case q of ordering <- distinctOrdering inner plan <- case inner of s@Select{} -> translate s { selectOrderBy = [], selectLimit = Nothing } - s@SelectExpr{} -> translate s { selectOrderBy = [], selectLimit = Nothing } _ -> Left "DISTINCT requires SELECT" Right (limited ordering (selectLimit inner) (Distinct plan)) - Select - { selectCols = cols - , selectFrom = fromC - , selectWhere = mWhere - , selectGroupBy = groupBy - , selectOrderBy = orderBy - , selectLimit = mLimit - } -> do - plan0 <- source fromC mWhere - let (plan, _) = grouped groupBy [] plan0 - Right (Project cols (limited orderBy mLimit plan)) - SelectExpr items fromC mWhere groupBy orderBy mLimit -> do + Select items fromC mWhere groupBy orderBy mLimit -> do plan0 <- source fromC mWhere let (plan, items') = grouped groupBy items plan0 - Right $ if any (\(c, _) -> c `elem` map fst items') orderBy - then orderedProjection items' orderBy mLimit plan - else Compute items' (limited orderBy mLimit plan) + Right $ if all (\(label, expression) -> expression == Col label) items' + then Project (map fst items') (limited orderBy mLimit plan) + else if any (\(c, _) -> c `elem` map fst items') orderBy + then orderedProjection items' orderBy mLimit plan + else Compute items' (limited orderBy mLimit plan) _ -> Left "only SELECT is supported by translate" -- | 在排序前计算别名并保留输出顺序 diff --git a/chusql-core/engine/src/ChuSQL/Core/Engine/Runtime/Dependencies.hs b/chusql-core/engine/src/ChuSQL/Core/Engine/Runtime/Dependencies.hs index f426dc6..8102f84 100644 --- a/chusql-core/engine/src/ChuSQL/Core/Engine/Runtime/Dependencies.hs +++ b/chusql-core/engine/src/ChuSQL/Core/Engine/Runtime/Dependencies.hs @@ -10,8 +10,7 @@ import Data.List (nub) queryTables :: Statement -> [String] queryTables statement = nub (case statement of SelectDistinct child -> queryTables child - Select _ source condition _ _ _ -> sourceTables source ++ concatMap expressionTables condition - SelectExpr items source condition _ _ _ -> sourceTables source + Select items source condition _ _ _ -> sourceTables source ++ concatMap (expressionTables . snd) items ++ concatMap expressionTables condition _ -> []) diff --git a/chusql-core/engine/src/ChuSQL/Core/Engine/Semantic.hs b/chusql-core/engine/src/ChuSQL/Core/Engine/Semantic.hs index cf23a48..02d7d56 100644 --- a/chusql-core/engine/src/ChuSQL/Core/Engine/Semantic.hs +++ b/chusql-core/engine/src/ChuSQL/Core/Engine/Semantic.hs @@ -238,21 +238,13 @@ inferSubqueryOutput db outerScope sq = case subqueryStatement sq of mapM_ (requireOrdering "DISTINCT" . snd) columns _ <- distinctOrdering q Right columns - q@Select{selectCols = cols} -> do - env <- checkFrom db enclosing (selectFrom q) - checkResolvedWith db enclosing q - mapM (columnTypeOf env) cols - q@SelectExpr{selectItems = items} -> do + q@Select{selectItems = items} -> do env <- checkFrom db enclosing (selectFrom q) checkResolvedWith db enclosing q mapM (\(l, e) -> (\t -> (l, t)) <$> inferExpr db "SELECT" (Scope env enclosing) e) items _ -> Left "subquery must be a SELECT" where enclosing = scopeFlat outerScope - -- \| 查这一列的推导类型 - columnTypeOf env c = do - (_, col) <- scopeAt "SELECT" (Scope env enclosing) c - Right (c, inferredColumnType (columnType col)) -- | 聚合的参数:列要在,且不能嵌套聚合 aggregateArg :: Database -> String -> Scope -> Expr -> Either String InferredType @@ -450,27 +442,13 @@ checkResolved db = checkResolvedWith db [] checkResolvedWith :: Database -> [(String, Column)] -> Statement -> Either String () checkResolvedWith db outer q = case q of SelectDistinct inner -> () <$ inferSubqueryOutput db (Scope [] outer) (Subquery (SelectDistinct inner) []) - Select - { selectCols = cols - , selectFrom = fromC - , selectWhere = mWhere - , selectGroupBy = groupBy - , selectOrderBy = orderBy - } -> do - env <- checkFrom db outer fromC - let full = Scope env outer - checkColumns "SELECT" full cols - checkGrouping full groupBy (map (\c -> (c, Col c)) cols) - checkColumns "ORDER BY" full (map fst orderBy) - mapM_ (checkRuntimeColumn "ORDER BY" full . fst) orderBy - mapM_ (checkNoAggregate "WHERE") mWhere - mapM_ (checkBool db "WHERE" full) mWhere - SelectExpr items fromC mWhere groupBy orderBy _ -> do + Select items fromC mWhere groupBy orderBy _ -> do env <- checkFrom db outer fromC let full = Scope env outer + direct = all (\(label, expression) -> expression == Col label) items mapM_ (\item -> () <$ inferExpr db "SELECT" full (snd item)) items - checkGrouping full groupBy (items ++ [(c, Col c) | (c, _) <- orderBy, c `notElem` map fst items]) - mapM_ (checkOrder db full items . fst) orderBy + checkGrouping full groupBy (items ++ [(c, Col c) | (c, _) <- orderBy, not direct, c `notElem` map fst items]) + mapM_ ((if direct then checkRuntimeColumn "ORDER BY" full else checkOrder db full items) . fst) orderBy mapM_ (checkNoAggregate "WHERE") mWhere mapM_ (checkBool db "WHERE" full) mWhere Insert tbl cols rows -> do @@ -850,9 +828,7 @@ outerRefsOf db stmt = nub [c | c <- statementColumns stmt, not (inInner c)] statementColumns :: Statement -> [String] statementColumns stmt = case stmt of SelectDistinct q -> statementColumns q - Select cols fromC mWhere groupBy orderBy _ -> - cols ++ fromColumns fromC ++ concatMap colsInExpr mWhere ++ groupBy ++ map fst orderBy - SelectExpr items fromC mWhere groupBy orderBy _ -> + Select items fromC mWhere groupBy orderBy _ -> concatMap (colsInExpr . snd) items ++ fromColumns fromC ++ concatMap colsInExpr mWhere ++ groupBy ++ map fst orderBy _ -> [] where @@ -866,14 +842,12 @@ statementColumns stmt = case stmt of statementFrom :: Statement -> FromClause statementFrom (SelectDistinct q) = statementFrom q statementFrom Select{selectFrom = fromC} = fromC -statementFrom SelectExpr{selectFrom = fromC} = fromC statementFrom _ = FromUnit -- | 解析子查询里的 SELECT resolveSubqueryStatement :: Database -> [(String, Column)] -> Statement -> Either String Statement resolveSubqueryStatement db outer (SelectDistinct q) = SelectDistinct <$> resolveSubqueryStatement db outer q -resolveSubqueryStatement db outer q@Select{} = resolveQuery db outer q (map (\c -> (c, Col c)) (selectCols q)) -resolveSubqueryStatement db outer q@SelectExpr{} = resolveQuery db outer q (selectItems q) +resolveSubqueryStatement db outer q@Select{} = resolveQuery db outer q (selectItems q) resolveSubqueryStatement _ _ _ = Left "subquery must be a SELECT" -- | 列名解析入口:查询走连接解析,改数据的语句按本表列解析 @@ -881,7 +855,6 @@ resolveStatement :: Database -> Statement -> Either String Statement resolveStatement db q = case q of SelectDistinct inner -> SelectDistinct <$> resolveStatement db inner Select{} -> resolveSelect db q - SelectExpr{} -> resolveSelect db q Update tbl assigns mWhere -> do (key, t) <- resolveTable db tbl let env = tableCols t @@ -910,8 +883,7 @@ scopedColumnAt place inner outer c = scopeAt place (Scope inner outer) c -- | 单表保留原表头,连接使用唯一前缀 resolveSelect :: Database -> Statement -> Either String Statement -resolveSelect db q@Select{} = resolveQuery db [] q (map (\c -> (c, Col c)) (selectCols q)) -resolveSelect db q@SelectExpr{} = resolveQuery db [] q (selectItems q) +resolveSelect db q@Select{} = resolveQuery db [] q (selectItems q) resolveSelect _ q = Right q -- | 检查排序输出别名或来源列 @@ -978,11 +950,9 @@ resolveQuery db outer q items = do [] -> name "ORDER BY" c [label] -> Right label _ -> Left ("ORDER BY: ambiguous projection alias: " ++ c) - qIsExpression = case q of SelectExpr{} -> True; _ -> False + qIsExpression = any (\(label, expression) -> expression /= Col label) items ordering <- mapM (\(c, d) -> (\k -> (k, d)) <$> orderName c) (selectOrderBy q) - pure $ case q of - Select{} -> Select (map fst projected) source condition grouping ordering (selectLimit q) - _ -> SelectExpr projected source condition grouping ordering (selectLimit q) + pure (Select projected source condition grouping ordering (selectLimit q)) -- | 收集没有别名遮蔽的来源表名 sourceTableNames :: FromClause -> [String] @@ -1028,19 +998,7 @@ resolveFrom db outer (FromJoin kind left right cond) = do -- | 派生表的输出列名:列取裸名,表达式保留原标签 nameDerivedColumns :: Statement -> Either String Statement nameDerivedColumns (SelectDistinct q) = SelectDistinct <$> nameDerivedColumns q -nameDerivedColumns q@Select{selectCols = cols, selectFrom = fromC} = do - let names = map lastTablePart cols - checkDerivedNames names - Right - ( SelectExpr - [(n, Col c) | (n, c) <- zip names cols] - fromC - (selectWhere q) - (selectGroupBy q) - (selectOrderBy q) - (selectLimit q) - ) -nameDerivedColumns q@SelectExpr{selectItems = items} = do +nameDerivedColumns q@Select{selectItems = items} = do let names = map derivedItemName items checkDerivedNames names Right q{selectItems = zip names (map snd items)} diff --git a/chusql-core/engine/src/ChuSQL/Core/Engine/Syntax/AST.hs b/chusql-core/engine/src/ChuSQL/Core/Engine/Syntax/AST.hs index f8c4745..5a98f43 100644 --- a/chusql-core/engine/src/ChuSQL/Core/Engine/Syntax/AST.hs +++ b/chusql-core/engine/src/ChuSQL/Core/Engine/Syntax/AST.hs @@ -8,14 +8,7 @@ import ChuSQL.Core.Engine.Runtime.Functions (FunctionId) data Statement = Select - { selectCols :: [String] - , selectFrom :: FromClause - , selectWhere :: Maybe Expr - , selectGroupBy :: [String] - , selectOrderBy :: [(String, SortDir)] - , selectLimit :: Maybe Int - } - | SelectExpr + -- | 输出名称与投影表达式,普通列用 Col { selectItems :: [(String, Expr)] , selectFrom :: FromClause , selectWhere :: Maybe Expr @@ -170,7 +163,7 @@ data SortDir makeSelect :: [String] -> String -> Maybe Expr -> Statement makeSelect cols tbl w = Select - { selectCols = cols + { selectItems = [(c, Col c) | c <- cols] , selectFrom = FromTable Nothing tbl , selectWhere = w , selectGroupBy = [] @@ -181,7 +174,6 @@ makeSelect cols tbl w = -- | 将去重排序映射到输出列 distinctOrdering :: Statement -> Either String [(String, SortDir)] distinctOrdering q@Select{} = resolveDistinctOrdering q -distinctOrdering q@SelectExpr{} = resolveDistinctOrdering q distinctOrdering _ = Left "DISTINCT requires SELECT" -- | 解析去重输出的排序列 @@ -189,8 +181,7 @@ resolveDistinctOrdering :: Statement -> Either String [(String, SortDir)] resolveDistinctOrdering q = mapM resolve (selectOrderBy q) where items = case q of - Select { selectCols = cols } -> [(c, Col c) | c <- cols] - SelectExpr { selectItems = projected } -> projected + Select { selectItems = projected } -> projected _ -> [] -- | 排序键必须出现在去重结果中 resolve (column, direction) = case [label | (label, e) <- items, label == column || e == Col column] of diff --git a/chusql-core/engine/src/ChuSQL/Core/Engine/Syntax/Parser.hs b/chusql-core/engine/src/ChuSQL/Core/Engine/Syntax/Parser.hs index 1e93f61..08fb747 100644 --- a/chusql-core/engine/src/ChuSQL/Core/Engine/Syntax/Parser.hs +++ b/chusql-core/engine/src/ChuSQL/Core/Engine/Syntax/Parser.hs @@ -697,9 +697,7 @@ selectStatement = do groupBy <- fromMaybe [] <$> optional groupByClause orderBy <- fromMaybe [] <$> optional orderByClause mLimit <- optional limitClause - pure $ (if distinct then SelectDistinct else id) $ if all (\(name, e) -> e == Col name) cols - then Select (map fst cols) fromC mWhere groupBy orderBy mLimit - else SelectExpr cols fromC mWhere groupBy orderBy mLimit + pure $ (if distinct then SelectDistinct else id) (Select cols fromC mWhere groupBy orderBy mLimit) -- | 读 WITH:展开每个 CTE 再读主查询 withStatement :: Parser Statement @@ -741,20 +739,11 @@ cteKey = map toLower renameColumns :: String -> [String] -> Statement -> Either String Statement renameColumns _ [] q = Right q renameColumns name cols (SelectDistinct q) = SelectDistinct <$> renameColumns name cols q -renameColumns name cols q@Select { selectCols = names } = do - checkCteArity name cols names - Right - ( SelectExpr - [(c, Col n) | (c, n) <- zip cols names] - (selectFrom q) - (selectWhere q) - (selectGroupBy q) - (selectOrderBy q) - (selectLimit q) - ) -renameColumns name cols q@SelectExpr { selectItems = items } = do +renameColumns name cols q@Select { selectItems = items } = do checkCteArity name cols (map snd items) - ordering <- mapM renameOrder (selectOrderBy q) + ordering <- if all (\(label, expression) -> expression == Col label) items + then Right (selectOrderBy q) + else mapM renameOrder (selectOrderBy q) Right q { selectItems = zip cols (map snd items), selectOrderBy = ordering } where -- | 列清单同步改写内层排序输出别名 @@ -774,11 +763,7 @@ checkCteArity name cols out expandStatement :: [(String, Statement)] -> Statement -> Either String Statement expandStatement env stmt = case stmt of SelectDistinct q -> SelectDistinct <$> expandStatement env q - q@Select { selectFrom = fromC, selectWhere = mWhere } -> do - fromC' <- expandClause env fromC - w <- traverse (expandExpr env) mWhere - Right q { selectFrom = fromC', selectWhere = w } - q@SelectExpr { selectFrom = fromC, selectItems = items, selectWhere = mWhere } -> do + q@Select { selectFrom = fromC, selectItems = items, selectWhere = mWhere } -> do fromC' <- expandClause env fromC items' <- traverse (\(name, e) -> fmap ((,) name) (expandExpr env e)) items w <- traverse (expandExpr env) mWhere diff --git a/chusql-core/engine/test/RuntimeSpec.hs b/chusql-core/engine/test/RuntimeSpec.hs index 5f45dbb..58d18d6 100644 --- a/chusql-core/engine/test/RuntimeSpec.hs +++ b/chusql-core/engine/test/RuntimeSpec.hs @@ -420,7 +420,7 @@ spec = do it "binds calls before execution" $ do let bound = parseStatement "SELECT length('abc')" >>= prepare [] case bound of - Right SelectExpr {selectItems = [(_, BoundFunction (FunctionId 1) _ [_])]} -> pure () + Right Select {selectItems = [(_, BoundFunction (FunctionId 1) _ [_])]} -> pure () _ -> expectationFailure (show bound) it "rejects unknown SQL functions before scanning" $ sql "SELECT missing('abc')" `shouldSatisfy` isFailure diff --git a/chusql-core/engine/test/Spec.hs b/chusql-core/engine/test/Spec.hs index e450e45..dec4ddf 100644 --- a/chusql-core/engine/test/Spec.hs +++ b/chusql-core/engine/test/Spec.hs @@ -564,7 +564,7 @@ main = hspec $ do parseStatement "SELECT name FROM users JOIN orders ON id = user_id" `shouldBe` Right ( Select - { selectCols = ["name"] + { selectItems = [("name", Col "name")] , selectFrom = FromJoin InnerJoin @@ -582,7 +582,7 @@ main = hspec $ do parseStatement "SELECT u.name FROM users u JOIN orders o ON u.id = o.user_id" `shouldBe` Right ( Select - { selectCols = ["u.name"] + { selectItems = [("u.name", Col "u.name")] , selectFrom = FromJoin InnerJoin @@ -600,7 +600,7 @@ main = hspec $ do parseStatement "SELECT u.name FROM users u LEFT JOIN orders o ON u.id = o.user_id" `shouldBe` Right ( Select - { selectCols = ["u.name"] + { selectItems = [("u.name", Col "u.name")] , selectFrom = FromJoin LeftJoin @@ -633,11 +633,11 @@ main = hspec $ do parseStatement "SELECT d.name FROM (SELECT name FROM users) d" `shouldBe` Right ( Select - { selectCols = ["d.name"] + { selectItems = [("d.name", Col "d.name")] , selectFrom = FromSubquery (Just "d") - (Select ["name"] (FromTable Nothing "users") Nothing [] [] Nothing) + (Select [("name", Col "name")] (FromTable Nothing "users") Nothing [] [] Nothing) , selectWhere = Nothing , selectGroupBy = [] , selectOrderBy = [] @@ -654,14 +654,14 @@ main = hspec $ do ( FromJoin InnerJoin (FromTable (Just "u") "users") - (FromSubquery (Just "d") (Select ["name"] (FromTable Nothing "users") Nothing [] [] Nothing)) + (FromSubquery (Just "d") (Select [("name", Col "name")] (FromTable Nothing "users") Nothing [] [] Nothing)) (Eq (Col "u.name") (Col "d.name")) ) it "parses a projection alias" $ do parseStatement "SELECT count(*) AS total FROM orders" `shouldBe` Right - ( SelectExpr + ( Select [("total", CountAll)] (FromTable Nothing "orders") Nothing @@ -713,11 +713,11 @@ main = hspec $ do parseStatement "WITH t AS (SELECT name FROM users) SELECT t.name FROM t" `shouldBe` Right ( Select - { selectCols = ["t.name"] + { selectItems = [("t.name", Col "t.name")] , selectFrom = FromSubquery (Just "t") - (Select ["name"] (FromTable Nothing "users") Nothing [] [] Nothing) + (Select [("name", Col "name")] (FromTable Nothing "users") Nothing [] [] Nothing) , selectWhere = Nothing , selectGroupBy = [] , selectOrderBy = [] @@ -737,6 +737,14 @@ main = hspec $ do values "WITH t(who) AS (SELECT name FROM users) SELECT t.who FROM t ORDER BY t.who" `shouldBe` Right [[VStr "Alice"], [VStr "Bob"], [VStr "Carol"]] + it "keeps source ordering when renaming repeated CTE columns" $ do + values "WITH t(first, second) AS (SELECT name, name FROM users ORDER BY name DESC LIMIT 1) SELECT first, second FROM t" + `shouldBe` Right [[VStr "Carol", VStr "Carol"]] + + it "renames expression ordering aliases with CTE columns" $ do + values "WITH t(next_age) AS (SELECT age + 1 AS years FROM users ORDER BY years DESC LIMIT 1) SELECT next_age FROM t" + `shouldBe` Right [[VInt 31]] + it "takes a bare column from a CTE" $ do values "WITH t(who) AS (SELECT name FROM users) SELECT who FROM t ORDER BY who" `shouldBe` Right [[VStr "Alice"], [VStr "Bob"], [VStr "Carol"]] @@ -771,11 +779,11 @@ main = hspec $ do it "parses >= into GtE" $ do parseStatement "SELECT name FROM users WHERE age >= 18" - `shouldBe` Right (Select ["name"] (FromTable Nothing "users") (Just (GtE (Col "age") (LitInt 18))) [] [] Nothing) + `shouldBe` Right (Select [("name", Col "name")] (FromTable Nothing "users") (Just (GtE (Col "age") (LitInt 18))) [] [] Nothing) it "parses <= into LtE" $ do parseStatement "SELECT name FROM users WHERE age <= 30" - `shouldBe` Right (Select ["name"] (FromTable Nothing "users") (Just (LtE (Col "age") (LitInt 30))) [] [] Nothing) + `shouldBe` Right (Select [("name", Col "name")] (FromTable Nothing "users") (Just (LtE (Col "age") (LitInt 30))) [] [] Nothing) it "parses <> and != into the same node" $ do sql "SELECT name FROM users WHERE age <> 17" @@ -855,11 +863,11 @@ main = hspec $ do it "parses > ANY into a quantified comparison" $ do parseStatement "SELECT name FROM users WHERE age > ANY (SELECT age FROM orders)" - `shouldBe` Right (Select ["name"] (FromTable Nothing "users") (Just (QuantCmp CmpGt (Col "age") (Subquery (Select ["age"] (FromTable Nothing "orders") Nothing [] [] Nothing) []) AnyQ)) [] [] Nothing) + `shouldBe` Right (Select [("name", Col "name")] (FromTable Nothing "users") (Just (QuantCmp CmpGt (Col "age") (Subquery (Select [("age", Col "age")] (FromTable Nothing "orders") Nothing [] [] Nothing) []) AnyQ)) [] [] Nothing) it "parses <> ALL into a quantified comparison" $ do parseStatement "SELECT name FROM users WHERE age <> ALL (SELECT age FROM orders)" - `shouldBe` Right (Select ["name"] (FromTable Nothing "users") (Just (QuantCmp CmpNe (Col "age") (Subquery (Select ["age"] (FromTable Nothing "orders") Nothing [] [] Nothing) []) AllQ)) [] [] Nothing) + `shouldBe` Right (Select [("name", Col "name")] (FromTable Nothing "users") (Just (QuantCmp CmpNe (Col "age") (Subquery (Select [("age", Col "age")] (FromTable Nothing "orders") Nothing [] [] Nothing) []) AllQ)) [] [] Nothing) it "still reads plain comparisons" $ do values "SELECT name FROM users WHERE age > 20 ORDER BY name" @@ -1269,7 +1277,7 @@ main = hspec $ do it "user is reserved as an alias but still usable inside a longer name" $ do parseStatement "SELECT * FROM users user" `shouldSatisfy` isLeft - parseStatement "SELECT user1 FROM users" `shouldBe` Right (Select ["user1"] (FromTable Nothing "users") Nothing [] [] Nothing) + parseStatement "SELECT user1 FROM users" `shouldBe` Right (Select [("user1", Col "user1")] (FromTable Nothing "users") Nothing [] [] Nothing) describe "ChuSQL.Core.Engine (DELETE)" $ do it "parses DELETE with WHERE" $ do @@ -1407,7 +1415,7 @@ main = hspec $ do it "executes ORDER BY age ASC" $ do let q = Select - { selectCols = ["name"] + { selectItems = [("name", Col "name")] , selectFrom = FromTable Nothing "users" , selectWhere = Nothing , selectGroupBy = [] @@ -1424,7 +1432,7 @@ main = hspec $ do it "executes ORDER BY age DESC" $ do let q = Select - { selectCols = ["name"] + { selectItems = [("name", Col "name")] , selectFrom = FromTable Nothing "users" , selectWhere = Nothing , selectGroupBy = [] @@ -1454,7 +1462,7 @@ main = hspec $ do it "executes LIMIT without ORDER BY" $ do let q = Select - { selectCols = ["name"] + { selectItems = [("name", Col "name")] , selectFrom = FromTable Nothing "users" , selectWhere = Nothing , selectGroupBy = [] @@ -1470,7 +1478,7 @@ main = hspec $ do it "executes LIMIT with ORDER BY" $ do let q = Select - { selectCols = ["name"] + { selectItems = [("name", Col "name")] , selectFrom = FromTable Nothing "users" , selectWhere = Nothing , selectGroupBy = [] @@ -1486,7 +1494,7 @@ main = hspec $ do it "executes LIMIT 0" $ do let q = Select - { selectCols = ["name"] + { selectItems = [("name", Col "name")] , selectFrom = FromTable Nothing "users" , selectWhere = Nothing , selectGroupBy = [] @@ -1535,7 +1543,7 @@ main = hspec $ do runStatement testDB ( Select - { selectCols = ["u.name"] + { selectItems = [("u.name", Col "u.name")] , selectFrom = FromJoin InnerJoin @@ -2512,7 +2520,7 @@ main = hspec $ do runIPCStorage ( runStatementM ( Select - { selectCols = ["name"] + { selectItems = [("name", Col "name")] , selectFrom = FromTable Nothing "ipc_idx" , selectWhere = Just (Eq (Col "id") (LitInt 42)) , selectGroupBy = [] diff --git a/chusql-interface/src/ChuSQL/Interface/Config.hs b/chusql-interface/src/ChuSQL/Interface/Config.hs index 0074fbc..6afeea2 100644 --- a/chusql-interface/src/ChuSQL/Interface/Config.hs +++ b/chusql-interface/src/ChuSQL/Interface/Config.hs @@ -49,7 +49,6 @@ data WebConfig = WebConfig , wcMaxPageSize :: Int , wcMaxRows :: Int , wcMaxSqlLength :: Int - , wcSeedDemo :: Bool } deriving (Show, Eq) @@ -73,7 +72,6 @@ defaultWebConfig = , wcMaxPageSize = 500 , wcMaxRows = 1000 , wcMaxSqlLength = 20000 - , wcSeedDemo = False } -- | 把设置键统一成连字符写法,重名时连字符优先 @@ -148,7 +146,6 @@ webConfigFromSection saved = , wcMaxPageSize = sectionInt "max-page-size" saved (wcMaxPageSize defaultWebConfig) , wcMaxRows = sectionInt "max-rows" saved (wcMaxRows defaultWebConfig) , wcMaxSqlLength = sectionInt "max-sql-length" saved (wcMaxSqlLength defaultWebConfig) - , wcSeedDemo = sectionBool "seed" saved (wcSeedDemo defaultWebConfig) } -- | 分区里一个键的非空字符串值 diff --git a/chusql-interface/src/ChuSQL/Interface/Settings.hs b/chusql-interface/src/ChuSQL/Interface/Settings.hs index c45a930..ec83869 100644 --- a/chusql-interface/src/ChuSQL/Interface/Settings.hs +++ b/chusql-interface/src/ChuSQL/Interface/Settings.hs @@ -61,7 +61,6 @@ settingCatalogue = , owned "storage-btree-order" "Storage B+tree order" "storage" "int" "4" "btree" "order" , owned "storage-buffer-pool" "Storage buffer pool pages" "storage" "int" "1024" "buffer" "pool_size" , owned "storage-log" "Storage log level" "storage" "text" "info" "log" "level" - , item "seed" "Seed demo data on start" "storage" "bool" "1" True True , owned "tcp-listen-host" "TCP listen address" "network" "text" "127.0.0.1" "server" "listen_host" , owned "tcp-port" "TCP port" "network" "int" "7777" "server" "port" , owned "tcp-max-message" "TCP max request line (bytes)" "network" "int" "1048576" "server" "max_message" @@ -231,7 +230,6 @@ effectiveSettings cfg = , ("max-page-size", tshow (wcMaxPageSize cfg)) , ("max-rows", tshow (wcMaxRows cfg)) , ("max-sql-length", tshow (wcMaxSqlLength cfg)) - , ("seed", boolText (wcSeedDemo cfg)) , ("data-dir", maybe "" T.pack (wcDataDir cfg)) , ("log-files", T.pack (wcLogFiles cfg)) ] diff --git a/chusql-server/src/ChuSQL/Server/Backend.hs b/chusql-server/src/ChuSQL/Server/Backend.hs index 372b7d5..9852cfc 100644 --- a/chusql-server/src/ChuSQL/Server/Backend.hs +++ b/chusql-server/src/ChuSQL/Server/Backend.hs @@ -76,8 +76,7 @@ data Backend = Backend columnsFromStatement :: Database -> Statement -> [String] columnsFromStatement db stmt = case prepare db stmt of Right (SelectDistinct q) -> columnsFromStatement db q - Right (Select cols _ _ _ _ _) -> cols - Right (SelectExpr items _ _ _ _ _) -> map fst items + Right (Select items _ _ _ _ _) -> map fst items Right ShowDomains -> ["domain", "base_type"] _ -> [] @@ -331,9 +330,6 @@ statementTables :: Statement -> [Text] statementTables stmt = nub (case stmt of SelectDistinct q -> statementTables q Select{} -> - tableRefsOf (selectFrom stmt) - ++ concatMap exprTables (maybe [] (: []) (selectWhere stmt) ++ map Col (selectCols stmt ++ selectGroupBy stmt ++ map fst (selectOrderBy stmt))) - SelectExpr{} -> tableRefsOf (selectFrom stmt) ++ concatMap exprTables (maybe [] (: []) (selectWhere stmt) ++ map snd (selectItems stmt) ++ map Col (selectGroupBy stmt ++ map fst (selectOrderBy stmt))) Insert table _ rows -> T.pack table : concatMap exprTables (concat rows) diff --git a/chusql-server/src/ChuSQL/Server/Privileges.hs b/chusql-server/src/ChuSQL/Server/Privileges.hs index f3716ec..82b54d7 100644 --- a/chusql-server/src/ChuSQL/Server/Privileges.hs +++ b/chusql-server/src/ChuSQL/Server/Privileges.hs @@ -199,8 +199,7 @@ reconcileObjects service = withTables service (catalog (OA.objectReconcile (pvBa requiredActions :: Statement -> Maybe [(Text, Text)] requiredActions statement = case statement of SelectDistinct q -> requiredActions q - Select{} -> Just (selectNeeds (selectFrom statement) (maybe [] (: []) (selectWhere statement))) - SelectExpr{} -> Just (selectNeeds (selectFrom statement) (maybe [] (: []) (selectWhere statement) ++ map snd (selectItems statement))) + Select{} -> Just (selectNeeds (selectFrom statement) (maybe [] (: []) (selectWhere statement) ++ map snd (selectItems statement))) Insert table _ rows -> Just ((T.pack table, "insert") : selectsOf (concat rows)) Update table assignments condition -> Just ((T.pack table, "update") : selectsOf (map snd assignments ++ maybe [] (: []) condition)) Delete table condition -> Just ((T.pack table, "delete") : selectsOf (maybe [] (: []) condition)) diff --git a/chusql-server/src/ChuSQL/Server/Session.hs b/chusql-server/src/ChuSQL/Server/Session.hs index 190ab60..8a57d91 100644 --- a/chusql-server/src/ChuSQL/Server/Session.hs +++ b/chusql-server/src/ChuSQL/Server/Session.hs @@ -328,7 +328,6 @@ transactionData :: Statement -> Bool transactionData statement = case statement of SelectDistinct q -> transactionData q Select{} -> True - SelectExpr{} -> True Insert{} -> True Update{} -> True Delete{} -> True diff --git a/chusql-web/app/Main.hs b/chusql-web/app/Main.hs index 67025fd..c5cff9a 100644 --- a/chusql-web/app/Main.hs +++ b/chusql-web/app/Main.hs @@ -17,10 +17,8 @@ import ChuSQL.Interface.Config ( ) import ChuSQL.Interface.Link (clientPing, closeClient, connectClient) import ChuSQL.Interface.RateLimit (newRateLimiter) -import ChuSQL.Interface.Session (authenticateSession, newSession) import ChuSQL.Interface.Settings (effectiveSettings) import ChuSQL.Interface.TOML (resolveConfigPath) -import ChuSQL.Web.Demo (SeedReport (..), seedDemo) import Control.Exception (IOException, try) import Data.Char (toLower) import Data.String (fromString) @@ -52,7 +50,6 @@ data Options = Options , optMaxPageSize :: Maybe Int , optMaxRows :: Maybe Int , optMaxSqlLength :: Maybe Int - , optSeedDemo :: Maybe Bool , optHelp :: Bool } @@ -74,7 +71,6 @@ emptyOptions = , optMaxPageSize = Nothing , optMaxRows = Nothing , optMaxSqlLength = Nothing - , optSeedDemo = Nothing , optHelp = False } @@ -99,7 +95,6 @@ parseArgs = go emptyOptions go opts ("--max-page-size" : v : rest) = withInt "--max-page-size" v (\n -> go opts{optMaxPageSize = Just n} rest) go opts ("--max-rows" : v : rest) = withInt "--max-rows" v (\n -> go opts{optMaxRows = Just n} rest) go opts ("--max-sql-length" : v : rest) = withInt "--max-sql-length" v (\n -> go opts{optMaxSqlLength = Just n} rest) - go opts ("--seed" : v : rest) = go opts{optSeedDemo = Just (isTrue v)} rest go opts ("--cookie-secure" : v : rest) = go opts{optCookieSecure = Just (isTrue v)} rest go _ (a : _) = Left ("unrecognized argument or missing value: " ++ a) @@ -136,7 +131,6 @@ usage = do putStrLn " --max-page-size N rows per page ceiling ([web] max_page_size, default 500)" putStrLn " --max-rows N rows returned per query ([web] max_rows, default 1000)" putStrLn " --max-sql-length N max SQL characters ([web] max_sql_length, default 20000)" - putStrLn " --seed BOOL load demo data when the db is empty ([web] seed, default false)" putStrLn "" putStrLn "administrator password: lives in the __system_users system table, never in settings.toml" putStrLn " the installer always sets one; an account whose hash is still empty signs in with an empty password" @@ -164,7 +158,6 @@ applyOptions cfg opts = , wcMaxPageSize = orElse (optMaxPageSize opts) (wcMaxPageSize cfg) , wcMaxRows = orElse (optMaxRows opts) (wcMaxRows cfg) , wcMaxSqlLength = orElse (optMaxSqlLength opts) (wcMaxSqlLength cfg) - , wcSeedDemo = orElse (optSeedDemo opts) (wcSeedDemo cfg) } where -- | 有就用新的,没有留旧值 @@ -220,7 +213,6 @@ run opts = do printBanner cfg configPath staticDir reportCredential cfg legacy checkServer (aeServerHost env) (aeServerPort env) - seedIfWanted cfg (aeServerHost env) (aeServerPort env) let settings = Warp.setPort (wcPort cfg) (Warp.setHost (fromString (wcHost cfg)) Warp.defaultSettings) serve settings app @@ -262,32 +254,6 @@ reportCredential cfg legacy = do putStrLn " !! remove it: the administrator password lives in the __system_users system table" else pure () --- | 配了 seed 就补演示数据(管理员已设口令时跳过) -seedIfWanted :: WebConfig -> Text -> Int -> IO () -seedIfWanted cfg host port - | not (wcSeedDemo cfg) = pure () - | otherwise = do - opened <- connectClient host port - case opened of - Left message -> TIO.putStrLn ("demo data skipped: " <> message) - Right client -> do - session <- newSession client - signed <- authenticateSession session (rootUserName cfg) "" - case signed of - Left message -> TIO.putStrLn ("demo data skipped: " <> message <> " (set the administrator password after seeding)") - Right () -> do - result <- seedDemo session - case result of - Left message -> TIO.putStrLn ("demo data skipped: " <> message) - Right report -> - TIO.putStrLn - ( "demo data: " - <> (if null (srCreated report) then "already present" else "created " <> T.pack (unwords (srCreated report))) - <> (if null (srSkipped report) then "" else ", kept " <> T.pack (unwords (srSkipped report))) - <> (if null (srIndexes report) then "" else ", index on " <> T.pack (unwords (srIndexes report))) - ) - closeClient client - -- | ping 一次 server,报告它通不通 checkServer :: Text -> Int -> IO () checkServer host port = do diff --git a/chusql-web/chusql-web.cabal b/chusql-web/chusql-web.cabal index afb0815..20c7388 100644 --- a/chusql-web/chusql-web.cabal +++ b/chusql-web/chusql-web.cabal @@ -12,7 +12,6 @@ build-type: Simple library hs-source-dirs: src exposed-modules: ChuSQL.Web.API - ChuSQL.Web.Demo ChuSQL.Web.Secure ChuSQL.Web.Static ChuSQL.Web.UISettings diff --git a/chusql-web/src/ChuSQL/Web/API.hs b/chusql-web/src/ChuSQL/Web/API.hs index cc6b0e8..7b068a2 100644 --- a/chusql-web/src/ChuSQL/Web/API.hs +++ b/chusql-web/src/ChuSQL/Web/API.hs @@ -101,7 +101,6 @@ import ChuSQL.Interface.Settings ( writeSettingsFile, ) import ChuSQL.Interface.TOML (defaultConfigFile) -import ChuSQL.Web.Demo (SeedReport (..), seedDemo) import ChuSQL.Web.Secure (bodyLimitDynamic, sameOriginOnly, securityHeaders, contentSecurityPolicy) import ChuSQL.Web.Static (contentTypeOf, readStatic, safeRelative) import ChuSQL.Web.UISettings ( @@ -331,7 +330,6 @@ routes env = do post "/api/tables/:t/indexes" (withDatabase env createIndexH) delete "/api/tables/:t/indexes/:col" (withDatabase env dropIndexH) delete "/api/tables/:t/columns/:col" (withDatabase env dropColumnH) - post "/api/demo-data" (withDatabase env demoDataH) get "/api/roles" (withDatabase env rolesH) post "/api/roles" (withDatabase env createRoleH) delete "/api/roles/:name" (withDatabase env dropRoleH) @@ -1241,24 +1239,6 @@ dropColumnH env = do Left err -> reply400 "bad_request" (T.pack err) Right sql -> runWrite ws sql --- | 一键灌演示数据(缺什么补什么,可以反复点) -demoDataH :: AppEnv -> ActionM () -demoDataH env = do - ws <- requireAdminSession env - _ <- requireDatabaseName ws - result <- liftIO (seedDemo (wsSession ws)) - case result of - Left message -> serverError message - Right report -> - json - ( object - [ "ok" .= True - , "created" .= srCreated report - , "skipped" .= srSkipped report - , "indexes" .= srIndexes report - ] - ) - -- | 角色总览:只有管理员能看 rolesH :: AppEnv -> ActionM () rolesH env = do diff --git a/chusql-web/src/ChuSQL/Web/Demo.hs b/chusql-web/src/ChuSQL/Web/Demo.hs deleted file mode 100644 index 1965c8f..0000000 --- a/chusql-web/src/ChuSQL/Web/Demo.hs +++ /dev/null @@ -1,166 +0,0 @@ -{-# LANGUAGE OverloadedStrings #-} - -module ChuSQL.Web.Demo ( - SeedReport (..), - demoTableSpecs, - demoRows, - demoIndexes, - demoNames, - demoPlan, - seedDemo, -) where - -import ChuSQL.Core.Model (Value (..)) -import ChuSQL.Core.Protocol (TableInfo (..)) -import ChuSQL.Interface.Actions ( - ColumnSpec (..), - CreateTableSpec (..), - createIndexSql, - createTableSql, - insertRowsSql, - ) -import ChuSQL.Interface.Session (Session, catalog, runStatement) -import Data.Text (Text) -import qualified Data.Text as T - --- 演示数据:三张表加一个二级索引,语句与界面走同一套拼 SQL 的代码。 - --- | 演示表(建表顺序即依赖顺序;没有外键约束,纯展示) -demoTableSpecs :: [CreateTableSpec] -demoTableSpecs = - [ CreateTableSpec "users" [ColumnSpec "id" "int", ColumnSpec "name" "str", ColumnSpec "age" "int"] - , CreateTableSpec "orders" [ColumnSpec "id" "int", ColumnSpec "user_id" "int", ColumnSpec "product" "str", ColumnSpec "amount" "int"] - , CreateTableSpec "products" [ColumnSpec "id" "int", ColumnSpec "name" "str", ColumnSpec "sku" "int", ColumnSpec "price" "int"] - ] - --- | 每张表的演示行 -demoRows :: [(T.Text, [[(String, Value)]])] -demoRows = - [ ( "users" - , [ [("id", VInt i), ("name", VStr name), ("age", VInt age)] - | (i, (name, age)) <- zip [1 :: Int ..] userRecords - ] - ) - , ( "orders" - , [ [("id", VInt i), ("user_id", VInt uid), ("product", VStr p), ("amount", VInt a)] - | (i, (uid, p, a)) <- zip [1 :: Int ..] orderRecords - ] - ) - , ( "products" - , [ [("id", VInt i), ("name", VStr n), ("sku", VInt sku), ("price", VInt price)] - | (i, (n, sku, price)) <- zip [1 :: Int ..] productRecords - ] - ) - ] - --- | 演示索引:products.sku 取值唯一 -demoIndexes :: [(T.Text, T.Text)] -demoIndexes = [("products", "sku")] - --- | 演示数据涉及的表名 -demoNames :: [T.Text] -demoNames = map ctsTable demoTableSpecs - --- | 完整的一套语句(建表 + 插行 + 建索引),按顺序执行 -demoPlan :: Either String [String] -demoPlan = do - creates <- mapM createTableSql demoTableSpecs - inserts <- mapM (uncurry insertRowsSql) demoRows - indexes <- mapM (uncurry createIndexSql) demoIndexes - pure (creates ++ inserts ++ indexes) - -data SeedReport = SeedReport - { srCreated :: [String] - , srSkipped :: [String] - , srIndexes :: [String] - } - deriving (Show, Eq) - --- | 按需灌演示数据:缺表补表、缺索引补索引 -seedDemo :: Session -> IO (Either Text SeedReport) -seedDemo session = do - catalogResult <- catalog session - case catalogResult of - Left message -> pure (Left message) - Right infos -> do - let existingTables = map tiTable infos - missing = [spec | spec <- demoTableSpecs, T.unpack (ctsTable spec) `notElem` existingTables] - skipped = [T.unpack (ctsTable spec) | spec <- demoTableSpecs, T.unpack (ctsTable spec) `elem` existingTables] - missingNames = map ctsTable missing - wantedIndexes = - [ (t, c) - | (t, c) <- demoIndexes - , t `elem` missingNames || indexMissing infos t c - ] - created <- runAll (map createTableSql missing) - case created of - Left message -> pure (Left message) - Right () -> do - rowsDone <- runAll [insertRowsSql t rs | (t, rs) <- demoRows, t `elem` missingNames] - case rowsDone of - Left message -> pure (Left message) - Right () -> do - indexes <- runAll [createIndexSql t c | (t, c) <- wantedIndexes] - pure $ fmap (const (SeedReport (map T.unpack missingNames) skipped (map (T.unpack . snd) wantedIndexes))) indexes - where - -- | 顺序跑完一串语句,首错即停 - runAll :: [Either String String] -> IO (Either Text ()) - runAll [] = pure (Right ()) - runAll (sql : rest) = case sql of - Left e -> pure (Left (T.pack e)) - Right statement -> do - result <- runStatement session (T.pack statement) - case result of - Left message -> pure (Left message) - Right _ -> runAll rest - - -- | 目录里这张表缺不缺这个索引 - indexMissing :: [TableInfo] -> Text -> Text -> Bool - indexMissing infos t c = case lookup (T.unpack t) [(tiTable i, tiIndexes i) | i <- infos] of - Nothing -> True - Just cols -> T.unpack c `notElem` cols - --- | 演示用户数据 -userRecords :: [(String, Int)] -userRecords = - [ ("Alice", 24) - , ("Bob", 31) - , ("Carol", 45) - , ("Dave", 19) - , ("Erin", 38) - , ("Frank", 52) - , ("Grace", 27) - , ("Heidi", 33) - , ("Ivan", 41) - , ("Judy", 29) - ] - --- | 演示订单数据 -orderRecords :: [(Int, String, Int)] -orderRecords = - [ (1, "Laptop", 1299) - , (1, "Mouse", 25) - , (2, "Keyboard", 79) - , (3, "Monitor", 349) - , (3, "Webcam", 89) - , (4, "Headset", 119) - , (5, "SSD", 139) - , (5, "RAM", 99) - , (6, "Dock", 199) - , (7, "Cable", 12) - , (8, "Stand", 45) - , (9, "Lamp", 39) - ] - --- | 演示产品数据 -productRecords :: [(String, Int, Int)] -productRecords = - [ ("Laptop", 1001, 1299) - , ("Mouse", 1002, 25) - , ("Keyboard", 1003, 79) - , ("Monitor", 1004, 349) - , ("Webcam", 1005, 89) - , ("Headset", 1006, 119) - , ("SSD", 1007, 139) - , ("RAM", 1008, 99) - ] diff --git a/chusql-web/static/api.js b/chusql-web/static/api.js index b4f03a0..a186eaf 100644 --- a/chusql-web/static/api.js +++ b/chusql-web/static/api.js @@ -297,11 +297,6 @@ export async function query(sql, database, tabId) { } } -// 灌演示数据。 -export async function seedDemoData(database) { - return request('/api/demo-data', jsonInit('POST', {}), database); -} - // ---------------------------------------------------------------- 设置 // 读取服务器设置。 diff --git a/chusql-web/static/app.js b/chusql-web/static/app.js index ee92eea..dca3eae 100644 --- a/chusql-web/static/app.js +++ b/chusql-web/static/app.js @@ -147,7 +147,6 @@ function renderShell() {