├── .codeclimate.yml ├── .gitattributes ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md └── src ├── classes ├── ContextMetadata.cls ├── ContextMetadata.cls-meta.xml ├── ContextMetadata_Tests.cls ├── ContextMetadata_Tests.cls-meta.xml ├── EnvironmentMetadata.cls ├── EnvironmentMetadata.cls-meta.xml ├── EnvironmentMetadata_Tests.cls ├── EnvironmentMetadata_Tests.cls-meta.xml ├── FieldMetadata.cls ├── FieldMetadata.cls-meta.xml ├── FieldMetadata_Tests.cls ├── FieldMetadata_Tests.cls-meta.xml ├── FieldSetMetadata.cls ├── FieldSetMetadata.cls-meta.xml ├── FieldSetMetadata_Tests.cls ├── FieldSetMetadata_Tests.cls-meta.xml ├── LimitsMetadata.cls ├── LimitsMetadata.cls-meta.xml ├── LimitsMetadata_Tests.cls ├── LimitsMetadata_Tests.cls-meta.xml ├── QueueMetadata.cls ├── QueueMetadata.cls-meta.xml ├── QueueMetadata_Tests.cls ├── QueueMetadata_Tests.cls-meta.xml ├── RecordTypeMetadata.cls ├── RecordTypeMetadata.cls-meta.xml ├── RecordTypeMetadata_Tests.cls ├── RecordTypeMetadata_Tests.cls-meta.xml ├── SobjectMetadata.cls ├── SobjectMetadata.cls-meta.xml ├── SobjectMetadata_Tests.cls └── SobjectMetadata_Tests.cls-meta.xml └── package.xml /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | apexmetrics: 3 | enabled: true 4 | duplication: 5 | enabled: true 6 | eslint: 7 | enabled: true 8 | checks: 9 | no-unused-expressions: 10 | enabled: false 11 | ratings: 12 | paths: 13 | - "**.cls" 14 | - "**.trigger" 15 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Set the default line return behavior, in case people don't have core.autocrlf set. 2 | * text=auto eol=lf 3 | 4 | # Common git file types 5 | .gitattributes text 6 | .gitignore text 7 | *.md text 8 | 9 | # Salesforce-specfic file types 10 | *.app text 11 | *.cls text 12 | *.cmp text 13 | *.component text 14 | *.css text 15 | *.html text 16 | *.js text 17 | *.page text 18 | *.resource text binary 19 | *.trigger text 20 | *.xml text 21 | 22 | ## Specific Salesforce static resources that should be treated like text 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #Folders to exclude 2 | .settings/ 3 | config/ 4 | debug/ 5 | deploy/ 6 | 7 | #Files to exclude 8 | *.log 9 | *.sublime-project 10 | *.sublime-workspace 11 | *.sublime-settings 12 | 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "7" 4 | install: 5 | - npm install -g jsforce-metadata-tools 6 | script: 7 | - jsforce-deploy --checkOnly -u $DEPLOYMENT_USERNAME -p $DEPLOYMENT_PASSWORD$DEPLOYMENT_TOKEN -D $TRAVIS_BUILD_DIR/src -l $DEPLOYMENT_LOGIN_URL --rollbackOnError true --testLevel $DEPLOYMENT_TEST_LEVEL --pollTimeout $POLL_TIMEOUT --pollInterval $POLL_INTERVAL--verbose 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Jonathan Gillespie 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SimpleMetadata 2 | [![Build Status](https://travis-ci.org/jongpie/SimpleMetadata.svg?branch=fieldset-metadata)](https://travis-ci.org/jongpie/SimpleMetadata) 3 |
4 | A lightweight library of Apex classes for Salesforce that provide easy access to metadata information 5 |
6 |
7 | 8 | Deploy to Salesforce 10 | 11 | 12 | ## Overview 13 | Each class has at least 2 contstructors 14 | 1. Constructor that accepts strings parameters - ideal for Lightning components/Javascript where strings are needed 15 | 2. Constructor that accepts Apex metadata classes, like Schema.SObjectType and Schema.SObjectField - ideal for Apex development where you want something safer than strings 16 | 17 | Each class returns an immutable DTO with no public methods. Each member variables follows these naming conventions: 18 | 1. Variables are named using camelCase - this is less important in Apex development since Apex is case-insensitive, but important to note for Lightning development since Javascript is case-sensitive. 19 | 2. Variables called 'apiName' refer to the API name or Developer Name, including the namespace prefix. Example: sobjectName = 'MyNameSpace__MyObject__c'; 20 | 3. Variables called 'localApiName' refer to the API name or Developer Name, excluding the namespace prefix. Example: sobjectName = 'MyObject__c'; 21 | 4. Variables called 'label' refer to the label displayed to the user - if translations are available, then the label is translated to the user's language. Example: new SobjectMetadata('MyObject__c').label; // Gets the localized/translated label for your custom object 22 | 5. Variables called 'displayFieldApiName' refer to the name field of an SObject - typically, the field is actually called Name, but there are exceptions, like Case.CaseNumber, Task.Subject, Order.OrderNumber, etc. 23 | 24 | ## EnvironmentMetadata.cls 25 | * Contains metadata information for the current environment. No parameters are needed to construct it. 26 | 27 | ``` 28 | new EnvironmentMetadata() 29 | ``` 30 | 31 |
See Sample JSON 32 | 33 | { 34 | "BaseUrl": "https://mydomain.my.salesforce.com", 35 | "InstanceName": "EU11", 36 | "IsChatterEnabled": true, 37 | "IsKnowledgeEnabled": false, 38 | "IsMultiCurrencyEnabled": false, 39 | "IsPersonAccountEnabled": false, 40 | "IsProduction": true, 41 | "IsSandbox": false, 42 | "IsTerritoryManagementEnabled": false, 43 | "Name": "Jonathan Gillespie's Org", 44 | "OrganizationId": "00D0Y0000019999999", 45 | "OrganizationType": "Developer Edition", 46 | "QueueApiNames": [ 47 | "My_Queue" 48 | ] 49 | "SobjectApiNames": [ 50 | "AcceptedEventRelation", 51 | "Account", 52 | "AccountCleanInfo", 53 | "AccountContactRole", 54 | "AccountFeed", 55 | "AccountHistory", 56 | "AccountPartner", 57 | "AccountShare", 58 | "ActionLinkGroupTemplate", 59 | "ActionLinkTemplate", 60 | "ActivityExtension", 61 | "ActivityHistory", 62 | "ActivityRecurrence", 63 | "ActivityRecurrenceException", 64 | "AdditionalNumber", 65 | "AggregateResult", 66 | "Announcement", 67 | "ApexClass", 68 | "ApexComponent", 69 | "ApexEmailNotification", 70 | "ApexLog", 71 | "ApexPage", 72 | "ApexPageInfo", 73 | "ApexTestQueueItem", 74 | "ApexTestResult", 75 | "ApexTestResultLimits", 76 | "ApexTestRunResult", 77 | "ApexTestSuite", 78 | "ApexTrigger", 79 | "AppMenuItem", 80 | "Asset", 81 | "AssetFeed", 82 | "AssetHistory", 83 | "AssetRelationship", 84 | "AssetRelationshipFeed", 85 | "AssetRelationshipHistory", 86 | "AssetShare", 87 | "AssetTokenEvent", 88 | "AssignmentRule", 89 | "AsyncApexJob", 90 | "AttachedContentDocument", 91 | "Attachment", 92 | "AuraDefinition", 93 | "AuraDefinitionBundle", 94 | "AuraDefinitionBundleInfo", 95 | "AuraDefinitionInfo", 96 | "AuthConfig", 97 | "AuthConfigProviders", 98 | "AuthProvider", 99 | "AuthSession", 100 | "BackgroundOperation", 101 | "BrandTemplate", 102 | "BusinessHours", 103 | "BusinessProcess", 104 | "CallCenter", 105 | "Campaign", 106 | "CampaignFeed", 107 | "CampaignHistory", 108 | "CampaignMember", 109 | "CampaignMemberStatus", 110 | "CampaignShare", 111 | "Case", 112 | "CaseComment", 113 | "CaseContactRole", 114 | "CaseFeed", 115 | "CaseHistory", 116 | "CaseShare", 117 | "CaseSolution", 118 | "CaseStatus", 119 | "CaseTeamMember", 120 | "CaseTeamRole", 121 | "CaseTeamTemplate", 122 | "CaseTeamTemplateMember", 123 | "CaseTeamTemplateRecord", 124 | "CategoryData", 125 | "CategoryNode", 126 | "CategoryNodeLocalization", 127 | "ChatterActivity", 128 | "ChatterConversation", 129 | "ChatterConversationMember", 130 | "ChatterExtension", 131 | "ChatterExtensionConfig", 132 | "ChatterExtensionLocalization", 133 | "ChatterMessage", 134 | "ClientBrowser", 135 | "CollaborationGroup", 136 | "CollaborationGroupFeed", 137 | "CollaborationGroupMember", 138 | "CollaborationGroupMemberRequest", 139 | "CollaborationGroupRecord", 140 | "CollaborationInvitation", 141 | "CombinedAttachment", 142 | "Community", 143 | "ConnectedApplication", 144 | "Contact", 145 | "ContactCleanInfo", 146 | "ContactFeed", 147 | "ContactHistory", 148 | "ContactShare", 149 | "ContentAsset", 150 | "ContentBody", 151 | "ContentDistribution", 152 | "ContentDistributionView", 153 | "ContentDocument", 154 | "ContentDocumentFeed", 155 | "ContentDocumentHistory", 156 | "ContentDocumentLink", 157 | "ContentFolder", 158 | "ContentFolderItem", 159 | "ContentFolderLink", 160 | "ContentFolderMember", 161 | "ContentVersion", 162 | "ContentVersionHistory", 163 | "ContentWorkspace", 164 | "ContentWorkspaceDoc", 165 | "ContentWorkspaceMember", 166 | "ContentWorkspacePermission", 167 | "ContractContactRole", 168 | "Contract", 169 | "ContractFeed", 170 | "ContractHistory", 171 | "ContractStatus", 172 | "CorsWhitelistEntry", 173 | "CronJobDetail", 174 | "CronTrigger", 175 | "CspTrustedSite", 176 | "CustomBrand", 177 | "CustomBrandAsset", 178 | "CustomObjectUserLicenseMetrics", 179 | "CustomPermission", 180 | "CustomPermissionDependency", 181 | "DandBCompany", 182 | "Dashboard", 183 | "DashboardComponent", 184 | "DashboardComponentFeed", 185 | "DashboardFeed", 186 | "DataAssessmentFieldMetric", 187 | "DataAssessmentMetric", 188 | "DataAssessmentValueMetric", 189 | "DatacloudAddress", 190 | "DatacloudCompany", 191 | "DatacloudContact", 192 | "DatacloudDandBCompany", 193 | "DatacloudOwnedEntity", 194 | "DatacloudPurchaseUsage", 195 | "DataStatistics", 196 | "DataType", 197 | "DeclinedEventRelation", 198 | "DirectMessage", 199 | "DirectMessageFeed", 200 | "DirectMessageMember", 201 | "Document", 202 | "DocumentAttachmentMap", 203 | "Domain", 204 | "DomainSite", 205 | "DuplicateRecordItem", 206 | "DuplicateRecordSet", 207 | "DuplicateRule", 208 | "EmailCapture", 209 | "EmailDomainKey", 210 | "EmailMessage", 211 | "EmailMessageRelation", 212 | "EmailServicesAddress", 213 | "EmailServicesFunction", 214 | "EmailStatus", 215 | "EmailTemplate", 216 | "EmbeddedServiceDetail", 217 | "EntityDefinition", 218 | "EntityParticle", 219 | "EntitySubscription", 220 | "Event", 221 | "EventBusSubscriber", 222 | "EventFeed", 223 | "EventLogFile", 224 | "EventRelation", 225 | "ExternalDataSource", 226 | "ExternalDataUserAuth", 227 | "FeedAttachment", 228 | "FeedComment", 229 | "FeedItem", 230 | "FeedLike", 231 | "FeedPollChoice", 232 | "FeedPollVote", 233 | "FeedRevision", 234 | "FeedSignal", 235 | "FeedTrackedChange", 236 | "FieldDefinition", 237 | "FieldPermissions", 238 | "FileSearchActivity", 239 | "FiscalYearSettings", 240 | "FlexQueueItem", 241 | "FlowInterview", 242 | "FlowInterviewShare", 243 | "Folder", 244 | "FolderedContentDocument", 245 | "ForecastShare", 246 | "Goal", 247 | "GoalFeed", 248 | "GoalHistory", 249 | "GoalLink", 250 | "GoalShare", 251 | "GrantedByLicense", 252 | "Group", 253 | "GroupMember", 254 | "Holiday", 255 | "Idea", 256 | "IdeaComment", 257 | "IdpEventLog", 258 | "InstalledMobileApp", 259 | "KnowledgeableUser", 260 | "Lead", 261 | "LeadCleanInfo", 262 | "LeadFeed", 263 | "LeadHistory", 264 | "LeadShare", 265 | "LeadStatus", 266 | "ListEmail", 267 | "ListEmailRecipientSource", 268 | "ListEmailShare", 269 | "ListView", 270 | "ListViewChart", 271 | "ListViewChartInstance", 272 | "LoginGeo", 273 | "LoginHistory", 274 | "LoginIp", 275 | "LookedUpFromActivity", 276 | "Macro", 277 | "MacroHistory", 278 | "MacroInstruction", 279 | "MacroShare", 280 | "MailmergeTemplate", 281 | "MatchingRule", 282 | "MatchingRuleItem", 283 | "Metric", 284 | "MetricDataLink", 285 | "MetricDataLinkHistory", 286 | "MetricFeed", 287 | "MetricHistory", 288 | "MetricShare", 289 | "Name", 290 | "NamedCredential", 291 | "Note", 292 | "NoteAndAttachment", 293 | "OauthToken", 294 | "ObjectPermissions", 295 | "OpenActivity", 296 | "Opportunity", 297 | "OpportunityCompetitor", 298 | "OpportunityContactRole", 299 | "OpportunityFeed", 300 | "OpportunityFieldHistory", 301 | "OpportunityHistory", 302 | "OpportunityLineItem", 303 | "OpportunityPartner", 304 | "OpportunityShare", 305 | "OpportunityStage", 306 | "Order", 307 | "OrderFeed", 308 | "OrderHistory", 309 | "OrderItem", 310 | "OrderItemFeed", 311 | "OrderItemHistory", 312 | "OrderShare", 313 | "Organization", 314 | "OrgLifecycleNotification", 315 | "OrgWideEmailAddress", 316 | "OutgoingEmail", 317 | "OutgoingEmailRelation", 318 | "OwnedContentDocument", 319 | "OwnerChangeOptionInfo", 320 | "PackageLicense", 321 | "Partner", 322 | "PartnerRole", 323 | "Period", 324 | "PermissionSet", 325 | "PermissionSetAssignment", 326 | "PermissionSetLicense", 327 | "PermissionSetLicenseAssign", 328 | "PicklistValueInfo", 329 | "PlatformAction", 330 | "PlatformCachePartition", 331 | "PlatformCachePartitionType", 332 | "Pricebook2", 333 | "Pricebook2History", 334 | "PricebookEntry", 335 | "ProcessDefinition", 336 | "ProcessInstance", 337 | "ProcessInstanceHistory", 338 | "ProcessInstanceNode", 339 | "ProcessInstanceStep", 340 | "ProcessInstanceWorkitem", 341 | "ProcessNode", 342 | "Product2", 343 | "Product2Feed", 344 | "Product2History", 345 | "Profile", 346 | "Publisher", 347 | "PushTopic", 348 | "QueueSobject", 349 | "QuoteTemplateRichTextData", 350 | "RecentlyViewed", 351 | "RecordType", 352 | "RecordTypeLocalization", 353 | "RelationshipDomain", 354 | "RelationshipInfo", 355 | "Report", 356 | "ReportFeed", 357 | "SamlSsoConfig", 358 | "Scontrol", 359 | "ScontrolLocalization", 360 | "SearchActivity", 361 | "SearchLayout", 362 | "SearchPromotionRule", 363 | "SecureAgent", 364 | "SecureAgentPlugin", 365 | "SecureAgentPluginProperty", 366 | "SecureAgentsCluster", 367 | "SecurityCustomBaseline", 368 | "SessionPermSetActivation", 369 | "SetupAuditTrail", 370 | "SetupEntityAccess", 371 | "Site", 372 | "SiteFeed", 373 | "SiteHistory", 374 | "Solution", 375 | "SolutionFeed", 376 | "SolutionHistory", 377 | "SolutionStatus", 378 | "Stamp", 379 | "StampAssignment", 380 | "StampLocalization", 381 | "StaticResource", 382 | "StreamingChannel", 383 | "StreamingChannelShare", 384 | "Task", 385 | "TaskFeed", 386 | "TaskPriority", 387 | "TaskStatus", 388 | "TenantSecret", 389 | "TenantUsageEntitlement", 390 | "TestSuiteMembership", 391 | "ThirdPartyAccountLink", 392 | "TodayGoal", 393 | "TodayGoalShare", 394 | "Topic", 395 | "TopicAssignment", 396 | "TopicFeed", 397 | "TopicLocalization", 398 | "TwoFactorInfo", 399 | "TwoFactorMethodsInfo", 400 | "TwoFactorTempCode", 401 | "UndecidedEventRelation", 402 | "User", 403 | "UserAppInfo", 404 | "UserAppMenuCustomization", 405 | "UserAppMenuCustomizationShare", 406 | "UserAppMenuItem", 407 | "UserEntityAccess", 408 | "UserFeed", 409 | "UserFieldAccess", 410 | "UserLicense", 411 | "UserListView", 412 | "UserListViewCriterion", 413 | "UserLogin", 414 | "UserPackageLicense", 415 | "UserPermissionAccess", 416 | "UserPreference", 417 | "UserProvAccount", 418 | "UserProvAccountStaging", 419 | "UserProvisioningConfig", 420 | "UserProvisioningLog", 421 | "UserProvisioningRequest", 422 | "UserProvisioningRequestShare", 423 | "UserProvMockTarget", 424 | "UserRecordAccess", 425 | "UserRole", 426 | "UserShare", 427 | "VerificationHistory", 428 | "VisualforceAccessMetrics", 429 | "Vote", 430 | "WaveCompatibilityCheckItem", 431 | "WebLink", 432 | "WebLinkLocalization", 433 | "WorkCoaching", 434 | "WorkCoachingFeed", 435 | "WorkCoachingHistory", 436 | "WorkCoachingShare", 437 | "WorkFeedback", 438 | "WorkFeedbackHistory", 439 | "WorkFeedbackQuestion", 440 | "WorkFeedbackQuestionHistory", 441 | "WorkFeedbackQuestionSet", 442 | "WorkFeedbackQuestionSetHistory", 443 | "WorkFeedbackQuestionSetShare", 444 | "WorkFeedbackQuestionShare", 445 | "WorkFeedbackRequest", 446 | "WorkFeedbackRequestFeed", 447 | "WorkFeedbackRequestHistory", 448 | "WorkFeedbackRequestShare", 449 | "WorkFeedbackShare", 450 | "WorkFeedbackTemplate", 451 | "WorkFeedbackTemplateShare", 452 | "WorkPerformanceCycle", 453 | "WorkPerformanceCycleFeed", 454 | "WorkPerformanceCycleHistory", 455 | "WorkPerformanceCycleShare" 456 | ] 457 | } 458 | 459 |
460 | 461 | ## SobjectMetadata.cls 462 | * Contains metadata information for the specified SObject. There are 2 ways to create an instance of SobjectMetadata 463 | 464 | 1. By passing the SObject's API name as a string in the constructor 465 | ``` 466 | new SobjectMetadata('Account') 467 | ``` 468 | 469 | 2. By passing the SObject Type in the constructor 470 | ``` 471 | new SobjectMetadata(Schema.Account.SObjectType) 472 | ``` 473 | 474 | ### Sample Usage 475 | Scenario: if the user has access to delete an SObject, then delete it 476 | 477 | ``` 478 | public class MyClass { 479 | 480 | public void deleteRecord(MyCustomObject__c myRecord) { 481 | // If the user does not have access to delete, then stop 482 | if(new SobjectMetadata('MyCustomObject__c').isDeletable == false) return; 483 | 484 | //Otherwise, delete the record 485 | delete myRecord.MyCustomField__c; 486 | } 487 | 488 | } 489 | ``` 490 | 491 | ## FieldMetadata.cls 492 | * Contains metadata information for the specified field. There are 2 ways to create an instance of FieldMetadata 493 | 494 | 1. By passing the SObject's API name and the field's API name as strings in the constructor 495 | ``` 496 | new FieldMetadata('Account', 'Type') 497 | ``` 498 | 499 | 2. By passing the SObject Type and the SObject Field in the constructor 500 | ``` 501 | new FieldMetadata(Schema.Account.SObjectType, Schema.Account.Type) 502 | ``` 503 | 504 | ### Sample Usage 505 | Scenario: if the user has access to edit a field, set the value 506 | 507 | ``` 508 | public class MyClass { 509 | 510 | public void setMyField(MyCustomObject__c myRecord) { 511 | // If the user does not have access to delete, then stop 512 | if(new FieldMetadata('MyCustomObject__c', 'MyCustomField__c').isUpdateable) { 513 | 514 | // Otherwise, set the field 515 | myRecord.MyCustomField__c = 'some value'; 516 | } 517 | 518 | } 519 | ``` 520 | 521 | ## FieldSetMetadata.cls 522 | * Contains metadata information for the specified field set, as well as the field set's SObject and the field metadata for each field set member. There are 2 ways to create an instance of FieldMetadata 523 | 524 | 1. By passing the SObject's API name and the field set's API name as strings in the constructor 525 | ``` 526 | new FieldSetMetadata('Lead', 'MyFieldSet') 527 | ``` 528 | 529 | 2. By passing the FieldSet in the constructor 530 | ``` 531 | new FieldSetMetadata(SObjectType.Lead.FieldSets.MyFieldSet); 532 | ``` 533 | 534 | ## RecordTypeMetadata.cls 535 | * Contains metadata information for a record type by combinging RecordTypeInfo and RecordType objects together. There are 3 ways to create an instance of RecordTypeMetadata 536 | 537 | 1. By passing the SObject's API name and the RecordType's API name (DeveloperName) in the constructor 538 | ``` 539 | new RecordTypeMetadata('Account', 'My_RecordType_Developer_Name'); 540 | ``` 541 | 542 | 2. By passing the RecordType's ID in the constructor 543 | ``` 544 | new RecordTypeMetadata(myAccountRecord.RecordTypeId); 545 | ``` 546 | 547 | 3. By passing the Schema.SObjectType and the Schema.RecordTypeInfo in the constructor 548 | ``` 549 | Schema.SObjectType accountSObjectType = Schema.Account.SObjectType; 550 | Schema.RecordTypeInfo someAccountRecordTypeInfo; 551 | new RecordTypeMetadata(accountSObjectType, someAccountRecordTypeInfo); 552 | ``` 553 | 554 |
See Sample JSON 555 | 556 | { 557 | "ApiName": "MyNamespace__My_RecordType_Developer_Name" 558 | "Id": "0120Y000000EEEEE", 559 | "IsActive": true, 560 | "IsAvailable": true, 561 | "IsDefaultRecordTypeMapping": true, 562 | "IsMaster": false, 563 | "Label": "My Record Type", 564 | "LocalName": "My_RecordType_Developer_Name" 565 | "Namespace": "MyNamespace", 566 | "SobjectApiName": "Account" 567 | } 568 | 569 |
570 | 571 | ## QueueMetadata.cls 572 | * Contains metadata information for a queue, including the queue members and the supported SObject names. There are 2 ways to create an instance of QueueMetadata 573 | 574 | 1. By passing the Queue's API name (DeveloperName) in the constructor 575 | ``` 576 | new QueueMetadata('My_Queue_Developer_Name'); 577 | ``` 578 | 579 | 2. By passing the Queue's ID in the constructor 580 | ``` 581 | Id myQueueId = '00G0Y0000000000'; 582 | new QueueMetadata(myQueueId); 583 | ``` 584 | 585 |
See Sample JSON 586 | 587 | { 588 | "ApiName": "My_Queue", 589 | "DoesIncludeBosses": true, 590 | "DoesSendEmailToMembers": true, 591 | "Email": "fake@test.com", 592 | "Label": "My Queue", 593 | "Id": "00G0Y0000011111111", 594 | "QueueMembers": [ 595 | { 596 | "QueueId": "00G0Y0000011111111", 597 | "QueueMemberId": "0110Y000000fHUyQAM", 598 | "Type": "User", 599 | "UserOrGroupId": "0050Y000001LrM3QAK" 600 | }, 601 | { 602 | "QueueId": "00G0Y0000011111111", 603 | "QueueMemberId": "0110Y0000000000000", 604 | "Type": "User", 605 | "UserOrGroupId": "0050Y0000000000000" 606 | }, 607 | { 608 | "QueueId": "00G0Y0000011111111", 609 | "QueueMemberId": "0110Y000001q5sUQAQ", 610 | "Type": "Group", 611 | "UserOrGroupId": "00G0Y000001inOQUAY" 612 | } 613 | ], 614 | "SobjectApiNames": [ 615 | "Case", 616 | "Lead" 617 | ] 618 | } 619 | 620 |
-------------------------------------------------------------------------------- /src/classes/ContextMetadata.cls: -------------------------------------------------------------------------------- 1 | /************************************************************************************************* 2 | * This file is part of the SimpleMetadata project, released under the MIT License. * 3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. * 4 | *************************************************************************************************/ 5 | global class ContextMetadata { 6 | 7 | @AuraEnabled global final Boolean IsApexRest {get; private set;} 8 | @AuraEnabled global final Boolean IsBatch {get; private set;} 9 | @AuraEnabled global final Boolean IsExecuting {get; private set;} 10 | @AuraEnabled global final Boolean IsFuture {get; private set;} 11 | @AuraEnabled global final Boolean IsLightning {get; private set;} 12 | @AuraEnabled global final Boolean IsLightningConsole {get; private set;} 13 | @AuraEnabled global final Boolean IsQueueable {get; private set;} 14 | @AuraEnabled global final Boolean IsSalesforce1 {get; private set;} 15 | @AuraEnabled global final Boolean IsScheduled {get; private set;} 16 | @AuraEnabled global final Boolean IsVisualforce {get; private set;} 17 | 18 | global ContextMetadata() { 19 | this.IsApexRest = RestContext.request != null; 20 | this.IsBatch = System.isBatch(); 21 | this.IsExecuting = Trigger.isExecuting; 22 | this.IsFuture = System.isFuture(); 23 | this.IsLightning = UserInfo.getUiThemeDisplayed() == 'Theme4d'; 24 | this.IsLightningConsole = UserInfo.getUiThemeDisplayed() == 'Theme4u'; 25 | this.IsQueueable = System.isQueueable(); 26 | this.IsSalesforce1 = UserInfo.getUiThemeDisplayed() == 'Theme4t'; 27 | this.IsScheduled = System.isScheduled(); 28 | this.IsVisualforce = ApexPages.currentPage() != null; 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /src/classes/ContextMetadata.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 43.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/ContextMetadata_Tests.cls: -------------------------------------------------------------------------------- 1 | /************************************************************************************************* 2 | * This file is part of the SimpleMetadata project, released under the MIT License. * 3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. * 4 | *************************************************************************************************/ 5 | @isTest 6 | private class ContextMetadata_Tests { 7 | 8 | @isTest 9 | static void it_should_return_context_metadata() { 10 | ContextMetadata contextMetadata = new ContextMetadata(); 11 | validateAttributesAreSet(contextMetadata); 12 | validateCaseSentivityForJavascript(contextMetadata); 13 | } 14 | 15 | private static void validateAttributesAreSet(ContextMetadata contextMetadata) { 16 | System.assertEquals(RestContext.request != null, contextMetadata.IsApexRest); 17 | System.assertEquals(System.isBatch(), contextMetadata.IsBatch); 18 | System.assertEquals(Trigger.isExecuting, contextMetadata.IsExecuting); 19 | System.assertEquals(System.isFuture(), contextMetadata.IsFuture); 20 | System.assertEquals(UserInfo.getUiThemeDisplayed() == 'Theme4d', contextMetadata.IsLightning); 21 | System.assertEquals(UserInfo.getUiThemeDisplayed() == 'Theme4u', contextMetadata.IsLightningConsole); 22 | System.assertEquals(System.isQueueable(), contextMetadata.IsQueueable); 23 | System.assertEquals(UserInfo.getUiThemeDisplayed() == 'Theme4t', contextMetadata.IsSalesforce1); 24 | System.assertEquals(System.isScheduled(), contextMetadata.IsScheduled); 25 | System.assertEquals(ApexPages.currentPage() != null, contextMetadata.IsVisualforce); 26 | } 27 | 28 | private static void validateCaseSentivityForJavascript(ContextMetadata contextMetadata) { 29 | // Validate that the attributes are named exactly as expected so that javascript can rely on them 30 | String jsonContextMetadata = JSON.serialize(contextMetadata); 31 | Map untypedContextMetadata = (Map)JSON.deserializeUntyped(jsonContextMetadata); 32 | 33 | // One negative to confirm that the strings in our map are case sensitive 34 | System.assert(untypedContextMetadata.containsKey('ISAPEXREST') == false); 35 | // Now for the 'real' tests 36 | System.assert(untypedContextMetadata.containsKey('IsApexRest')); 37 | System.assert(untypedContextMetadata.containsKey('IsBatch')); 38 | System.assert(untypedContextMetadata.containsKey('IsExecuting')); 39 | System.assert(untypedContextMetadata.containsKey('IsFuture')); 40 | System.assert(untypedContextMetadata.containsKey('IsLightning')); 41 | System.assert(untypedContextMetadata.containsKey('IsLightningConsole')); 42 | System.assert(untypedContextMetadata.containsKey('IsQueueable')); 43 | System.assert(untypedContextMetadata.containsKey('IsSalesforce1')); 44 | System.assert(untypedContextMetadata.containsKey('IsScheduled')); 45 | System.assert(untypedContextMetadata.containsKey('IsVisualforce')); 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /src/classes/ContextMetadata_Tests.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 43.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/EnvironmentMetadata.cls: -------------------------------------------------------------------------------- 1 | /************************************************************************************************* 2 | * This file is part of the SimpleMetadata project, released under the MIT License. * 3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. * 4 | *************************************************************************************************/ 5 | global class EnvironmentMetadata { 6 | 7 | // Some info must be queried from the Organization object, so cache the results to limit query count to 1 8 | private static final Organization ORGANIZATION; 9 | 10 | static { 11 | ORGANIZATION = [SELECT Id, Name, InstanceName, NamespacePrefix, OrganizationType, IsSandbox FROM Organization LIMIT 1]; 12 | } 13 | 14 | @AuraEnabled global final String BaseUrl {get; private set;} 15 | @AuraEnabled global final String InstanceName {get; private set;} 16 | @AuraEnabled global final Boolean IsChatterEnabled {get; private set;} 17 | @AuraEnabled global final Boolean IsKnowledgeEnabled {get; private set;} 18 | @AuraEnabled global final Boolean IsMultiCurrencyEnabled {get; private set;} 19 | @AuraEnabled global final Boolean IsPersonAccountEnabled {get; private set;} 20 | @AuraEnabled global final Boolean IsProduction {get; private set;} 21 | @AuraEnabled global final Boolean IsSandbox {get; private set;} 22 | @AuraEnabled global final Boolean IsTerritoryManagementEnabled {get; private set;} 23 | @AuraEnabled global final String Namespace {get; private set;} 24 | @AuraEnabled global final Id OrganizationId {get; private set;} 25 | @AuraEnabled global final String OrganizationName {get; private set;} 26 | @AuraEnabled global final String OrganizationType {get; private set;} 27 | @AuraEnabled global final List QueueApiNames {get; private set;} 28 | @AuraEnabled global final List SobjectApiNames {get; private set;} 29 | 30 | global EnvironmentMetadata() { 31 | Map sobjectTypes = Schema.getGlobalDescribe(); 32 | 33 | this.BaseUrl = Url.getSalesforceBaseUrl().toExternalForm(); 34 | this.InstanceName = ORGANIZATION.InstanceName; 35 | this.IsChatterEnabled = sobjectTypes.containsKey('FeedItem'); 36 | this.IsKnowledgeEnabled = sobjectTypes.containsKey('KnowledgeArticle'); 37 | this.IsMultiCurrencyEnabled = UserInfo.isMultiCurrencyOrganization(); 38 | this.IsPersonAccountEnabled = sobjectTypes.get('Account').getDescribe().fields.getMap().containsKey('IsPersonAccount'); 39 | this.IsProduction = ORGANIZATION.IsSandbox == false; 40 | this.IsSandbox = ORGANIZATION.IsSandbox; 41 | this.IsTerritoryManagementEnabled = sobjectTypes.containsKey('Territory'); 42 | this.Namespace = ORGANIZATION.NamespacePrefix; 43 | this.OrganizationId = ORGANIZATION.Id; 44 | this.OrganizationName = ORGANIZATION.Name; 45 | this.OrganizationType = ORGANIZATION.OrganizationType; 46 | this.QueueApiNames = QueueMetadata.getQueueApiNames(); 47 | this.SobjectApiNames = this.getSobjectApiNames(sobjectTypes); 48 | } 49 | 50 | private List getSobjectApiNames(Map sobjectTypes) { 51 | // We could just use this.sobjectApiNames = new List(sobjectTypes.keySet()); 52 | // However, it returns the names in lowercase, which can cause problems with Javascript/Lightning since it's case-sensitive 53 | List sobjectApiNames = new List(); 54 | for(Schema.SobjectType sobjectType : sobjectTypes.values()) { 55 | sobjectApiNames.add(String.valueOf(sobjectType)); 56 | } 57 | sobjectApiNames.sort(); 58 | return sobjectApiNames; 59 | } 60 | 61 | } -------------------------------------------------------------------------------- /src/classes/EnvironmentMetadata.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 43.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/EnvironmentMetadata_Tests.cls: -------------------------------------------------------------------------------- 1 | /************************************************************************************************* 2 | * This file is part of the SimpleMetadata project, released under the MIT License. * 3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. * 4 | *************************************************************************************************/ 5 | @isTest 6 | private class EnvironmentMetadata_Tests { 7 | 8 | @isTest 9 | static void it_should_return_environment_metadata() { 10 | Test.startTest(); 11 | 12 | EnvironmentMetadata environmentMetadata = new EnvironmentMetadata(); 13 | validateAttributesAreSet(environmentMetadata); 14 | validateCaseSentivityForJavascript(environmentMetadata); 15 | 16 | Test.stopTest(); 17 | } 18 | 19 | @isTest 20 | static void it_should_cache_organization_object_query() { 21 | Test.startTest(); 22 | 23 | System.assertEquals(0, Limits.getQueries()); 24 | new EnvironmentMetadata(); 25 | Integer initialQueryCount = Limits.getQueries(); 26 | // Only the first initialization should use queries, multiple initializations should use cached results 27 | for(Integer i = 0; i < 10; i++) { 28 | new EnvironmentMetadata(); 29 | } 30 | System.assertEquals(initialQueryCount, Limits.getQueries()); 31 | 32 | Test.stopTest(); 33 | } 34 | 35 | private static void validateAttributesAreSet(EnvironmentMetadata environmentMetadata) { 36 | Organization organization = [SELECT Id, Name, InstanceName, NamespacePrefix, OrganizationType, IsSandbox FROM Organization LIMIT 1]; 37 | Map sobjectTypes = Schema.getGlobalDescribe(); 38 | 39 | System.assertEquals(URL.getSalesforceBaseUrl().toExternalForm(), environmentMetadata.BaseUrl); 40 | System.assertEquals(organization.InstanceName, environmentMetadata.InstanceName); 41 | System.assertEquals(sobjectTypes.containsKey('FeedItem'), environmentMetadata.IsChatterEnabled); 42 | System.assertEquals(sobjectTypes.containsKey('KnowledgeArticle'), environmentMetadata.IsKnowledgeEnabled); 43 | System.assertEquals(UserInfo.isMultiCurrencyOrganization(), environmentMetadata.IsMultiCurrencyEnabled); 44 | System.assertEquals(sobjectTypes.get('Account').getDescribe().fields.getMap().containsKey('IsPersonAccount'), environmentMetadata.IsPersonAccountEnabled); 45 | System.assertEquals(organization.IsSandbox == false, environmentMetadata.IsProduction); 46 | System.assertEquals(organization.IsSandbox, environmentMetadata.IsSandbox); 47 | System.assertEquals(sobjectTypes.containsKey('Territory'), environmentMetadata.IsTerritoryManagementEnabled); 48 | System.assertEquals(organization.NamespacePrefix, environmentMetadata.Namespace); 49 | System.assertEquals(organization.Id, environmentMetadata.OrganizationId); 50 | System.assertEquals(organization.Name, environmentMetadata.OrganizationName); 51 | System.assertEquals(organization.OrganizationType, environmentMetadata.OrganizationType); 52 | //System.assert(environmentMetadata.SobjectTypeNames.containsAll(sobjectTypes.keySet())); 53 | } 54 | 55 | private static void validateCaseSentivityForJavascript(EnvironmentMetadata environmentMetadata) { 56 | // Validate that the attributes are named exactly as expected so that javascript can rely on them 57 | String jsonEnvironmentMetadata = JSON.serialize(environmentMetadata); 58 | Map untypedEnvironmentMetadata = (Map)JSON.deserializeUntyped(jsonEnvironmentMetadata); 59 | 60 | // One negative to confirm that the strings in our map are case sensitive 61 | System.assert(untypedEnvironmentMetadata.containsKey('BASEURL') == false); 62 | // Now for the 'real' tests 63 | System.assert(untypedEnvironmentMetadata.containsKey('BaseUrl')); 64 | System.assert(untypedEnvironmentMetadata.containsKey('InstanceName')); 65 | System.assert(untypedEnvironmentMetadata.containsKey('IsChatterEnabled')); 66 | System.assert(untypedEnvironmentMetadata.containsKey('IsKnowledgeEnabled')); 67 | System.assert(untypedEnvironmentMetadata.containsKey('IsMultiCurrencyEnabled')); 68 | System.assert(untypedEnvironmentMetadata.containsKey('IsPersonAccountEnabled')); 69 | System.assert(untypedEnvironmentMetadata.containsKey('IsProduction')); 70 | System.assert(untypedEnvironmentMetadata.containsKey('IsSandbox')); 71 | System.assert(untypedEnvironmentMetadata.containsKey('IsTerritoryManagementEnabled')); 72 | System.assert(untypedEnvironmentMetadata.containsKey('Namespace')); 73 | System.assert(untypedEnvironmentMetadata.containsKey('OrganizationId')); 74 | System.assert(untypedEnvironmentMetadata.containsKey('OrganizationName')); 75 | System.assert(untypedEnvironmentMetadata.containsKey('OrganizationType')); 76 | System.assert(untypedEnvironmentMetadata.containsKey('SobjectApiNames')); 77 | } 78 | 79 | } -------------------------------------------------------------------------------- /src/classes/EnvironmentMetadata_Tests.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 43.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/FieldMetadata.cls: -------------------------------------------------------------------------------- 1 | /************************************************************************************************* 2 | * This file is part of the SimpleMetadata project, released under the MIT License. * 3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. * 4 | *************************************************************************************************/ 5 | global class FieldMetadata { 6 | 7 | @AuraEnabled global final String ApiName {get; private set;} 8 | @AuraEnabled global final Integer ByteLength {get; private set;} 9 | @AuraEnabled global final Object DefaultValue {get; private set;} 10 | @AuraEnabled global final Integer Digits {get; private set;} 11 | @AuraEnabled global final String DisplayType {get; private set;} 12 | @AuraEnabled global final String InlineHelpText {get; private set;} 13 | @AuraEnabled global final Boolean IsAccessible {get; private set;} 14 | @AuraEnabled global final Boolean IsAutoNumber {get; private set;} 15 | @AuraEnabled global final Boolean IsCalculated {get; private set;} 16 | @AuraEnabled global final Boolean IsCaseSensitive {get; private set;} 17 | @AuraEnabled global final Boolean IsCreateable {get; private set;} 18 | @AuraEnabled global final Boolean IsCustom {get; private set;} 19 | @AuraEnabled global final Boolean IsDefaultedOnCreate {get; private set;} 20 | @AuraEnabled global final Boolean IsFilterable {get; private set;} 21 | @AuraEnabled global final Boolean IsGroupable {get; private set;} 22 | @AuraEnabled global final Boolean IsNameField {get; private set;} 23 | @AuraEnabled global final Boolean IsNillable {get; private set;} 24 | @AuraEnabled global final Boolean IsNamePointing {get; private set;} 25 | @AuraEnabled global final Boolean IsRequired {get; private set;} 26 | @AuraEnabled global final Boolean IsSortable {get; private set;} 27 | @AuraEnabled global final Boolean IsUpdateable {get; private set;} 28 | @AuraEnabled global final String Label {get; private set;} 29 | @AuraEnabled global final String LocalApiName {get; private set;} 30 | @AuraEnabled global final Integer MaxLength {get; private set;} 31 | @AuraEnabled global final String Namespace {get; private set;} 32 | @AuraEnabled global final List PicklistOptions {get; private set;} 33 | @AuraEnabled global final Integer Precision {get; private set;} 34 | @AuraEnabled global final String RelationshipApiName {get; private set;} 35 | @AuraEnabled global final Integer RelationshipOrder {get; private set;} 36 | @AuraEnabled global final List RelationshipReferences {get; private set;} 37 | @AuraEnabled global final Integer Scale {get; private set;} 38 | @AuraEnabled global final String SobjectApiName {get; private set;} 39 | 40 | global FieldMetadata(String sobjectApiName, String fieldApiName) { 41 | this( 42 | Schema.getGlobalDescribe().get(sobjectApiName), 43 | Schema.getGlobalDescribe().get(sobjectApiName).getDescribe().fields.getMap().get(fieldApiName) 44 | ); 45 | } 46 | 47 | global FieldMetadata(Schema.SobjectType sobjectType, Schema.SobjectField sobjectField) { 48 | Schema.DescribeSobjectResult sobjectDescribe = sobjectType.getDescribe(); 49 | Schema.DescribeFieldResult fieldDescribe = sobjectField.getDescribe(); 50 | 51 | this.ApiName = String.valueOf(sobjectField); 52 | this.ByteLength = fieldDescribe.getByteLength(); 53 | this.DefaultValue = fieldDescribe.getDefaultValue(); 54 | this.Digits = fieldDescribe.getDigits(); 55 | this.DisplayType = fieldDescribe.getType().name(); 56 | this.InlineHelpText = fieldDescribe.getInlineHelpText(); 57 | this.IsAccessible = fieldDescribe.isAccessible(); 58 | this.IsAutoNumber = fieldDescribe.isAutoNumber(); 59 | this.IsCalculated = fieldDescribe.isCalculated(); 60 | this.IsCaseSensitive = fieldDescribe.isCaseSensitive(); 61 | this.IsCreateable = fieldDescribe.isCreateable(); 62 | this.IsCustom = fieldDescribe.isCustom(); 63 | this.IsDefaultedOnCreate = fieldDescribe.isDefaultedOnCreate(); 64 | this.IsFilterable = fieldDescribe.isFilterable(); 65 | this.IsGroupable = fieldDescribe.isGroupable(); 66 | this.IsNameField = fieldDescribe.isNameField(); 67 | this.IsNillable = fieldDescribe.isNillable(); 68 | this.IsNamePointing = fieldDescribe.isNamePointing(); 69 | this.IsRequired = fieldDescribe.isNillable() == false && fieldDescribe.isCreateable(); // If a field is NOT nillable, then it's required 70 | this.IsSortable = fieldDescribe.isSortable(); 71 | this.IsUpdateable = fieldDescribe.isUpdateable(); 72 | this.Label = fieldDescribe.getLabel(); 73 | this.LocalApiName = fieldDescribe.getLocalName(); 74 | this.MaxLength = fieldDescribe.getLength(); 75 | this.Namespace = this.getNamespace(); 76 | this.PicklistOptions = this.getPicklistOptions(fieldDescribe); 77 | this.Precision = fieldDescribe.getPrecision(); 78 | this.RelationshipApiName = fieldDescribe.getRelationshipName(); 79 | this.RelationshipOrder = fieldDescribe.getRelationshipOrder(); 80 | this.RelationshipReferences = this.getRelationshipReferences(fieldDescribe); 81 | this.Scale = fieldDescribe.getScale(); 82 | this.SobjectApiName = String.valueOf(sobjectType); 83 | } 84 | 85 | private String getNamespace() { 86 | Integer localNameIndex = this.apiName.replace('__c', '').indexOf('__'); 87 | return localNameIndex < 0 ? null : this.apiName.substring(0, localNameIndex); 88 | } 89 | 90 | private List getPicklistOptions(Schema.DescribeFieldResult fieldDescribe) { 91 | List picklistOptions = new List(); 92 | 93 | if(fieldDescribe.getPickListValues().isEmpty()) return picklistOptions; 94 | 95 | picklistOptions.add(new PicklistEntryMetadata()); // Add an empty picklist value 96 | for(Schema.PicklistEntry picklistEntry : fieldDescribe.getPickListValues()) { 97 | picklistOptions.add(new PicklistEntryMetadata(picklistEntry)); 98 | } 99 | return picklistOptions; 100 | } 101 | 102 | private List getRelationshipReferences(Schema.DescribeFieldResult fieldDescribe) { 103 | List relationshipReferences = new List(); 104 | for(Schema.SobjectType sobjectType : fieldDescribe.getReferenceTo()) { 105 | relationshipReferences.add(new SobjectMetadata(sobjectType)); 106 | } 107 | return relationshipReferences; 108 | } 109 | 110 | global class PicklistEntryMetadata { 111 | 112 | @AuraEnabled global final Boolean IsDefaultValue {get; private set;} 113 | @AuraEnabled global final String Label {get; private set;} 114 | @AuraEnabled global final String Value {get; private set;} 115 | 116 | global PicklistEntryMetadata() { 117 | this.IsDefaultValue = false; 118 | this.Label = ''; 119 | this.Value = ''; 120 | } 121 | 122 | global PicklistEntryMetadata(Schema.PicklistEntry picklistEntry) { 123 | this.IsDefaultValue = picklistEntry.isDefaultValue(); 124 | this.Label = picklistEntry.getLabel(); 125 | this.Value = picklistEntry.getValue(); 126 | } 127 | 128 | } 129 | 130 | } -------------------------------------------------------------------------------- /src/classes/FieldMetadata.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 43.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/FieldMetadata_Tests.cls: -------------------------------------------------------------------------------- 1 | /************************************************************************************************* 2 | * This file is part of the SimpleMetadata project, released under the MIT License. * 3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. * 4 | *************************************************************************************************/ 5 | @isTest 6 | private class FieldMetadata_Tests { 7 | 8 | @isTest 9 | static void it_should_return_metadata_for_sobject_name_and_field_api_name() { 10 | String sobjectname = 'Account'; 11 | String fieldName = 'Name'; 12 | 13 | Test.startTest(); 14 | 15 | FieldMetadata accountFieldMetadata = new FieldMetadata(sobjectName, fieldName); 16 | validateAttributesAreSet(String.valueOf(fieldName), accountFieldMetadata); 17 | validateCaseSentivityForJavascript(accountFieldMetadata); 18 | 19 | Test.stopTest(); 20 | } 21 | 22 | @isTest 23 | static void it_should_return_metadata_for_sobject_type_token_and_field_token() { 24 | SobjectType accountSobjectType = Account.SobjectType; 25 | SobjectField accountNameField = Account.Name; 26 | 27 | Test.startTest(); 28 | 29 | FieldMetadata accountFieldMetadata = new FieldMetadata(accountSobjectType, accountNameField); 30 | validateAttributesAreSet(String.valueOf(accountNameField), accountFieldMetadata); 31 | validateCaseSentivityForJavascript(accountFieldMetadata); 32 | 33 | Test.stopTest(); 34 | } 35 | 36 | @isTest 37 | static void it_should_return_metadata_for_account_parentid_lookup_field_token() { 38 | SobjectField parentIdField = Account.ParentId; 39 | 40 | Test.startTest(); 41 | 42 | FieldMetadata accountFieldMetadata = new FieldMetadata(Account.SobjectType, parentIdField); 43 | validateAttributesAreSet(String.valueOf(parentIdField), accountFieldMetadata); 44 | validateCaseSentivityForJavascript(accountFieldMetadata); 45 | 46 | Test.stopTest(); 47 | } 48 | 49 | @isTest 50 | static void it_should_return_metadata_for_account_type_picklist_field_token() { 51 | SobjectField typeField = Account.Type; 52 | 53 | Test.startTest(); 54 | 55 | FieldMetadata accountFieldMetadata = new FieldMetadata(Account.SobjectType, typeField); 56 | validateAttributesAreSet(String.valueOf(typeField), accountFieldMetadata); 57 | validateCaseSentivityForJavascript(accountFieldMetadata); 58 | 59 | Test.stopTest(); 60 | } 61 | 62 | private static void validateAttributesAreSet(String fieldName, FieldMetadata fieldMetadata) { 63 | String sobjectName = 'Account'; 64 | DescribeFieldResult fieldDescribe = Schema.SobjectType.Account.fields.getMap().get(fieldName).getDescribe(); 65 | 66 | System.assertEquals(fieldDescribe.getName(), fieldMetadata.ApiName); 67 | System.assertEquals(fieldDescribe.getByteLength(), fieldMetadata.ByteLength); 68 | System.assertEquals(fieldDescribe.getDefaultValue(), fieldMetadata.DefaultValue); 69 | System.assertEquals(fieldDescribe.getDigits(), fieldMetadata.Digits); 70 | System.assertEquals(fieldDescribe.getType().name(), fieldMetadata.DisplayType); 71 | System.assertEquals(fieldDescribe.getInlineHelpText(), fieldMetadata.InlineHelpText); 72 | System.assertEquals(fieldDescribe.isAccessible(), fieldMetadata.IsAccessible); 73 | System.assertEquals(fieldDescribe.isAutoNumber(), fieldMetadata.IsAutoNumber); 74 | System.assertEquals(fieldDescribe.isCalculated(), fieldMetadata.IsCalculated); 75 | System.assertEquals(fieldDescribe.isCaseSensitive(), fieldMetadata.IsCaseSensitive); 76 | System.assertEquals(fieldDescribe.isCreateable(), fieldMetadata.IsCreateable); 77 | System.assertEquals(fieldDescribe.isCustom(), fieldMetadata.IsCustom); 78 | System.assertEquals(fieldDescribe.isDefaultedOnCreate(), fieldMetadata.IsDefaultedOnCreate); 79 | System.assertEquals(fieldDescribe.isFilterable(), fieldMetadata.IsFilterable); 80 | System.assertEquals(fieldDescribe.isGroupable(), fieldMetadata.IsGroupable); 81 | System.assertEquals(fieldDescribe.isNameField(), fieldMetadata.IsNameField); 82 | System.assertEquals(fieldDescribe.isNillable(), fieldMetadata.IsNillable); 83 | System.assertEquals(fieldDescribe.isNillable() == false && fieldDescribe.isCreateable(), fieldMetadata.IsRequired); 84 | System.assertEquals(fieldDescribe.isSortable(), fieldMetadata.IsSortable); 85 | System.assertEquals(fieldDescribe.isUpdateable(), fieldMetadata.IsUpdateable); 86 | System.assertEquals(fieldDescribe.getLabel(), fieldMetadata.Label); 87 | System.assertEquals(fieldDescribe.getLocalName(), fieldMetadata.LocalApiName); 88 | System.assertEquals(fieldDescribe.getLength(), fieldMetadata.MaxLength); 89 | //System.assertEquals(this.getNamespace(), fieldMetadata.namespace); 90 | //System.assertEquals(this.getPicklistOptions(fieldDescribe), fieldMetadata.picklistOptions); 91 | System.assertEquals(fieldDescribe.getPrecision(), fieldMetadata.Precision); 92 | System.assertEquals(fieldDescribe.getRelationshipName(), fieldMetadata.RelationshipApiName); 93 | System.assertEquals(fieldDescribe.getRelationshipOrder(), fieldMetadata.RelationshipOrder); 94 | //System.assertEquals( this.getRelationshipReferences(fieldDescribe), fieldMetadata.RelationshipReferences); 95 | System.assertEquals(fieldDescribe.getScale(), fieldMetadata.Scale); 96 | System.assertEquals(sobjectName, fieldMetadata.SobjectApiName); 97 | } 98 | 99 | private static void validateCaseSentivityForJavascript(FieldMetadata fieldMetadata) { 100 | // Validate that the attributes are named exactly as expected so that javascript can rely on them 101 | String jsonFieldMetadata = JSON.serialize(fieldMetadata); 102 | Map untypedFieldMetadata = (Map)JSON.deserializeUntyped(jsonFieldMetadata); 103 | 104 | // One negative to confirm that the strings in our map are case sensitive 105 | System.assert(untypedFieldMetadata.containsKey('APINAME') == false); 106 | // Now for the 'real' tests 107 | System.assert(untypedFieldMetadata.containsKey('ApiName')); 108 | System.assert(untypedFieldMetadata.containsKey('ByteLength')); 109 | System.assert(untypedFieldMetadata.containsKey('DefaultValue')); 110 | System.assert(untypedFieldMetadata.containsKey('Digits')); 111 | System.assert(untypedFieldMetadata.containsKey('DisplayType')); 112 | System.assert(untypedFieldMetadata.containsKey('InlineHelpText')); 113 | System.assert(untypedFieldMetadata.containsKey('IsAccessible')); 114 | System.assert(untypedFieldMetadata.containsKey('IsAutoNumber')); 115 | System.assert(untypedFieldMetadata.containsKey('IsCalculated')); 116 | System.assert(untypedFieldMetadata.containsKey('IsCaseSensitive')); 117 | System.assert(untypedFieldMetadata.containsKey('IsCreateable')); 118 | System.assert(untypedFieldMetadata.containsKey('IsCustom')); 119 | System.assert(untypedFieldMetadata.containsKey('IsDefaultedOnCreate')); 120 | System.assert(untypedFieldMetadata.containsKey('IsFilterable')); 121 | System.assert(untypedFieldMetadata.containsKey('IsGroupable')); 122 | System.assert(untypedFieldMetadata.containsKey('IsNameField')); 123 | System.assert(untypedFieldMetadata.containsKey('IsNillable')); 124 | System.assert(untypedFieldMetadata.containsKey('IsRequired')); 125 | System.assert(untypedFieldMetadata.containsKey('IsSortable')); 126 | System.assert(untypedFieldMetadata.containsKey('IsUpdateable')); 127 | System.assert(untypedFieldMetadata.containsKey('Label')); 128 | System.assert(untypedFieldMetadata.containsKey('LocalApiName')); 129 | System.assert(untypedFieldMetadata.containsKey('MaxLength')); 130 | System.assert(untypedFieldMetadata.containsKey('Namespace')); 131 | System.assert(untypedFieldMetadata.containsKey('PicklistOptions')); 132 | System.assert(untypedFieldMetadata.containsKey('Precision')); 133 | System.assert(untypedFieldMetadata.containsKey('RelationshipApiName')); 134 | System.assert(untypedFieldMetadata.containsKey('RelationshipOrder')); 135 | System.assert(untypedFieldMetadata.containsKey('RelationshipReferences')); 136 | System.assert(untypedFieldMetadata.containsKey('Scale')); 137 | System.assert(untypedFieldMetadata.containsKey('SobjectApiName')); 138 | } 139 | 140 | } -------------------------------------------------------------------------------- /src/classes/FieldMetadata_Tests.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 43.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/FieldSetMetadata.cls: -------------------------------------------------------------------------------- 1 | /************************************************************************************************* 2 | * This file is part of the SimpleMetadata project, released under the MIT License. * 3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. * 4 | *************************************************************************************************/ 5 | global class FieldSetMetadata { 6 | 7 | @AuraEnabled global final String ApiName {get; private set;} 8 | @AuraEnabled global final String Description {get; private set;} 9 | @AuraEnabled global final List FieldSetMembers {get; private set;} 10 | @AuraEnabled global final String Label {get; private set;} 11 | @AuraEnabled global final String LocalApiName {get; private set;} 12 | @AuraEnabled global final String Namespace {get; private set;} 13 | @AuraEnabled global final String SobjectApiName {get; private set;} 14 | 15 | global FieldSetMetadata(String sobjectApiName, String fieldSetApiName) { 16 | this(Schema.getGlobalDescribe().get(sobjectApiName).getDescribe().fieldSets.getMap().get(fieldSetApiName)); 17 | } 18 | 19 | global FieldSetMetadata(Schema.FieldSet fieldSet) { 20 | this.ApiName = this.getApiName(fieldSet); 21 | this.Description = fieldSet.getDescription(); 22 | this.FieldSetMembers = this.getFieldSetMembers(fieldSet); 23 | this.Label = fieldSet.getLabel(); 24 | this.LocalApiName = fieldSet.getName(); 25 | this.Namespace = fieldSet.getNamespace(); 26 | this.SobjectApiName = String.valueOf(fieldSet.getSobjectType()); 27 | } 28 | 29 | private String getApiName(Schema.FieldSet fieldSet) { 30 | String namespace = fieldSet.getNamespace() == null ? '' : fieldSet.getNamespace() + '__'; 31 | return namespace + fieldSet.getName(); 32 | } 33 | 34 | private List getFieldSetMembers(Schema.FieldSet fieldSet) { 35 | List fieldSetMembers = new List(); 36 | for(Schema.FieldSetMember fieldSetMember : fieldSet.getFields()) { 37 | FieldSetMemberMetadata fieldSetMemberMetadata = new FieldSetMemberMetadata(fieldSet.getSobjectType(), fieldSetMember); 38 | 39 | fieldSetMembers.add(fieldSetMemberMetadata); 40 | } 41 | fieldSetMembers.sort(); 42 | return fieldSetMembers; 43 | } 44 | 45 | global class FieldSetMemberMetadata implements Comparable { 46 | 47 | @AuraEnabled global final String DisplayType {get; private set;} 48 | @AuraEnabled global final FieldMetadata Field {get; private set;} 49 | @AuraEnabled global final String FieldPath {get; private set;} 50 | @AuraEnabled global final Boolean IsDbRequired {get; private set;} 51 | @AuraEnabled global final Boolean IsRequired {get; private set;} 52 | @AuraEnabled global final String Label {get; private set;} 53 | @AuraEnabled global final String SobjectApiName {get; private set;} 54 | 55 | global Integer compareTo(Object compareTo) { 56 | FieldSetMemberMetadata compareToFieldSetMember = (FieldSetMemberMetadata)compareTo; 57 | 58 | if(this.FieldPath == compareToFieldSetMember.FieldPath) return 0; 59 | else if(this.FieldPath > compareToFieldSetMember.FieldPath) return 1; 60 | else return -1; 61 | } 62 | 63 | private FieldSetMemberMetadata(Schema.SobjectType sobjectType, Schema.FieldSetMember fieldSetMember) { 64 | this.DisplayType = fieldSetMember.getType().name(); 65 | this.Field = this.getFieldMetadata(sobjectType, fieldSetMember); 66 | this.FieldPath = fieldSetMember.getFieldPath(); 67 | this.IsDbRequired = fieldSetMember.getDbRequired(); 68 | this.IsRequired = fieldSetMember.getRequired(); 69 | this.Label = fieldSetMember.getLabel(); 70 | this.SobjectApiName = String.valueOf(sobjectType); 71 | } 72 | 73 | private FieldMetadata getFieldMetadata(Schema.SobjectType sobjectType, Schema.FieldSetMember fieldSetMember) { 74 | FieldMetadata fieldMetadata; 75 | 76 | List fieldChain = fieldSetMember.getFieldPath().split('\\.'); 77 | 78 | if(fieldChain.size() == 0) return fieldMetadata; 79 | 80 | Schema.SobjectType currentFieldSobjectType = Schema.getGlobalDescribe().get(this.sobjectApiName); 81 | String currentFieldSobjectApiName = String.valueOf(sobjectType); 82 | String currentFieldApiName; 83 | 84 | for(Integer i = 0; i < fieldChain.size(); i++) { 85 | currentFieldApiName = fieldChain[i]; 86 | 87 | for(Schema.SobjectField sobjectField : Schema.getGlobalDescribe().get(currentFieldSobjectApiName).getDescribe().fields.getMap().values()) { 88 | DescribeFieldResult fieldDescribe = sobjectField.getDescribe(); 89 | 90 | if(fieldDescribe.getRelationshipName() != currentFieldApiName) continue; 91 | if(fieldDescribe.getReferenceTo().isEmpty()) continue; 92 | 93 | currentFieldSobjectType = fieldDescribe.getReferenceTo()[0]; 94 | currentFieldSobjectApiName = currentFieldSobjectType.getDescribe().getName(); 95 | break; 96 | } 97 | } 98 | 99 | return new FieldMetadata(currentFieldSobjectApiName, currentFieldApiName); 100 | } 101 | 102 | } 103 | 104 | } -------------------------------------------------------------------------------- /src/classes/FieldSetMetadata.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 43.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/FieldSetMetadata_Tests.cls: -------------------------------------------------------------------------------- 1 | /************************************************************************************************* 2 | * This file is part of the SimpleMetadata project, released under the MIT License. * 3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. * 4 | *************************************************************************************************/ 5 | @isTest 6 | private class FieldSetMetadata_Tests { 7 | 8 | @isTest 9 | static void it_should_return_metadata_for_sobject_api_name_and_field_set_api_name() { 10 | Schema.FieldSet fieldSet = getFieldSet(); 11 | if(fieldSet == null) return; 12 | 13 | Test.startTest(); 14 | 15 | String sobjectName = String.valueOf(fieldSet.getSobjectType()); 16 | String fieldSetNamespace = fieldSet.getNamespace() == null ? '' : fieldSet.getNamespace() + '__'; 17 | String fieldSetName = fieldSetNamespace + fieldSet.getName(); 18 | FieldSetMetadata fieldSetMetadata = new FieldSetMetadata(sobjectName, fieldSetName); 19 | validateAttributesAreSet(fieldSet, fieldSetMetadata); 20 | validateCaseSentivityForJavascript(fieldSetMetadata); 21 | 22 | Test.stopTest(); 23 | } 24 | 25 | @isTest 26 | static void it_should_return_metadata_for_field_set_token() { 27 | Schema.FieldSet fieldSet = getFieldSet(); 28 | if(fieldSet == null) return; 29 | 30 | Test.startTest(); 31 | 32 | FieldSetMetadata fieldSetMetadata = new FieldSetMetadata(fieldSet); 33 | validateAttributesAreSet(fieldSet, fieldSetMetadata); 34 | validateCaseSentivityForJavascript(fieldSetMetadata); 35 | 36 | Test.stopTest(); 37 | } 38 | 39 | private static Schema.FieldSet getFieldSet() { 40 | // Dynamically check for field sets in some of the most commonly used objects 41 | // If not results are found, then test coverage will drop 42 | List commonSobjectNames = new List{ 43 | 'Account', 'Lead', 'Contact', 'Opportunity' 44 | }; 45 | for(String sobjectName : commonSobjectNames) { 46 | Schema.DescribeSobjectResult sobjectDescribe = Schema.getGlobalDescribe().get(sobjectName).getDescribe(); 47 | // If there are any fields sets found, return the first one 48 | if(sobjectDescribe.fieldSets.getMap().isEmpty() == false) return sobjectDescribe.fieldSets.getMap().values()[0]; 49 | } 50 | return null; 51 | } 52 | 53 | private static void validateAttributesAreSet(Schema.FieldSet fieldSet, FieldSetMetadata fieldSetMetadata) { 54 | String namespacePrefix = ''; 55 | if(fieldSet.getNamespace() != null) namespacePrefix = fieldSet.getNamespace() + '__'; 56 | String fieldSetName = namespacePrefix + fieldSet.getName(); 57 | 58 | System.assertEquals(fieldSetName, fieldSetMetadata.ApiName); 59 | System.assertEquals(fieldSet.getDescription(), fieldSetMetadata.Description); 60 | System.assertEquals(fieldSet.getFields().size(), fieldSetMetadata.FieldSetMembers.size()); 61 | // TODO add asserts for field set members' field metadata 62 | System.assertEquals(fieldSet.getLabel(), fieldSetMetadata.Label); 63 | // TODO add assert for localName 64 | System.assertEquals(fieldSet.getNamespace(), fieldSetMetadata.Namespace); 65 | System.assertEquals(String.valueOf(fieldSet.getSobjectType()), fieldSetMetadata.SobjectApiName); 66 | } 67 | 68 | private static void validateCaseSentivityForJavascript(FieldSetMetadata fieldSetMetadata) { 69 | // Validate that the attributes are named exactly as expected so that javascript can rely on them 70 | String jsonFieldSetMetadata = JSON.serialize(fieldSetMetadata); 71 | Map untypedFieldSetMetadata = (Map)JSON.deserializeUntyped(jsonFieldSetMetadata); 72 | 73 | // One negative to confirm that the strings in our map are case sensitive 74 | System.assert(untypedFieldSetMetadata.containsKey('APINAME') == false); 75 | // Now for the 'real' tests 76 | System.assert(untypedFieldSetMetadata.containsKey('ApiName')); 77 | System.assert(untypedFieldSetMetadata.containsKey('Description')); 78 | System.assert(untypedFieldSetMetadata.containsKey('FieldSetMembers')); 79 | System.assert(untypedFieldSetMetadata.containsKey('Label')); 80 | System.assert(untypedFieldSetMetadata.containsKey('LocalApiName')); 81 | System.assert(untypedFieldSetMetadata.containsKey('Namespace')); 82 | System.assert(untypedFieldSetMetadata.containsKey('SobjectApiName')); 83 | // TODO add asserts for FieldSetMembers 84 | } 85 | 86 | } -------------------------------------------------------------------------------- /src/classes/FieldSetMetadata_Tests.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 43.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/LimitsMetadata.cls: -------------------------------------------------------------------------------- 1 | /************************************************************************************************* 2 | * This file is part of the SimpleMetadata project, released under the MIT License. * 3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. * 4 | *************************************************************************************************/ 5 | global class LimitsMetadata { 6 | 7 | @AuraEnabled global final LimitUsageMetadata AggregateQueries {get; private set;} 8 | @AuraEnabled global final LimitUsageMetadata AsyncCalls {get; private set;} 9 | @AuraEnabled global final LimitUsageMetadata Callouts {get; private set;} 10 | @AuraEnabled global final LimitUsageMetadata CpuTime {get; private set;} 11 | @AuraEnabled global final LimitUsageMetadata DmlRows {get; private set;} 12 | @AuraEnabled global final LimitUsageMetadata DmlStatements {get; private set;} 13 | @AuraEnabled global final LimitUsageMetadata EmailInvocations {get; private set;} 14 | @AuraEnabled global final LimitUsageMetadata FutureCalls {get; private set;} 15 | @AuraEnabled global final LimitUsageMetadata HeapSize {get; private set;} 16 | @AuraEnabled global final LimitUsageMetadata MobilePushApexCalls {get; private set;} 17 | @AuraEnabled global final LimitUsageMetadata QueueableJobs {get; private set;} 18 | @AuraEnabled global final LimitUsageMetadata SoqlQueryLocatorRows {get; private set;} 19 | @AuraEnabled global final LimitUsageMetadata SoqlQueryRows {get; private set;} 20 | @AuraEnabled global final LimitUsageMetadata SoqlQueries {get; private set;} 21 | @AuraEnabled global final LimitUsageMetadata SoslSearches {get; private set;} 22 | 23 | global LimitsMetadata() { 24 | this.AggregateQueries = new LimitUsageMetadata(Limits.getAggregateQueries(), Limits.getLimitAggregateQueries()); 25 | this.AsyncCalls = new LimitUsageMetadata(Limits.getAsyncCalls(), Limits.getLimitAsyncCalls()); 26 | this.Callouts = new LimitUsageMetadata(Limits.getCallouts(), Limits.getLimitCallouts()); 27 | this.CpuTime = new LimitUsageMetadata(Limits.getCPUTime(), Limits.getLimitCPUTime()); 28 | this.DmlRows = new LimitUsageMetadata(Limits.getDmlRows(), Limits.getLimitDmlRows()); 29 | this.DmlStatements = new LimitUsageMetadata(Limits.getDmlStatements(), Limits.getLimitDmlStatements()); 30 | this.EmailInvocations = new LimitUsageMetadata(Limits.getEmailInvocations(), Limits.getLimitEmailInvocations()); 31 | this.FutureCalls = new LimitUsageMetadata(Limits.getFutureCalls(), Limits.getLimitFutureCalls()); 32 | this.HeapSize = new LimitUsageMetadata(Limits.getHeapSize(), Limits.getLimitHeapSize()); 33 | this.MobilePushApexCalls = new LimitUsageMetadata(Limits.getMobilePushApexCalls(), Limits.getLimitMobilePushApexCalls()); 34 | this.QueueableJobs = new LimitUsageMetadata(Limits.getQueueableJobs(), Limits.getLimitQueueableJobs()); 35 | this.SoqlQueries = new LimitUsageMetadata(Limits.getQueries(), Limits.getLimitQueries()); 36 | this.SoqlQueryLocatorRows = new LimitUsageMetadata(Limits.getQueryLocatorRows(), Limits.getLimitQueryLocatorRows()); 37 | this.SoqlQueryRows = new LimitUsageMetadata(Limits.getQueryRows(), Limits.getLimitQueryRows()); 38 | this.SoslSearches = new LimitUsageMetadata(Limits.getSoslQueries(), Limits.getLimitSoslQueries()); 39 | } 40 | 41 | global class LimitUsageMetadata { 42 | 43 | @AuraEnabled global final Integer Max {get; private set;} 44 | @AuraEnabled global final Integer Used {get; private set;} 45 | 46 | global LimitUsageMetadata(Integer used, Integer max){ 47 | this.Max = max; 48 | this.Used = used; 49 | } 50 | 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /src/classes/LimitsMetadata.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 43.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/LimitsMetadata_Tests.cls: -------------------------------------------------------------------------------- 1 | /************************************************************************************************* 2 | * This file is part of the SimpleMetadata project, released under the MIT License. * 3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. * 4 | *************************************************************************************************/ 5 | @isTest 6 | private class LimitsMetadata_Tests { 7 | 8 | @isTest 9 | static void it_should_return_limits_metadata() { 10 | LimitsMetadata limitsMetadata = new LimitsMetadata(); 11 | validateAttributesAreSet(limitsMetadata); 12 | validateCaseSentivityForJavascript(limitsMetadata); 13 | } 14 | 15 | private static void validateAttributesAreSet(LimitsMetadata limitsMetadata) { 16 | System.assertEquals(Limits.getAggregateQueries(), limitsMetadata.AggregateQueries.Used); 17 | System.assertEquals(Limits.getLimitAggregateQueries(), limitsMetadata.AggregateQueries.Max); 18 | System.assertEquals(Limits.getAsyncCalls(), limitsMetadata.AsyncCalls.Used); 19 | System.assertEquals(Limits.getLimitAsyncCalls(), limitsMetadata.AsyncCalls.Max); 20 | System.assertEquals(Limits.getCallouts(), limitsMetadata.Callouts.Used); 21 | System.assertEquals(Limits.getLimitCallouts(), limitsMetadata.Callouts.Max); 22 | //System.assertEquals(Limits.getCPUTime(), limitsMetadata.CpuTime.Used); 23 | System.assertEquals(Limits.getLimitCPUTime(), limitsMetadata.CpuTime.Max); 24 | System.assertEquals(Limits.getDMLRows(), limitsMetadata.DmlRows.Used); 25 | System.assertEquals(Limits.getLimitDMLRows(), limitsMetadata.DmlRows.Max); 26 | System.assertEquals(Limits.getDMLStatements(), limitsMetadata.DmlStatements.Used); 27 | System.assertEquals(Limits.getLimitDMLStatements(), limitsMetadata.DmlStatements.Max); 28 | System.assertEquals(Limits.getEmailInvocations(), limitsMetadata.EmailInvocations.Used); 29 | System.assertEquals(Limits.getLimitEmailInvocations(), limitsMetadata.EmailInvocations.Max); 30 | System.assertEquals(Limits.getFutureCalls(), limitsMetadata.FutureCalls.Used); 31 | System.assertEquals(Limits.getLimitFutureCalls(), limitsMetadata.FutureCalls.Max); 32 | //System.assertEquals(Limits.getHeapSize(), limitsMetadata.HeapSize.Used); 33 | System.assertEquals(Limits.getLimitHeapSize(), limitsMetadata.HeapSize.Max); 34 | System.assertEquals(Limits.getMobilePushApexCalls(), limitsMetadata.MobilePushApexCalls.Used); 35 | System.assertEquals(Limits.getLimitMobilePushApexCalls(), limitsMetadata.MobilePushApexCalls.Max); 36 | System.assertEquals(Limits.getQueueableJobs(), limitsMetadata.QueueableJobs.Used); 37 | System.assertEquals(Limits.getLimitQueueableJobs(), limitsMetadata.QueueableJobs.Max); 38 | System.assertEquals(Limits.getQueries(), limitsMetadata.SoqlQueries.Used); 39 | System.assertEquals(Limits.getLimitQueries(), limitsMetadata.SoqlQueries.Max); 40 | System.assertEquals(Limits.getQueryLocatorRows(), limitsMetadata.SoqlQueryLocatorRows.Used); 41 | System.assertEquals(Limits.getLimitQueryLocatorRows(), limitsMetadata.SoqlQueryLocatorRows.Max); 42 | System.assertEquals(Limits.getQueryRows(), limitsMetadata.SoqlQueryRows.Used); 43 | System.assertEquals(Limits.getLimitQueryRows(), limitsMetadata.SoqlQueryRows.Max); 44 | System.assertEquals(Limits.getSOSLQueries(), limitsMetadata.SoslSearches.Used); 45 | System.assertEquals(Limits.getLimitSoslQueries(), limitsMetadata.SoslSearches.Max); 46 | } 47 | 48 | private static void validateCaseSentivityForJavascript(LimitsMetadata limitsMetadata) { 49 | // Validate that the attributes are named exactly as expected so that javascript can rely on them 50 | String jsonLimitsMetadata = JSON.serialize(limitsMetadata); 51 | Map untypedLimitsMetadata = (Map)JSON.deserializeUntyped(jsonLimitsMetadata); 52 | 53 | // One negative to confirm that the strings in our map are case sensitive 54 | System.assert(untypedLimitsMetadata.containsKey('AGGREGATEQUERIES') == false); 55 | // Now for the 'real' tests 56 | System.assert(untypedLimitsMetadata.containsKey('AggregateQueries')); 57 | System.assert(untypedLimitsMetadata.containsKey('AsyncCalls')); 58 | System.assert(untypedLimitsMetadata.containsKey('Callouts')); 59 | System.assert(untypedLimitsMetadata.containsKey('CpuTime')); 60 | System.assert(untypedLimitsMetadata.containsKey('DmlRows')); 61 | System.assert(untypedLimitsMetadata.containsKey('DmlStatements')); 62 | System.assert(untypedLimitsMetadata.containsKey('EmailInvocations')); 63 | System.assert(untypedLimitsMetadata.containsKey('FutureCalls')); 64 | System.assert(untypedLimitsMetadata.containsKey('HeapSize')); 65 | System.assert(untypedLimitsMetadata.containsKey('MobilePushApexCalls')); 66 | System.assert(untypedLimitsMetadata.containsKey('QueueableJobs')); 67 | System.assert(untypedLimitsMetadata.containsKey('SoqlQueries')); 68 | System.assert(untypedLimitsMetadata.containsKey('SoqlQueryLocatorRows')); 69 | System.assert(untypedLimitsMetadata.containsKey('SoqlQueryRows')); 70 | System.assert(untypedLimitsMetadata.containsKey('SoslSearches')); 71 | } 72 | 73 | } -------------------------------------------------------------------------------- /src/classes/LimitsMetadata_Tests.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 43.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/QueueMetadata.cls: -------------------------------------------------------------------------------- 1 | /************************************************************************************************* 2 | * This file is part of the SimpleMetadata project, released under the MIT License. * 3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. * 4 | *************************************************************************************************/ 5 | global class QueueMetadata { 6 | 7 | // Stores cached query results 8 | private static final Map QUERIED_QUEUES_BY_ID; 9 | private static final Map QUERIED_QUEUES_BY_DEVELOPER_NAME; 10 | 11 | static { 12 | // Query & cache queues 13 | QUERIED_QUEUES_BY_ID = new Map(); 14 | QUERIED_QUEUES_BY_DEVELOPER_NAME = new Map(); 15 | 16 | for(Group queue : [ 17 | SELECT DeveloperName, DoesIncludeBosses, DoesSendEmailToMembers, Email, Id, Name, 18 | (SELECT SobjectType FROM QueueSobjects), 19 | (SELECT Id, GroupId, UserOrGroupId FROM GroupMembers) 20 | FROM Group 21 | WHERE Type = 'Queue' 22 | ]) { 23 | QUERIED_QUEUES_BY_ID.put(queue.Id, queue); 24 | QUERIED_QUEUES_BY_DEVELOPER_NAME.put(queue.DeveloperName, queue); 25 | } 26 | } 27 | 28 | public static List getQueueApiNames() { 29 | List queueApiNames = new List(QUERIED_QUEUES_BY_DEVELOPER_NAME.keySet()); 30 | queueApiNames.sort(); 31 | return queueApiNames; 32 | } 33 | 34 | @AuraEnabled global final String ApiName {get; private set;} 35 | @AuraEnabled global final Boolean DoesIncludeBosses {get; private set;} 36 | @AuraEnabled global final Boolean DoesSendEmailToMembers {get; private set;} 37 | @AuraEnabled global final String Email {get; private set;} 38 | @AuraEnabled global final Id Id {get; private set;} 39 | @AuraEnabled global final String Label {get; private set;} 40 | @AuraEnabled global final List QueueMembers {get; private set;} 41 | @AuraEnabled global final List SobjectApiNames {get; private set;} 42 | 43 | global QueueMetadata(String queueApiName) { 44 | this(QUERIED_QUEUES_BY_DEVELOPER_NAME.get(queueApiName).Id); 45 | } 46 | 47 | global QueueMetadata(Id queueId) { 48 | Group queue = QUERIED_QUEUES_BY_ID.get(queueId); 49 | 50 | this.ApiName = queue.DeveloperName; 51 | this.DoesIncludeBosses = queue.DoesIncludeBosses; 52 | this.DoesSendEmailToMembers = queue.DoesSendEmailToMembers; 53 | this.Email = queue.Email; 54 | this.Id = queue.Id; 55 | this.Label = queue.Name; 56 | this.QueueMembers = this.getQueueMembers(queue); 57 | this.SobjectApiNames = this.getSobjectApiNames(queue); 58 | } 59 | 60 | private List getQueueMembers(Group queue) { 61 | List queueMembers = new List(); 62 | for(GroupMember queueMember : queue.GroupMembers) { 63 | queueMembers.add(new QueueMemberMetadata(queueMember)); 64 | } 65 | queueMembers.sort(); 66 | return queueMembers; 67 | } 68 | 69 | private List getSobjectApiNames(Group queue) { 70 | List sobjectApiNames = new List(); 71 | for(QueueSobject queueSobject : queue.QueueSobjects) { 72 | sobjectApiNames.add(queueSobject.SobjectType); 73 | } 74 | sobjectApiNames.sort(); 75 | return sobjectApiNames; 76 | } 77 | 78 | global class QueueMemberMetadata implements Comparable { 79 | 80 | @AuraEnabled global final Id Id {get; private set;} 81 | @AuraEnabled global final Id QueueId {get; private set;} 82 | @AuraEnabled global final String Type {get; private set;} 83 | @AuraEnabled global final Id UserOrGroupId {get; private set;} 84 | 85 | global Integer compareTo(Object compareTo) { 86 | QueueMemberMetadata compareToQueueMember = (QueueMemberMetadata)compareTo; 87 | 88 | if(this.UserOrGroupId == compareToQueueMember.UserOrGroupId) return 0; 89 | else if(this.UserOrGroupId > compareToQueueMember.UserOrGroupId) return 1; 90 | else return -1; 91 | } 92 | 93 | private QueueMemberMetadata(GroupMember groupMember) { 94 | this.Id = groupMember.Id; 95 | this.QueueId = groupMember.GroupId; 96 | this.Type = String.valueOf(groupMember.UserOrGroupId.getSobjectType()); 97 | this.UserOrGroupId = groupMember.UserOrGroupId; 98 | } 99 | 100 | } 101 | 102 | } -------------------------------------------------------------------------------- /src/classes/QueueMetadata.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 43.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/QueueMetadata_Tests.cls: -------------------------------------------------------------------------------- 1 | /************************************************************************************************* 2 | * This file is part of the SimpleMetadata project, released under the MIT License. * 3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. * 4 | *************************************************************************************************/ 5 | @isTest 6 | private class QueueMetadata_Tests { 7 | 8 | private static final String queueDeveloperName = 'queueDeveloperName'; 9 | 10 | @testSetup 11 | static void testSetup() { 12 | // Create queue 13 | Group queue = new Group(DeveloperName = queueDeveloperName, Name = queueDeveloperName, Type = 'Queue'); 14 | insert queue; 15 | 16 | // Create queue Sobject 17 | QueueSobject queueCaseSobject = new QueueSobject(QueueId = queue.Id, SobjectType = 'Case'); 18 | insert queueCaseSobject; 19 | 20 | // Create queue members 21 | List queueMembers = new List(); 22 | for(User user : [SELECT Id FROM User WHERE IsActive = true AND Id != :UserInfo.getUserId()]) { 23 | GroupMember queueMember = new GroupMember( 24 | GroupId = queue.Id, 25 | UserOrGroupId = UserInfo.getUserId() 26 | ); 27 | queueMembers.add(queueMember); 28 | } 29 | insert queueMembers; 30 | } 31 | 32 | @isTest 33 | static void it_should_return_queue_metadata_for_id() { 34 | Group queue = getQueue(); 35 | 36 | Test.startTest(); 37 | 38 | QueueMetadata queueMetadata = new QueueMetadata(queue.Id); 39 | validateAttributesAreSet(queue, queueMetadata); 40 | validateCaseSentivityForJavascript(queueMetadata); 41 | 42 | Test.stopTest(); 43 | } 44 | 45 | @isTest 46 | static void it_should_return_queue_metadata_for_api_name() { 47 | Group queue = getQueue(); 48 | 49 | Test.startTest(); 50 | 51 | QueueMetadata queueMetadata = new QueueMetadata(queue.DeveloperName); 52 | validateAttributesAreSet(queue, queueMetadata); 53 | validateCaseSentivityForJavascript(queueMetadata); 54 | 55 | Test.stopTest(); 56 | } 57 | 58 | private static Group getQueue() { 59 | Group queue = [ 60 | SELECT Id, Name, DeveloperName, DoesIncludeBosses, DoesSendEmailToMembers, Email, OwnerId, Owner.Name 61 | FROM Group 62 | WHERE Type = 'Queue' 63 | AND DeveloperName = :queueDeveloperName 64 | ]; 65 | return queue; 66 | } 67 | 68 | private static void validateAttributesAreSet(Group queue, QueueMetadata queueMetadata) { 69 | System.assertEquals(queue.DeveloperName, queueMetadata.ApiName); 70 | System.assertEquals(queue.DoesIncludeBosses, queueMetadata.DoesIncludeBosses); 71 | System.assertEquals(queue.DoesSendEmailToMembers, queueMetadata.DoesSendEmailToMembers); 72 | System.assertEquals(queue.Email, queueMetadata.Email); 73 | System.assertEquals(queue.Id, queueMetadata.Id); 74 | System.assertEquals(queue.Name, queueMetadata.Label); 75 | } 76 | 77 | private static void validateCaseSentivityForJavascript(QueueMetadata queueMetadata) { 78 | // Validate that the attributes are named exactly as expected so that javascript can rely on them 79 | String jsonQueueMetadata = JSON.serialize(queueMetadata); 80 | Map untypedQueueMetadata = (Map)JSON.deserializeUntyped(jsonQueueMetadata); 81 | 82 | // One negative to confirm that the strings in our map are case sensitive 83 | System.assert(untypedQueueMetadata.containsKey('APINAME') == false); 84 | // Now for the 'real' tests 85 | System.assert(untypedQueueMetadata.containsKey('ApiName')); 86 | System.assert(untypedQueueMetadata.containsKey('DoesIncludeBosses')); 87 | System.assert(untypedQueueMetadata.containsKey('DoesSendEmailToMembers')); 88 | System.assert(untypedQueueMetadata.containsKey('Email')); 89 | System.assert(untypedQueueMetadata.containsKey('Id')); 90 | System.assert(untypedQueueMetadata.containsKey('Label')); 91 | System.assert(untypedQueueMetadata.containsKey('QueueMembers')); 92 | System.assert(untypedQueueMetadata.containsKey('SobjectApiNames')); 93 | } 94 | 95 | } -------------------------------------------------------------------------------- /src/classes/QueueMetadata_Tests.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 43.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/RecordTypeMetadata.cls: -------------------------------------------------------------------------------- 1 | /************************************************************************************************* 2 | * This file is part of the SimpleMetadata project, released under the MIT License. * 3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. * 4 | *************************************************************************************************/ 5 | global class RecordTypeMetadata implements Comparable { 6 | 7 | @AuraEnabled global final String ApiName {get; private set;} 8 | @AuraEnabled global final Id Id {get; private set;} 9 | @AuraEnabled global final Boolean IsActive {get; private set;} 10 | @AuraEnabled global final Boolean IsAvailable {get; private set;} 11 | @AuraEnabled global final Boolean IsDefault {get; private set;} 12 | @AuraEnabled global final Boolean IsMaster {get; private set;} 13 | @AuraEnabled global final String Label {get; private set;} 14 | @AuraEnabled global final String LocalApiName {get; private set;} 15 | @AuraEnabled global final String Namespace {get; private set;} 16 | @AuraEnabled global final String SobjectApiName {get; private set;} 17 | 18 | global RecordTypeMetadata(String sobjectApiName, String recordTypeApiName) { 19 | this( 20 | Schema.getGlobalDescribe().get(sobjectApiName), 21 | Schema.getGlobalDescribe().get(sobjectApiName).getDescribe().getRecordTypeInfosByDeveloperName().get(recordTypeApiName) 22 | ); 23 | } 24 | 25 | global RecordTypeMetadata(Schema.SobjectType sobjectType, Id recordTypeId) { 26 | this( 27 | sobjectType, 28 | sobjectType.getDescribe().getRecordTypeInfosById().get(recordTypeId) 29 | ); 30 | } 31 | 32 | global RecordTypeMetadata(Schema.SobjectType sobjectType, Schema.RecordTypeInfo recordTypeInfo) { 33 | this.ApiName = this.getApiName(recordTypeInfo); 34 | this.Id = recordTypeInfo.getRecordTypeId(); 35 | this.IsActive = recordTypeInfo.isActive(); 36 | this.IsAvailable = recordTypeInfo.isAvailable(); 37 | this.IsDefault = recordTypeInfo.isDefaultRecordTypeMapping(); 38 | this.IsMaster = recordTypeInfo.isMaster(); 39 | this.Label = recordTypeInfo.getName(); 40 | this.LocalApiName = this.getLocalApiName(recordTypeInfo.getDeveloperName()); 41 | this.Namespace = this.getNamespace(recordTypeInfo.getDeveloperName()); 42 | this.SobjectApiName = String.valueOf(sobjectType); 43 | } 44 | 45 | global Integer compareTo(Object compareTo) { 46 | RecordTypeMetadata compareToRecordTypeMetadata = (RecordTypeMetadata)compareTo; 47 | String key = this.SobjectApiName + this.ApiName; 48 | String compareToKey = compareToRecordTypeMetadata.SobjectApiName + compareToRecordTypeMetadata.ApiName; 49 | 50 | if(key == compareToKey) return 0; 51 | else if(key > compareToKey) return 1; 52 | else return -1; 53 | } 54 | 55 | private String getApiName(Schema.RecordTypeInfo recordTypeInfo) { 56 | String namespacePrefix = String.isEmpty(this.getNamespace(recordTypeInfo.getDeveloperName())) ? '' : this.getNamespace(recordTypeInfo.getDeveloperName()) + '__'; 57 | return namespacePrefix + recordTypeInfo.getDeveloperName(); 58 | } 59 | 60 | private String getLocalApiName(String apiName) { 61 | return apiName.contains('__') ? apiName.substringAfter('__') : apiName; 62 | } 63 | 64 | private String getNamespace(String apiName) { 65 | return apiName.contains('__') ? apiName.substringBefore('__') : null; 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /src/classes/RecordTypeMetadata.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 43.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/RecordTypeMetadata_Tests.cls: -------------------------------------------------------------------------------- 1 | /************************************************************************************************* 2 | * This file is part of the SimpleMetadata project, released under the MIT License. * 3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. * 4 | *************************************************************************************************/ 5 | @isTest 6 | private class RecordTypeMetadata_Tests { 7 | 8 | private static final String ORG_NAMESPACE_PREFIX; 9 | 10 | static { 11 | ORG_NAMESPACE_PREFIX = [SELECT NamespacePrefix FROM Organization].NamespacePrefix; 12 | } 13 | 14 | @isTest 15 | static void it_should_return_record_type_metadata_for_record_type_info() { 16 | // For larger orgs with a lot of record types, we don't need to test every record type 17 | // We'll keep a count and stop after 5 to keep tests quick 18 | Integer count = 0; 19 | 20 | Schema.SobjectType accountSobjectType = Schema.Account.SobjectType; 21 | for(Schema.RecordTypeInfo recordTypeInfo : Schema.SobjectType.Account.getRecordTypeInfos()) { 22 | if(count >= 5) break; 23 | 24 | RecordTypeMetadata recordTypeMetadata = new RecordTypeMetadata(accountSobjectType, recordTypeInfo); 25 | count++; 26 | } 27 | } 28 | 29 | @isTest 30 | static void it_should_return_record_type_metadata_for_sobject_and_record_type_api_names() { 31 | for(RecordType recordType : [SELECT Id, BusinessProcessId, Description, DeveloperName, NamespacePrefix, SobjectType FROM RecordType LIMIT 5]) { 32 | Schema.RecordTypeInfo recordTypeInfo = Schema.getGlobalDescribe().get(recordType.SobjectType).getDescribe().getRecordTypeInfosById().get(recordType.Id); 33 | String namespace = recordType.NamespacePrefix == null || recordType.NamespacePrefix == ORG_NAMESPACE_PREFIX ? '' : recordType.NamespacePrefix + '__'; 34 | RecordTypeMetadata recordTypeMetadata = new RecordTypeMetadata(recordType.SobjectType, namespace + recordType.DeveloperName); 35 | validateAttributesAreSet(recordTypeInfo, recordType, recordType.SobjectType, recordTypeMetadata); 36 | validateCaseSentivityForJavascript(recordTypeMetadata); 37 | } 38 | } 39 | 40 | @isTest 41 | static void it_should_return_record_type_metadata_for_record_type_id() { 42 | Schema.RecordTypeInfo queryableRecordTypeInfo; 43 | for(Schema.RecordTypeInfo recordTypeInfo : Schema.SobjectType.Account.getRecordTypeInfos()) { 44 | if(recordTypeInfo.isMaster()) continue; 45 | 46 | queryableRecordTypeInfo = recordTypeInfo; 47 | break; 48 | } 49 | 50 | if(queryableRecordTypeInfo == null) return; // This will be null in orgs with no record types, so the test can't finish 51 | 52 | RecordTypeMetadata recordTypeMetadata = new RecordTypeMetadata(Schema.Account.SobjectType, queryableRecordTypeInfo.getRecordTypeId()); 53 | RecordType recordType = [ 54 | SELECT Id, DeveloperName, NamespacePrefix, SobjectType 55 | FROM RecordType WHERE Id = :queryableRecordTypeInfo.getRecordTypeId() 56 | ]; 57 | validateAttributesAreSet(queryableRecordTypeInfo, recordType, recordType.SobjectType, recordTypeMetadata); 58 | validateCaseSentivityForJavascript(recordTypeMetadata); 59 | } 60 | 61 | private static void validateAttributesAreSet(RecordTypeInfo recordTypeInfo, RecordType recordType, String sobjectApiName, RecordTypeMetadata recordTypeMetadata) { 62 | String namespace; 63 | String namespacePrefix = ''; 64 | if(recordType != null && recordType.NamespacePrefix != null && recordType.NamespacePrefix != ORG_NAMESPACE_PREFIX) { 65 | namespace = recordType.NamespacePrefix; 66 | namespacePrefix = recordType.NamespacePrefix + '__'; 67 | } 68 | String recordTypeName = recordType == null ? null : namespacePrefix + recordType.DeveloperName; 69 | 70 | System.assertEquals(recordType == null ? null : recordTypeName, recordTypeMetadata.ApiName); 71 | System.assertEquals(recordTypeInfo.getRecordTypeId(), recordTypeMetadata.Id); 72 | System.assertEquals(recordTypeInfo.isActive(), recordTypeMetadata.IsActive); 73 | System.assertEquals(recordTypeInfo.isAvailable(), recordTypeMetadata.IsAvailable); 74 | System.assertEquals(recordTypeInfo.isDefaultRecordTypeMapping(), recordTypeMetadata.IsDefault); 75 | System.assertEquals(recordTypeInfo.isMaster(), recordTypeMetadata.IsMaster); 76 | System.assertEquals(recordTypeInfo.getName(), recordTypeMetadata.Label); 77 | System.assertEquals(recordType == null ? null : recordType.DeveloperName, recordTypeMetadata.LocalApiName); 78 | System.assertEquals(recordType == null ? null : namespace, recordTypeMetadata.Namespace); 79 | System.assertEquals(sobjectApiName, recordTypeMetadata.SobjectApiName); 80 | } 81 | 82 | private static void validateCaseSentivityForJavascript(RecordTypeMetadata recordTypeMetadata) { 83 | // Validate that the attributes are named exactly as expected so that javascript can rely on them 84 | String jsonRecordTypeMetadata = JSON.serialize(recordTypeMetadata); 85 | Map untypedRecordTypeMetadata = (Map)JSON.deserializeUntyped(jsonRecordTypeMetadata); 86 | 87 | // One negative to confirm that the strings in our map are case sensitive 88 | System.assert(untypedRecordTypeMetadata.containsKey('APINAME') == false); 89 | // Now for the 'real' tests 90 | System.assert(untypedRecordTypeMetadata.containsKey('ApiName')); 91 | System.assert(untypedRecordTypeMetadata.containsKey('Id')); 92 | System.assert(untypedRecordTypeMetadata.containsKey('IsActive')); 93 | System.assert(untypedRecordTypeMetadata.containsKey('IsAvailable')); 94 | System.assert(untypedRecordTypeMetadata.containsKey('IsDefault')); 95 | System.assert(untypedRecordTypeMetadata.containsKey('IsMaster')); 96 | System.assert(untypedRecordTypeMetadata.containsKey('Label')); 97 | System.assert(untypedRecordTypeMetadata.containsKey('LocalApiName')); 98 | System.assert(untypedRecordTypeMetadata.containsKey('Namespace')); 99 | System.assert(untypedRecordTypeMetadata.containsKey('SobjectApiName')); 100 | } 101 | 102 | } -------------------------------------------------------------------------------- /src/classes/RecordTypeMetadata_Tests.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 43.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/SobjectMetadata.cls: -------------------------------------------------------------------------------- 1 | /************************************************************************************************* 2 | * This file is part of the SimpleMetadata project, released under the MIT License. * 3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. * 4 | *************************************************************************************************/ 5 | global class SobjectMetadata { 6 | 7 | @AuraEnabled global final String ApiName {get; private set;} 8 | @AuraEnabled global final List ChildRelationships {get; private set;} 9 | @AuraEnabled global final String DisplayFieldApiName {get; private set;} 10 | @AuraEnabled global final List FieldApiNames {get; private set;} 11 | @AuraEnabled global final List FieldSetApiNames {get; private set;} 12 | @AuraEnabled global final Boolean HasMultiCurrency {get; private set;} 13 | @AuraEnabled global final Boolean HasSubtypes {get; private set;} 14 | @AuraEnabled global final Boolean IsAccessible {get; private set;} 15 | @AuraEnabled global final Boolean IsChatterFeedEnabled {get; private set;} 16 | @AuraEnabled global final Boolean IsCreateable {get; private set;} 17 | @AuraEnabled global final Boolean IsCustom {get; private set;} 18 | @AuraEnabled global final Boolean IsCustomSetting {get; private set;} 19 | @AuraEnabled global final Boolean IsDeletable {get; private set;} 20 | @AuraEnabled global final Boolean IsMruEnabled {get; private set;} 21 | @AuraEnabled global final Boolean IsMergeable {get; private set;} 22 | @AuraEnabled global final Boolean IsQueryable {get; private set;} 23 | @AuraEnabled global final Boolean IsSearchable {get; private set;} 24 | @AuraEnabled global final Boolean IsUndeletable {get; private set;} 25 | @AuraEnabled global final Boolean IsUpdateable {get; private set;} 26 | @AuraEnabled global final String KeyPrefix {get; private set;} 27 | @AuraEnabled global final String Label {get; private set;} 28 | @AuraEnabled global final String LabelPlural {get; private set;} 29 | @AuraEnabled global final String LocalApiName {get; private set;} 30 | @AuraEnabled global final String Namespace {get; private set;} 31 | @AuraEnabled global final List RecordTypes {get; private set;} 32 | @AuraEnabled global final String TabIcon {get; private set;} 33 | 34 | global SobjectMetadata(String sobjectApiName) { 35 | this(Schema.getGlobalDescribe().get(sobjectApiName)); 36 | } 37 | 38 | global SobjectMetadata(Schema.SobjectType sobjectType) { 39 | DescribeSobjectResult sobjectDescribe = sobjectType.getDescribe(); 40 | 41 | this.ApiName = String.valueOf(sobjectType); 42 | this.ChildRelationships = this.getChildRelationships(sobjectDescribe.getChildRelationships()); 43 | this.DisplayFieldApiName = this.getDisplayFieldApiName(sobjectDescribe); 44 | this.FieldApiNames = this.getFieldApiNames(sobjectDescribe); 45 | this.FieldSetApiNames = this.getFieldSetApiNames(sobjectDescribe); 46 | this.HasMultiCurrency = sobjectDescribe.fields.getMap().containsKey('CurrencyIsoCode'); 47 | this.HasSubtypes = sobjectDescribe.getHasSubtypes(); 48 | this.IsAccessible = sobjectDescribe.isAccessible(); 49 | this.IsChatterFeedEnabled = sobjectDescribe.isFeedEnabled(); 50 | this.IsCreateable = sobjectDescribe.isCreateable(); 51 | this.IsCustom = sobjectDescribe.isCustom(); 52 | this.IsCustomSetting = sobjectDescribe.isCustomSetting(); 53 | this.IsDeletable = sobjectDescribe.isDeletable(); 54 | this.IsMergeable = sobjectDescribe.isMergeable(); 55 | this.IsMruEnabled = sobjectDescribe.isMruEnabled(); 56 | this.IsQueryable = sobjectDescribe.isQueryable(); 57 | this.IsSearchable = sobjectDescribe.isSearchable(); 58 | this.IsUndeletable = sobjectDescribe.isUndeletable(); 59 | this.IsUpdateable = sobjectDescribe.isUpdateable(); 60 | this.KeyPrefix = sobjectDescribe.getKeyPrefix(); 61 | this.Label = sobjectDescribe.getLabel(); 62 | this.LabelPlural = sobjectDescribe.getLabelPlural(); 63 | this.LocalApiName = sobjectDescribe.getLocalName(); 64 | this.Namespace = this.getNamespace(); 65 | this.RecordTypes = this.getRecordTypes(sobjectType, sobjectDescribe.getRecordTypeInfos()); 66 | this.TabIcon = this.getTabIcon(); 67 | } 68 | 69 | private List getChildRelationships(List relationships) { 70 | List childRelationships = new List(); 71 | for(Schema.ChildRelationship relationship : relationships) { 72 | childRelationships.add(new ChildRelationshipMetadata(relationship)); 73 | } 74 | childRelationships.sort(); 75 | return childRelationships; 76 | } 77 | 78 | private String getDisplayFieldApiName(Schema.DescribeSobjectResult sobjectDescribe) { 79 | // There are several commonly used names for the display field name - typically, Name 80 | // Check the common names first before resorting to looping through all Sobject fields 81 | // The order of the field names has been sorted based on number of objects in a dev org with that field 82 | List educatedGuesses = new List{ 83 | 'Name', 'DeveloperName', 'ApiName', 'Title', 'Subject', 84 | 'AssetRelationshipNumber', 'CaseNumber', 'ContractNumber', 85 | 'Domain', 'FriendlyName', 'FunctionName', 'Label', 'LocalPart', 86 | 'OrderItemNumber', 'OrderNumber', 'SolutionName', 'TestSuiteName' 87 | }; 88 | for(String fieldName : educatedGuesses) { 89 | Schema.SobjectField field = sobjectDescribe.fields.getMap().get(fieldName); 90 | 91 | if(field == null) continue; 92 | 93 | Schema.DescribeFieldResult fieldDescribe = field.getDescribe(); 94 | 95 | if(fieldDescribe.isNameField()) return fieldDescribe.getName(); 96 | } 97 | 98 | return null; 99 | } 100 | 101 | private List getFieldApiNames(Schema.DescribeSobjectResult sobjectDescribe) { 102 | List fieldApiNames = new List(); 103 | for(Schema.SobjectField field : sobjectDescribe.fields.getMap().values()) { 104 | fieldApiNames.add(String.valueOf(field)); 105 | } 106 | fieldApiNames.sort(); 107 | return fieldApiNames; 108 | } 109 | 110 | private List getFieldSetApiNames(Schema.DescribeSobjectResult sobjectDescribe) { 111 | List fieldSetApiNames = new List(); 112 | for(Schema.FieldSet fieldSet : sobjectDescribe.fieldSets.getMap().values()) { 113 | String namespace = fieldSet.getNameSpace() == null ? '' : FieldSet.getNamespace() + '__'; 114 | fieldSetApiNames.add(namespace + fieldSet.getName()); 115 | } 116 | fieldSetApiNames.sort(); 117 | return fieldSetApiNames; 118 | } 119 | 120 | private String getNamespace() { 121 | Integer localNameIndex = this.ApiName.replace('__c', '').indexOf('__'); 122 | return localNameIndex < 0 ? null : this.ApiName.substring(0, localNameIndex); 123 | } 124 | 125 | private List getRecordTypes(Schema.SobjectType sobjectType, List recordTypeInfos) { 126 | List recordTypes = new List(); 127 | for(Schema.RecordTypeInfo recordTypeInfo : recordTypeInfos) { 128 | recordTypes.add(new RecordTypeMetadata(sobjectType, recordTypeInfo)); 129 | } 130 | recordTypes.sort(); 131 | return recordTypes; 132 | } 133 | 134 | private String getTabIcon() { 135 | String tabIcon; 136 | for(Schema.DescribeTabSetResult tabSetResult : Schema.describeTabs()) { 137 | if(tabIcon != null) break; 138 | 139 | for(Schema.DescribeTabResult tabResult : tabSetResult.getTabs()) { 140 | if(tabIcon != null) break; 141 | if(tabResult.getSobjectName() != this.ApiName) continue; 142 | 143 | String iconType = tabResult.isCustom() ? 'custom' : 'standard'; 144 | String svgIconName; 145 | for(Schema.DescribeIconResult icon : tabResult.getIcons()) { 146 | if(icon.getContentType() != 'image/svg+xml') continue; 147 | 148 | svgIconName = icon.getUrl().substringAfterLast('/').replace('.svg', ''); 149 | tabIcon = iconType + ':' + svgIconName; 150 | break; 151 | } 152 | } 153 | } 154 | // Hardcoded exceptions - Salesforce doesn't return SVGs for these objects, so hardcoding is necessary 155 | if(tabIcon == null && this.ApiName == 'Asset') tabIcon = 'standard:maintenance_asset'; 156 | if(tabIcon == null && this.ApiName == 'AssetRelationship') tabIcon = 'standard:asset_relationship'; 157 | 158 | return tabIcon; 159 | } 160 | 161 | global class ChildRelationshipMetadata implements Comparable { 162 | 163 | @AuraEnabled global String ChildSobjectApiName {get; private set;} 164 | @AuraEnabled global String FieldApiName {get; private set;} 165 | @AuraEnabled global String FieldRelationshipApiName {get; private set;} 166 | @AuraEnabled global Boolean IsCascadeDelete {get; private set;} 167 | @AuraEnabled global Boolean IsRestrictedDelete {get; private set;} 168 | @AuraEnabled global String RelationshipApiName {get; private set;} 169 | 170 | global ChildRelationshipMetadata(Schema.ChildRelationship childRelationship) { 171 | this.ChildSobjectApiName = String.valueOf(childRelationship.getChildSobject()); 172 | this.FieldApiName = String.valueOf(childRelationship.getField()); 173 | this.FieldRelationshipApiName = childRelationship.getField().getDescribe().getRelationshipName(); 174 | this.IsCascadeDelete = childRelationship.isCascadeDelete(); 175 | this.IsRestrictedDelete = childRelationship.isRestrictedDelete(); 176 | this.RelationshipApiName = childRelationship.getRelationshipName(); 177 | } 178 | 179 | global Integer compareTo(Object compareTo) { 180 | ChildRelationshipMetadata compareToChildRelationship = (ChildRelationshipMetadata)compareTo; 181 | String key = this.ChildSobjectApiName + this.FieldApiName; 182 | String compareToKey = compareToChildRelationship.ChildSobjectApiName + compareToChildRelationship.FieldApiName; 183 | 184 | if(key == compareToKey) return 0; 185 | else if(key > compareToKey) return 1; 186 | else return -1; 187 | } 188 | 189 | } 190 | 191 | } -------------------------------------------------------------------------------- /src/classes/SobjectMetadata.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 43.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/SobjectMetadata_Tests.cls: -------------------------------------------------------------------------------- 1 | /************************************************************************************************* 2 | * This file is part of the SimpleMetadata project, released under the MIT License. * 3 | * See LICENSE file or go to https://github.com/jongpie/SimpleMetadata for full license details. * 4 | *************************************************************************************************/ 5 | @isTest 6 | private class SobjectMetadata_Tests { 7 | 8 | @isTest 9 | static void it_should_return_metadata_for_account_sobject_token() { 10 | SobjectMetadata accountMetadata = new SobjectMetadata(Schema.Account.SobjectType); 11 | validateAttributesAreSet(accountMetadata); 12 | validateCaseSentivityForJavascript(accountMetadata); 13 | } 14 | 15 | @isTest 16 | static void it_should_return_metadata_for_account_sobject_api_name() { 17 | SobjectMetadata accountMetadata = new SobjectMetadata('Account'); 18 | validateAttributesAreSet(accountMetadata); 19 | validateCaseSentivityForJavascript(accountMetadata); 20 | } 21 | 22 | private static void validateAttributesAreSet(SobjectMetadata sobjectMetadata) { 23 | Schema.DescribeSobjectResult accountDescribe = Schema.Account.SobjectType.getDescribe(); 24 | 25 | System.assertEquals('Account', sobjectMetadata.ApiName); 26 | System.assertEquals('Name', sobjectMetadata.DisplayFieldApiName); 27 | System.assertEquals(accountDescribe.getChildRelationships().size(), sobjectMetadata.ChildRelationships.size()); 28 | System.assertEquals(accountDescribe.fields.getMap().size(), sobjectMetadata.FieldApiNames.size()); 29 | System.assertEquals(accountDescribe.getHasSubtypes(), sobjectMetadata.HasSubtypes); 30 | System.assertEquals(accountDescribe.isAccessible(), sobjectMetadata.IsAccessible); 31 | System.assertEquals(accountDescribe.isFeedEnabled(), sobjectMetadata.IsChatterFeedEnabled); 32 | System.assertEquals(accountDescribe.isCreateable(), sobjectMetadata.IsCreateable); 33 | System.assertEquals(accountDescribe.isCustom(), sobjectMetadata.IsCustom); 34 | System.assertEquals(accountDescribe.isCustomSetting(), sobjectMetadata.IsCustomSetting); 35 | System.assertEquals(accountDescribe.isDeletable(), sobjectMetadata.IsDeletable); 36 | System.assertEquals(accountDescribe.isMergeable(), sobjectMetadata.IsMergeable); 37 | System.assertEquals(accountDescribe.isMruEnabled(), sobjectMetadata.IsMRUEnabled); 38 | System.assertEquals(accountDescribe.isQueryable(), sobjectMetadata.IsQueryable); 39 | System.assertEquals(accountDescribe.isSearchable(), sobjectMetadata.IsSearchable); 40 | System.assertEquals(accountDescribe.isUndeletable(), sobjectMetadata.IsUndeletable); 41 | System.assertEquals(accountDescribe.isUpdateable(), sobjectMetadata.IsUpdateable); 42 | System.assertEquals(accountDescribe.getKeyPrefix(), sobjectMetadata.KeyPrefix); 43 | System.assertEquals(accountDescribe.getLabel(), sobjectMetadata.Label); 44 | System.assertEquals(accountDescribe.getLabelPlural(), sobjectMetadata.LabelPlural); 45 | System.assertEquals(accountDescribe.getLocalName(), sobjectMetadata.LocalApiName); 46 | System.assertEquals(accountDescribe.getRecordTypeInfos().size(), sobjectMetadata.RecordTypes.size()); 47 | System.assertEquals('standard:account', sobjectMetadata.TabIcon); 48 | 49 | System.assertNotEquals(null, sobjectMetadata.ApiName); 50 | System.assertNotEquals(null, sobjectMetadata.ChildRelationships); 51 | System.assertNotEquals(null, sobjectMetadata.DisplayFieldApiName); 52 | System.assertNotEquals(null, sobjectMetadata.HasMultiCurrency); 53 | System.assertNotEquals(null, sobjectMetadata.HasSubtypes); 54 | System.assertNotEquals(null, sobjectMetadata.IsAccessible); 55 | System.assertNotEquals(null, sobjectMetadata.IsChatterFeedEnabled); 56 | System.assertNotEquals(null, sobjectMetadata.IsCreateable); 57 | System.assertNotEquals(null, sobjectMetadata.IsCustom); 58 | System.assertNotEquals(null, sobjectMetadata.IsCustomSetting); 59 | System.assertNotEquals(null, sobjectMetadata.IsDeletable); 60 | System.assertNotEquals(null, sobjectMetadata.IsMruEnabled); 61 | System.assertNotEquals(null, sobjectMetadata.IsMergeable); 62 | System.assertNotEquals(null, sobjectMetadata.IsQueryable); 63 | System.assertNotEquals(null, sobjectMetadata.IsSearchable); 64 | System.assertNotEquals(null, sobjectMetadata.IsUndeletable); 65 | System.assertNotEquals(null, sobjectMetadata.IsUpdateable); 66 | System.assertNotEquals(null, sobjectMetadata.FieldApiNames); 67 | System.assertNotEquals(null, sobjectMetadata.FieldSetApiNames); 68 | System.assertNotEquals(null, sobjectMetadata.KeyPrefix); 69 | System.assertNotEquals(null, sobjectMetadata.Label); 70 | System.assertNotEquals(null, sobjectMetadata.LabelPlural); 71 | System.assertNotEquals(null, sobjectMetadata.LocalApiName); 72 | System.assertNotEquals(null, sobjectMetadata.RecordTypes); 73 | System.assertNotEquals(null, sobjectMetadata.TabIcon); 74 | } 75 | 76 | private static void validateCaseSentivityForJavascript(SobjectMetadata sobjectMetadata) { 77 | // Validate that the attributes are named exactly as expected so that javascript can rely on them 78 | String jsonSobjectMetadata = JSON.serialize(sobjectMetadata); 79 | Map untypedSobjectMetadata = (Map)JSON.deserializeUntyped(jsonSobjectMetadata); 80 | 81 | // One negative to confirm that the strings in our map are case sensitive 82 | System.assert(untypedSobjectMetadata.containsKey('APINAME') == false); 83 | // Now for the 'real' tests 84 | System.assert(untypedSobjectMetadata.containsKey('ApiName')); 85 | System.assert(untypedSobjectMetadata.containsKey('ChildRelationships')); 86 | System.assert(untypedSobjectMetadata.containsKey('DisplayFieldApiName')); 87 | System.assert(untypedSobjectMetadata.containsKey('FieldApiNames')); 88 | System.assert(untypedSobjectMetadata.containsKey('FieldSetApiNames')); 89 | System.assert(untypedSobjectMetadata.containsKey('HasMultiCurrency')); 90 | System.assert(untypedSobjectMetadata.containsKey('HasSubtypes')); 91 | System.assert(untypedSobjectMetadata.containsKey('IsAccessible')); 92 | System.assert(untypedSobjectMetadata.containsKey('IsChatterFeedEnabled')); 93 | System.assert(untypedSobjectMetadata.containsKey('IsCreateable')); 94 | System.assert(untypedSobjectMetadata.containsKey('IsCustom')); 95 | System.assert(untypedSobjectMetadata.containsKey('IsCustomSetting')); 96 | System.assert(untypedSobjectMetadata.containsKey('IsDeletable')); 97 | System.assert(untypedSobjectMetadata.containsKey('IsMruEnabled')); 98 | System.assert(untypedSobjectMetadata.containsKey('IsMergeable')); 99 | System.assert(untypedSobjectMetadata.containsKey('IsQueryable')); 100 | System.assert(untypedSobjectMetadata.containsKey('IsSearchable')); 101 | System.assert(untypedSobjectMetadata.containsKey('IsUndeletable')); 102 | System.assert(untypedSobjectMetadata.containsKey('IsUpdateable')); 103 | System.assert(untypedSobjectMetadata.containsKey('KeyPrefix')); 104 | System.assert(untypedSobjectMetadata.containsKey('Label')); 105 | System.assert(untypedSobjectMetadata.containsKey('LabelPlural')); 106 | System.assert(untypedSobjectMetadata.containsKey('LocalApiName')); 107 | System.assert(untypedSobjectMetadata.containsKey('Namespace')); 108 | System.assert(untypedSobjectMetadata.containsKey('RecordTypes')); 109 | System.assert(untypedSobjectMetadata.containsKey('TabIcon')); 110 | } 111 | 112 | } -------------------------------------------------------------------------------- /src/classes/SobjectMetadata_Tests.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 43.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | * 5 | ApexClass 6 | 7 | 43.0 8 | 9 | --------------------------------------------------------------------------------