swallowkit 1.0.0-beta.16 → 1.0.0-beta.18

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.
@@ -19,6 +19,9 @@ function generateCompactAzureFunctionsCRUD(model, sharedPackageName, authPolicy)
19
19
  const modelCamel = (0, model_parser_1.toCamelCase)(modelName);
20
20
  const modelKebab = (0, model_parser_1.toKebabCase)(modelName);
21
21
  const schemaName = model.schemaName;
22
+ const partitionKeyPath = model.partitionKey; // e.g. "/tenantId"
23
+ const partitionKeyField = partitionKeyPath.slice(1); // e.g. "tenantId"
24
+ const isIdPartition = partitionKeyField === 'id';
22
25
  const hasAuth = !!authPolicy;
23
26
  const authImport = hasAuth ? `\n${(0, auth_generator_1.generateAuthImportTS)()}\n` : '';
24
27
  const readGuard = hasAuth ? `\n${(0, auth_generator_1.generateAuthGuardTS)(authPolicy, 'read')}\n` : '';
@@ -27,6 +30,30 @@ function generateCompactAzureFunctionsCRUD(model, sharedPackageName, authPolicy)
27
30
  ? ` const authErr = handleAuthError(error);
28
31
  if (authErr) return authErr;\n`
29
32
  : '';
33
+ // SDK クライアント初期化ヘルパー(PK≠/id の場合、および delete で使用)
34
+ const sdkClientInit = `const { CosmosClient } = await import('@azure/cosmos');
35
+ const endpoint = process.env.CosmosDBConnection__accountEndpoint;
36
+ let client: InstanceType<typeof CosmosClient>;
37
+ if (endpoint) {
38
+ const { DefaultAzureCredential } = await import('@azure/identity');
39
+ client = new CosmosClient({ endpoint, aadCredentials: new DefaultAzureCredential() });
40
+ } else {
41
+ client = new CosmosClient(process.env.CosmosDBConnection!);
42
+ }
43
+ const database = client.database(process.env.COSMOS_DB_DATABASE_NAME || 'AppDatabase');
44
+ const container = database.container(containerName);`;
45
+ // getById ハンドラー: PK=/id の場合は input binding、それ以外は SDK
46
+ const getByIdHandler = isIdPartition
47
+ ? generateGetByIdWithBinding(modelCamel, schemaName, readGuard, authCatchBlock)
48
+ : generateGetByIdWithSdk(modelCamel, schemaName, readGuard, authCatchBlock, sdkClientInit);
49
+ // update ハンドラー: PK=/id の場合は input binding、それ以外は SDK
50
+ const updateHandler = isIdPartition
51
+ ? generateUpdateWithBinding(modelCamel, schemaName, writeGuard, authCatchBlock)
52
+ : generateUpdateWithSdk(modelCamel, schemaName, partitionKeyField, writeGuard, authCatchBlock, sdkClientInit);
53
+ // delete ハンドラー: 常に SDK(既存パターン)、PK に応じて分岐
54
+ const deleteHandler = isIdPartition
55
+ ? generateDeleteIdPartition(modelCamel, writeGuard, authCatchBlock, sdkClientInit)
56
+ : generateDeleteCustomPartition(modelCamel, partitionKeyField, writeGuard, authCatchBlock, sdkClientInit);
30
57
  return `import { app, HttpRequest, HttpResponseInit, InvocationContext } from '@azure/functions';
31
58
  import { z } from 'zod/v4';
32
59
  import crypto from 'crypto';
@@ -68,38 +95,7 @@ ${authCatchBlock} context.error(\`Error fetching from \${containerName}:\`,
68
95
  },
69
96
  });
70
97
 
71
- // GET /api/${modelCamel}/{id} - ID指定取得
72
- app.http('${modelCamel}-get-by-id', {
73
- methods: ['GET'],
74
- route: '${modelCamel}/{id}',
75
- authLevel: 'anonymous',
76
- extraInputs: [
77
- {
78
- type: 'cosmosDB',
79
- name: 'cosmosInput',
80
- databaseName: process.env.COSMOS_DB_DATABASE_NAME || 'AppDatabase',
81
- containerName,
82
- connection: 'CosmosDBConnection',
83
- id: '{id}',
84
- partitionKey: '{id}',
85
- },
86
- ],
87
- handler: async (request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> => {
88
- try {${readGuard}
89
- const document = context.extraInputs.get('cosmosInput');
90
-
91
- if (!document) {
92
- return { status: 404, jsonBody: { error: 'Item not found' } };
93
- }
94
-
95
- const validated = ${schemaName}.parse(document);
96
- return { status: 200, jsonBody: validated };
97
- } catch (error) {
98
- ${authCatchBlock} context.error(\`Error fetching item from \${containerName}:\`, error);
99
- return { status: 500, jsonBody: { error: 'Failed to fetch item' } };
100
- }
101
- },
102
- });
98
+ ${getByIdHandler}
103
99
 
104
100
  // POST /api/${modelCamel} - 新規作成
105
101
  app.http('${modelCamel}-create', {
@@ -145,7 +141,82 @@ ${authCatchBlock} context.error(\`Error creating item in \${containerName}:
145
141
  },
146
142
  });
147
143
 
148
- // PUT /api/${modelCamel}/{id} - 更新
144
+ ${updateHandler}
145
+
146
+ ${deleteHandler}
147
+ `;
148
+ }
149
+ // --- TS getById ハンドラー生成ヘルパー ---
150
+ function generateGetByIdWithBinding(modelCamel, schemaName, readGuard, authCatchBlock) {
151
+ return `// GET /api/${modelCamel}/{id} - ID指定取得
152
+ app.http('${modelCamel}-get-by-id', {
153
+ methods: ['GET'],
154
+ route: '${modelCamel}/{id}',
155
+ authLevel: 'anonymous',
156
+ extraInputs: [
157
+ {
158
+ type: 'cosmosDB',
159
+ name: 'cosmosInput',
160
+ databaseName: process.env.COSMOS_DB_DATABASE_NAME || 'AppDatabase',
161
+ containerName,
162
+ connection: 'CosmosDBConnection',
163
+ id: '{id}',
164
+ partitionKey: '{id}',
165
+ },
166
+ ],
167
+ handler: async (request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> => {
168
+ try {${readGuard}
169
+ const document = context.extraInputs.get('cosmosInput');
170
+
171
+ if (!document) {
172
+ return { status: 404, jsonBody: { error: 'Item not found' } };
173
+ }
174
+
175
+ const validated = ${schemaName}.parse(document);
176
+ return { status: 200, jsonBody: validated };
177
+ } catch (error) {
178
+ ${authCatchBlock} context.error(\`Error fetching item from \${containerName}:\`, error);
179
+ return { status: 500, jsonBody: { error: 'Failed to fetch item' } };
180
+ }
181
+ },
182
+ });`;
183
+ }
184
+ function generateGetByIdWithSdk(modelCamel, schemaName, readGuard, authCatchBlock, sdkClientInit) {
185
+ return `// GET /api/${modelCamel}/{id} - ID指定取得 (custom partition key)
186
+ app.http('${modelCamel}-get-by-id', {
187
+ methods: ['GET'],
188
+ route: '${modelCamel}/{id}',
189
+ authLevel: 'anonymous',
190
+ handler: async (request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> => {
191
+ try {${readGuard}
192
+ const id = request.params.id;
193
+ if (!id) {
194
+ return { status: 400, jsonBody: { error: 'ID is required' } };
195
+ }
196
+
197
+ ${sdkClientInit}
198
+
199
+ const { resources } = await container.items.query({
200
+ query: 'SELECT * FROM c WHERE c.id = @id',
201
+ parameters: [{ name: '@id', value: id }],
202
+ }).fetchAll();
203
+
204
+ if (!resources || resources.length === 0) {
205
+ return { status: 404, jsonBody: { error: 'Item not found' } };
206
+ }
207
+
208
+ const validated = ${schemaName}.parse(resources[0]);
209
+ return { status: 200, jsonBody: validated };
210
+ } catch (error) {
211
+ ${authCatchBlock} context.error(\`Error fetching item from \${containerName}:\`, error);
212
+ return { status: 500, jsonBody: { error: 'Failed to fetch item' } };
213
+ }
214
+ },
215
+ });`;
216
+ }
217
+ // --- TS update ハンドラー生成ヘルパー ---
218
+ function generateUpdateWithBinding(modelCamel, schemaName, writeGuard, authCatchBlock) {
219
+ return `// PUT /api/${modelCamel}/{id} - 更新
149
220
  app.http('${modelCamel}-update', {
150
221
  methods: ['PUT'],
151
222
  route: '${modelCamel}/{id}',
@@ -206,9 +277,63 @@ ${authCatchBlock} context.error(\`Error updating item in \${containerName}:
206
277
  return { status: 500, jsonBody: { error: 'Failed to update item' } };
207
278
  }
208
279
  },
209
- });
280
+ });`;
281
+ }
282
+ function generateUpdateWithSdk(modelCamel, schemaName, partitionKeyField, writeGuard, authCatchBlock, sdkClientInit) {
283
+ return `// PUT /api/${modelCamel}/{id} - 更新 (custom partition key)
284
+ app.http('${modelCamel}-update', {
285
+ methods: ['PUT'],
286
+ route: '${modelCamel}/{id}',
287
+ authLevel: 'anonymous',
288
+ handler: async (request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> => {
289
+ try {${writeGuard}
290
+ const id = request.params.id;
291
+ if (!id) {
292
+ return { status: 400, jsonBody: { error: 'ID is required' } };
293
+ }
294
+
295
+ ${sdkClientInit}
210
296
 
211
- // DELETE /api/${modelCamel}/{id} - 削除
297
+ const { resources } = await container.items.query({
298
+ query: 'SELECT * FROM c WHERE c.id = @id',
299
+ parameters: [{ name: '@id', value: id }],
300
+ }).fetchAll();
301
+
302
+ if (!resources || resources.length === 0) {
303
+ return { status: 404, jsonBody: { error: 'Item not found' } };
304
+ }
305
+
306
+ const existingDocument = resources[0];
307
+ const body = await request.json() as any;
308
+ const { createdAt, updatedAt, ...userData } = body;
309
+
310
+ const dataWithManagedFields = {
311
+ ...userData,
312
+ id,
313
+ createdAt: existingDocument.createdAt,
314
+ updatedAt: new Date().toISOString(),
315
+ };
316
+
317
+ const result = ${schemaName}.safeParse(dataWithManagedFields);
318
+
319
+ if (!result.success) {
320
+ context.error('Validation failed:', result.error.issues);
321
+ return { status: 400, jsonBody: { error: 'Validation failed', details: result.error.issues } };
322
+ }
323
+
324
+ const pkValue = result.data.${partitionKeyField};
325
+ await container.items.upsert(result.data);
326
+ return { status: 200, jsonBody: result.data };
327
+ } catch (error) {
328
+ ${authCatchBlock} context.error(\`Error updating item in \${containerName}:\`, error);
329
+ return { status: 500, jsonBody: { error: 'Failed to update item' } };
330
+ }
331
+ },
332
+ });`;
333
+ }
334
+ // --- TS delete ハンドラー生成ヘルパー ---
335
+ function generateDeleteIdPartition(modelCamel, writeGuard, authCatchBlock, sdkClientInit) {
336
+ return `// DELETE /api/${modelCamel}/{id} - 削除
212
337
  app.http('${modelCamel}-delete', {
213
338
  methods: ['DELETE'],
214
339
  route: '${modelCamel}/{id}',
@@ -220,17 +345,7 @@ app.http('${modelCamel}-delete', {
220
345
  return { status: 400, jsonBody: { error: 'ID is required' } };
221
346
  }
222
347
 
223
- const { CosmosClient } = await import('@azure/cosmos');
224
- const endpoint = process.env.CosmosDBConnection__accountEndpoint;
225
- let client: InstanceType<typeof CosmosClient>;
226
- if (endpoint) {
227
- const { DefaultAzureCredential } = await import('@azure/identity');
228
- client = new CosmosClient({ endpoint, aadCredentials: new DefaultAzureCredential() });
229
- } else {
230
- client = new CosmosClient(process.env.CosmosDBConnection!);
231
- }
232
- const database = client.database(process.env.COSMOS_DB_DATABASE_NAME || 'AppDatabase');
233
- const container = database.container(containerName);
348
+ ${sdkClientInit}
234
349
 
235
350
  await container.item(id, id).delete();
236
351
  context.log(\`Deleted item \${id} from \${containerName}\`);
@@ -244,18 +359,119 @@ ${authCatchBlock} context.error(\`Error deleting item from \${containerName
244
359
  return { status: 500, jsonBody: { error: 'Failed to delete item' } };
245
360
  }
246
361
  },
247
- });
248
- `;
362
+ });`;
363
+ }
364
+ function generateDeleteCustomPartition(modelCamel, partitionKeyField, writeGuard, authCatchBlock, sdkClientInit) {
365
+ return `// DELETE /api/${modelCamel}/{id} - 削除 (custom partition key)
366
+ app.http('${modelCamel}-delete', {
367
+ methods: ['DELETE'],
368
+ route: '${modelCamel}/{id}',
369
+ authLevel: 'anonymous',
370
+ handler: async (request: HttpRequest, context: InvocationContext): Promise<HttpResponseInit> => {
371
+ try {${writeGuard}
372
+ const id = request.params.id;
373
+ if (!id) {
374
+ return { status: 400, jsonBody: { error: 'ID is required' } };
375
+ }
376
+
377
+ ${sdkClientInit}
378
+
379
+ // パーティションキー値を取得するためにドキュメントを読み取り
380
+ const { resources } = await container.items.query({
381
+ query: 'SELECT * FROM c WHERE c.id = @id',
382
+ parameters: [{ name: '@id', value: id }],
383
+ }).fetchAll();
384
+
385
+ if (!resources || resources.length === 0) {
386
+ return { status: 404, jsonBody: { error: 'Item not found' } };
387
+ }
388
+
389
+ const pkValue = resources[0].${partitionKeyField};
390
+ await container.item(id, pkValue).delete();
391
+ context.log(\`Deleted item \${id} from \${containerName}\`);
392
+
393
+ return { status: 204 };
394
+ } catch (error: any) {
395
+ if (error.code === 404) {
396
+ return { status: 404, jsonBody: { error: 'Item not found' } };
397
+ }
398
+ ${authCatchBlock} context.error(\`Error deleting item from \${containerName}:\`, error);
399
+ return { status: 500, jsonBody: { error: 'Failed to delete item' } };
400
+ }
401
+ },
402
+ });`;
249
403
  }
250
404
  function generateCSharpAzureFunctionsCRUD(model, authPolicy) {
251
405
  const modelName = model.name;
252
406
  const modelCamel = (0, model_parser_1.toCamelCase)(modelName);
253
407
  const className = `${modelName}Functions`;
254
408
  const containerName = modelName.endsWith('s') ? modelName : `${modelName}s`;
409
+ const partitionKeyPath = model.partitionKey;
410
+ const partitionKeyField = partitionKeyPath.slice(1);
411
+ const isIdPartition = partitionKeyField === 'id';
255
412
  const hasAuth = !!authPolicy;
256
413
  const authUsing = hasAuth ? 'using Functions.Auth;\n' : '';
257
414
  const readGuard = hasAuth ? `\n${(0, auth_generator_1.generateAuthGuardCSharp)(authPolicy, 'read')}\n` : '';
258
415
  const writeGuard = hasAuth ? `\n${(0, auth_generator_1.generateAuthGuardCSharp)(authPolicy, 'write')}\n` : '';
416
+ // PK値の取得ロジック(create 用)
417
+ const createPkExpr = isIdPartition
418
+ ? 'id'
419
+ : `payload["${partitionKeyField}"]?.GetValue<string>() ?? throw new InvalidOperationException("Partition key field '${partitionKeyField}' is required.")`;
420
+ // ReadCosmosItemAsync: PK=/id の場合は直接読み取り、それ以外はクエリ
421
+ const readItemMethod = isIdPartition
422
+ ? ` private static async Task<JsonObject> ReadCosmosItemAsync(Container container, string id)
423
+ {
424
+ var response = await container.ReadItemStreamAsync(id, new PartitionKey(id));
425
+ if (response.StatusCode == HttpStatusCode.NotFound)
426
+ {
427
+ throw new CosmosException("Item not found", HttpStatusCode.NotFound, 0, response.Headers.ActivityId, response.Headers.RequestCharge);
428
+ }
429
+
430
+ if (!response.IsSuccessStatusCode)
431
+ {
432
+ throw new InvalidOperationException($"Cosmos read failed with status {(int)response.StatusCode}.");
433
+ }
434
+
435
+ using var document = await JsonDocument.ParseAsync(response.Content);
436
+ return JsonNode.Parse(document.RootElement.GetRawText())?.AsObject()
437
+ ?? throw new JsonException("Cosmos item payload must be a JSON object.");
438
+ }`
439
+ : ` private static async Task<JsonObject> ReadCosmosItemAsync(Container container, string id)
440
+ {
441
+ var query = new QueryDefinition("SELECT * FROM c WHERE c.id = @id")
442
+ .WithParameter("@id", id);
443
+ using var iterator = container.GetItemQueryStreamIterator(query);
444
+
445
+ while (iterator.HasMoreResults)
446
+ {
447
+ var page = await iterator.ReadNextAsync();
448
+ if (!page.IsSuccessStatusCode)
449
+ {
450
+ throw new InvalidOperationException($"Cosmos query failed with status {(int)page.StatusCode}.");
451
+ }
452
+
453
+ using var document = await JsonDocument.ParseAsync(page.Content);
454
+ if (document.RootElement.TryGetProperty("Documents", out var documents))
455
+ {
456
+ foreach (var item in documents.EnumerateArray())
457
+ {
458
+ return JsonNode.Parse(item.GetRawText())?.AsObject()
459
+ ?? throw new JsonException("Cosmos item payload must be a JSON object.");
460
+ }
461
+ }
462
+ }
463
+
464
+ throw new CosmosException("Item not found", HttpStatusCode.NotFound, 0, "", 0);
465
+ }`;
466
+ // Replace / Delete の PK 解決ロジック
467
+ const replacePkExpr = isIdPartition
468
+ ? 'new PartitionKey(id)'
469
+ : `new PartitionKey(payload["${partitionKeyField}"]?.GetValue<string>())`;
470
+ const deleteLogic = isIdPartition
471
+ ? ` await container.DeleteItemAsync<JsonObject>(id, new PartitionKey(id));`
472
+ : ` var existing = await ReadCosmosItemAsync(container, id);
473
+ var pkValue = existing["${partitionKeyField}"]?.GetValue<string>();
474
+ await container.DeleteItemAsync<JsonObject>(id, new PartitionKey(pkValue));`;
259
475
  return `using System.Net;
260
476
  using System.Text;
261
477
  using System.Text.Json;
@@ -348,23 +564,7 @@ public sealed class ${className}
348
564
  private static Stream CreateJsonStream(JsonObject payload) =>
349
565
  new MemoryStream(Encoding.UTF8.GetBytes(payload.ToJsonString()));
350
566
 
351
- private static async Task<JsonObject> ReadCosmosItemAsync(Container container, string id)
352
- {
353
- var response = await container.ReadItemStreamAsync(id, new PartitionKey(id));
354
- if (response.StatusCode == HttpStatusCode.NotFound)
355
- {
356
- throw new CosmosException("Item not found", HttpStatusCode.NotFound, 0, response.Headers.ActivityId, response.Headers.RequestCharge);
357
- }
358
-
359
- if (!response.IsSuccessStatusCode)
360
- {
361
- throw new InvalidOperationException($"Cosmos read failed with status {(int)response.StatusCode}.");
362
- }
363
-
364
- using var document = await JsonDocument.ParseAsync(response.Content);
365
- return JsonNode.Parse(document.RootElement.GetRawText())?.AsObject()
366
- ?? throw new JsonException("Cosmos item payload must be a JSON object.");
367
- }
567
+ ${readItemMethod}
368
568
 
369
569
  private static async Task<HttpResponseData> WriteJsonAsync(HttpRequestData request, HttpStatusCode status, object payload)
370
570
  {
@@ -451,7 +651,8 @@ public sealed class ${className}
451
651
  using var client = CreateCosmosClient();
452
652
  var container = GetContainer(client);
453
653
  using var stream = CreateJsonStream(payload);
454
- var response = await container.CreateItemStreamAsync(stream, new PartitionKey(id));
654
+ var pkValue = ${createPkExpr};
655
+ var response = await container.CreateItemStreamAsync(stream, new PartitionKey(pkValue));
455
656
  if (!response.IsSuccessStatusCode)
456
657
  {
457
658
  throw new InvalidOperationException($"Cosmos create failed with status {(int)response.StatusCode}.");
@@ -496,7 +697,7 @@ public sealed class ${className}
496
697
  var payload = BuildManagedDocument(body, id, createdAt, DateTimeOffset.UtcNow.ToString("O"));
497
698
 
498
699
  using var stream = CreateJsonStream(payload);
499
- var response = await container.ReplaceItemStreamAsync(stream, id, new PartitionKey(id));
700
+ var response = await container.ReplaceItemStreamAsync(stream, id, ${replacePkExpr});
500
701
  if (!response.IsSuccessStatusCode)
501
702
  {
502
703
  throw new InvalidOperationException($"Cosmos replace failed with status {(int)response.StatusCode}.");
@@ -525,7 +726,7 @@ public sealed class ${className}
525
726
  {${writeGuard}
526
727
  using var client = CreateCosmosClient();
527
728
  var container = GetContainer(client);
528
- await container.DeleteItemAsync<JsonObject>(id, new PartitionKey(id));
729
+ ${deleteLogic}
529
730
 
530
731
  return request.CreateResponse(HttpStatusCode.NoContent);
531
732
  }
@@ -547,6 +748,9 @@ function generatePythonAzureFunctionsCRUD(model, authPolicy) {
547
748
  const modelCamel = (0, model_parser_1.toCamelCase)(modelName);
548
749
  const modelSnake = (0, model_parser_1.toKebabCase)(modelName).replace(/-/g, "_");
549
750
  const containerName = modelName.endsWith('s') ? modelName : `${modelName}s`;
751
+ const partitionKeyPath = model.partitionKey;
752
+ const partitionKeyField = partitionKeyPath.slice(1);
753
+ const isIdPartition = partitionKeyField === 'id';
550
754
  const hasAuth = !!authPolicy;
551
755
  const authImport = hasAuth ? '\nfrom auth.jwt_helper import require_auth, require_roles, handle_auth_error\n' : '';
552
756
  // generateAuthGuardPython outputs at 4-space indent; inside try: we need 8-space
@@ -555,6 +759,72 @@ function generatePythonAzureFunctionsCRUD(model, authPolicy) {
555
759
  const readGuard = hasAuth ? '\n' + readGuardRaw.split('\n').map(l => ' ' + l).join('\n') : '';
556
760
  const writeGuard = hasAuth ? '\n' + writeGuardRaw.split('\n').map(l => ' ' + l).join('\n') : '';
557
761
  const authCatch = hasAuth ? `\n auth_err = handle_auth_error(exc)\n if auth_err:\n return auth_err` : '';
762
+ // getById / update の読み取りロジック
763
+ const getByIdRead = isIdPartition
764
+ ? `container.read_item(item=item_id, partition_key=item_id)`
765
+ : `list(container.query_items(
766
+ query="SELECT * FROM c WHERE c.id = @id",
767
+ parameters=[{"name": "@id", "value": item_id}],
768
+ enable_cross_partition_query=True,
769
+ ))`;
770
+ const getByIdBody = isIdPartition
771
+ ? ` container = _get_container()
772
+ item = container.read_item(item=item_id, partition_key=item_id)
773
+ return _json_response(item, 200)`
774
+ : ` container = _get_container()
775
+ items = list(container.query_items(
776
+ query="SELECT * FROM c WHERE c.id = @id",
777
+ parameters=[{"name": "@id", "value": item_id}],
778
+ enable_cross_partition_query=True,
779
+ ))
780
+ if not items:
781
+ return _json_response({"error": "${modelName} not found", "id": item_id}, 404)
782
+ return _json_response(items[0], 200)`;
783
+ const updateBody = isIdPartition
784
+ ? ` container = _get_container()
785
+ existing = container.read_item(item=item_id, partition_key=item_id)
786
+ body = req.get_json()
787
+ payload = _build_managed_document(
788
+ body,
789
+ item_id,
790
+ existing.get("createdAt") or datetime.now(timezone.utc).isoformat(),
791
+ datetime.now(timezone.utc).isoformat(),
792
+ )
793
+ container.replace_item(item=item_id, body=payload)
794
+ return _json_response(payload, 200)`
795
+ : ` container = _get_container()
796
+ items = list(container.query_items(
797
+ query="SELECT * FROM c WHERE c.id = @id",
798
+ parameters=[{"name": "@id", "value": item_id}],
799
+ enable_cross_partition_query=True,
800
+ ))
801
+ if not items:
802
+ return _json_response({"error": "${modelName} not found", "id": item_id}, 404)
803
+ existing = items[0]
804
+ body = req.get_json()
805
+ payload = _build_managed_document(
806
+ body,
807
+ item_id,
808
+ existing.get("createdAt") or datetime.now(timezone.utc).isoformat(),
809
+ datetime.now(timezone.utc).isoformat(),
810
+ )
811
+ container.replace_item(item=existing, body=payload)
812
+ return _json_response(payload, 200)`;
813
+ const deleteBody = isIdPartition
814
+ ? ` container = _get_container()
815
+ container.delete_item(item=item_id, partition_key=item_id)
816
+ return func.HttpResponse(status_code=204)`
817
+ : ` container = _get_container()
818
+ items = list(container.query_items(
819
+ query="SELECT * FROM c WHERE c.id = @id",
820
+ parameters=[{"name": "@id", "value": item_id}],
821
+ enable_cross_partition_query=True,
822
+ ))
823
+ if not items:
824
+ return _json_response({"error": "${modelName} not found", "id": item_id}, 404)
825
+ pk_value = items[0].get("${partitionKeyField}")
826
+ container.delete_item(item=item_id, partition_key=pk_value)
827
+ return func.HttpResponse(status_code=204)`;
558
828
  return {
559
829
  registration: `from blueprints.${modelSnake} import bp as ${modelSnake}_bp\napp.register_blueprint(${modelSnake}_bp)`,
560
830
  blueprint: `import json
@@ -625,9 +895,7 @@ def ${modelSnake}_get_all(req: func.HttpRequest) -> func.HttpResponse:
625
895
  def ${modelSnake}_get_by_id(req: func.HttpRequest) -> func.HttpResponse:
626
896
  item_id = req.route_params.get("id")
627
897
  try:${readGuard}
628
- container = _get_container()
629
- item = container.read_item(item=item_id, partition_key=item_id)
630
- return _json_response(item, 200)
898
+ ${getByIdBody}
631
899
  except exceptions.CosmosResourceNotFoundError:
632
900
  return _json_response({"error": "${modelName} not found", "id": item_id}, 404)
633
901
  except Exception as exc:${authCatch}
@@ -655,17 +923,7 @@ def ${modelSnake}_create(req: func.HttpRequest) -> func.HttpResponse:
655
923
  def ${modelSnake}_update(req: func.HttpRequest) -> func.HttpResponse:
656
924
  item_id = req.route_params.get("id")
657
925
  try:${writeGuard}
658
- container = _get_container()
659
- existing = container.read_item(item=item_id, partition_key=item_id)
660
- body = req.get_json()
661
- payload = _build_managed_document(
662
- body,
663
- item_id,
664
- existing.get("createdAt") or datetime.now(timezone.utc).isoformat(),
665
- datetime.now(timezone.utc).isoformat(),
666
- )
667
- container.replace_item(item=item_id, body=payload)
668
- return _json_response(payload, 200)
926
+ ${updateBody}
669
927
  except exceptions.CosmosResourceNotFoundError:
670
928
  return _json_response({"error": "${modelName} not found", "id": item_id}, 404)
671
929
  except ValueError:
@@ -678,9 +936,7 @@ def ${modelSnake}_update(req: func.HttpRequest) -> func.HttpResponse:
678
936
  def ${modelSnake}_delete(req: func.HttpRequest) -> func.HttpResponse:
679
937
  item_id = req.route_params.get("id")
680
938
  try:${writeGuard}
681
- container = _get_container()
682
- container.delete_item(item=item_id, partition_key=item_id)
683
- return func.HttpResponse(status_code=204)
939
+ ${deleteBody}
684
940
  except exceptions.CosmosResourceNotFoundError:
685
941
  return _json_response({"error": "${modelName} not found", "id": item_id}, 404)
686
942
  except Exception as exc:${authCatch}
@@ -1 +1 @@
1
- {"version":3,"file":"functions-generator.js","sourceRoot":"","sources":["../../../src/core/scaffold/functions-generator.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"functions-generator.js","sourceRoot":"","sources":["../../../src/core/scaffold/functions-generator.ts"],"names":[],"mappings":"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"}
@@ -14,6 +14,7 @@ export interface ModelInfo {
14
14
  nestedSchemaRefs: NestedSchemaRef[];
15
15
  connectorConfig?: ModelConnectorConfig;
16
16
  authPolicy?: ModelAuthPolicy;
17
+ partitionKey: string;
17
18
  }
18
19
  export interface FieldInfo {
19
20
  name: string;
@@ -61,6 +62,12 @@ export declare function parseConnectorConfig(content: string): ModelConnectorCon
61
62
  * パターン: export const authPolicy = { roles: [...], read: [...], write: [...] }
62
63
  */
63
64
  export declare function parseAuthPolicy(content: string): ModelAuthPolicy | undefined;
65
+ /**
66
+ * パーティションキーを抽出する
67
+ * export const partitionKey = '/tenantId' のようなエクスポートを検出
68
+ * 未指定の場合はデフォルト '/id' を返す
69
+ */
70
+ export declare function parsePartitionKey(content: string): string;
64
71
  /**
65
72
  * 文字列を kebab-case に変換
66
73
  */
@@ -1 +1 @@
1
- {"version":3,"file":"model-parser.d.ts","sourceRoot":"","sources":["../../../src/core/scaffold/model-parser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEpE,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,eAAe,CAAC,EAAE,oBAAoB,CAAC;IACvC,UAAU,CAAC,EAAE,eAAe,CAAC;CAC9B;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAiE1E;AAufD;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKhD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG/C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CA2FtF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAsC5E;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,SAAS,GAAE,MAAwB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAwB5F"}
1
+ {"version":3,"file":"model-parser.d.ts","sourceRoot":"","sources":["../../../src/core/scaffold/model-parser.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAEpE,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,eAAe,CAAC,EAAE,oBAAoB,CAAC;IACvC,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,OAAO,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,CAgF1E;AAufD;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAKhD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG/C;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,oBAAoB,GAAG,SAAS,CA2FtF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAsC5E;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGzD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAI/C;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,SAAS,GAAE,MAAwB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAwB5F"}
@@ -41,6 +41,7 @@ exports.toPascalCase = toPascalCase;
41
41
  exports.toCamelCase = toCamelCase;
42
42
  exports.parseConnectorConfig = parseConnectorConfig;
43
43
  exports.parseAuthPolicy = parseAuthPolicy;
44
+ exports.parsePartitionKey = parsePartitionKey;
44
45
  exports.toKebabCase = toKebabCase;
45
46
  exports.getAllModels = getAllModels;
46
47
  const fs = __importStar(require("fs"));
@@ -78,6 +79,8 @@ async function parseModelFile(modelPath) {
78
79
  const connectorConfig = parseConnectorConfig(content);
79
80
  // authPolicy を抽出(ロールベースアクセス制御用メタデータ)
80
81
  const authPolicy = parseAuthPolicy(content);
82
+ // partitionKey を抽出(Cosmos DB パーティションキー)
83
+ const partitionKey = parsePartitionKey(content);
81
84
  // ネストしたスキーマ参照を検出
82
85
  const nestedSchemaRefs = detectNestedSchemaRefs(modelPath, content, schemaName);
83
86
  // フィールド情報を抽出(動的インポートを使用)
@@ -88,6 +91,16 @@ async function parseModelFile(modelPath) {
88
91
  const hasId = fields.some(f => f.name === "id");
89
92
  const hasCreatedAt = fields.some(f => f.name === "createdAt");
90
93
  const hasUpdatedAt = fields.some(f => f.name === "updatedAt");
94
+ // パーティションキーのバリデーション
95
+ if (partitionKey !== '/id') {
96
+ if (!partitionKey.startsWith('/')) {
97
+ console.warn(`⚠️ [${modelName}] partitionKey should start with '/': got '${partitionKey}'`);
98
+ }
99
+ const pkField = partitionKey.startsWith('/') ? partitionKey.slice(1) : partitionKey;
100
+ if (fields.length > 0 && !fields.some(f => f.name === pkField)) {
101
+ console.warn(`⚠️ [${modelName}] partitionKey field '${pkField}' not found in schema fields`);
102
+ }
103
+ }
91
104
  return {
92
105
  name: modelName,
93
106
  displayName,
@@ -98,6 +111,7 @@ async function parseModelFile(modelPath) {
98
111
  hasCreatedAt,
99
112
  hasUpdatedAt,
100
113
  nestedSchemaRefs,
114
+ partitionKey,
101
115
  ...(connectorConfig ? { connectorConfig } : {}),
102
116
  ...(authPolicy ? { authPolicy } : {}),
103
117
  };
@@ -693,6 +707,15 @@ function parseAuthPolicy(content) {
693
707
  ...(write ? { write } : {}),
694
708
  };
695
709
  }
710
+ /**
711
+ * パーティションキーを抽出する
712
+ * export const partitionKey = '/tenantId' のようなエクスポートを検出
713
+ * 未指定の場合はデフォルト '/id' を返す
714
+ */
715
+ function parsePartitionKey(content) {
716
+ const match = content.match(/export\s+const\s+partitionKey\s*=\s*['"]([^'"]+)['"]/);
717
+ return match ? match[1] : '/id';
718
+ }
696
719
  /**
697
720
  * 文字列を kebab-case に変換
698
721
  */