@intentius/chant-lexicon-sql 0.118.1 → 0.121.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/clickhouse/apply/apply.d.ts +1 -1
- package/dist/clickhouse/apply/apply.d.ts.map +1 -1
- package/dist/clickhouse/apply/statements.d.ts +8 -0
- package/dist/clickhouse/apply/statements.d.ts.map +1 -1
- package/dist/clickhouse/import/generator.d.ts +1 -1
- package/dist/clickhouse/import/generator.d.ts.map +1 -1
- package/dist/clickhouse/import/inlined.d.ts +49 -0
- package/dist/clickhouse/import/inlined.d.ts.map +1 -0
- package/dist/clickhouse/import/live-export.d.ts +22 -0
- package/dist/clickhouse/import/live-export.d.ts.map +1 -1
- package/dist/clickhouse/live/bind.d.ts +8 -0
- package/dist/clickhouse/live/bind.d.ts.map +1 -1
- package/dist/clickhouse/live/catalog.d.ts +15 -0
- package/dist/clickhouse/live/catalog.d.ts.map +1 -1
- package/dist/clickhouse/live/describe-resources.d.ts.map +1 -1
- package/dist/clickhouse/plan/commands.d.ts.map +1 -1
- package/dist/clickhouse/plan/deep.d.ts +19 -2
- package/dist/clickhouse/plan/deep.d.ts.map +1 -1
- package/dist/clickhouse/plan/diff.d.ts.map +1 -1
- package/dist/clickhouse/plan/normalize.d.ts +3 -0
- package/dist/clickhouse/plan/normalize.d.ts.map +1 -1
- package/dist/clickhouse/plan/rebuild-handoff.d.ts +2 -0
- package/dist/clickhouse/plan/rebuild-handoff.d.ts.map +1 -1
- package/dist/clickhouse/rebuild/engines.d.ts +44 -0
- package/dist/clickhouse/rebuild/engines.d.ts.map +1 -0
- package/dist/clickhouse/rebuild/verify.d.ts +25 -1
- package/dist/clickhouse/rebuild/verify.d.ts.map +1 -1
- package/dist/clickhouse/testing/fake-server.d.ts +5 -0
- package/dist/clickhouse/testing/fake-server.d.ts.map +1 -1
- package/dist/config.d.ts +36 -8
- package/dist/config.d.ts.map +1 -1
- package/dist/core/foreign-tables.d.ts +13 -0
- package/dist/core/foreign-tables.d.ts.map +1 -0
- package/dist/files/clickhouse.d.ts +7 -3
- package/dist/files/clickhouse.d.ts.map +1 -1
- package/dist/files/postgres.d.ts +3 -0
- package/dist/files/postgres.d.ts.map +1 -1
- package/dist/import-parser.d.ts.map +1 -1
- package/dist/integrity.json +2 -2
- package/dist/manifest.json +1 -1
- package/dist/op/activities/clickhouse-emulator.d.ts +7 -1
- package/dist/op/activities/clickhouse-emulator.d.ts.map +1 -1
- package/dist/op/activities/postgres-emulator.d.ts +8 -1
- package/dist/op/activities/postgres-emulator.d.ts.map +1 -1
- package/dist/postgres/access/changes.d.ts +23 -0
- package/dist/postgres/access/changes.d.ts.map +1 -0
- package/dist/postgres/apply/apply.d.ts.map +1 -1
- package/dist/postgres/entities.d.ts.map +1 -1
- package/dist/postgres/live/bind.d.ts +8 -1
- package/dist/postgres/live/bind.d.ts.map +1 -1
- package/dist/postgres/live/catalog.d.ts +3 -3
- package/dist/postgres/live/catalog.d.ts.map +1 -1
- package/dist/postgres/live/client.d.ts +31 -0
- package/dist/postgres/live/client.d.ts.map +1 -1
- package/dist/postgres/plan/commands.d.ts.map +1 -1
- package/dist/postgres/plan/deep.d.ts.map +1 -1
- package/dist/sql-files.d.ts +2 -1
- package/dist/sql-files.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/clickhouse/apply/apply.ts +8 -2
- package/src/clickhouse/apply/statements.ts +32 -5
- package/src/clickhouse/import/generator.ts +8 -3
- package/src/clickhouse/import/import.test.ts +72 -0
- package/src/clickhouse/import/inlined-functions.e2e.test.ts +87 -0
- package/src/clickhouse/import/inlined.test.ts +48 -0
- package/src/clickhouse/import/inlined.ts +200 -0
- package/src/clickhouse/import/live-export.ts +75 -2
- package/src/clickhouse/live/access.e2e.test.ts +71 -18
- package/src/clickhouse/live/bind.ts +10 -0
- package/src/clickhouse/live/catalog.ts +25 -2
- package/src/clickhouse/live/describe-resources.ts +5 -2
- package/src/clickhouse/live/live.test.ts +8 -0
- package/src/clickhouse/plan/commands.ts +6 -3
- package/src/clickhouse/plan/deep-grants.test.ts +67 -0
- package/src/clickhouse/plan/deep.ts +70 -6
- package/src/clickhouse/plan/diff.ts +4 -1
- package/src/clickhouse/plan/normalize.ts +5 -2
- package/src/clickhouse/plan/plan.test.ts +9 -1
- package/src/clickhouse/plan/rebuild-handoff.ts +11 -1
- package/src/clickhouse/rebuild/engines.ts +163 -0
- package/src/clickhouse/rebuild/rebuild-collapsing.e2e.test.ts +120 -0
- package/src/clickhouse/rebuild/rebuild-into-collapsing.e2e.test.ts +198 -0
- package/src/clickhouse/rebuild/rebuild.test.ts +78 -0
- package/src/clickhouse/rebuild/verify.ts +153 -24
- package/src/clickhouse/testing/fake-server.ts +3 -2
- package/src/codegen/classifier-page.ts +1 -1
- package/src/config.ts +18 -4
- package/src/core/foreign-tables.ts +28 -0
- package/src/files/clickhouse.ts +71 -5
- package/src/files/postgres.ts +2 -1
- package/src/import-parser.ts +2 -0
- package/src/migration-statements.test.ts +33 -0
- package/src/migration-statements.ts +2 -0
- package/src/op/__snapshots__/watch-pipeline.test.ts.snap +1 -1
- package/src/op/activities/clickhouse-emulator.ts +22 -1
- package/src/op/activities/postgres-apply-lock-timeout.e2e.test.ts +87 -0
- package/src/op/activities/postgres-apply.test.ts +32 -0
- package/src/op/activities/postgres-emulator.test.ts +20 -0
- package/src/op/activities/postgres-emulator.ts +41 -1
- package/src/op/apply-gate-access-clickhouse.e2e.test.ts +195 -0
- package/src/op/apply-gate-access.e2e.test.ts +207 -0
- package/src/postgres/access/access.test.ts +26 -1
- package/src/postgres/access/changes.ts +39 -0
- package/src/postgres/apply/apply.ts +10 -7
- package/src/postgres/entities.ts +20 -1
- package/src/postgres/live/bind.ts +16 -4
- package/src/postgres/live/catalog.ts +3 -15
- package/src/postgres/live/client.ts +85 -0
- package/src/postgres/live/live.test.ts +54 -0
- package/src/postgres/live/lock-timeout.e2e.test.ts +70 -0
- package/src/postgres/plan/commands.ts +2 -14
- package/src/postgres/plan/deep.ts +44 -2
- package/src/serializer.test.ts +4 -0
- package/src/skills/chant-sql-postgres-plan.md +1 -1
- package/src/skills/chant-sql-rebuild.md +2 -0
- package/src/skills/chant-sql.md +1 -1
- package/src/sql-files.test.ts +78 -1
- package/src/sql-files.ts +2 -1
package/src/sql-files.test.ts
CHANGED
|
@@ -3,7 +3,8 @@ import { mkdir, realpath, rm, writeFile } from "node:fs/promises";
|
|
|
3
3
|
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { build } from "@intentius/chant/build";
|
|
6
|
-
import { readSqlFile, sqlFileDeclarations, SqlFileError } from "./sql-files";
|
|
6
|
+
import { readSqlFile, sqlFileDeclarations, sqlFileEntities, SqlFileError } from "./sql-files";
|
|
7
|
+
import { database, grant, policy, role, table, user } from "./clickhouse/entities";
|
|
7
8
|
import { sqlPlugin } from "./plugin";
|
|
8
9
|
import { sqlSerializer } from "./serializer";
|
|
9
10
|
import { guessDialect, SqlFileParser } from "./import-parser";
|
|
@@ -63,6 +64,7 @@ describe("chant import of a .sql file", () => {
|
|
|
63
64
|
expect(guessDialect("CREATE TABLE a.t (x UInt8) ENGINE = Log")).toBe("clickhouse");
|
|
64
65
|
expect(guessDialect("CREATE VIEW a.v AS SELECT 1")).toBe("clickhouse");
|
|
65
66
|
expect(guessDialect("CREATE FUNCTION f AS (x) -> x + 1")).toBe("clickhouse");
|
|
67
|
+
expect(guessDialect("CREATE ROW POLICY p ON a.t USING 1 TO r")).toBe("clickhouse");
|
|
66
68
|
expect(guessDialect("CREATE FUNCTION app.f() RETURNS int LANGUAGE sql AS $$ SELECT 1 $$")).toBe("postgres");
|
|
67
69
|
expect(new SqlFileParser().parse(PG_DDL).resources.map((r) => r.type)).toEqual(["Postgres::Enum", "Postgres::Table", "Postgres::Table", "Postgres::Index"]);
|
|
68
70
|
});
|
|
@@ -102,8 +104,83 @@ CREATE TABLE analytics.counts (kind String, n UInt64) ENGINE = SummingMergeTree
|
|
|
102
104
|
CREATE MATERIALIZED VIEW analytics.counts_mv TO analytics.counts AS SELECT kind, count() AS n FROM analytics.events GROUP BY kind;
|
|
103
105
|
CREATE DICTIONARY analytics.kinds (kind String, label String DEFAULT '') PRIMARY KEY kind SOURCE(clickhouse(table 'counts' db 'analytics')) LAYOUT(complex_key_hashed()) LIFETIME(300);
|
|
104
106
|
CREATE FUNCTION kind_label AS (k) -> upper(k);
|
|
107
|
+
CREATE ROLE reader SETTINGS max_memory_usage = 1000000000;
|
|
108
|
+
CREATE USER app HOST ANY DEFAULT ROLE reader DEFAULT DATABASE analytics;
|
|
109
|
+
CREATE ROW POLICY own_kinds ON analytics.events USING kind = 'a' TO reader;
|
|
110
|
+
GRANT SELECT(ts, kind) ON analytics.events TO reader;
|
|
111
|
+
GRANT reader TO app;
|
|
105
112
|
`;
|
|
106
113
|
|
|
114
|
+
describe("a file of ClickHouse access control (#3711)", () => {
|
|
115
|
+
const ACCESS = `CREATE DATABASE shop;
|
|
116
|
+
CREATE TABLE shop.events (id UInt64, tenant String) ENGINE = MergeTree ORDER BY id;
|
|
117
|
+
CREATE ROLE reader SETTINGS max_memory_usage = 1000000000;
|
|
118
|
+
CREATE USER app HOST ANY DEFAULT ROLE reader DEFAULT DATABASE shop;
|
|
119
|
+
CREATE ROW POLICY tenant_a ON shop.events USING tenant = 'a' TO reader;
|
|
120
|
+
GRANT SELECT(id, tenant) ON shop.events TO reader;
|
|
121
|
+
GRANT reader TO app;
|
|
122
|
+
`;
|
|
123
|
+
const t = (s: string) => Object.assign([s], { raw: [s] }) as unknown as TemplateStringsArray;
|
|
124
|
+
const shopDb = database(t("CREATE DATABASE shop"));
|
|
125
|
+
const events = table`CREATE TABLE ${shopDb}.events (id UInt64, tenant String) ENGINE = MergeTree ORDER BY id`;
|
|
126
|
+
const reader = role(t("CREATE ROLE reader SETTINGS max_memory_usage = 1000000000"));
|
|
127
|
+
const app = user(t("CREATE USER app HOST ANY DEFAULT ROLE reader DEFAULT DATABASE shop"));
|
|
128
|
+
const tagged = [
|
|
129
|
+
shopDb,
|
|
130
|
+
events,
|
|
131
|
+
reader,
|
|
132
|
+
app,
|
|
133
|
+
policy`CREATE ROW POLICY tenant_a ON ${events} USING tenant = 'a' TO ${reader}`,
|
|
134
|
+
grant`GRANT SELECT(id, tenant) ON ${events} TO ${reader}`,
|
|
135
|
+
grant`GRANT reader TO ${app}`,
|
|
136
|
+
];
|
|
137
|
+
const props = (e: unknown) => {
|
|
138
|
+
const { source: _source, ...rest } = (e as { props: Record<string, unknown> }).props;
|
|
139
|
+
return JSON.parse(JSON.stringify(rest)) as Record<string, unknown>;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
test("users, roles, row policies and grants build to the declarations the tags make", () => {
|
|
143
|
+
const read = sqlFileEntities("clickhouse", [{ origin: "access.sql", ddl: ACCESS }]);
|
|
144
|
+
expect([...read.values()].map((e) => e.entityType)).toEqual(tagged.map((e) => e.entityType));
|
|
145
|
+
expect([...read.values()].map(props)).toEqual(tagged.map(props));
|
|
146
|
+
expect(readSqlFile("clickhouse", ACCESS, { origin: "access.sql" }).map((o) => [o.type, o.name])).toEqual([
|
|
147
|
+
["ClickHouse::Database", "shop"],
|
|
148
|
+
["ClickHouse::Table", "shop.events"],
|
|
149
|
+
["ClickHouse::Role", "reader"],
|
|
150
|
+
["ClickHouse::User", "app"],
|
|
151
|
+
["ClickHouse::RowPolicy", "shop.tenant_a"],
|
|
152
|
+
["ClickHouse::Grant", "grant select(id, tenant) on shop.events to reader"],
|
|
153
|
+
["ClickHouse::Grant", "grant reader to app"],
|
|
154
|
+
]);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test("with a database for unqualified names, a policy's and a grant's table are qualified", () => {
|
|
158
|
+
const objects = readSqlFile("clickhouse", "CREATE ROW POLICY p ON events USING 1 TO reader;\nGRANT SELECT ON events TO reader;\nGRANT SELECT ON *.* TO reader", { origin: "a.sql", schema: "shop" });
|
|
159
|
+
expect(objects.map((o) => o.ddl)).toEqual(["CREATE ROW POLICY p ON shop.events USING 1 TO reader", "GRANT SELECT ON shop.events TO reader", "GRANT SELECT ON *.* TO reader"]);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("a password is refused with the tag's message, and so is a REVOKE", () => {
|
|
163
|
+
let tagMessage = "";
|
|
164
|
+
try {
|
|
165
|
+
user(t("CREATE USER app IDENTIFIED BY 'secret'"));
|
|
166
|
+
} catch (e) {
|
|
167
|
+
tagMessage = (e as Error).message;
|
|
168
|
+
}
|
|
169
|
+
expect(tagMessage).toMatch(/IDENTIFIED BY holds a password/);
|
|
170
|
+
const err = (() => {
|
|
171
|
+
try {
|
|
172
|
+
readSqlFile("clickhouse", "CREATE USER app IDENTIFIED BY 'secret';\nREVOKE SELECT ON shop.events FROM reader", { origin: "users.sql" });
|
|
173
|
+
} catch (e) {
|
|
174
|
+
return e as SqlFileError;
|
|
175
|
+
}
|
|
176
|
+
throw new Error("read");
|
|
177
|
+
})();
|
|
178
|
+
expect(err).toBeInstanceOf(SqlFileError);
|
|
179
|
+
expect(err.problems).toEqual([`${tagMessage}: CREATE USER app IDENTIFIED BY 'secret'`, expect.stringMatching(/holds a REVOKE; declare the grants a grantee keeps.*: REVOKE SELECT ON shop\.events FROM reader$/)]);
|
|
180
|
+
expect(err.message).not.toContain("not a CREATE statement");
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
107
184
|
describe("chant build reads the .sql files in the source directory", () => {
|
|
108
185
|
const dirs: string[] = [];
|
|
109
186
|
afterAll(async () => {
|
package/src/sql-files.ts
CHANGED
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
* PRIVILEGES` as an object, with `COMMENT ON`, `ALTER TABLE ... ROW LEVEL
|
|
16
16
|
* SECURITY` and `ALTER TABLE ... ADD <table constraint>` folded into the
|
|
17
17
|
* object they finish; ClickHouse reads `CREATE DATABASE`, `TABLE`, `VIEW`,
|
|
18
|
-
* `MATERIALIZED VIEW`, `DICTIONARY
|
|
18
|
+
* `MATERIALIZED VIEW`, `DICTIONARY`, `FUNCTION`, `USER`, `ROLE` and `ROW
|
|
19
|
+
* POLICY`, and `GRANT` (#3711). Any other statement, and any
|
|
19
20
|
* statement that does not parse, throws a {@link SqlFileError} naming every
|
|
20
21
|
* such statement: none is left out.
|
|
21
22
|
*
|