@dbml/connector 3.7.4 → 3.8.1

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.
@@ -0,0 +1,131 @@
1
+ -- Create users table as a transient table
2
+ CREATE OR REPLACE TRANSIENT TABLE users (
3
+ user_id INT AUTOINCREMENT PRIMARY KEY,
4
+ username VARCHAR(50) UNIQUE NOT NULL,
5
+ email VARCHAR(100) UNIQUE NOT NULL,
6
+ password_hash VARCHAR(255) NOT NULL,
7
+ first_name VARCHAR(50),
8
+ last_name VARCHAR(50),
9
+ full_name VARCHAR(100),
10
+ date_of_birth DATE,
11
+ created_at TIMESTAMP_NTZ DEFAULT CURRENT_TIMESTAMP(),
12
+ last_login TIMESTAMP_NTZ,
13
+ is_active BOOLEAN DEFAULT TRUE
14
+ );
15
+
16
+ -- Create products table as a transient table
17
+ CREATE OR REPLACE TRANSIENT TABLE products (
18
+ product_id INT AUTOINCREMENT PRIMARY KEY,
19
+ name VARCHAR(100) NOT NULL,
20
+ description TEXT,
21
+ price DECIMAL(10, 2) NOT NULL,
22
+ stock_quantity INTEGER NOT NULL DEFAULT 0,
23
+ category VARCHAR(50),
24
+ created_at TIMESTAMP_NTZ DEFAULT CURRENT_TIMESTAMP(),
25
+ updated_at TIMESTAMP_NTZ DEFAULT CURRENT_TIMESTAMP(),
26
+ is_available BOOLEAN DEFAULT TRUE
27
+ );
28
+
29
+ -- Create orders table as a transient table
30
+ CREATE OR REPLACE TRANSIENT TABLE orders (
31
+ order_id INT AUTOINCREMENT PRIMARY KEY,
32
+ user_id INT NOT NULL,
33
+ order_date TIMESTAMP_NTZ DEFAULT CURRENT_TIMESTAMP(),
34
+ total_amount DECIMAL(12, 2) NOT NULL,
35
+ status VARCHAR(20) DEFAULT 'pending',
36
+ shipping_address TEXT NOT NULL,
37
+ billing_address TEXT NOT NULL,
38
+ CONSTRAINT fk_user FOREIGN KEY (user_id) REFERENCES users(user_id)
39
+ );
40
+
41
+ -- Create order_items table as a transient table
42
+ CREATE OR REPLACE TRANSIENT TABLE order_items (
43
+ order_item_id INT AUTOINCREMENT PRIMARY KEY,
44
+ order_id INT NOT NULL,
45
+ product_id INT NOT NULL,
46
+ quantity INTEGER NOT NULL,
47
+ unit_price DECIMAL(10, 2) NOT NULL,
48
+ CONSTRAINT fk_order FOREIGN KEY (order_id) REFERENCES orders(order_id),
49
+ CONSTRAINT fk_product FOREIGN KEY (product_id) REFERENCES products(product_id)
50
+ );
51
+
52
+ -- Create table with all data types
53
+ CREATE OR REPLACE TABLE all_data_types (
54
+ -- String Types
55
+ string_col STRING DEFAULT 'default_string',
56
+ varchar_col VARCHAR(100) DEFAULT 'default_varchar',
57
+ char_col CHAR(10) DEFAULT 'default_char',
58
+ nchar_col NCHAR(10) DEFAULT 'default_nchar',
59
+ text_col TEXT DEFAULT 'default_text',
60
+ binary_col BINARY,
61
+ varbinary_col VARBINARY,
62
+ array_col ARRAY DEFAULT ARRAY_CONSTRUCT('default_array1', 'default_array2'),
63
+ json_col VARIANT DEFAULT PARSE_JSON('{"default_key": "default_value"}'),
64
+
65
+ -- Numeric Types
66
+ int_col INT DEFAULT 42,
67
+ bigint_col BIGINT DEFAULT 9223372036854775807,
68
+ smallint_col SMALLINT DEFAULT 32767,
69
+ tinyint_col TINYINT DEFAULT 127,
70
+ number_col NUMBER(10, 2) DEFAULT 99.99,
71
+ decimal_col DECIMAL(10, 2) DEFAULT 99.99,
72
+ real_col REAL DEFAULT 3.402823e+38,
73
+ float_col FLOAT DEFAULT 1.7976931348623157e+308,
74
+ double_col DOUBLE DEFAULT 1.7976931348623157e+308,
75
+
76
+ -- Boolean Type
77
+ boolean_col BOOLEAN DEFAULT TRUE,
78
+
79
+ -- Date/Time Types
80
+ date_col DATE DEFAULT CURRENT_DATE(),
81
+ time_col TIME DEFAULT CURRENT_TIME(),
82
+ timestamp_col TIMESTAMP_NTZ DEFAULT CURRENT_TIMESTAMP(),
83
+ timestamp_tz_col TIMESTAMP_TZ DEFAULT CURRENT_TIMESTAMP(),
84
+ timestamp_ltz_col TIMESTAMP_LTZ DEFAULT CURRENT_TIMESTAMP()
85
+ );
86
+
87
+ -- Create table with user-defined data types
88
+ CREATE OR REPLACE TABLE user_define_data_types (
89
+ id INT AUTOINCREMENT PRIMARY KEY,
90
+ name VARCHAR(50),
91
+ gender VARCHAR(10), -- Enforcing enum-like behavior can be handled in application logic
92
+ age_range VARIANT, -- Example range check for age can be handled in application logic
93
+ height FLOAT,
94
+ weight FLOAT
95
+ );
96
+
97
+ -- Create table with comments
98
+ CREATE OR REPLACE TABLE table_with_comments (
99
+ id INT AUTOINCREMENT PRIMARY KEY,
100
+ name VARCHAR(100),
101
+ description TEXT,
102
+ created_at TIMESTAMP_NTZ DEFAULT CURRENT_TIMESTAMP()
103
+ );
104
+
105
+ -- Add comments
106
+ COMMENT ON TABLE table_with_comments IS 'This table stores information about various items.';
107
+ COMMENT ON COLUMN table_with_comments.id IS 'Unique identifier for each item.';
108
+ COMMENT ON COLUMN table_with_comments.name IS 'Name of the item.';
109
+ COMMENT ON COLUMN table_with_comments.description IS 'Detailed description of the item.';
110
+ COMMENT ON COLUMN table_with_comments.created_at IS 'Timestamp when the item was created.';
111
+
112
+ -- Create Authors table
113
+ CREATE OR REPLACE TABLE Authors (
114
+ AuthorID INT AUTOINCREMENT,
115
+ NationalityID INT,
116
+ AuthorName VARCHAR(100),
117
+ BirthYear INT,
118
+ PRIMARY KEY (AuthorID, NationalityID) -- Composite primary key
119
+ );
120
+
121
+ -- Create Books table
122
+ CREATE OR REPLACE TABLE Books (
123
+ BookID INT AUTOINCREMENT PRIMARY KEY,
124
+ AuthorID INT,
125
+ NationalityID INT,
126
+ ISBN VARCHAR(20),
127
+ Title VARCHAR(200),
128
+ UNIQUE (ISBN),
129
+ CONSTRAINT FK_AuthorNationality FOREIGN KEY (AuthorID, NationalityID)
130
+ REFERENCES Authors (AuthorID, NationalityID)
131
+ );
@@ -0,0 +1,64 @@
1
+ import { readFile } from 'fs/promises';
2
+ import { BigQueryCredentials } from '../connectors/types';
3
+
4
+ export async function loadCredentialFromFile(filename: string): Promise<string> {
5
+ try {
6
+ const data = await readFile(filename, { encoding: 'utf8' });
7
+ return data;
8
+ } catch (error) {
9
+ if ((error as TypeError).name === 'TypeError' || (error as Error).name === 'Error') {
10
+ throw new Error(`Load credential error: ${(error as Error).message}`);
11
+ }
12
+
13
+ throw error;
14
+ }
15
+ }
16
+
17
+ export function parseBigQueryCredential(credentialString: string): BigQueryCredentials {
18
+ try {
19
+ const credentialJson = JSON.parse(credentialString);
20
+
21
+ const {
22
+ project_id: projectId,
23
+ client_email: clientEmail,
24
+ private_key: privateKey,
25
+ datasets,
26
+ } = credentialJson;
27
+
28
+ if (typeof projectId !== 'string' || !projectId || !projectId.trim()) {
29
+ throw new Error('project_id must be a non-empty string');
30
+ }
31
+
32
+ if (typeof clientEmail !== 'string' || !clientEmail || !clientEmail.trim()) {
33
+ throw new Error('client_email must be a non-empty string');
34
+ }
35
+
36
+ if (typeof privateKey !== 'string' || !privateKey || !privateKey.trim()) {
37
+ throw new Error('private_key must be a non-empty string');
38
+ }
39
+
40
+ if (typeof clientEmail !== 'string' || !clientEmail || !clientEmail.trim()) {
41
+ throw new Error('client_email must be a non-empty string');
42
+ }
43
+
44
+ // valid datasets: ['dataset_1', 'dataset_2']
45
+ const parsedDatasets = !Array.isArray(datasets)
46
+ ? []
47
+ : datasets.filter((dataset) => typeof dataset === 'string');
48
+
49
+ return {
50
+ projectId,
51
+ credentials: {
52
+ clientEmail,
53
+ privateKey,
54
+ },
55
+ datasets: parsedDatasets,
56
+ };
57
+ } catch (error) {
58
+ if (error instanceof SyntaxError) {
59
+ throw new Error('Credentials must be in JSON format');
60
+ }
61
+
62
+ throw error;
63
+ }
64
+ }
@@ -0,0 +1,73 @@
1
+ import {
2
+ FieldsDictionary,
3
+ IndexesDictionary,
4
+ Table,
5
+ TableConstraintsDictionary,
6
+ } from '../connectors/types';
7
+
8
+ export function getIntersection<T>(firstList: T[], secondList: T[]): T[] {
9
+ return firstList.filter((item) => secondList.includes(item));
10
+ }
11
+
12
+ export function getTableSchemaKey(schemaName: string, tableName: string) {
13
+ if (!tableName || !tableName.trim()) {
14
+ throw new Error('Table name must be a non-empty string');
15
+ }
16
+
17
+ return schemaName ? `${schemaName}.${tableName}` : `${tableName}`;
18
+ }
19
+
20
+ export function mergeTables(firstTableList: Table[], secondTable: Table[]): Table[] {
21
+ return firstTableList.concat(secondTable);
22
+ }
23
+
24
+ export function mergeFieldDictionary(
25
+ firstDict: FieldsDictionary,
26
+ secondDict: FieldsDictionary
27
+ ): FieldsDictionary {
28
+ const result: FieldsDictionary = Object.assign({}, firstDict);
29
+
30
+ Object.keys(secondDict).forEach((key) => {
31
+ if (!result[key]) {
32
+ result[key] = [];
33
+ }
34
+
35
+ result[key] = result[key].concat(secondDict[key]);
36
+ });
37
+
38
+ return result;
39
+ }
40
+
41
+ export function mergeIndexDictionary(
42
+ firstDict: IndexesDictionary,
43
+ secondDict: IndexesDictionary
44
+ ): IndexesDictionary {
45
+ const result: IndexesDictionary = Object.assign({}, firstDict);
46
+
47
+ Object.keys(secondDict).forEach((key) => {
48
+ if (!result[key]) {
49
+ result[key] = [];
50
+ }
51
+
52
+ result[key] = result[key].concat(secondDict[key]);
53
+ });
54
+
55
+ return result;
56
+ }
57
+
58
+ export function mergeTableConstraintDictionary(
59
+ firstDict: TableConstraintsDictionary,
60
+ secondDict: TableConstraintsDictionary
61
+ ): TableConstraintsDictionary {
62
+ const result: TableConstraintsDictionary = Object.assign({}, firstDict);
63
+
64
+ Object.keys(secondDict).forEach((key) => {
65
+ if (!result[key]) {
66
+ result[key] = {};
67
+ }
68
+
69
+ result[key] = secondDict[key];
70
+ });
71
+
72
+ return result;
73
+ }
@@ -0,0 +1,60 @@
1
+ // You cannot use the "=" inside database's schema name. It will be treated as a delimiter.
2
+ const SCHEMAS_DELIMITER = 'schemas=';
3
+
4
+ const haveSchemas = (str: string): boolean => {
5
+ return str.toLowerCase().includes(SCHEMAS_DELIMITER);
6
+ };
7
+
8
+ const getSchemasPart = (str: string | undefined): string => {
9
+ return str ? str.toLowerCase().split(SCHEMAS_DELIMITER)[1] : '';
10
+ };
11
+
12
+ const noSchemaResult = (connectionString: string) => ({
13
+ connectionString,
14
+ schemas: [],
15
+ });
16
+
17
+ const parseOdbcSchema = (connectionString: string) => {
18
+ const connectionParts = connectionString.split(';');
19
+ const schemasPart = connectionParts.find((part) => haveSchemas(part));
20
+
21
+ return {
22
+ connectionString: connectionParts.filter((part) => !haveSchemas(part)).join(';'),
23
+ schemas: parseSchema(getSchemasPart(schemasPart)),
24
+ };
25
+ };
26
+
27
+ export const parseJdbcSchema = (connectionString: string) => {
28
+ const connectionParts = connectionString.split('?');
29
+ const connectionArgs = connectionParts[1].split('&');
30
+ const schemasPart = connectionArgs.find((part) => haveSchemas(part));
31
+
32
+ return {
33
+ connectionString: connectionParts[0],
34
+ schemas: parseSchema(getSchemasPart(schemasPart)),
35
+ };
36
+ };
37
+
38
+ export const parseConnectionString = (connectionString: string, connectionStringType: 'jdbc' | 'odbc') => {
39
+ if (!haveSchemas(connectionString)) return noSchemaResult(connectionString);
40
+
41
+ return connectionStringType === 'jdbc'
42
+ ? parseJdbcSchema(connectionString)
43
+ : parseOdbcSchema(connectionString);
44
+ };
45
+
46
+ export const buildSchemaQuery = (columnName: string, schemas: string[], prefix = 'AND'): string => {
47
+ if (schemas.length === 0) return '';
48
+ return `${prefix} ${columnName} IN (${schemas.map((schema) => `'${schema}'`).join(', ')})`;
49
+ };
50
+
51
+ // Inputs: schemas string -> Output: schema array string[]
52
+ // schema1, schema2 -> ['schema1', 'schema2']
53
+ // schema3,schema4 -> ['schema3", 'schema4']
54
+ // "schema5,gg", "schema6", schema7 -> ['schema5,gg', 'schema6', 'schema7']
55
+ // schema8 -> ['schema8']
56
+ export const parseSchema = (schemas: string | undefined): string[] => {
57
+ if (!schemas) return [];
58
+ const schemasWithDoubleQuotes = schemas.split(/,(?=(?:[^"]*(?:"[^"]*")*)*$)/).map((s) => s.trim());
59
+ return schemasWithDoubleQuotes.map((s) => s.replace(/"/g, ''));
60
+ };