posti 3.5.0 → 4.0.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.
Files changed (104) hide show
  1. package/{LICENSE.md → LICENSE} +1 -1
  2. package/README.md +333 -112
  3. package/dist/cli/args.d.ts +17 -0
  4. package/dist/cli/args.d.ts.map +1 -0
  5. package/dist/cli/args.js +80 -0
  6. package/dist/cli/args.js.map +1 -0
  7. package/dist/cli.d.ts +3 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +85 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/config/defaults.d.ts +2 -0
  12. package/dist/config/defaults.d.ts.map +1 -0
  13. package/dist/config/defaults.js +2 -0
  14. package/dist/config/defaults.js.map +1 -0
  15. package/dist/config/index.d.ts +5 -0
  16. package/dist/config/index.d.ts.map +1 -0
  17. package/dist/config/index.js +97 -1
  18. package/dist/config/index.js.map +1 -0
  19. package/dist/config/paths.d.ts +4 -0
  20. package/dist/config/paths.d.ts.map +1 -0
  21. package/dist/config/paths.js +16 -0
  22. package/dist/config/paths.js.map +1 -0
  23. package/dist/config/schema.d.ts +27 -0
  24. package/dist/config/schema.d.ts.map +1 -0
  25. package/dist/config/schema.js +24 -0
  26. package/dist/config/schema.js.map +1 -0
  27. package/dist/db/dialects.d.ts +15 -0
  28. package/dist/db/dialects.d.ts.map +1 -0
  29. package/dist/db/dialects.js +270 -0
  30. package/dist/db/dialects.js.map +1 -0
  31. package/dist/db/index.d.ts +27 -0
  32. package/dist/db/index.d.ts.map +1 -0
  33. package/dist/db/index.js +49 -0
  34. package/dist/db/index.js.map +1 -0
  35. package/dist/db/migrate.d.ts +8 -0
  36. package/dist/db/migrate.d.ts.map +1 -0
  37. package/dist/db/migrate.js +58 -0
  38. package/dist/db/migrate.js.map +1 -0
  39. package/dist/db/migrations/001_initial_schema.d.ts +3 -0
  40. package/dist/db/migrations/001_initial_schema.d.ts.map +1 -0
  41. package/dist/db/migrations/001_initial_schema.js +17 -0
  42. package/dist/db/migrations/001_initial_schema.js.map +1 -0
  43. package/dist/db/migrations/index.d.ts +3 -0
  44. package/dist/db/migrations/index.d.ts.map +1 -0
  45. package/dist/db/migrations/index.js +3 -0
  46. package/dist/db/migrations/index.js.map +1 -0
  47. package/dist/db/operations.d.ts +13 -0
  48. package/dist/db/operations.d.ts.map +1 -0
  49. package/dist/db/operations.js +179 -0
  50. package/dist/db/operations.js.map +1 -0
  51. package/dist/fetcher/url-parser.d.ts +9 -0
  52. package/dist/fetcher/url-parser.d.ts.map +1 -0
  53. package/dist/fetcher/url-parser.js +19 -0
  54. package/dist/fetcher/url-parser.js.map +1 -0
  55. package/dist/index.d.ts +15 -0
  56. package/dist/index.d.ts.map +1 -0
  57. package/dist/index.js +9 -1
  58. package/dist/index.js.map +1 -0
  59. package/dist/loader/index.d.ts +7 -0
  60. package/dist/loader/index.d.ts.map +1 -0
  61. package/dist/loader/index.js +145 -0
  62. package/dist/loader/index.js.map +1 -0
  63. package/dist/loader/state.d.ts +5 -0
  64. package/dist/loader/state.d.ts.map +1 -0
  65. package/dist/loader/state.js +26 -0
  66. package/dist/loader/state.js.map +1 -0
  67. package/dist/parser/field-definitions.d.ts +14 -0
  68. package/dist/parser/field-definitions.d.ts.map +1 -0
  69. package/dist/parser/field-definitions.js +91 -0
  70. package/dist/parser/field-definitions.js.map +1 -0
  71. package/dist/parser/file-converter.d.ts +2 -0
  72. package/dist/parser/file-converter.d.ts.map +1 -0
  73. package/dist/parser/file-converter.js +7 -0
  74. package/dist/parser/file-converter.js.map +1 -0
  75. package/dist/parser/line-parser.d.ts +4 -0
  76. package/dist/parser/line-parser.d.ts.map +1 -0
  77. package/dist/parser/line-parser.js +28 -0
  78. package/dist/parser/line-parser.js.map +1 -0
  79. package/dist/parser/unzipper.d.ts +2 -0
  80. package/dist/parser/unzipper.d.ts.map +1 -0
  81. package/dist/parser/unzipper.js +11 -0
  82. package/dist/parser/unzipper.js.map +1 -0
  83. package/dist/utils/chunks.d.ts +2 -0
  84. package/dist/utils/chunks.d.ts.map +1 -0
  85. package/dist/utils/chunks.js +10 -0
  86. package/dist/utils/chunks.js.map +1 -0
  87. package/dist/utils/logger.d.ts +7 -0
  88. package/dist/utils/logger.d.ts.map +1 -0
  89. package/dist/utils/logger.js +8 -0
  90. package/dist/utils/logger.js.map +1 -0
  91. package/dist/utils/progress.d.ts +14 -0
  92. package/dist/utils/progress.d.ts.map +1 -0
  93. package/dist/utils/progress.js +68 -0
  94. package/dist/utils/progress.js.map +1 -0
  95. package/dist/utils/time.d.ts +2 -0
  96. package/dist/utils/time.d.ts.map +1 -0
  97. package/dist/utils/time.js +14 -0
  98. package/dist/utils/time.js.map +1 -0
  99. package/package.json +76 -63
  100. package/CHANGELOG.md +0 -345
  101. package/dist/classes/Posti.js +0 -11
  102. package/dist/classes/Sequelize.js +0 -15
  103. package/dist/posti.js +0 -2
  104. package/dist/utils/index.js +0 -55
package/dist/cli.js ADDED
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync } from "node:fs";
3
+ import { parseArgs } from "./cli/args.js";
4
+ import { loadConfig } from "./config/index.js";
5
+ import { closeConnection, createConnection } from "./db/index.js";
6
+ import { runMigrations } from "./db/migrate.js";
7
+ import { run } from "./loader/index.js";
8
+ import { logger } from "./utils/logger.js";
9
+ import { formatDuration } from "./utils/time.js";
10
+ const args = parseArgs(process.argv.slice(2));
11
+ if (args.help) {
12
+ printHelp();
13
+ process.exit(0);
14
+ }
15
+ if (args.version) {
16
+ printVersion();
17
+ process.exit(0);
18
+ }
19
+ const started = Date.now();
20
+ try {
21
+ const config = await loadConfig(args);
22
+ if (args.command === "migrate") {
23
+ const db = await createConnection(config);
24
+ try {
25
+ await runMigrations(db, config);
26
+ }
27
+ finally {
28
+ await closeConnection(db);
29
+ }
30
+ logger.success(`Migrations complete in ${formatDuration(Date.now() - started)}`);
31
+ }
32
+ else {
33
+ await run(config, { force: args.force });
34
+ logger.success(`Finished in ${formatDuration(Date.now() - started)}`);
35
+ }
36
+ }
37
+ catch (error) {
38
+ logger.error(error instanceof Error ? error.message : String(error));
39
+ process.exit(1);
40
+ }
41
+ function printHelp() {
42
+ console.info(`
43
+ posti - Finnish postal data loader
44
+
45
+ Usage: posti [command] [options]
46
+
47
+ Commands:
48
+ run Fetch and load postal data (default)
49
+ migrate Run database migrations only
50
+
51
+ Options:
52
+ --config <path> Path to config file
53
+ --force Force re-processing even if files haven't changed
54
+ --no-migrate Skip automatic database migrations on startup
55
+ --dialect <dialect> Database dialect (postgres, mysql, mariadb, sqlite)
56
+ --host <host> Database host
57
+ --port <port> Database port
58
+ --database <name> Database name (or file path for SQLite)
59
+ --user <user> Database user
60
+ --password <pass> Database password
61
+ --tables <list> Comma-separated tables (addresses,postalcodes,postalcode_changes)
62
+ --help Show this help
63
+ --version Show version
64
+
65
+ Environment variables:
66
+ POSTI_CONFIG Path to config file
67
+ POSTI_DIALECT Database dialect
68
+ POSTI_HOST Database host
69
+ POSTI_PORT Database port
70
+ POSTI_USER Database user
71
+ POSTI_PASSWORD Database password
72
+ POSTI_DATABASE Database name
73
+ POSTI_TABLE_PREFIX Table name prefix (default: posti_)
74
+ `.trim());
75
+ }
76
+ function printVersion() {
77
+ try {
78
+ const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
79
+ console.info(`posti v${pkg.version}`);
80
+ }
81
+ catch {
82
+ console.info("posti (unknown version)");
83
+ }
84
+ }
85
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9C,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,SAAS,EAAE,CAAC;IACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;IACjB,YAAY,EAAE,CAAC;IACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAE3B,IAAI,CAAC;IACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC;IAEtC,IAAI,IAAI,CAAC,OAAO,KAAK,SAAS,EAAE,CAAC;QAC/B,MAAM,EAAE,GAAG,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC;YACH,MAAM,aAAa,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QAClC,CAAC;gBAAS,CAAC;YACT,MAAM,eAAe,CAAC,EAAE,CAAC,CAAC;QAC5B,CAAC;QACD,MAAM,CAAC,OAAO,CAAC,0BAA0B,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;IACnF,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QACzC,MAAM,CAAC,OAAO,CAAC,eAAe,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;IACxE,CAAC;AACH,CAAC;AAAC,OAAO,KAAK,EAAE,CAAC;IACf,MAAM,CAAC,KAAK,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,CAAC,IAAI,CACV;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCH,CAAC,IAAI,EAAE,CACL,CAAC;AACJ,CAAC;AAED,SAAS,YAAY;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAE,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;QAC3F,OAAO,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAC1C,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const POSTI_INDEX_URL = "https://www.posti.fi/webpcode/";
2
+ //# sourceMappingURL=defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,mCAAmC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export const POSTI_INDEX_URL = "https://www.posti.fi/webpcode/";
2
+ //# sourceMappingURL=defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/config/defaults.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,gCAAgC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { ParsedArgs } from "../cli/args.js";
2
+ import type { PostiConfig } from "./schema.js";
3
+ export type { PostiConfig } from "./schema.js";
4
+ export declare function loadConfig(args?: Partial<ParsedArgs>): Promise<PostiConfig>;
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAG/C,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,wBAAsB,UAAU,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAQjF"}
@@ -1 +1,97 @@
1
- "use strict";require("core-js/modules/es.object.keys.js"),require("core-js/modules/es.symbol.js"),require("core-js/modules/es.array.filter.js"),require("core-js/modules/es.object.get-own-property-descriptor.js"),require("core-js/modules/es.array.for-each.js"),require("core-js/modules/es.object.get-own-property-descriptors.js"),require("core-js/modules/es.object.define-properties.js"),exports.__esModule=!0,exports["default"]=void 0,require("core-js/modules/es.object.define-property.js");var _os=_interopRequireDefault(require("os")),_path=_interopRequireDefault(require("path"));function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function ownKeys(object,enumerableOnly){var keys=Object.keys(object);if(Object.getOwnPropertySymbols){var symbols=Object.getOwnPropertySymbols(object);enumerableOnly&&(symbols=symbols.filter(function(sym){return Object.getOwnPropertyDescriptor(object,sym).enumerable})),keys.push.apply(keys,symbols)}return keys}function _objectSpread(target){for(var source,i=1;i<arguments.length;i++)source=null==arguments[i]?{}:arguments[i],i%2?ownKeys(Object(source),!0).forEach(function(key){_defineProperty(target,key,source[key])}):Object.getOwnPropertyDescriptors?Object.defineProperties(target,Object.getOwnPropertyDescriptors(source)):ownKeys(Object(source)).forEach(function(key){Object.defineProperty(target,key,Object.getOwnPropertyDescriptor(source,key))});return target}function _defineProperty(obj,key,value){return key in obj?Object.defineProperty(obj,key,{value:value,enumerable:!0,configurable:!0,writable:!0}):obj[key]=value,obj}var baseDir=_path["default"].resolve(_os["default"].homedir()+"/.posti"),tempDir=_path["default"].resolve(baseDir+"/data"),latestFile=_path["default"].resolve(baseDir+"/latest.json"),downloadConfig={format:"{bar} {percentage}% | ETA: {eta}s | {value}/{total} b",stopOnComplete:!0,clearOnComplete:!0,barCompleteChar:"\u2588",barIncompleteChar:"\u2591",fps:4},insertConfig=_objectSpread(_objectSpread({},downloadConfig),{},{format:"{bar} {percentage}% | ETA: {eta}s | {value}/{total} rows"}),_default={webpcode:{index:"https://www.posti.fi/webpcode/",files:"http://www.posti.fi/webpcode"},cache:{baseDir:baseDir,tempDir:tempDir,latestFile:latestFile},progressbar:{downloadConfig:downloadConfig,insertConfig:insertConfig}};exports["default"]=_default;
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { getConfigDir } from "./paths.js";
4
+ import { configSchema } from "./schema.js";
5
+ export async function loadConfig(args) {
6
+ const fileConfig = await loadFileConfig(args);
7
+ const envOverrides = loadEnvOverrides();
8
+ const cliOverrides = loadCliOverrides(args);
9
+ // Merge: file < env < cli
10
+ const merged = { ...fileConfig, ...envOverrides, ...cliOverrides };
11
+ return configSchema.parse(merged);
12
+ }
13
+ async function loadFileConfig(args) {
14
+ const explicitConfig = args?.config ?? process.env.POSTI_CONFIG;
15
+ const configPath = explicitConfig ?? (await findConfigFile());
16
+ if (!configPath)
17
+ return {};
18
+ try {
19
+ const resolved = path.resolve(configPath);
20
+ const mod = await import(resolved);
21
+ if (typeof mod === "object" && mod !== null && "default" in mod) {
22
+ const defaultExport = mod.default;
23
+ if (typeof defaultExport === "object" && defaultExport !== null) {
24
+ return defaultExport;
25
+ }
26
+ }
27
+ if (explicitConfig) {
28
+ throw new Error(`Config file '${configPath}' does not export a valid configuration object`);
29
+ }
30
+ return {};
31
+ }
32
+ catch (error) {
33
+ if (explicitConfig) {
34
+ throw new Error(`Failed to load config file '${configPath}': ${error instanceof Error ? error.message : String(error)}`);
35
+ }
36
+ return {};
37
+ }
38
+ }
39
+ function loadEnvOverrides() {
40
+ const overrides = {};
41
+ if (process.env.POSTI_DIALECT)
42
+ overrides.dialect = process.env.POSTI_DIALECT;
43
+ if (process.env.POSTI_HOST)
44
+ overrides.host = process.env.POSTI_HOST;
45
+ if (process.env.POSTI_PORT)
46
+ overrides.port = Number.parseInt(process.env.POSTI_PORT, 10);
47
+ if (process.env.POSTI_USER)
48
+ overrides.user = process.env.POSTI_USER;
49
+ if (process.env.POSTI_PASSWORD)
50
+ overrides.password = process.env.POSTI_PASSWORD;
51
+ if (process.env.POSTI_DATABASE)
52
+ overrides.database = process.env.POSTI_DATABASE;
53
+ if (process.env.POSTI_TABLE_PREFIX)
54
+ overrides.tablePrefix = process.env.POSTI_TABLE_PREFIX;
55
+ return overrides;
56
+ }
57
+ function loadCliOverrides(args) {
58
+ const overrides = {};
59
+ if (args?.dialect)
60
+ overrides.dialect = args.dialect;
61
+ if (args?.host)
62
+ overrides.host = args.host;
63
+ if (args?.port)
64
+ overrides.port = args.port;
65
+ if (args?.user)
66
+ overrides.user = args.user;
67
+ if (args?.password)
68
+ overrides.password = args.password;
69
+ if (args?.database)
70
+ overrides.database = args.database;
71
+ if (args?.tables)
72
+ overrides.tables = args.tables;
73
+ if (args?.noMigrate)
74
+ overrides.migrate = false;
75
+ return overrides;
76
+ }
77
+ async function findConfigFile() {
78
+ // Check XDG config dir
79
+ const xdgConfig = path.join(getConfigDir(), "config.js");
80
+ if (await fileExists(xdgConfig))
81
+ return xdgConfig;
82
+ // Check CWD
83
+ const cwdConfig = path.resolve("posti.config.js");
84
+ if (await fileExists(cwdConfig))
85
+ return cwdConfig;
86
+ return undefined;
87
+ }
88
+ async function fileExists(filePath) {
89
+ try {
90
+ await fs.access(filePath);
91
+ return true;
92
+ }
93
+ catch {
94
+ return false;
95
+ }
96
+ }
97
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function getConfigDir(): string;
2
+ export declare function getCacheDir(): string;
3
+ export declare function getStateDir(): string;
4
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/config/paths.ts"],"names":[],"mappings":"AAKA,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED,wBAAgB,WAAW,IAAI,MAAM,CAGpC;AAED,wBAAgB,WAAW,IAAI,MAAM,CAGpC"}
@@ -0,0 +1,16 @@
1
+ import os from "node:os";
2
+ import path from "node:path";
3
+ const APP_NAME = "posti";
4
+ export function getConfigDir() {
5
+ const base = process.env.XDG_CONFIG_HOME ?? path.join(os.homedir(), ".config");
6
+ return path.join(base, APP_NAME);
7
+ }
8
+ export function getCacheDir() {
9
+ const base = process.env.XDG_CACHE_HOME ?? path.join(os.homedir(), ".cache");
10
+ return path.join(base, APP_NAME);
11
+ }
12
+ export function getStateDir() {
13
+ const base = process.env.XDG_STATE_HOME ?? path.join(os.homedir(), ".local", "state");
14
+ return path.join(base, APP_NAME);
15
+ }
16
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/config/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,QAAQ,GAAG,OAAO,CAAC;AAEzB,MAAM,UAAU,YAAY;IAC1B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IAC/E,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;IAC7E,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,WAAW;IACzB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;IACtF,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACnC,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { z } from "zod";
2
+ export declare const configSchema: z.ZodObject<{
3
+ dialect: z.ZodEnum<{
4
+ mariadb: "mariadb";
5
+ mysql: "mysql";
6
+ postgres: "postgres";
7
+ sqlite: "sqlite";
8
+ }>;
9
+ host: z.ZodOptional<z.ZodString>;
10
+ port: z.ZodOptional<z.ZodNumber>;
11
+ user: z.ZodOptional<z.ZodString>;
12
+ password: z.ZodOptional<z.ZodString>;
13
+ database: z.ZodString;
14
+ tablePrefix: z.ZodDefault<z.ZodString>;
15
+ migrate: z.ZodDefault<z.ZodBoolean>;
16
+ process: z.ZodDefault<z.ZodObject<{
17
+ chunkSize: z.ZodDefault<z.ZodNumber>;
18
+ deleteOnComplete: z.ZodDefault<z.ZodBoolean>;
19
+ }, z.core.$strip>>;
20
+ tables: z.ZodDefault<z.ZodArray<z.ZodEnum<{
21
+ addresses: "addresses";
22
+ postalcode_changes: "postalcode_changes";
23
+ postalcodes: "postalcodes";
24
+ }>>>;
25
+ }, z.core.$strip>;
26
+ export type PostiConfig = z.infer<typeof configSchema>;
27
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;iBAqBvB,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { z } from "zod";
2
+ export const configSchema = z.object({
3
+ dialect: z.enum(["postgres", "mysql", "mariadb", "sqlite"]),
4
+ host: z.string().optional(),
5
+ port: z.number().int().min(1).max(65535).optional(),
6
+ user: z.string().optional(),
7
+ password: z.string().optional(),
8
+ database: z.string(),
9
+ tablePrefix: z
10
+ .string()
11
+ .regex(/^\w*$/, "tablePrefix must contain only letters, numbers, and underscores")
12
+ .default("posti_"),
13
+ migrate: z.boolean().default(true),
14
+ process: z
15
+ .object({
16
+ chunkSize: z.number().int().positive().default(1000),
17
+ deleteOnComplete: z.boolean().default(true),
18
+ })
19
+ .default({ chunkSize: 1000, deleteOnComplete: true }),
20
+ tables: z
21
+ .array(z.enum(["addresses", "postalcodes", "postalcode_changes"]))
22
+ .default(["addresses", "postalcodes", "postalcode_changes"]),
23
+ });
24
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IAC3D,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE;IACnD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,WAAW,EAAE,CAAC;SACX,MAAM,EAAE;SACR,KAAK,CAAC,OAAO,EAAE,iEAAiE,CAAC;SACjF,OAAO,CAAC,QAAQ,CAAC;IACpB,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;IAClC,OAAO,EAAE,CAAC;SACP,MAAM,CAAC;QACN,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;QACpD,gBAAgB,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;KAC5C,CAAC;SACD,OAAO,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC;IACvD,MAAM,EAAE,CAAC;SACN,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,aAAa,EAAE,oBAAoB,CAAC,CAAC,CAAC;SACjE,OAAO,CAAC,CAAC,WAAW,EAAE,aAAa,EAAE,oBAAoB,CAAC,CAAC;CAC/D,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { PostiConfig } from "../config/schema.js";
2
+ interface IndexDefinition {
3
+ name: string;
4
+ columns: string[];
5
+ }
6
+ declare const tableIndexes: Record<string, IndexDefinition[]>;
7
+ export declare function getCreateTableSQL(dialect: PostiConfig["dialect"], tableName: string, tableType: string): string;
8
+ export type SqlValue = string | number | null;
9
+ export declare function getInsertSQL(dialect: PostiConfig["dialect"], tableName: string, rows: Record<string, SqlValue>[]): {
10
+ sql: string;
11
+ values: SqlValue[];
12
+ };
13
+ export declare function getUpsertSQL(dialect: PostiConfig["dialect"], tempTableName: string, finalTableName: string, tableType: string): string;
14
+ export { tableIndexes };
15
+ //# sourceMappingURL=dialects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialects.d.ts","sourceRoot":"","sources":["../../src/db/dialects.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAiGvD,UAAU,eAAe;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAOD,QAAA,MAAM,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,EAAE,CA0CnD,CAAC;AAwCF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAoC/G;AAED,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;AAE9C,wBAAgB,YAAY,CAC1B,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,EAC/B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,GAC/B;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,QAAQ,EAAE,CAAA;CAAE,CA2BrC;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,WAAW,CAAC,SAAS,CAAC,EAC/B,aAAa,EAAE,MAAM,EACrB,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,GAChB,MAAM,CA2CR;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,270 @@
1
+ import { quoteIdentifier } from "./operations.js";
2
+ const addressColumns = [
3
+ { name: "id", type: "INTEGER PRIMARY KEY AUTOINCREMENT" },
4
+ { name: "record", type: "VARCHAR(5)" },
5
+ { name: "updated_at", type: "DATE" },
6
+ { name: "postal_code", type: "VARCHAR(5)" },
7
+ { name: "post_office_name", type: "VARCHAR(30)" },
8
+ { name: "post_office_name_swe", type: "VARCHAR(30)" },
9
+ { name: "post_office_short_name", type: "VARCHAR(12)" },
10
+ { name: "post_office_short_name_swe", type: "VARCHAR(12)" },
11
+ { name: "address", type: "VARCHAR(30)" },
12
+ { name: "address_swe", type: "VARCHAR(30)" },
13
+ { name: "empty1", type: "VARCHAR(12)" },
14
+ { name: "empty2", type: "VARCHAR(12)" },
15
+ { name: "odd_even", type: "INTEGER" },
16
+ { name: "smallest_building_number_1", type: "INTEGER" },
17
+ { name: "smallest_delivery_letter_1", type: "VARCHAR(1)" },
18
+ { name: "divider_1", type: "VARCHAR(1)" },
19
+ { name: "smallest_building_number_2", type: "INTEGER" },
20
+ { name: "smallest_delivery_letter_2", type: "VARCHAR(1)" },
21
+ { name: "highest_building_number_1", type: "INTEGER" },
22
+ { name: "highest_delivery_letter_1", type: "VARCHAR(1)" },
23
+ { name: "divider_2", type: "VARCHAR(1)" },
24
+ { name: "highest_building_number_2", type: "INTEGER" },
25
+ { name: "highest_delivery_letter_2", type: "VARCHAR(1)" },
26
+ { name: "municipality_id_code", type: "VARCHAR(3)" },
27
+ { name: "municipality_name", type: "VARCHAR(20)" },
28
+ { name: "municipality_name_swe", type: "VARCHAR(20)" },
29
+ { name: "created_at", type: "TIMESTAMP" },
30
+ { name: "updated_at_row", type: "TIMESTAMP" },
31
+ ];
32
+ const zipcodeColumns = [
33
+ { name: "id", type: "INTEGER PRIMARY KEY AUTOINCREMENT" },
34
+ { name: "record", type: "VARCHAR(5)" },
35
+ { name: "updated_at", type: "DATE" },
36
+ { name: "postal_code", type: "VARCHAR(5)" },
37
+ { name: "post_office_name", type: "VARCHAR(30)" },
38
+ { name: "post_office_name_swe", type: "VARCHAR(30)" },
39
+ { name: "post_office_short_name", type: "VARCHAR(12)" },
40
+ { name: "post_office_short_name_swe", type: "VARCHAR(12)" },
41
+ { name: "entry_into_force_at", type: "DATE" },
42
+ { name: "type_code", type: "INTEGER" },
43
+ { name: "region_id", type: "VARCHAR(5)" },
44
+ { name: "region_name", type: "VARCHAR(30)" },
45
+ { name: "region_name_swe", type: "VARCHAR(30)" },
46
+ { name: "municipality_id_code", type: "VARCHAR(3)" },
47
+ { name: "municipality_name", type: "VARCHAR(20)" },
48
+ { name: "municipality_name_swe", type: "VARCHAR(20)" },
49
+ { name: "municipality_language", type: "INTEGER" },
50
+ { name: "created_at", type: "TIMESTAMP" },
51
+ { name: "updated_at_row", type: "TIMESTAMP" },
52
+ ];
53
+ const zipcodeChangeColumns = [
54
+ { name: "id", type: "INTEGER PRIMARY KEY AUTOINCREMENT" },
55
+ { name: "record", type: "VARCHAR(4)" },
56
+ { name: "level", type: "VARCHAR(1)" },
57
+ { name: "updated_at", type: "DATE" },
58
+ { name: "extraction_start_at", type: "DATE" },
59
+ { name: "extraction_end_at", type: "DATE" },
60
+ { name: "old_postal_code", type: "VARCHAR(5)" },
61
+ { name: "old_post_office_name", type: "VARCHAR(30)" },
62
+ { name: "old_post_office_name_swe", type: "VARCHAR(30)" },
63
+ { name: "old_post_office_short_name", type: "VARCHAR(12)" },
64
+ { name: "old_post_office_short_name_swe", type: "VARCHAR(12)" },
65
+ { name: "reserved", type: "VARCHAR(131)" },
66
+ { name: "postal_code", type: "VARCHAR(5)" },
67
+ { name: "post_office_name", type: "VARCHAR(30)" },
68
+ { name: "post_office_name_swe", type: "VARCHAR(30)" },
69
+ { name: "post_office_short_name", type: "VARCHAR(12)" },
70
+ { name: "post_office_short_name_swe", type: "VARCHAR(12)" },
71
+ { name: "municipality_id_code", type: "VARCHAR(3)" },
72
+ { name: "municipality_name", type: "VARCHAR(20)" },
73
+ { name: "municipality_name_swe", type: "VARCHAR(20)" },
74
+ { name: "region_id", type: "VARCHAR(2)" },
75
+ { name: "region_name", type: "VARCHAR(30)" },
76
+ { name: "region_name_swe", type: "VARCHAR(30)" },
77
+ { name: "changed_at", type: "DATE" },
78
+ { name: "event_code", type: "INTEGER" },
79
+ { name: "created_at", type: "TIMESTAMP" },
80
+ { name: "updated_at_row", type: "TIMESTAMP" },
81
+ ];
82
+ const tableColumns = {
83
+ addresses: addressColumns,
84
+ postalcodes: zipcodeColumns,
85
+ postalcode_changes: zipcodeChangeColumns,
86
+ };
87
+ // Meaningful indexes for realistic query patterns.
88
+ // The UNIQUE constraint (defined separately) already covers upsert conflict detection.
89
+ // These indexes target lookup, filtering, and join patterns:
90
+ // - Single-column indexes for common WHERE/JOIN columns
91
+ // - Composite indexes for queries that filter on multiple columns together
92
+ const tableIndexes = {
93
+ addresses: [
94
+ // Lookup by postal code (most common query)
95
+ { name: "postal_code", columns: ["postal_code"] },
96
+ // Address lookup: postal code + street name together
97
+ { name: "postal_code_address", columns: ["postal_code", "address"] },
98
+ // Filter/join by municipality
99
+ { name: "municipality_id_code", columns: ["municipality_id_code"] },
100
+ // Search by post office name (Finnish)
101
+ { name: "post_office_name", columns: ["post_office_name"] },
102
+ // Search by post office name (Swedish)
103
+ { name: "post_office_name_swe", columns: ["post_office_name_swe"] },
104
+ // Search by street name
105
+ { name: "address", columns: ["address"] },
106
+ { name: "address_swe", columns: ["address_swe"] },
107
+ ],
108
+ postalcodes: [
109
+ // postal_code is already UNIQUE — no separate index needed
110
+ // Filter by type (normal, PO box, corporate, etc.)
111
+ { name: "type_code", columns: ["type_code"] },
112
+ // Filter/join by municipality
113
+ { name: "municipality_id_code", columns: ["municipality_id_code"] },
114
+ // Filter by region
115
+ { name: "region_id", columns: ["region_id"] },
116
+ // Search by post office name
117
+ { name: "post_office_name", columns: ["post_office_name"] },
118
+ { name: "post_office_name_swe", columns: ["post_office_name_swe"] },
119
+ // Filter by municipality language distribution
120
+ { name: "municipality_language", columns: ["municipality_language"] },
121
+ ],
122
+ postalcode_changes: [
123
+ // Lookup changes for a specific new postal code
124
+ { name: "postal_code", columns: ["postal_code"] },
125
+ // Lookup changes for a specific old postal code
126
+ { name: "old_postal_code", columns: ["old_postal_code"] },
127
+ // Date range queries on when changes happened
128
+ { name: "changed_at", columns: ["changed_at"] },
129
+ // Filter by type of change event
130
+ { name: "event_code", columns: ["event_code"] },
131
+ // Filter/join by municipality
132
+ { name: "municipality_id_code", columns: ["municipality_id_code"] },
133
+ ],
134
+ };
135
+ const uniqueKeys = {
136
+ addresses: [
137
+ "postal_code",
138
+ "address",
139
+ "odd_even",
140
+ "smallest_building_number_1",
141
+ "smallest_building_number_2",
142
+ "highest_building_number_1",
143
+ "highest_building_number_2",
144
+ ],
145
+ postalcodes: ["postal_code"],
146
+ postalcode_changes: ["old_postal_code", "postal_code", "changed_at", "event_code"],
147
+ };
148
+ function getAutoIncrementType(dialect) {
149
+ switch (dialect) {
150
+ case "sqlite":
151
+ return "INTEGER PRIMARY KEY AUTOINCREMENT";
152
+ case "mysql":
153
+ case "mariadb":
154
+ return "INTEGER PRIMARY KEY AUTO_INCREMENT";
155
+ case "postgres":
156
+ return "SERIAL PRIMARY KEY";
157
+ }
158
+ }
159
+ function getTimestampDefault(dialect) {
160
+ switch (dialect) {
161
+ case "sqlite":
162
+ return "TIMESTAMP DEFAULT (datetime('now'))";
163
+ case "mysql":
164
+ case "mariadb":
165
+ return "TIMESTAMP DEFAULT CURRENT_TIMESTAMP";
166
+ case "postgres":
167
+ return "TIMESTAMP DEFAULT NOW()";
168
+ }
169
+ }
170
+ export function getCreateTableSQL(dialect, tableName, tableType) {
171
+ const columns = tableColumns[tableType];
172
+ if (!columns)
173
+ throw new Error(`Unknown table type: ${tableType}`);
174
+ const quoted = quoteIdentifier(dialect, tableName);
175
+ const uniqs = uniqueKeys[tableType] ?? [];
176
+ const colDefs = columns.map((col) => {
177
+ const qName = quoteIdentifier(dialect, col.name);
178
+ if (col.name === "id") {
179
+ return ` ${qName} ${getAutoIncrementType(dialect)}`;
180
+ }
181
+ if (col.name === "created_at" || col.name === "updated_at_row") {
182
+ return ` ${qName} ${getTimestampDefault(dialect)}`;
183
+ }
184
+ return ` ${qName} ${col.type}`;
185
+ });
186
+ if (uniqs.length > 0) {
187
+ const uniqCols = uniqs.map((c) => quoteIdentifier(dialect, c)).join(", ");
188
+ colDefs.push(` UNIQUE (${uniqCols})`);
189
+ }
190
+ const createTable = `CREATE TABLE IF NOT EXISTS ${quoted} (\n${colDefs.join(",\n")}\n)`;
191
+ // Generate CREATE INDEX statements
192
+ const indexes = tableIndexes[tableType] ?? [];
193
+ const indexStatements = indexes.map((idx) => {
194
+ const idxName = quoteIdentifier(dialect, `idx_${tableName}_${idx.name}`);
195
+ const idxCols = idx.columns.map((c) => quoteIdentifier(dialect, c)).join(", ");
196
+ // MySQL/MariaDB do not support CREATE INDEX IF NOT EXISTS
197
+ const ifNotExists = dialect === "mysql" || dialect === "mariadb" ? "" : "IF NOT EXISTS ";
198
+ return `CREATE INDEX ${ifNotExists}${idxName} ON ${quoted} (${idxCols})`;
199
+ });
200
+ return [createTable, ...indexStatements].join(";\n");
201
+ }
202
+ export function getInsertSQL(dialect, tableName, rows) {
203
+ if (rows.length === 0)
204
+ return { sql: "", values: [] };
205
+ const firstRow = rows[0];
206
+ if (!firstRow)
207
+ return { sql: "", values: [] };
208
+ const columnNames = Object.keys(firstRow);
209
+ const quoted = quoteIdentifier(dialect, tableName);
210
+ const quotedCols = columnNames.map((c) => quoteIdentifier(dialect, c)).join(", ");
211
+ const values = [];
212
+ const rowPlaceholders = [];
213
+ for (const row of rows) {
214
+ const placeholders = [];
215
+ for (const col of columnNames) {
216
+ values.push(row[col] ?? null);
217
+ if (dialect === "postgres") {
218
+ placeholders.push(`$${values.length}`);
219
+ }
220
+ else {
221
+ placeholders.push("?");
222
+ }
223
+ }
224
+ rowPlaceholders.push(`(${placeholders.join(", ")})`);
225
+ }
226
+ const sql = `INSERT INTO ${quoted} (${quotedCols}) VALUES ${rowPlaceholders.join(", ")}`;
227
+ return { sql, values };
228
+ }
229
+ export function getUpsertSQL(dialect, tempTableName, finalTableName, tableType) {
230
+ const columns = tableColumns[tableType];
231
+ if (!columns)
232
+ throw new Error(`Unknown table type: ${tableType}`);
233
+ const uniqs = uniqueKeys[tableType] ?? [];
234
+ const dataColumns = columns.filter((c) => c.name !== "id" && c.name !== "created_at" && c.name !== "updated_at_row");
235
+ const quotedFinal = quoteIdentifier(dialect, finalTableName);
236
+ const quotedTemp = quoteIdentifier(dialect, tempTableName);
237
+ const colNames = dataColumns.map((c) => quoteIdentifier(dialect, c.name));
238
+ const selectCols = colNames.join(", ");
239
+ switch (dialect) {
240
+ case "sqlite": {
241
+ // SQLite doesn't support INSERT...SELECT...ON CONFLICT
242
+ // Use INSERT OR REPLACE which handles the upsert behavior
243
+ return `INSERT OR REPLACE INTO ${quotedFinal} (${selectCols})
244
+ SELECT ${selectCols} FROM ${quotedTemp}`;
245
+ }
246
+ case "mysql":
247
+ case "mariadb": {
248
+ const updateSet = dataColumns
249
+ .filter((c) => !uniqs.includes(c.name))
250
+ .map((c) => `${quoteIdentifier(dialect, c.name)} = VALUES(${quoteIdentifier(dialect, c.name)})`)
251
+ .join(", ");
252
+ return `INSERT INTO ${quotedFinal} (${selectCols})
253
+ SELECT ${selectCols} FROM ${quotedTemp}
254
+ ON DUPLICATE KEY UPDATE ${updateSet}, ${quoteIdentifier(dialect, "updated_at_row")} = CURRENT_TIMESTAMP`;
255
+ }
256
+ case "postgres": {
257
+ const conflictCols = uniqs.map((c) => quoteIdentifier(dialect, c)).join(", ");
258
+ const updateSet = dataColumns
259
+ .filter((c) => !uniqs.includes(c.name))
260
+ .map((c) => `${quoteIdentifier(dialect, c.name)} = EXCLUDED.${quoteIdentifier(dialect, c.name)}`)
261
+ .join(", ");
262
+ return `INSERT INTO ${quotedFinal} (${selectCols})
263
+ SELECT ${selectCols} FROM ${quotedTemp}
264
+ ON CONFLICT (${conflictCols})
265
+ DO UPDATE SET ${updateSet}, ${quoteIdentifier(dialect, "updated_at_row")} = NOW()`;
266
+ }
267
+ }
268
+ }
269
+ export { tableIndexes };
270
+ //# sourceMappingURL=dialects.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialects.js","sourceRoot":"","sources":["../../src/db/dialects.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAOlD,MAAM,cAAc,GAAkB;IACpC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,mCAAmC,EAAE;IACzD,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE;IACtC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE;IACpC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,EAAE;IAC3C,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,aAAa,EAAE;IACjD,EAAE,IAAI,EAAE,sBAAsB,EAAE,IAAI,EAAE,aAAa,EAAE;IACrD,EAAE,IAAI,EAAE,wBAAwB,EAAE,IAAI,EAAE,aAAa,EAAE;IACvD,EAAE,IAAI,EAAE,4BAA4B,EAAE,IAAI,EAAE,aAAa,EAAE;IAC3D,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,aAAa,EAAE;IACxC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE;IAC5C,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE;IACvC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,aAAa,EAAE;IACvC,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE;IACrC,EAAE,IAAI,EAAE,4BAA4B,EAAE,IAAI,EAAE,SAAS,EAAE;IACvD,EAAE,IAAI,EAAE,4BAA4B,EAAE,IAAI,EAAE,YAAY,EAAE;IAC1D,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE;IACzC,EAAE,IAAI,EAAE,4BAA4B,EAAE,IAAI,EAAE,SAAS,EAAE;IACvD,EAAE,IAAI,EAAE,4BAA4B,EAAE,IAAI,EAAE,YAAY,EAAE;IAC1D,EAAE,IAAI,EAAE,2BAA2B,EAAE,IAAI,EAAE,SAAS,EAAE;IACtD,EAAE,IAAI,EAAE,2BAA2B,EAAE,IAAI,EAAE,YAAY,EAAE;IACzD,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE;IACzC,EAAE,IAAI,EAAE,2BAA2B,EAAE,IAAI,EAAE,SAAS,EAAE;IACtD,EAAE,IAAI,EAAE,2BAA2B,EAAE,IAAI,EAAE,YAAY,EAAE;IACzD,EAAE,IAAI,EAAE,sBAAsB,EAAE,IAAI,EAAE,YAAY,EAAE;IACpD,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,aAAa,EAAE;IAClD,EAAE,IAAI,EAAE,uBAAuB,EAAE,IAAI,EAAE,aAAa,EAAE;IACtD,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE;IACzC,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,EAAE;CAC9C,CAAC;AAEF,MAAM,cAAc,GAAkB;IACpC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,mCAAmC,EAAE;IACzD,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE;IACtC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE;IACpC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,EAAE;IAC3C,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,aAAa,EAAE;IACjD,EAAE,IAAI,EAAE,sBAAsB,EAAE,IAAI,EAAE,aAAa,EAAE;IACrD,EAAE,IAAI,EAAE,wBAAwB,EAAE,IAAI,EAAE,aAAa,EAAE;IACvD,EAAE,IAAI,EAAE,4BAA4B,EAAE,IAAI,EAAE,aAAa,EAAE;IAC3D,EAAE,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,MAAM,EAAE;IAC7C,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE;IACtC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE;IACzC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE;IAC5C,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,aAAa,EAAE;IAChD,EAAE,IAAI,EAAE,sBAAsB,EAAE,IAAI,EAAE,YAAY,EAAE;IACpD,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,aAAa,EAAE;IAClD,EAAE,IAAI,EAAE,uBAAuB,EAAE,IAAI,EAAE,aAAa,EAAE;IACtD,EAAE,IAAI,EAAE,uBAAuB,EAAE,IAAI,EAAE,SAAS,EAAE;IAClD,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE;IACzC,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,EAAE;CAC9C,CAAC;AAEF,MAAM,oBAAoB,GAAkB;IAC1C,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,mCAAmC,EAAE;IACzD,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,YAAY,EAAE;IACtC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE;IACrC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE;IACpC,EAAE,IAAI,EAAE,qBAAqB,EAAE,IAAI,EAAE,MAAM,EAAE;IAC7C,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,MAAM,EAAE;IAC3C,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,YAAY,EAAE;IAC/C,EAAE,IAAI,EAAE,sBAAsB,EAAE,IAAI,EAAE,aAAa,EAAE;IACrD,EAAE,IAAI,EAAE,0BAA0B,EAAE,IAAI,EAAE,aAAa,EAAE;IACzD,EAAE,IAAI,EAAE,4BAA4B,EAAE,IAAI,EAAE,aAAa,EAAE;IAC3D,EAAE,IAAI,EAAE,gCAAgC,EAAE,IAAI,EAAE,aAAa,EAAE;IAC/D,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,cAAc,EAAE;IAC1C,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,YAAY,EAAE;IAC3C,EAAE,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,aAAa,EAAE;IACjD,EAAE,IAAI,EAAE,sBAAsB,EAAE,IAAI,EAAE,aAAa,EAAE;IACrD,EAAE,IAAI,EAAE,wBAAwB,EAAE,IAAI,EAAE,aAAa,EAAE;IACvD,EAAE,IAAI,EAAE,4BAA4B,EAAE,IAAI,EAAE,aAAa,EAAE;IAC3D,EAAE,IAAI,EAAE,sBAAsB,EAAE,IAAI,EAAE,YAAY,EAAE;IACpD,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,aAAa,EAAE;IAClD,EAAE,IAAI,EAAE,uBAAuB,EAAE,IAAI,EAAE,aAAa,EAAE;IACtD,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,YAAY,EAAE;IACzC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE;IAC5C,EAAE,IAAI,EAAE,iBAAiB,EAAE,IAAI,EAAE,aAAa,EAAE;IAChD,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE;IACpC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE;IACvC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE;IACzC,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,WAAW,EAAE;CAC9C,CAAC;AAEF,MAAM,YAAY,GAAkC;IAClD,SAAS,EAAE,cAAc;IACzB,WAAW,EAAE,cAAc;IAC3B,kBAAkB,EAAE,oBAAoB;CACzC,CAAC;AAOF,mDAAmD;AACnD,uFAAuF;AACvF,6DAA6D;AAC7D,0DAA0D;AAC1D,6EAA6E;AAC7E,MAAM,YAAY,GAAsC;IACtD,SAAS,EAAE;QACT,4CAA4C;QAC5C,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,aAAa,CAAC,EAAE;QACjD,qDAAqD;QACrD,EAAE,IAAI,EAAE,qBAAqB,EAAE,OAAO,EAAE,CAAC,aAAa,EAAE,SAAS,CAAC,EAAE;QACpE,8BAA8B;QAC9B,EAAE,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAE,CAAC,sBAAsB,CAAC,EAAE;QACnE,uCAAuC;QACvC,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,CAAC,kBAAkB,CAAC,EAAE;QAC3D,uCAAuC;QACvC,EAAE,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAE,CAAC,sBAAsB,CAAC,EAAE;QACnE,wBAAwB;QACxB,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,SAAS,CAAC,EAAE;QACzC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,aAAa,CAAC,EAAE;KAClD;IACD,WAAW,EAAE;QACX,2DAA2D;QAC3D,mDAAmD;QACnD,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,WAAW,CAAC,EAAE;QAC7C,8BAA8B;QAC9B,EAAE,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAE,CAAC,sBAAsB,CAAC,EAAE;QACnE,mBAAmB;QACnB,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,WAAW,CAAC,EAAE;QAC7C,6BAA6B;QAC7B,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,CAAC,kBAAkB,CAAC,EAAE;QAC3D,EAAE,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAE,CAAC,sBAAsB,CAAC,EAAE;QACnE,+CAA+C;QAC/C,EAAE,IAAI,EAAE,uBAAuB,EAAE,OAAO,EAAE,CAAC,uBAAuB,CAAC,EAAE;KACtE;IACD,kBAAkB,EAAE;QAClB,gDAAgD;QAChD,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,CAAC,aAAa,CAAC,EAAE;QACjD,gDAAgD;QAChD,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,CAAC,iBAAiB,CAAC,EAAE;QACzD,8CAA8C;QAC9C,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,YAAY,CAAC,EAAE;QAC/C,iCAAiC;QACjC,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,YAAY,CAAC,EAAE;QAC/C,8BAA8B;QAC9B,EAAE,IAAI,EAAE,sBAAsB,EAAE,OAAO,EAAE,CAAC,sBAAsB,CAAC,EAAE;KACpE;CACF,CAAC;AAEF,MAAM,UAAU,GAA6B;IAC3C,SAAS,EAAE;QACT,aAAa;QACb,SAAS;QACT,UAAU;QACV,4BAA4B;QAC5B,4BAA4B;QAC5B,2BAA2B;QAC3B,2BAA2B;KAC5B;IACD,WAAW,EAAE,CAAC,aAAa,CAAC;IAC5B,kBAAkB,EAAE,CAAC,iBAAiB,EAAE,aAAa,EAAE,YAAY,EAAE,YAAY,CAAC;CACnF,CAAC;AAEF,SAAS,oBAAoB,CAAC,OAA+B;IAC3D,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,QAAQ;YACX,OAAO,mCAAmC,CAAC;QAC7C,KAAK,OAAO,CAAC;QACb,KAAK,SAAS;YACZ,OAAO,oCAAoC,CAAC;QAC9C,KAAK,UAAU;YACb,OAAO,oBAAoB,CAAC;IAChC,CAAC;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,OAA+B;IAC1D,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,QAAQ;YACX,OAAO,qCAAqC,CAAC;QAC/C,KAAK,OAAO,CAAC;QACb,KAAK,SAAS;YACZ,OAAO,qCAAqC,CAAC;QAC/C,KAAK,UAAU;YACb,OAAO,yBAAyB,CAAC;IACrC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,OAA+B,EAAE,SAAiB,EAAE,SAAiB;IACrG,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;IACxC,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,SAAS,EAAE,CAAC,CAAC;IAElE,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACnD,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IAE1C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QAClC,MAAM,KAAK,GAAG,eAAe,CAAC,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,GAAG,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;YACtB,OAAO,KAAK,KAAK,IAAI,oBAAoB,CAAC,OAAO,CAAC,EAAE,CAAC;QACvD,CAAC;QACD,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,IAAI,GAAG,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;YAC/D,OAAO,KAAK,KAAK,IAAI,mBAAmB,CAAC,OAAO,CAAC,EAAE,CAAC;QACtD,CAAC;QACD,OAAO,KAAK,KAAK,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1E,OAAO,CAAC,IAAI,CAAC,aAAa,QAAQ,GAAG,CAAC,CAAC;IACzC,CAAC;IAED,MAAM,WAAW,GAAG,8BAA8B,MAAM,OAAO,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;IAExF,mCAAmC;IACnC,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IAC9C,MAAM,eAAe,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QAC1C,MAAM,OAAO,GAAG,eAAe,CAAC,OAAO,EAAE,OAAO,SAAS,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QACzE,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/E,0DAA0D;QAC1D,MAAM,WAAW,GAAG,OAAO,KAAK,OAAO,IAAI,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,gBAAgB,CAAC;QACzF,OAAO,gBAAgB,WAAW,GAAG,OAAO,OAAO,MAAM,KAAK,OAAO,GAAG,CAAC;IAC3E,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,WAAW,EAAE,GAAG,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACvD,CAAC;AAID,MAAM,UAAU,YAAY,CAC1B,OAA+B,EAC/B,SAAiB,EACjB,IAAgC;IAEhC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAEtD,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACzB,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAC9C,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACnD,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAElF,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,MAAM,eAAe,GAAa,EAAE,CAAC;IAErC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,YAAY,GAAa,EAAE,CAAC;QAClC,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;YAC9B,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC;YAC9B,IAAI,OAAO,KAAK,UAAU,EAAE,CAAC;gBAC3B,YAAY,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC;YACzC,CAAC;iBAAM,CAAC;gBACN,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;QACD,eAAe,CAAC,IAAI,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,GAAG,GAAG,eAAe,MAAM,KAAK,UAAU,YAAY,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IACzF,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,OAA+B,EAC/B,aAAqB,EACrB,cAAsB,EACtB,SAAiB;IAEjB,MAAM,OAAO,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;IACxC,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,SAAS,EAAE,CAAC,CAAC;IAElE,MAAM,KAAK,GAAG,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IAC1C,MAAM,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC,IAAI,KAAK,YAAY,IAAI,CAAC,CAAC,IAAI,KAAK,gBAAgB,CAAC,CAAC;IACrH,MAAM,WAAW,GAAG,eAAe,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;IAC7D,MAAM,UAAU,GAAG,eAAe,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAE3D,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1E,MAAM,UAAU,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEvC,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,QAAQ,EAAE,CAAC;YACd,uDAAuD;YACvD,0DAA0D;YAC1D,OAAO,0BAA0B,WAAW,KAAK,UAAU;SACxD,UAAU,SAAS,UAAU,EAAE,CAAC;QACrC,CAAC;QACD,KAAK,OAAO,CAAC;QACb,KAAK,SAAS,EAAE,CAAC;YACf,MAAM,SAAS,GAAG,WAAW;iBAC1B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;iBACtC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,aAAa,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;iBAC/F,IAAI,CAAC,IAAI,CAAC,CAAC;YAEd,OAAO,eAAe,WAAW,KAAK,UAAU;SAC7C,UAAU,SAAS,UAAU;0BACZ,SAAS,KAAK,eAAe,CAAC,OAAO,EAAE,gBAAgB,CAAC,sBAAsB,CAAC;QACrG,CAAC;QACD,KAAK,UAAU,EAAE,CAAC;YAChB,MAAM,YAAY,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9E,MAAM,SAAS,GAAG,WAAW;iBAC1B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;iBACtC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,eAAe,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;iBAChG,IAAI,CAAC,IAAI,CAAC,CAAC;YAEd,OAAO,eAAe,WAAW,KAAK,UAAU;SAC7C,UAAU,SAAS,UAAU;eACvB,YAAY;gBACX,SAAS,KAAK,eAAe,CAAC,OAAO,EAAE,gBAAgB,CAAC,UAAU,CAAC;QAC/E,CAAC;IACH,CAAC;AACH,CAAC;AAED,OAAO,EAAE,YAAY,EAAE,CAAC"}