supatool 0.1.23 → 0.3.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.
- package/README.md +260 -38
- package/dist/bin/helptext.js +106 -20
- package/dist/bin/supatool.js +172 -21
- package/dist/generator/client.js +9 -0
- package/dist/generator/crudGenerator.js +194 -0
- package/dist/generator/docGenerator.js +64 -0
- package/dist/generator/rlsGenerator.js +111 -0
- package/dist/generator/schemaCrudGenerator.js +560 -0
- package/dist/generator/sqlGenerator.js +100 -0
- package/dist/generator/typeGenerator.js +55 -0
- package/dist/generator/types.js +2 -0
- package/dist/index.js +123 -37
- package/dist/integrations/supabase/crud-autogen/tasks.js +220 -0
- package/dist/integrations/supabase/crud-autogen/workflows.js +220 -0
- package/dist/parser/modelParser.js +18 -0
- package/dist/sync/config.js +98 -0
- package/dist/sync/definitionExtractor.js +1205 -0
- package/dist/sync/fetchRemoteSchemas.js +369 -0
- package/dist/sync/generateMigration.js +276 -0
- package/dist/sync/index.js +22 -0
- package/dist/sync/migrationRunner.js +271 -0
- package/dist/sync/parseLocalSchemas.js +97 -0
- package/dist/sync/sync.js +208 -0
- package/dist/sync/utils.js +52 -0
- package/dist/sync/writeSchema.js +161 -0
- package/package.json +18 -3
@@ -0,0 +1,220 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.getWorkflowsByFilters = getWorkflowsByFilters;
|
4
|
+
exports.getWorkflowsSingleByFilters = getWorkflowsSingleByFilters;
|
5
|
+
exports.getWorkflowsById = getWorkflowsById;
|
6
|
+
exports.createWorkflows = createWorkflows;
|
7
|
+
exports.updateWorkflows = updateWorkflows;
|
8
|
+
exports.deleteWorkflows = deleteWorkflows;
|
9
|
+
exports.queryWorkflows = queryWorkflows;
|
10
|
+
// Supabase CRUD operations for workflows
|
11
|
+
// This file is automatically generated. Do not edit it directly.
|
12
|
+
const client_1 = require("../client");
|
13
|
+
// Function to apply filters to a query
|
14
|
+
function applyFilters(query, filters) {
|
15
|
+
for (const [key, value] of Object.entries(filters)) {
|
16
|
+
if (Array.isArray(value)) {
|
17
|
+
query = query.in(key, value); // Use 'in' for array values
|
18
|
+
}
|
19
|
+
else if (typeof value === 'object' && value !== null) {
|
20
|
+
for (const [operator, val] of Object.entries(value)) {
|
21
|
+
switch (operator) {
|
22
|
+
case 'eq':
|
23
|
+
query = query.eq(key, val);
|
24
|
+
break;
|
25
|
+
case 'neq':
|
26
|
+
query = query.neq(key, val);
|
27
|
+
break;
|
28
|
+
case 'like':
|
29
|
+
query = query.like(key, val);
|
30
|
+
break;
|
31
|
+
case 'ilike':
|
32
|
+
query = query.ilike(key, val);
|
33
|
+
break;
|
34
|
+
case 'lt':
|
35
|
+
query = query.lt(key, val);
|
36
|
+
break;
|
37
|
+
case 'lte':
|
38
|
+
query = query.lte(key, val);
|
39
|
+
break;
|
40
|
+
case 'gte':
|
41
|
+
query = query.gte(key, val);
|
42
|
+
break;
|
43
|
+
case 'gt':
|
44
|
+
query = query.gt(key, val);
|
45
|
+
break;
|
46
|
+
case 'contains':
|
47
|
+
query = query.contains(key, val);
|
48
|
+
break;
|
49
|
+
case 'contains_any':
|
50
|
+
query = query.contains_any(key, val);
|
51
|
+
break;
|
52
|
+
case 'contains_all':
|
53
|
+
query = query.contains_all(key, val);
|
54
|
+
break;
|
55
|
+
// Add more operators as needed
|
56
|
+
default:
|
57
|
+
throw new Error('Unsupported operator: ' + operator);
|
58
|
+
}
|
59
|
+
}
|
60
|
+
}
|
61
|
+
else {
|
62
|
+
query = query.eq(key, value); // Default to 'eq' for simple values
|
63
|
+
}
|
64
|
+
}
|
65
|
+
return query;
|
66
|
+
}
|
67
|
+
// Read multiple rows with dynamic filters
|
68
|
+
async function getWorkflowsByFilters({ filters }) {
|
69
|
+
try {
|
70
|
+
let query = client_1.supabase.from('workflows').select('*');
|
71
|
+
query = applyFilters(query, filters);
|
72
|
+
const result = await query;
|
73
|
+
if (result.error) {
|
74
|
+
throw new Error(`Failed to fetch workflows: ${result.error.message}`);
|
75
|
+
}
|
76
|
+
return result.data || [];
|
77
|
+
}
|
78
|
+
catch (error) {
|
79
|
+
console.error('Error in getWorkflowsByFilters:', error);
|
80
|
+
throw error;
|
81
|
+
}
|
82
|
+
}
|
83
|
+
// Read a single row with dynamic filters
|
84
|
+
async function getWorkflowsSingleByFilters({ filters }) {
|
85
|
+
try {
|
86
|
+
let query = client_1.supabase.from('workflows').select('*');
|
87
|
+
query = applyFilters(query, filters).single();
|
88
|
+
const result = await query;
|
89
|
+
if (result.error) {
|
90
|
+
if (result.error.code === 'PGRST116') {
|
91
|
+
return null;
|
92
|
+
}
|
93
|
+
throw new Error(`Failed to fetch workflows: ${result.error.message}`);
|
94
|
+
}
|
95
|
+
return result.data;
|
96
|
+
}
|
97
|
+
catch (error) {
|
98
|
+
console.error('Error in getWorkflowsSingleByFilters:', error);
|
99
|
+
throw error;
|
100
|
+
}
|
101
|
+
}
|
102
|
+
// Read single row using id
|
103
|
+
async function getWorkflowsById({ id }) {
|
104
|
+
if (!id) {
|
105
|
+
throw new Error('ID is required');
|
106
|
+
}
|
107
|
+
try {
|
108
|
+
const result = await client_1.supabase
|
109
|
+
.from('workflows')
|
110
|
+
.select('*')
|
111
|
+
.eq('id', id)
|
112
|
+
.single();
|
113
|
+
if (result.error) {
|
114
|
+
if (result.error.code === 'PGRST116') {
|
115
|
+
return null;
|
116
|
+
}
|
117
|
+
throw new Error(`Failed to fetch workflows: ${result.error.message}`);
|
118
|
+
}
|
119
|
+
return result.data;
|
120
|
+
}
|
121
|
+
catch (error) {
|
122
|
+
console.error('Error in getWorkflowsById:', error);
|
123
|
+
throw error;
|
124
|
+
}
|
125
|
+
}
|
126
|
+
// Create Function
|
127
|
+
async function createWorkflows({ data }) {
|
128
|
+
if (!data) {
|
129
|
+
throw new Error('Data is required for creation');
|
130
|
+
}
|
131
|
+
try {
|
132
|
+
const result = await client_1.supabase
|
133
|
+
.from('workflows')
|
134
|
+
.insert([data])
|
135
|
+
.select()
|
136
|
+
.single();
|
137
|
+
if (result.error) {
|
138
|
+
throw new Error(`Failed to create workflows: ${result.error.message}`);
|
139
|
+
}
|
140
|
+
if (!result.data) {
|
141
|
+
throw new Error('No data returned after creation');
|
142
|
+
}
|
143
|
+
return result.data;
|
144
|
+
}
|
145
|
+
catch (error) {
|
146
|
+
console.error('Error in createWorkflows:', error);
|
147
|
+
throw error;
|
148
|
+
}
|
149
|
+
}
|
150
|
+
// Update Function
|
151
|
+
async function updateWorkflows({ id, data }) {
|
152
|
+
if (!id) {
|
153
|
+
throw new Error('ID is required for update');
|
154
|
+
}
|
155
|
+
if (!data || Object.keys(data).length === 0) {
|
156
|
+
throw new Error('Update data is required');
|
157
|
+
}
|
158
|
+
try {
|
159
|
+
const result = await client_1.supabase
|
160
|
+
.from('workflows')
|
161
|
+
.update(data)
|
162
|
+
.eq('id', id)
|
163
|
+
.select()
|
164
|
+
.single();
|
165
|
+
if (result.error) {
|
166
|
+
if (result.error.code === 'PGRST116') {
|
167
|
+
throw new Error(`workflows with ID ${id} not found`);
|
168
|
+
}
|
169
|
+
throw new Error(`Failed to update workflows: ${result.error.message}`);
|
170
|
+
}
|
171
|
+
if (!result.data) {
|
172
|
+
throw new Error(`workflows with ID ${id} not found`);
|
173
|
+
}
|
174
|
+
return result.data;
|
175
|
+
}
|
176
|
+
catch (error) {
|
177
|
+
console.error('Error in updateWorkflows:', error);
|
178
|
+
throw error;
|
179
|
+
}
|
180
|
+
}
|
181
|
+
// Delete Function
|
182
|
+
async function deleteWorkflows({ id }) {
|
183
|
+
if (!id) {
|
184
|
+
throw new Error('ID is required for deletion');
|
185
|
+
}
|
186
|
+
try {
|
187
|
+
const result = await client_1.supabase
|
188
|
+
.from('workflows')
|
189
|
+
.delete()
|
190
|
+
.eq('id', id);
|
191
|
+
if (result.error) {
|
192
|
+
throw new Error(`Failed to delete workflows: ${result.error.message}`);
|
193
|
+
}
|
194
|
+
return true;
|
195
|
+
}
|
196
|
+
catch (error) {
|
197
|
+
console.error('Error in deleteWorkflows:', error);
|
198
|
+
throw error;
|
199
|
+
}
|
200
|
+
}
|
201
|
+
// Custom query function
|
202
|
+
async function queryWorkflows({ query }) {
|
203
|
+
if (!query) {
|
204
|
+
throw new Error('Query is required');
|
205
|
+
}
|
206
|
+
try {
|
207
|
+
const result = await client_1.supabase
|
208
|
+
.from('workflows')
|
209
|
+
.select(query);
|
210
|
+
if (result.error) {
|
211
|
+
throw new Error(`Failed to execute query: ${result.error.message}`);
|
212
|
+
}
|
213
|
+
return result.data || [];
|
214
|
+
}
|
215
|
+
catch (error) {
|
216
|
+
console.error('Error in queryWorkflows:', error);
|
217
|
+
throw error;
|
218
|
+
}
|
219
|
+
}
|
220
|
+
// All functions are exported individually above
|
@@ -0,0 +1,18 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.parseModelYaml = parseModelYaml;
|
7
|
+
// モデルYAMLパース用(最小雛形)
|
8
|
+
// 日本語コメント
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
10
|
+
const js_yaml_1 = __importDefault(require("js-yaml"));
|
11
|
+
/**
|
12
|
+
* モデルYAMLファイルをパースしてJSオブジェクトを返す
|
13
|
+
* @param filePath YAMLファイルパス
|
14
|
+
*/
|
15
|
+
function parseModelYaml(filePath) {
|
16
|
+
const file = fs_1.default.readFileSync(filePath, 'utf8');
|
17
|
+
return js_yaml_1.default.load(file);
|
18
|
+
}
|
@@ -0,0 +1,98 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
3
|
+
if (k2 === undefined) k2 = k;
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
7
|
+
}
|
8
|
+
Object.defineProperty(o, k2, desc);
|
9
|
+
}) : (function(o, m, k, k2) {
|
10
|
+
if (k2 === undefined) k2 = k;
|
11
|
+
o[k2] = m[k];
|
12
|
+
}));
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
15
|
+
}) : function(o, v) {
|
16
|
+
o["default"] = v;
|
17
|
+
});
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
19
|
+
var ownKeys = function(o) {
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
21
|
+
var ar = [];
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
23
|
+
return ar;
|
24
|
+
};
|
25
|
+
return ownKeys(o);
|
26
|
+
};
|
27
|
+
return function (mod) {
|
28
|
+
if (mod && mod.__esModule) return mod;
|
29
|
+
var result = {};
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
31
|
+
__setModuleDefault(result, mod);
|
32
|
+
return result;
|
33
|
+
};
|
34
|
+
})();
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
36
|
+
exports.loadConfig = loadConfig;
|
37
|
+
exports.resolveConfig = resolveConfig;
|
38
|
+
exports.createConfigTemplate = createConfigTemplate;
|
39
|
+
const fs = __importStar(require("fs"));
|
40
|
+
const path = __importStar(require("path"));
|
41
|
+
const dotenv_1 = require("dotenv");
|
42
|
+
// プロジェクト内の.env/.env.localファイルを読み込み
|
43
|
+
const envPath = path.join(process.cwd(), '.env');
|
44
|
+
const envLocalPath = path.join(process.cwd(), '.env.local');
|
45
|
+
// .env.local が優先される
|
46
|
+
if (fs.existsSync(envLocalPath)) {
|
47
|
+
(0, dotenv_1.config)({ path: envLocalPath });
|
48
|
+
}
|
49
|
+
else if (fs.existsSync(envPath)) {
|
50
|
+
(0, dotenv_1.config)({ path: envPath });
|
51
|
+
}
|
52
|
+
/**
|
53
|
+
* 設定ファイルから設定を読み込み
|
54
|
+
*/
|
55
|
+
function loadConfig(configPath) {
|
56
|
+
const defaultConfigPath = path.join(process.cwd(), 'supatool.config.json');
|
57
|
+
const finalConfigPath = configPath || defaultConfigPath;
|
58
|
+
if (fs.existsSync(finalConfigPath)) {
|
59
|
+
try {
|
60
|
+
const configData = fs.readFileSync(finalConfigPath, 'utf-8');
|
61
|
+
return JSON.parse(configData);
|
62
|
+
}
|
63
|
+
catch (error) {
|
64
|
+
console.warn(`設定ファイル読み込みエラー: ${finalConfigPath}`);
|
65
|
+
return {};
|
66
|
+
}
|
67
|
+
}
|
68
|
+
return {};
|
69
|
+
}
|
70
|
+
/**
|
71
|
+
* 環境変数と設定ファイルから最終設定を取得
|
72
|
+
*/
|
73
|
+
function resolveConfig(options, configPath) {
|
74
|
+
const fileConfig = loadConfig(configPath);
|
75
|
+
return {
|
76
|
+
connectionString: options.connectionString ||
|
77
|
+
process.env.SUPABASE_CONNECTION_STRING ||
|
78
|
+
process.env.DATABASE_URL ||
|
79
|
+
fileConfig.connectionString,
|
80
|
+
schemaDir: options.schemaDir || fileConfig.schemaDir || './supabase/schemas',
|
81
|
+
tablePattern: options.tablePattern || fileConfig.tablePattern || '*'
|
82
|
+
};
|
83
|
+
}
|
84
|
+
/**
|
85
|
+
* 設定ファイル雛形を生成
|
86
|
+
*/
|
87
|
+
function createConfigTemplate(outputPath) {
|
88
|
+
const template = {
|
89
|
+
connectionString: "postgresql://user:password@host:port/database",
|
90
|
+
schemaDir: "./supabase/schemas",
|
91
|
+
tablePattern: "*",
|
92
|
+
"_comment": "接続文字列は .env または .env.local ファイルでSUPABASE_CONNECTION_STRINGまたはDATABASE_URLで設定することを推奨"
|
93
|
+
};
|
94
|
+
fs.writeFileSync(outputPath, JSON.stringify(template, null, 2), 'utf-8');
|
95
|
+
console.log(`設定ファイル雛形を生成: ${outputPath}`);
|
96
|
+
console.log('⚠️ 設定ファイルを.gitignoreに追加することを忘れずに!');
|
97
|
+
console.log('💡 接続文字列は .env または .env.local ファイルで管理してください');
|
98
|
+
}
|