最近話題な生成AI。私が過去に作成したことがある似た内容のコード生成のためGrokに以下の指示をしたところ、概ね直ぐに使えるコードが生成された。
今まで何人日、何人月の工数の見積もりかけていたのが一瞬でできるわけで、そりゃプログラマーはクビにされてしまうなと。上流工程、ロジックをはっきりさせるスキルが必要でコードを書くスキルは自動化。ひと昔前に計算をBIツールやExcel等を使わずに人がそろばんや電卓をたたいていた人らが不要になったのと同じか。
【指示内容】
(1)Salesforceでattachment, file, note, linkについて
オブジェクト名 "test__c" に対するレコードに添付する場合で
そのレコードの "Status__c" 項目が "作成中" のときは
削除可能でそれ以外の場合は削除を不可能とする
Salesforceで登録するApexを作成してください。
なお、削除を不可能とする場合に
ロール名が"TEST System Admin"が割り当てられているユーザーは
いつでも削除可能としてください。
(2)生成されたコードのテストコードを作成して
【生成されたコード】(1)
trigger TestTrigger on Attachment (before delete), ContentDocumentLink (before delete), Note (before delete) { // 現在のユーザーのロールを取得 Id userId = UserInfo.getUserId(); User currentUser = [SELECT UserRole.Name FROM User WHERE Id = :userId LIMIT 1]; Boolean isTestSystemAdmin = currentUser.UserRole.Name == 'TEST System Admin';
// 削除対象のレコードのParentIdを取得
Set<Id> parentIds = new Set<Id>();
for (SObject record : Trigger.old) {
if (record instanceof Attachment) {
parentIds.add(((Attachment)record).ParentId);
} else if (record instanceof ContentDocumentLink) {
parentIds.add(((ContentDocumentLink)record).LinkedEntityId);
} else if (record instanceof Note) {
parentIds.add(((Note)record).ParentId);
}
}
// 関連するtest__cレコードのStatus__cを取得
Map<Id, test__c> testRecords = new Map<Id, test__c>(
[SELECT Id, Status__c FROM test__c WHERE Id IN :parentIds]
);
// 削除制御ロジック
for (SObject record : Trigger.old) {
Id parentId;
if (record instanceof Attachment) {
parentId = ((Attachment)record).ParentId;
} else if (record instanceof ContentDocumentLink) {
parentId = ((ContentDocumentLink)record).LinkedEntityId;
} else if (record instanceof Note) {
parentId = ((Note)record).ParentId;
}
test__c relatedRecord = testRecords.get(parentId);
if (relatedRecord != null && relatedRecord.Status__c != '作成中' && !isTestSystemAdmin) {
record.addError('Status__cが「作成中」以外の場合、TEST System Adminロール以外のユーザーは削除できません。');
}
}
}
【生成されたコード】(2)
@isTest private class TestTriggerTest { // テスト用のデータセットアップ @TestSetup static void setup() { // テスト用のユーザーロールを作成 UserRole adminRole = new UserRole(Name = 'TEST System Admin'); insert adminRole; UserRole standardRole = new UserRole(Name = 'Standard Role'); insert standardRole;
// テストユーザーを作成
Profile stdProfile = [SELECT Id FROM Profile WHERE Name = 'Standard User' LIMIT 1];
User adminUser = new User(
Alias = 'admin',
Email = 'admin@test.com',
EmailEncodingKey = 'UTF-8',
LastName = 'TestAdmin',
LanguageLocaleKey = 'en_US',
LocaleSidKey = 'en_US',
ProfileId = stdProfile.Id,
TimeZoneSidKey = 'Asia/Tokyo',
UserName = 'admin@testorg.com',
UserRoleId = adminRole.Id
);
User standardUser = new User(
Alias = 'std',
Email = 'standard@test.com',
EmailEncodingKey = 'UTF-8',
LastName = 'TestStandard',
LanguageLocaleKey = 'en_US',
LocaleSidKey = 'en_US',
ProfileId = stdProfile.Id,
TimeZoneSidKey = 'Asia/Tokyo',
UserName = 'standard@testorg.com',
UserRoleId = standardRole.Id
);
insert new List<User>{adminUser, standardUser};
// テスト用のtest__cレコードを作成
test__c recordDraft = new test__c(Status__c = '作成中');
test__c recordOther = new test__c(Status__c = '完了');
insert new List<test__c>{recordDraft, recordOther};
}
// Attachmentの削除テスト(作成中)
@isTest
static void testAttachmentDeletionDraft() {
User standardUser = [SELECT Id FROM User WHERE UserName = 'standard@testorg.com' LIMIT 1];
test__c draftRecord = [SELECT Id FROM test__c WHERE Status__c = '作成中' LIMIT 1];
// Attachmentを作成
Attachment att = new Attachment(
Name = 'TestAttachment.txt',
Body = Blob.valueOf('Test Content'),
ParentId = draftRecord.Id
);
insert att;
Test.startTest();
System.runAs(standardUser) {
try {
delete att;
System.assert(true, 'Attachment should be deleted successfully when Status__c is 作成中');
} catch (Exception e) {
System.assert(false, 'Unexpected error: ' + e.getMessage());
}
}
Test.stopTest();
}
// Attachmentの削除テスト(作成中以外、標準ユーザー)
@isTest
static void testAttachmentDeletionOtherStatusStandardUser() {
User standardUser = [SELECT Id FROM User WHERE UserName = 'standard@testorg.com' LIMIT 1];
test__c otherRecord = [SELECT Id FROM test__c WHERE Status__c = '完了' LIMIT 1];
// Attachmentを作成
Attachment att = new Attachment(
Name = 'TestAttachment.txt',
Body = Blob.valueOf('Test Content'),
ParentId = otherRecord.Id
);
insert att;
Test.startTest();
System.runAs(standardUser) {
try {
delete att;
System.assert(false, 'Deletion should fail for non-admin user when Status__c is not 作成中');
} catch (Exception e) {
System.assert(e.getMessage().contains('削除できません'), 'Expected error message not found');
}
}
Test.stopTest();
}
// Attachmentの削除テスト(作成中以外、Adminユーザー)
@isTest
static void testAttachmentDeletionOtherStatusAdmin() {
User adminUser = [SELECT Id FROM User WHERE UserName = 'admin@testorg.com' LIMIT 1];
test__c otherRecord = [SELECT Id FROM test__c WHERE Status__c = '完了' LIMIT 1];
// Attachmentを作成
Attachment att = new Attachment(
Name = 'TestAttachment.txt',
Body = Blob.valueOf('Test Content'),
ParentId = otherRecord.Id
);
insert att;
Test.startTest();
System.runAs(adminUser) {
try {
delete att;
System.assert(true, 'Admin should be able to delete Attachment regardless of Status__c');
} catch (Exception e) {
System.assert(false, 'Unexpected error: ' + e.getMessage());
}
}
Test.stopTest();
}
// ContentDocumentLinkの削除テスト(作成中)
@isTest
static void testContentDocumentLinkDeletionDraft() {
User standardUser = [SELECT Id FROM User WHERE UserName = 'standard@testorg.com' LIMIT 1];
test__c draftRecord = [SELECT Id FROM test__c WHERE Status__c = '作成中' LIMIT 1];
// ContentDocumentとContentVersionを作成
ContentVersion cv = new ContentVersion(
Title = 'TestFile',
PathOnClient = 'TestFile.txt',
VersionData = Blob.valueOf('Test Content'),
IsMajorVersion = true
);
insert cv;
ContentDocument cd = [SELECT Id FROM ContentDocument WHERE LatestPublishedVersionId = :cv.Id LIMIT 1];
ContentDocumentLink cdl = new ContentDocumentLink(
LinkedEntityId = draftRecord.Id,
ContentDocumentId = cd.Id,
ShareType = 'V'
);
insert cdl;
Test.startTest();
System.runAs(standardUser) {
try {
delete cdl;
System.assert(true, 'ContentDocumentLink should be deleted successfully when Status__c is 作成中');
} catch (Exception e) {
System.assert(false, 'Unexpected error: ' + e.getMessage());
}
}
Test.stopTest();
}
// Noteの削除テスト(作成中以外、標準ユーザー)
@isTest
static void testNoteDeletionOtherStatusStandardUser() {
User standardUser = [SELECT Id FROM User WHERE UserName = 'standard@testorg.com' LIMIT 1];
test__c otherRecord = [SELECT Id FROM test__c WHERE Status__c = '完了' LIMIT 1];
// Noteを作成
Note note = new Note(
Title = 'Test Note',
Body = 'Test Content',
ParentId = otherRecord.Id
);
insert note;
Test.startTest();
System.runAs(standardUser) {
try {
delete note;
System.assert(false, 'Deletion should fail for non-admin user when Status__c is not 作成中');
} catch (Exception e) {
System.assert(e.getMessage().contains('削除できません'), 'Expected error message not found');
}
}
Test.stopTest();
}
}
各種無料版の生成AIを検証しているが、ChatGPTはパワポファイルなどの自動生成ができるが文書は不向きに見える。Grokの方が文書生成(プログラム、小説、教科書、問題集などの類)は得意な気がするしインデント、段落分けがしっかりされる傾向ある。