From 25944035030acc0b7b4e4c061ad467459f787039 Mon Sep 17 00:00:00 2001 From: "Timothy J. Aveni" Date: Fri, 18 Sep 2026 16:20:03 -0700 Subject: [PATCH] Add native literal substring query predicates Implement checked containsInsensitive string predicates in GraphQL, protobuf, native SQL and bounded residual evaluation. ASCII folding is deterministic; SQL pattern characters remain literal. Retain deferred full-text index design. Studio migration awaits a decision on checked native getter forwarding across conformances; do not duplicate titles or bypass private state ownership. Compiler and local full-stack substring-query acceptance pass. --- proto/camino/schema.proto | 1 + src/gen/camino/schema_pb.ts | 7 ++++++- src/query/relational-compile.ts | 2 +- src/query/relational-proto.ts | 1 + src/query/relational.ts | 4 ++-- src/query/schema.ts | 1 + test/fixtures/query-workspace.ts | 2 +- test/query-compiler.test.ts | 4 ++++ 8 files changed, 17 insertions(+), 5 deletions(-) diff --git a/proto/camino/schema.proto b/proto/camino/schema.proto index 4db4bdb..6ff19ce 100644 --- a/proto/camino/schema.proto +++ b/proto/camino/schema.proto @@ -165,6 +165,7 @@ enum QueryComparisonOperator { QUERY_COMPARISON_OPERATOR_LTE = 5; QUERY_COMPARISON_OPERATOR_GT = 6; QUERY_COMPARISON_OPERATOR_GTE = 7; + QUERY_COMPARISON_OPERATOR_CONTAINS_INSENSITIVE = 8; } message QueryComparison { QueryOperand operand = 1; diff --git a/src/gen/camino/schema_pb.ts b/src/gen/camino/schema_pb.ts index 373f551..1315059 100644 --- a/src/gen/camino/schema_pb.ts +++ b/src/gen/camino/schema_pb.ts @@ -10,7 +10,7 @@ import type { Message } from "@bufbuild/protobuf"; * Describes the file camino/schema.proto. */ export const file_camino_schema: GenFile = /*@__PURE__*/ - fileDesc("ChNjYW1pbm8vc2NoZW1hLnByb3RvEgZjYW1pbm8iNwoOQXRvbURlZmluaXRpb24SDwoHYXRvbV9pZBgBIAEoCRIUCgxkaXNwbGF5X25hbWUYAiABKAkiWQoPQXRvbUNvbmZvcm1hbmNlEg8KB2F0b21faWQYASABKAkSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAIgASgJEhYKDmNvbmZvcm1hbmNlX2lkGAMgASgJIsIBCg9TdGF0ZUF0dGFjaG1lbnQSDwoHc2xvdF9pZBgBIAEoCRIYChBhdHRhY2hlZF9hdG9tX2lkGAIgASgJEhQKDGRpc3BsYXlfbmFtZRgDIAEoCRIXCg92YWx1ZV90eXBlX2pzb24YBCABKAkSGwoTc3RvcmFnZV9wb2xpY3lfanNvbhgFIAEoCRIaChJkZWZhdWx0X3ZhbHVlX2pzb24YBiABKAkSHAoUb3duZXJfY29uZm9ybWFuY2VfaWQYByABKAkiUAoSRW5kcG9pbnRDb25zdHJhaW50EhEKB2F0b21faWQYASABKAlIABIfChVpbnRlcmZhY2VfcmV2aXNpb25faWQYAiABKAlIAEIGCgRraW5kIvsBCgxFZGdlRW5kcG9pbnQSFQoNcHJvamVjdGlvbl9pZBgBIAEoCRIUCgxkaXNwbGF5X25hbWUYAiABKAkSLgoKY29uc3RyYWludBgDIAEoCzIaLmNhbWluby5FbmRwb2ludENvbnN0cmFpbnQSKAoLY2FyZGluYWxpdHkYBCABKA4yEy5jYW1pbm8uQ2FyZGluYWxpdHkSDwoHb3JkZXJlZBgFIAEoCBIRCglvbl9kZWxldGUYBiABKAkSFAoMcmV0YWluX290aGVyGAcgASgIEhAKCGtleV90eXBlGAggASgJEhgKEHB1YmxpY190cmF2ZXJzYWwYCSABKAgipQEKDkVkZ2VBdHRhY2htZW50EhQKDGVkZ2VfdHlwZV9pZBgBIAEoCRIUCgxkaXNwbGF5X25hbWUYAiABKAkSIwoFZmlyc3QYAyABKAsyFC5jYW1pbm8uRWRnZUVuZHBvaW50EiQKBnNlY29uZBgEIAEoCzIULmNhbWluby5FZGdlRW5kcG9pbnQSHAoUb3duZXJfY29uZm9ybWFuY2VfaWQYBSABKAkilQIKD1BlcnNpc3RlbmNlUGxhbhIUCgx3b3Jrc3BhY2VfaWQYASABKAkSHQoVd29ya3NwYWNlX3JldmlzaW9uX2lkGAIgASgJEiUKBWF0b21zGAMgAygLMhYuY2FtaW5vLkF0b21EZWZpbml0aW9uEi0KDGNvbmZvcm1hbmNlcxgEIAMoCzIXLmNhbWluby5BdG9tQ29uZm9ybWFuY2USJwoGc3RhdGVzGAUgAygLMhcuY2FtaW5vLlN0YXRlQXR0YWNobWVudBIlCgVlZGdlcxgGIAMoCzIWLmNhbWluby5FZGdlQXR0YWNobWVudBInCgdxdWVyaWVzGAcgAygLMhYuY2FtaW5vLkluc3RhbGxlZFF1ZXJ5Ip4BCg1RdWVyeUFyZ3VtZW50EhIKCHZhcmlhYmxlGAEgASgJSAASFgoMbGl0ZXJhbF9qc29uGAIgASgJSAASKQoEbGlzdBgDIAEoCzIZLmNhbWluby5RdWVyeUFyZ3VtZW50TGlzdEgAEi0KBm9iamVjdBgEIAEoCzIbLmNhbWluby5RdWVyeUFyZ3VtZW50T2JqZWN0SABCBwoFdmFsdWUiOgoRUXVlcnlBcmd1bWVudExpc3QSJQoGdmFsdWVzGAEgAygLMhUuY2FtaW5vLlF1ZXJ5QXJndW1lbnQilAEKE1F1ZXJ5QXJndW1lbnRPYmplY3QSNwoGZmllbGRzGAEgAygLMicuY2FtaW5vLlF1ZXJ5QXJndW1lbnRPYmplY3QuRmllbGRzRW50cnkaRAoLRmllbGRzRW50cnkSCwoDa2V5GAEgASgJEiQKBXZhbHVlGAIgASgLMhUuY2FtaW5vLlF1ZXJ5QXJndW1lbnQ6AjgBIkcKDlF1ZXJ5Q29uZGl0aW9uEg8KB2luY2x1ZGUYASABKAgSJAoFdmFsdWUYAiABKAsyFS5jYW1pbm8uUXVlcnlBcmd1bWVudCLUAwoOUXVlcnlTZWxlY3Rpb24SDAoEbmFtZRgBIAEoCRILCgNrZXkYAiABKAkSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAMgASgJEhEKCW1lbWJlcl9pZBgEIAEoCRIkChx0YXJnZXRfaW50ZXJmYWNlX3JldmlzaW9uX2lkGAUgASgJEioKCmNvbmRpdGlvbnMYBiADKAsyFi5jYW1pbm8uUXVlcnlDb25kaXRpb24SOAoJYXJndW1lbnRzGAcgAygLMiUuY2FtaW5vLlF1ZXJ5U2VsZWN0aW9uLkFyZ3VtZW50c0VudHJ5EikKCXNlbGVjdGlvbhgIIAMoCzIWLmNhbWluby5RdWVyeVNlbGVjdGlvbhIvCgpyZWxhdGlvbmFsGAkgASgLMhsuY2FtaW5vLlF1ZXJ5UmVsYXRpb25hbFBsYW4SKQoJcHJlZGljYXRlGAogASgLMhYuY2FtaW5vLlF1ZXJ5UHJlZGljYXRlEhkKEWxpdmVfc2VsZWN0aW9uX2lkGAsgASgJGkcKDkFyZ3VtZW50c0VudHJ5EgsKA2tleRgBIAEoCRIkCgV2YWx1ZRgCIAEoCzIVLmNhbWluby5RdWVyeUFyZ3VtZW50OgI4ASJqCg1RdWVyeVBhdGhTdGVwEhAKBnNvdXJjZRgBIAEoCEgAEhAKBnRhcmdldBgCIAEoCEgAEi0KCHJlbGF0aW9uGAMgASgLMhkuY2FtaW5vLlF1ZXJ5UmVsYXRpb25QYXRoSABCBgoEc3RlcCJ9ChFRdWVyeVJlbGF0aW9uUGF0aBIdChVpbnRlcmZhY2VfcmV2aXNpb25faWQYASABKAkSEQoJbWVtYmVyX2lkGAIgASgJEiQKHHRhcmdldF9pbnRlcmZhY2VfcmV2aXNpb25faWQYAyABKAkSEAoIb3B0aW9uYWwYBCABKAgiRQoRUXVlcnlGaWVsZE9wZXJhbmQSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAEgASgJEhEKCW1lbWJlcl9pZBgCIAEoCSK2AQoPUXVlcnlFeHByZXNzaW9uEiMKBHBhdGgYASADKAsyFS5jYW1pbm8uUXVlcnlQYXRoU3RlcBIqCgVmaWVsZBgCIAEoCzIZLmNhbWluby5RdWVyeUZpZWxkT3BlcmFuZEgAEg0KA3JlZhgDIAEoCUgAEg8KBWVudHJ5GAQgASgISAASEQoHbWFwX2tleRgFIAEoCEgAEhcKD3ZhbHVlX3R5cGVfanNvbhgGIAEoCUIGCgRsZWFmIoUBCg5RdWVyeVJlZHVjdGlvbhIwCghvcGVyYXRvchgBIAEoDjIeLmNhbWluby5RdWVyeUFnZ3JlZ2F0ZU9wZXJhdG9yEigKB29wZXJhbmQYAiABKAsyFy5jYW1pbm8uUXVlcnlFeHByZXNzaW9uEhcKD3ZhbHVlX3R5cGVfanNvbhgDIAEoCSJ1CgxRdWVyeU9wZXJhbmQSLQoKZXhwcmVzc2lvbhgBIAEoCzIXLmNhbWluby5RdWVyeUV4cHJlc3Npb25IABIrCglyZWR1Y3Rpb24YAiABKAsyFi5jYW1pbm8uUXVlcnlSZWR1Y3Rpb25IAEIJCgdvcGVyYW5kIpEBCg9RdWVyeUNvbXBhcmlzb24SJQoHb3BlcmFuZBgBIAEoCzIULmNhbWluby5RdWVyeU9wZXJhbmQSMQoIb3BlcmF0b3IYAiABKA4yHy5jYW1pbm8uUXVlcnlDb21wYXJpc29uT3BlcmF0b3ISJAoFdmFsdWUYAyABKAsyFS5jYW1pbm8uUXVlcnlBcmd1bWVudCI+ChJRdWVyeVByZWRpY2F0ZUxpc3QSKAoIY2hpbGRyZW4YASADKAsyFi5jYW1pbm8uUXVlcnlQcmVkaWNhdGUi9QEKFlF1ZXJ5UmVsYXRpb25QcmVkaWNhdGUSIwoEcGF0aBgBIAMoCzIVLmNhbWluby5RdWVyeVBhdGhTdGVwEisKCHJlbGF0aW9uGAIgASgLMhkuY2FtaW5vLlF1ZXJ5UmVsYXRpb25QYXRoEjgKCG9wZXJhdG9yGAMgASgOMiYuY2FtaW5vLlF1ZXJ5UmVsYXRpb25QcmVkaWNhdGVPcGVyYXRvchIpCglwcmVkaWNhdGUYBCABKAsyFi5jYW1pbm8uUXVlcnlQcmVkaWNhdGUSJAoFdmFsdWUYBSABKAsyFS5jYW1pbm8uUXVlcnlBcmd1bWVudCK6AQoXUXVlcnlSZWR1Y3Rpb25QcmVkaWNhdGUSIwoEcGF0aBgBIAMoCzIVLmNhbWluby5RdWVyeVBhdGhTdGVwEisKCHJlbGF0aW9uGAIgASgLMhkuY2FtaW5vLlF1ZXJ5UmVsYXRpb25QYXRoEiUKBXdoZXJlGAMgASgLMhYuY2FtaW5vLlF1ZXJ5UHJlZGljYXRlEiYKBmhhdmluZxgEIAEoCzIWLmNhbWluby5RdWVyeVByZWRpY2F0ZSKsAgoOUXVlcnlQcmVkaWNhdGUSKQoDYW5kGAEgASgLMhouY2FtaW5vLlF1ZXJ5UHJlZGljYXRlTGlzdEgAEigKAm9yGAIgASgLMhouY2FtaW5vLlF1ZXJ5UHJlZGljYXRlTGlzdEgAEiUKA25vdBgDIAEoCzIWLmNhbWluby5RdWVyeVByZWRpY2F0ZUgAEioKB2NvbXBhcmUYBCABKAsyFy5jYW1pbm8uUXVlcnlDb21wYXJpc29uSAASMgoIcmVsYXRpb24YBSABKAsyHi5jYW1pbm8uUXVlcnlSZWxhdGlvblByZWRpY2F0ZUgAEjEKBnJlZHVjZRgGIAEoCzIfLmNhbWluby5RdWVyeVJlZHVjdGlvblByZWRpY2F0ZUgAQgsKCXByZWRpY2F0ZSJhCghRdWVyeVJvdxIoCgZvYmplY3QYASABKAsyFi5jYW1pbm8uUXVlcnlPYmplY3RSb3dIABIkCgRwYWlyGAIgASgLMhQuY2FtaW5vLlF1ZXJ5UGFpclJvd0gAQgUKA3JvdyJVCg5RdWVyeU9iamVjdFJvdxIdChVpbnRlcmZhY2VfcmV2aXNpb25faWQYASABKAkSEgoKbWVtYmVyc2hpcBgCIAEoCBIQCghrZXlfdHlwZRgDIAEoCSJSCgxRdWVyeVBhaXJSb3cSIAoGc291cmNlGAEgASgLMhAuY2FtaW5vLlF1ZXJ5Um93EiAKBnRhcmdldBgCIAEoCzIQLmNhbWluby5RdWVyeVJvdyJFCghRdWVyeUtleRIMCgRwYXRoGAEgAygJEisKCmV4cHJlc3Npb24YAiABKAsyFy5jYW1pbm8uUXVlcnlFeHByZXNzaW9uIi8KDVF1ZXJ5RGlzdGluY3QSHgoEa2V5cxgBIAMoCzIQLmNhbWluby5RdWVyeUtleSJiCg5RdWVyeUV4cGFuc2lvbhIjCgRwYXRoGAEgAygLMhUuY2FtaW5vLlF1ZXJ5UGF0aFN0ZXASKwoIcmVsYXRpb24YAiABKAsyGS5jYW1pbm8uUXVlcnlSZWxhdGlvblBhdGgimAIKFFF1ZXJ5UmVsYXRpb25hbFN0YWdlEgoKAmlkGAEgASgNEhIKBWlucHV0GAIgASgNSAGIAQESHQoDcm93GAMgASgLMhAuY2FtaW5vLlF1ZXJ5Um93EisKBnNvdXJjZRgEIAEoCzIZLmNhbWluby5RdWVyeVJlbGF0aW9uUGF0aEgAEigKBmZpbHRlchgFIAEoCzIWLmNhbWluby5RdWVyeVByZWRpY2F0ZUgAEigKBmV4cGFuZBgGIAEoCzIWLmNhbWluby5RdWVyeUV4cGFuc2lvbkgAEikKCGRpc3RpbmN0GAcgASgLMhUuY2FtaW5vLlF1ZXJ5RGlzdGluY3RIAEILCglvcGVyYXRpb25CCAoGX2lucHV0IlMKGFF1ZXJ5UmVkdWN0aW9uUHJvamVjdGlvbhIMCgRwYXRoGAEgAygJEikKCXJlZHVjdGlvbhgCIAEoCzIWLmNhbWluby5RdWVyeVJlZHVjdGlvbiJQChNRdWVyeUFnZ3JlZ2F0ZU9yZGVyEiUKB29wZXJhbmQYASABKAsyFC5jYW1pbm8uUXVlcnlPcGVyYW5kEhIKCmRlc2NlbmRpbmcYAiABKAgi0gMKF1F1ZXJ5UmVsYXRpb25hbFRlcm1pbmFsEg0KBXN0YWdlGAEgASgNEgwKBHBhdGgYAiADKAkSDgoGZ3JvdXBzGAMgASgIEh4KBGtleXMYBCADKAsyEC5jYW1pbm8uUXVlcnlLZXkSNAoKcmVkdWN0aW9ucxgFIAMoCzIgLmNhbWluby5RdWVyeVJlZHVjdGlvblByb2plY3Rpb24SJQoFd2hlcmUYBiABKAsyFi5jYW1pbm8uUXVlcnlQcmVkaWNhdGUSJgoGaGF2aW5nGAcgASgLMhYuY2FtaW5vLlF1ZXJ5UHJlZGljYXRlEioKBW9yZGVyGAggAygLMhsuY2FtaW5vLlF1ZXJ5QWdncmVnYXRlT3JkZXISJAoFZmlyc3QYCSABKAsyFS5jYW1pbm8uUXVlcnlBcmd1bWVudBIiCgNhbGwYCiABKAsyFS5jYW1pbm8uUXVlcnlBcmd1bWVudBIkCgVhZnRlchgLIAEoCzIVLmNhbWluby5RdWVyeUFyZ3VtZW50EikKCXNlbGVjdGlvbhgMIAMoCzIWLmNhbWluby5RdWVyeVNlbGVjdGlvbhIQCghyZXNpZHVhbBgNIAEoCBIMCgRyb3dzGA4gASgIIncKE1F1ZXJ5UmVsYXRpb25hbFBsYW4SLAoGc3RhZ2VzGAEgAygLMhwuY2FtaW5vLlF1ZXJ5UmVsYXRpb25hbFN0YWdlEjIKCXRlcm1pbmFscxgCIAMoCzIfLmNhbWluby5RdWVyeVJlbGF0aW9uYWxUZXJtaW5hbCLpAgoQUXVlcnlSZWFkQmluZGluZxIPCgdhdG9tX2lkGAEgASgJEh0KFWludGVyZmFjZV9yZXZpc2lvbl9pZBgCIAEoCRIRCgltZW1iZXJfaWQYAyABKAkSGwoTZ2V0dGVyX29wZXJhdGlvbl9pZBgEIAEoCRIPCgdzbG90X2lkGAUgASgJEhQKDGVkZ2VfdHlwZV9pZBgGIAEoCRIVCg1wcm9qZWN0aW9uX2lkGAcgASgJEgsKA3JwYxgIIAEoCBIgChh3YXRjaF9zdGFydF9vcGVyYXRpb25faWQYCSABKAkSHwoXd2F0Y2hfc3RvcF9vcGVyYXRpb25faWQYCiABKAkSEgoKZmllbGRfbmFtZRgLIAEoCRIXCg92YWx1ZV90eXBlX2pzb24YDCABKAkSKAoLY2FyZGluYWxpdHkYDSABKA4yEy5jYW1pbm8uQ2FyZGluYWxpdHkSEAoIa2V5X3R5cGUYDiABKAkirwEKElF1ZXJ5RmllbGRDb250cmFjdBIdChVpbnRlcmZhY2VfcmV2aXNpb25faWQYASABKAkSEQoJbWVtYmVyX2lkGAIgASgJEhIKCmZpZWxkX25hbWUYAyABKAkSFwoPdmFsdWVfdHlwZV9qc29uGAQgASgJEigKC2NhcmRpbmFsaXR5GAUgASgOMhMuY2FtaW5vLkNhcmRpbmFsaXR5EhAKCGtleV90eXBlGAYgASgJIpIBCgxRdWVyeUJ1ZGdldHMSDAoEcm93cxgBIAEoDRINCgVkZXB0aBgCIAEoDRIUCgxyZXN1bHRfYnl0ZXMYAyABKA0SEgoKY2FuZGlkYXRlcxgEIAEoDRIRCglycGNfY2FsbHMYBSABKA0SEwoLY29uY3VycmVuY3kYBiABKA0SEwoLZGVhZGxpbmVfbXMYByABKA0i7wQKDkluc3RhbGxlZFF1ZXJ5EgoKAmlkGAEgASgJEhkKEWRlZmluaXRpb25fZGlnZXN0GAIgASgJEhYKDmJpbmRpbmdfZGlnZXN0GAMgASgJEhoKEG9iamVjdF9pbnRlcmZhY2UYBCABKAlIABIdChN3b3Jrc3BhY2VfaW50ZXJmYWNlGA4gASgJSAASKQoJc2VsZWN0aW9uGAUgAygLMhYuY2FtaW5vLlF1ZXJ5U2VsZWN0aW9uEioKCGJpbmRpbmdzGAYgAygLMhguY2FtaW5vLlF1ZXJ5UmVhZEJpbmRpbmcSJQoHYnVkZ2V0cxgHIAEoCzIULmNhbWluby5RdWVyeUJ1ZGdldHMSGwoTdmFyaWFibGVzX3R5cGVfanNvbhgIIAEoCRIYChBvdXRwdXRfdHlwZV9qc29uGAkgASgJEkcKEXZhcmlhYmxlX2RlZmF1bHRzGAogAygLMiwuY2FtaW5vLkluc3RhbGxlZFF1ZXJ5LlZhcmlhYmxlRGVmYXVsdHNFbnRyeRINCgV3YXRjaBgLIAEoCBIbChNwb2xsaW5nX2ludGVydmFsX21zGAwgASgNEh4KFnJwY19wcmVkaWNhdGVfb3Jfb3JkZXIYDSABKAgSFQoNcm9vdF9hdG9tX2lkcxgPIAMoCRIqCgZmaWVsZHMYECADKAsyGi5jYW1pbm8uUXVlcnlGaWVsZENvbnRyYWN0Gk4KFVZhcmlhYmxlRGVmYXVsdHNFbnRyeRILCgNrZXkYASABKAkSJAoFdmFsdWUYAiABKAsyFS5jYW1pbm8uUXVlcnlBcmd1bWVudDoCOAFCBgoEcm9vdCpoCgtDYXJkaW5hbGl0eRIbChdDQVJESU5BTElUWV9VTlNQRUNJRklFRBAAEhAKDE9QVElPTkFMX09ORRABEg8KC0VYQUNUTFlfT05FEAISCAoETUFOWRADEg8KC01BTllfVU5JUVVFEAQqmgIKFlF1ZXJ5QWdncmVnYXRlT3BlcmF0b3ISKAokUVVFUllfQUdHUkVHQVRFX09QRVJBVE9SX1VOU1BFQ0lGSUVEEAASIgoeUVVFUllfQUdHUkVHQVRFX09QRVJBVE9SX0NPVU5UEAESKgomUVVFUllfQUdHUkVHQVRFX09QRVJBVE9SX0NPVU5UX1BSRVNFTlQQAhIgChxRVUVSWV9BR0dSRUdBVEVfT1BFUkFUT1JfU1VNEAMSIAocUVVFUllfQUdHUkVHQVRFX09QRVJBVE9SX0FWRxAEEiAKHFFVRVJZX0FHR1JFR0FURV9PUEVSQVRPUl9NSU4QBRIgChxRVUVSWV9BR0dSRUdBVEVfT1BFUkFUT1JfTUFYEAYquQIKF1F1ZXJ5Q29tcGFyaXNvbk9wZXJhdG9yEikKJVFVRVJZX0NPTVBBUklTT05fT1BFUkFUT1JfVU5TUEVDSUZJRUQQABIgChxRVUVSWV9DT01QQVJJU09OX09QRVJBVE9SX0VREAESIAocUVVFUllfQ09NUEFSSVNPTl9PUEVSQVRPUl9JThACEiUKIVFVRVJZX0NPTVBBUklTT05fT1BFUkFUT1JfSVNfTlVMTBADEiAKHFFVRVJZX0NPTVBBUklTT05fT1BFUkFUT1JfTFQQBBIhCh1RVUVSWV9DT01QQVJJU09OX09QRVJBVE9SX0xURRAFEiAKHFFVRVJZX0NPTVBBUklTT05fT1BFUkFUT1JfR1QQBhIhCh1RVUVSWV9DT01QQVJJU09OX09QRVJBVE9SX0dURRAHKoQCCh5RdWVyeVJlbGF0aW9uUHJlZGljYXRlT3BlcmF0b3ISMQotUVVFUllfUkVMQVRJT05fUFJFRElDQVRFX09QRVJBVE9SX1VOU1BFQ0lGSUVEEAASKgomUVVFUllfUkVMQVRJT05fUFJFRElDQVRFX09QRVJBVE9SX1NPTUUQARIqCiZRVUVSWV9SRUxBVElPTl9QUkVESUNBVEVfT1BFUkFUT1JfTk9ORRACEigKJFFVRVJZX1JFTEFUSU9OX1BSRURJQ0FURV9PUEVSQVRPUl9JUxADEi0KKVFVRVJZX1JFTEFUSU9OX1BSRURJQ0FURV9PUEVSQVRPUl9JU19OVUxMEARiBnByb3RvMw"); + fileDesc("ChNjYW1pbm8vc2NoZW1hLnByb3RvEgZjYW1pbm8iNwoOQXRvbURlZmluaXRpb24SDwoHYXRvbV9pZBgBIAEoCRIUCgxkaXNwbGF5X25hbWUYAiABKAkiWQoPQXRvbUNvbmZvcm1hbmNlEg8KB2F0b21faWQYASABKAkSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAIgASgJEhYKDmNvbmZvcm1hbmNlX2lkGAMgASgJIsIBCg9TdGF0ZUF0dGFjaG1lbnQSDwoHc2xvdF9pZBgBIAEoCRIYChBhdHRhY2hlZF9hdG9tX2lkGAIgASgJEhQKDGRpc3BsYXlfbmFtZRgDIAEoCRIXCg92YWx1ZV90eXBlX2pzb24YBCABKAkSGwoTc3RvcmFnZV9wb2xpY3lfanNvbhgFIAEoCRIaChJkZWZhdWx0X3ZhbHVlX2pzb24YBiABKAkSHAoUb3duZXJfY29uZm9ybWFuY2VfaWQYByABKAkiUAoSRW5kcG9pbnRDb25zdHJhaW50EhEKB2F0b21faWQYASABKAlIABIfChVpbnRlcmZhY2VfcmV2aXNpb25faWQYAiABKAlIAEIGCgRraW5kIvsBCgxFZGdlRW5kcG9pbnQSFQoNcHJvamVjdGlvbl9pZBgBIAEoCRIUCgxkaXNwbGF5X25hbWUYAiABKAkSLgoKY29uc3RyYWludBgDIAEoCzIaLmNhbWluby5FbmRwb2ludENvbnN0cmFpbnQSKAoLY2FyZGluYWxpdHkYBCABKA4yEy5jYW1pbm8uQ2FyZGluYWxpdHkSDwoHb3JkZXJlZBgFIAEoCBIRCglvbl9kZWxldGUYBiABKAkSFAoMcmV0YWluX290aGVyGAcgASgIEhAKCGtleV90eXBlGAggASgJEhgKEHB1YmxpY190cmF2ZXJzYWwYCSABKAgipQEKDkVkZ2VBdHRhY2htZW50EhQKDGVkZ2VfdHlwZV9pZBgBIAEoCRIUCgxkaXNwbGF5X25hbWUYAiABKAkSIwoFZmlyc3QYAyABKAsyFC5jYW1pbm8uRWRnZUVuZHBvaW50EiQKBnNlY29uZBgEIAEoCzIULmNhbWluby5FZGdlRW5kcG9pbnQSHAoUb3duZXJfY29uZm9ybWFuY2VfaWQYBSABKAkilQIKD1BlcnNpc3RlbmNlUGxhbhIUCgx3b3Jrc3BhY2VfaWQYASABKAkSHQoVd29ya3NwYWNlX3JldmlzaW9uX2lkGAIgASgJEiUKBWF0b21zGAMgAygLMhYuY2FtaW5vLkF0b21EZWZpbml0aW9uEi0KDGNvbmZvcm1hbmNlcxgEIAMoCzIXLmNhbWluby5BdG9tQ29uZm9ybWFuY2USJwoGc3RhdGVzGAUgAygLMhcuY2FtaW5vLlN0YXRlQXR0YWNobWVudBIlCgVlZGdlcxgGIAMoCzIWLmNhbWluby5FZGdlQXR0YWNobWVudBInCgdxdWVyaWVzGAcgAygLMhYuY2FtaW5vLkluc3RhbGxlZFF1ZXJ5Ip4BCg1RdWVyeUFyZ3VtZW50EhIKCHZhcmlhYmxlGAEgASgJSAASFgoMbGl0ZXJhbF9qc29uGAIgASgJSAASKQoEbGlzdBgDIAEoCzIZLmNhbWluby5RdWVyeUFyZ3VtZW50TGlzdEgAEi0KBm9iamVjdBgEIAEoCzIbLmNhbWluby5RdWVyeUFyZ3VtZW50T2JqZWN0SABCBwoFdmFsdWUiOgoRUXVlcnlBcmd1bWVudExpc3QSJQoGdmFsdWVzGAEgAygLMhUuY2FtaW5vLlF1ZXJ5QXJndW1lbnQilAEKE1F1ZXJ5QXJndW1lbnRPYmplY3QSNwoGZmllbGRzGAEgAygLMicuY2FtaW5vLlF1ZXJ5QXJndW1lbnRPYmplY3QuRmllbGRzRW50cnkaRAoLRmllbGRzRW50cnkSCwoDa2V5GAEgASgJEiQKBXZhbHVlGAIgASgLMhUuY2FtaW5vLlF1ZXJ5QXJndW1lbnQ6AjgBIkcKDlF1ZXJ5Q29uZGl0aW9uEg8KB2luY2x1ZGUYASABKAgSJAoFdmFsdWUYAiABKAsyFS5jYW1pbm8uUXVlcnlBcmd1bWVudCLUAwoOUXVlcnlTZWxlY3Rpb24SDAoEbmFtZRgBIAEoCRILCgNrZXkYAiABKAkSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAMgASgJEhEKCW1lbWJlcl9pZBgEIAEoCRIkChx0YXJnZXRfaW50ZXJmYWNlX3JldmlzaW9uX2lkGAUgASgJEioKCmNvbmRpdGlvbnMYBiADKAsyFi5jYW1pbm8uUXVlcnlDb25kaXRpb24SOAoJYXJndW1lbnRzGAcgAygLMiUuY2FtaW5vLlF1ZXJ5U2VsZWN0aW9uLkFyZ3VtZW50c0VudHJ5EikKCXNlbGVjdGlvbhgIIAMoCzIWLmNhbWluby5RdWVyeVNlbGVjdGlvbhIvCgpyZWxhdGlvbmFsGAkgASgLMhsuY2FtaW5vLlF1ZXJ5UmVsYXRpb25hbFBsYW4SKQoJcHJlZGljYXRlGAogASgLMhYuY2FtaW5vLlF1ZXJ5UHJlZGljYXRlEhkKEWxpdmVfc2VsZWN0aW9uX2lkGAsgASgJGkcKDkFyZ3VtZW50c0VudHJ5EgsKA2tleRgBIAEoCRIkCgV2YWx1ZRgCIAEoCzIVLmNhbWluby5RdWVyeUFyZ3VtZW50OgI4ASJqCg1RdWVyeVBhdGhTdGVwEhAKBnNvdXJjZRgBIAEoCEgAEhAKBnRhcmdldBgCIAEoCEgAEi0KCHJlbGF0aW9uGAMgASgLMhkuY2FtaW5vLlF1ZXJ5UmVsYXRpb25QYXRoSABCBgoEc3RlcCJ9ChFRdWVyeVJlbGF0aW9uUGF0aBIdChVpbnRlcmZhY2VfcmV2aXNpb25faWQYASABKAkSEQoJbWVtYmVyX2lkGAIgASgJEiQKHHRhcmdldF9pbnRlcmZhY2VfcmV2aXNpb25faWQYAyABKAkSEAoIb3B0aW9uYWwYBCABKAgiRQoRUXVlcnlGaWVsZE9wZXJhbmQSHQoVaW50ZXJmYWNlX3JldmlzaW9uX2lkGAEgASgJEhEKCW1lbWJlcl9pZBgCIAEoCSK2AQoPUXVlcnlFeHByZXNzaW9uEiMKBHBhdGgYASADKAsyFS5jYW1pbm8uUXVlcnlQYXRoU3RlcBIqCgVmaWVsZBgCIAEoCzIZLmNhbWluby5RdWVyeUZpZWxkT3BlcmFuZEgAEg0KA3JlZhgDIAEoCUgAEg8KBWVudHJ5GAQgASgISAASEQoHbWFwX2tleRgFIAEoCEgAEhcKD3ZhbHVlX3R5cGVfanNvbhgGIAEoCUIGCgRsZWFmIoUBCg5RdWVyeVJlZHVjdGlvbhIwCghvcGVyYXRvchgBIAEoDjIeLmNhbWluby5RdWVyeUFnZ3JlZ2F0ZU9wZXJhdG9yEigKB29wZXJhbmQYAiABKAsyFy5jYW1pbm8uUXVlcnlFeHByZXNzaW9uEhcKD3ZhbHVlX3R5cGVfanNvbhgDIAEoCSJ1CgxRdWVyeU9wZXJhbmQSLQoKZXhwcmVzc2lvbhgBIAEoCzIXLmNhbWluby5RdWVyeUV4cHJlc3Npb25IABIrCglyZWR1Y3Rpb24YAiABKAsyFi5jYW1pbm8uUXVlcnlSZWR1Y3Rpb25IAEIJCgdvcGVyYW5kIpEBCg9RdWVyeUNvbXBhcmlzb24SJQoHb3BlcmFuZBgBIAEoCzIULmNhbWluby5RdWVyeU9wZXJhbmQSMQoIb3BlcmF0b3IYAiABKA4yHy5jYW1pbm8uUXVlcnlDb21wYXJpc29uT3BlcmF0b3ISJAoFdmFsdWUYAyABKAsyFS5jYW1pbm8uUXVlcnlBcmd1bWVudCI+ChJRdWVyeVByZWRpY2F0ZUxpc3QSKAoIY2hpbGRyZW4YASADKAsyFi5jYW1pbm8uUXVlcnlQcmVkaWNhdGUi9QEKFlF1ZXJ5UmVsYXRpb25QcmVkaWNhdGUSIwoEcGF0aBgBIAMoCzIVLmNhbWluby5RdWVyeVBhdGhTdGVwEisKCHJlbGF0aW9uGAIgASgLMhkuY2FtaW5vLlF1ZXJ5UmVsYXRpb25QYXRoEjgKCG9wZXJhdG9yGAMgASgOMiYuY2FtaW5vLlF1ZXJ5UmVsYXRpb25QcmVkaWNhdGVPcGVyYXRvchIpCglwcmVkaWNhdGUYBCABKAsyFi5jYW1pbm8uUXVlcnlQcmVkaWNhdGUSJAoFdmFsdWUYBSABKAsyFS5jYW1pbm8uUXVlcnlBcmd1bWVudCK6AQoXUXVlcnlSZWR1Y3Rpb25QcmVkaWNhdGUSIwoEcGF0aBgBIAMoCzIVLmNhbWluby5RdWVyeVBhdGhTdGVwEisKCHJlbGF0aW9uGAIgASgLMhkuY2FtaW5vLlF1ZXJ5UmVsYXRpb25QYXRoEiUKBXdoZXJlGAMgASgLMhYuY2FtaW5vLlF1ZXJ5UHJlZGljYXRlEiYKBmhhdmluZxgEIAEoCzIWLmNhbWluby5RdWVyeVByZWRpY2F0ZSKsAgoOUXVlcnlQcmVkaWNhdGUSKQoDYW5kGAEgASgLMhouY2FtaW5vLlF1ZXJ5UHJlZGljYXRlTGlzdEgAEigKAm9yGAIgASgLMhouY2FtaW5vLlF1ZXJ5UHJlZGljYXRlTGlzdEgAEiUKA25vdBgDIAEoCzIWLmNhbWluby5RdWVyeVByZWRpY2F0ZUgAEioKB2NvbXBhcmUYBCABKAsyFy5jYW1pbm8uUXVlcnlDb21wYXJpc29uSAASMgoIcmVsYXRpb24YBSABKAsyHi5jYW1pbm8uUXVlcnlSZWxhdGlvblByZWRpY2F0ZUgAEjEKBnJlZHVjZRgGIAEoCzIfLmNhbWluby5RdWVyeVJlZHVjdGlvblByZWRpY2F0ZUgAQgsKCXByZWRpY2F0ZSJhCghRdWVyeVJvdxIoCgZvYmplY3QYASABKAsyFi5jYW1pbm8uUXVlcnlPYmplY3RSb3dIABIkCgRwYWlyGAIgASgLMhQuY2FtaW5vLlF1ZXJ5UGFpclJvd0gAQgUKA3JvdyJVCg5RdWVyeU9iamVjdFJvdxIdChVpbnRlcmZhY2VfcmV2aXNpb25faWQYASABKAkSEgoKbWVtYmVyc2hpcBgCIAEoCBIQCghrZXlfdHlwZRgDIAEoCSJSCgxRdWVyeVBhaXJSb3cSIAoGc291cmNlGAEgASgLMhAuY2FtaW5vLlF1ZXJ5Um93EiAKBnRhcmdldBgCIAEoCzIQLmNhbWluby5RdWVyeVJvdyJFCghRdWVyeUtleRIMCgRwYXRoGAEgAygJEisKCmV4cHJlc3Npb24YAiABKAsyFy5jYW1pbm8uUXVlcnlFeHByZXNzaW9uIi8KDVF1ZXJ5RGlzdGluY3QSHgoEa2V5cxgBIAMoCzIQLmNhbWluby5RdWVyeUtleSJiCg5RdWVyeUV4cGFuc2lvbhIjCgRwYXRoGAEgAygLMhUuY2FtaW5vLlF1ZXJ5UGF0aFN0ZXASKwoIcmVsYXRpb24YAiABKAsyGS5jYW1pbm8uUXVlcnlSZWxhdGlvblBhdGgimAIKFFF1ZXJ5UmVsYXRpb25hbFN0YWdlEgoKAmlkGAEgASgNEhIKBWlucHV0GAIgASgNSAGIAQESHQoDcm93GAMgASgLMhAuY2FtaW5vLlF1ZXJ5Um93EisKBnNvdXJjZRgEIAEoCzIZLmNhbWluby5RdWVyeVJlbGF0aW9uUGF0aEgAEigKBmZpbHRlchgFIAEoCzIWLmNhbWluby5RdWVyeVByZWRpY2F0ZUgAEigKBmV4cGFuZBgGIAEoCzIWLmNhbWluby5RdWVyeUV4cGFuc2lvbkgAEikKCGRpc3RpbmN0GAcgASgLMhUuY2FtaW5vLlF1ZXJ5RGlzdGluY3RIAEILCglvcGVyYXRpb25CCAoGX2lucHV0IlMKGFF1ZXJ5UmVkdWN0aW9uUHJvamVjdGlvbhIMCgRwYXRoGAEgAygJEikKCXJlZHVjdGlvbhgCIAEoCzIWLmNhbWluby5RdWVyeVJlZHVjdGlvbiJQChNRdWVyeUFnZ3JlZ2F0ZU9yZGVyEiUKB29wZXJhbmQYASABKAsyFC5jYW1pbm8uUXVlcnlPcGVyYW5kEhIKCmRlc2NlbmRpbmcYAiABKAgi0gMKF1F1ZXJ5UmVsYXRpb25hbFRlcm1pbmFsEg0KBXN0YWdlGAEgASgNEgwKBHBhdGgYAiADKAkSDgoGZ3JvdXBzGAMgASgIEh4KBGtleXMYBCADKAsyEC5jYW1pbm8uUXVlcnlLZXkSNAoKcmVkdWN0aW9ucxgFIAMoCzIgLmNhbWluby5RdWVyeVJlZHVjdGlvblByb2plY3Rpb24SJQoFd2hlcmUYBiABKAsyFi5jYW1pbm8uUXVlcnlQcmVkaWNhdGUSJgoGaGF2aW5nGAcgASgLMhYuY2FtaW5vLlF1ZXJ5UHJlZGljYXRlEioKBW9yZGVyGAggAygLMhsuY2FtaW5vLlF1ZXJ5QWdncmVnYXRlT3JkZXISJAoFZmlyc3QYCSABKAsyFS5jYW1pbm8uUXVlcnlBcmd1bWVudBIiCgNhbGwYCiABKAsyFS5jYW1pbm8uUXVlcnlBcmd1bWVudBIkCgVhZnRlchgLIAEoCzIVLmNhbWluby5RdWVyeUFyZ3VtZW50EikKCXNlbGVjdGlvbhgMIAMoCzIWLmNhbWluby5RdWVyeVNlbGVjdGlvbhIQCghyZXNpZHVhbBgNIAEoCBIMCgRyb3dzGA4gASgIIncKE1F1ZXJ5UmVsYXRpb25hbFBsYW4SLAoGc3RhZ2VzGAEgAygLMhwuY2FtaW5vLlF1ZXJ5UmVsYXRpb25hbFN0YWdlEjIKCXRlcm1pbmFscxgCIAMoCzIfLmNhbWluby5RdWVyeVJlbGF0aW9uYWxUZXJtaW5hbCLpAgoQUXVlcnlSZWFkQmluZGluZxIPCgdhdG9tX2lkGAEgASgJEh0KFWludGVyZmFjZV9yZXZpc2lvbl9pZBgCIAEoCRIRCgltZW1iZXJfaWQYAyABKAkSGwoTZ2V0dGVyX29wZXJhdGlvbl9pZBgEIAEoCRIPCgdzbG90X2lkGAUgASgJEhQKDGVkZ2VfdHlwZV9pZBgGIAEoCRIVCg1wcm9qZWN0aW9uX2lkGAcgASgJEgsKA3JwYxgIIAEoCBIgChh3YXRjaF9zdGFydF9vcGVyYXRpb25faWQYCSABKAkSHwoXd2F0Y2hfc3RvcF9vcGVyYXRpb25faWQYCiABKAkSEgoKZmllbGRfbmFtZRgLIAEoCRIXCg92YWx1ZV90eXBlX2pzb24YDCABKAkSKAoLY2FyZGluYWxpdHkYDSABKA4yEy5jYW1pbm8uQ2FyZGluYWxpdHkSEAoIa2V5X3R5cGUYDiABKAkirwEKElF1ZXJ5RmllbGRDb250cmFjdBIdChVpbnRlcmZhY2VfcmV2aXNpb25faWQYASABKAkSEQoJbWVtYmVyX2lkGAIgASgJEhIKCmZpZWxkX25hbWUYAyABKAkSFwoPdmFsdWVfdHlwZV9qc29uGAQgASgJEigKC2NhcmRpbmFsaXR5GAUgASgOMhMuY2FtaW5vLkNhcmRpbmFsaXR5EhAKCGtleV90eXBlGAYgASgJIpIBCgxRdWVyeUJ1ZGdldHMSDAoEcm93cxgBIAEoDRINCgVkZXB0aBgCIAEoDRIUCgxyZXN1bHRfYnl0ZXMYAyABKA0SEgoKY2FuZGlkYXRlcxgEIAEoDRIRCglycGNfY2FsbHMYBSABKA0SEwoLY29uY3VycmVuY3kYBiABKA0SEwoLZGVhZGxpbmVfbXMYByABKA0i7wQKDkluc3RhbGxlZFF1ZXJ5EgoKAmlkGAEgASgJEhkKEWRlZmluaXRpb25fZGlnZXN0GAIgASgJEhYKDmJpbmRpbmdfZGlnZXN0GAMgASgJEhoKEG9iamVjdF9pbnRlcmZhY2UYBCABKAlIABIdChN3b3Jrc3BhY2VfaW50ZXJmYWNlGA4gASgJSAASKQoJc2VsZWN0aW9uGAUgAygLMhYuY2FtaW5vLlF1ZXJ5U2VsZWN0aW9uEioKCGJpbmRpbmdzGAYgAygLMhguY2FtaW5vLlF1ZXJ5UmVhZEJpbmRpbmcSJQoHYnVkZ2V0cxgHIAEoCzIULmNhbWluby5RdWVyeUJ1ZGdldHMSGwoTdmFyaWFibGVzX3R5cGVfanNvbhgIIAEoCRIYChBvdXRwdXRfdHlwZV9qc29uGAkgASgJEkcKEXZhcmlhYmxlX2RlZmF1bHRzGAogAygLMiwuY2FtaW5vLkluc3RhbGxlZFF1ZXJ5LlZhcmlhYmxlRGVmYXVsdHNFbnRyeRINCgV3YXRjaBgLIAEoCBIbChNwb2xsaW5nX2ludGVydmFsX21zGAwgASgNEh4KFnJwY19wcmVkaWNhdGVfb3Jfb3JkZXIYDSABKAgSFQoNcm9vdF9hdG9tX2lkcxgPIAMoCRIqCgZmaWVsZHMYECADKAsyGi5jYW1pbm8uUXVlcnlGaWVsZENvbnRyYWN0Gk4KFVZhcmlhYmxlRGVmYXVsdHNFbnRyeRILCgNrZXkYASABKAkSJAoFdmFsdWUYAiABKAsyFS5jYW1pbm8uUXVlcnlBcmd1bWVudDoCOAFCBgoEcm9vdCpoCgtDYXJkaW5hbGl0eRIbChdDQVJESU5BTElUWV9VTlNQRUNJRklFRBAAEhAKDE9QVElPTkFMX09ORRABEg8KC0VYQUNUTFlfT05FEAISCAoETUFOWRADEg8KC01BTllfVU5JUVVFEAQqmgIKFlF1ZXJ5QWdncmVnYXRlT3BlcmF0b3ISKAokUVVFUllfQUdHUkVHQVRFX09QRVJBVE9SX1VOU1BFQ0lGSUVEEAASIgoeUVVFUllfQUdHUkVHQVRFX09QRVJBVE9SX0NPVU5UEAESKgomUVVFUllfQUdHUkVHQVRFX09QRVJBVE9SX0NPVU5UX1BSRVNFTlQQAhIgChxRVUVSWV9BR0dSRUdBVEVfT1BFUkFUT1JfU1VNEAMSIAocUVVFUllfQUdHUkVHQVRFX09QRVJBVE9SX0FWRxAEEiAKHFFVRVJZX0FHR1JFR0FURV9PUEVSQVRPUl9NSU4QBRIgChxRVUVSWV9BR0dSRUdBVEVfT1BFUkFUT1JfTUFYEAYq7QIKF1F1ZXJ5Q29tcGFyaXNvbk9wZXJhdG9yEikKJVFVRVJZX0NPTVBBUklTT05fT1BFUkFUT1JfVU5TUEVDSUZJRUQQABIgChxRVUVSWV9DT01QQVJJU09OX09QRVJBVE9SX0VREAESIAocUVVFUllfQ09NUEFSSVNPTl9PUEVSQVRPUl9JThACEiUKIVFVRVJZX0NPTVBBUklTT05fT1BFUkFUT1JfSVNfTlVMTBADEiAKHFFVRVJZX0NPTVBBUklTT05fT1BFUkFUT1JfTFQQBBIhCh1RVUVSWV9DT01QQVJJU09OX09QRVJBVE9SX0xURRAFEiAKHFFVRVJZX0NPTVBBUklTT05fT1BFUkFUT1JfR1QQBhIhCh1RVUVSWV9DT01QQVJJU09OX09QRVJBVE9SX0dURRAHEjIKLlFVRVJZX0NPTVBBUklTT05fT1BFUkFUT1JfQ09OVEFJTlNfSU5TRU5TSVRJVkUQCCqEAgoeUXVlcnlSZWxhdGlvblByZWRpY2F0ZU9wZXJhdG9yEjEKLVFVRVJZX1JFTEFUSU9OX1BSRURJQ0FURV9PUEVSQVRPUl9VTlNQRUNJRklFRBAAEioKJlFVRVJZX1JFTEFUSU9OX1BSRURJQ0FURV9PUEVSQVRPUl9TT01FEAESKgomUVVFUllfUkVMQVRJT05fUFJFRElDQVRFX09QRVJBVE9SX05PTkUQAhIoCiRRVUVSWV9SRUxBVElPTl9QUkVESUNBVEVfT1BFUkFUT1JfSVMQAxItCilRVUVSWV9SRUxBVElPTl9QUkVESUNBVEVfT1BFUkFUT1JfSVNfTlVMTBAEYgZwcm90bzM"); /** * @generated from message camino.AtomDefinition @@ -1563,6 +1563,11 @@ export enum QueryComparisonOperator { * @generated from enum value: QUERY_COMPARISON_OPERATOR_GTE = 7; */ GTE = 7, + + /** + * @generated from enum value: QUERY_COMPARISON_OPERATOR_CONTAINS_INSENSITIVE = 8; + */ + CONTAINS_INSENSITIVE = 8, } /** diff --git a/src/query/relational-compile.ts b/src/query/relational-compile.ts index c9723bf..25a076f 100644 --- a/src/query/relational-compile.ts +++ b/src/query/relational-compile.ts @@ -53,7 +53,7 @@ const pairs = (node: ValueNode): readonly import("graphql").ObjectFieldNode[] => node.kind === "ObjectValue" ? node.fields : fail("QUERY_UNSUPPORTED_FEATURE", "Query structure must be a literal object", node); -const ops = new Set(["eq", "in", "isNull", "lt", "lte", "gt", "gte"]); +const ops = new Set(["eq", "containsInsensitive", "in", "isNull", "lt", "lte", "gt", "gte"]); const prefix = (a: readonly string[], b: readonly string[]) => a.every((part, i) => part === b[i]); export function relationalCompiler( diff --git a/src/query/relational-proto.ts b/src/query/relational-proto.ts index 9f5d6a3..157cb65 100644 --- a/src/query/relational-proto.ts +++ b/src/query/relational-proto.ts @@ -66,6 +66,7 @@ export function relationalWire( value: argument(p.value), operator: { eq: wire.QueryComparisonOperator.EQ, + containsInsensitive: wire.QueryComparisonOperator.CONTAINS_INSENSITIVE, in: wire.QueryComparisonOperator.IN, isNull: wire.QueryComparisonOperator.IS_NULL, lt: wire.QueryComparisonOperator.LT, diff --git a/src/query/relational.ts b/src/query/relational.ts index fee63c0..cbfd509 100644 --- a/src/query/relational.ts +++ b/src/query/relational.ts @@ -65,7 +65,7 @@ export type QueryPredicate = | { kind: "compare"; expression: QueryExpression; - operator: "eq" | "in" | "isNull" | "lt" | "lte" | "gt" | "gte"; + operator: "eq" | "containsInsensitive" | "in" | "isNull" | "lt" | "lte" | "gt" | "gte"; value: QueryArgument; } | { @@ -93,7 +93,7 @@ export type QueryAggregatePredicate = | { kind: "compare"; expression: QueryExpression | QueryReduction; - operator: "eq" | "in" | "isNull" | "lt" | "lte" | "gt" | "gte"; + operator: "eq" | "containsInsensitive" | "in" | "isNull" | "lt" | "lte" | "gt" | "gte"; value: QueryArgument; }; export interface QueryKey { diff --git a/src/query/schema.ts b/src/query/schema.ts index b89b0e9..5100548 100644 --- a/src/query/schema.ts +++ b/src/query/schema.ts @@ -139,6 +139,7 @@ export function querySchema( let result = comparisons.get(key); if (!result) { const fields: GraphQLInputFieldConfigMap = { eq: { type: value }, isNull: { type: GraphQLBoolean } }; + if (base.kind === "scalar" && base.name === "string") fields.containsInsensitive = { type: value }; if (base.kind === "scalar" && base.name !== "bytes") fields.in = { type: new GraphQLList(new GraphQLNonNull(value)) }; if (base.kind === "scalar" && base.name !== "bool" && base.name !== "bytes") diff --git a/test/fixtures/query-workspace.ts b/test/fixtures/query-workspace.ts index f245a5d..b8f868f 100644 --- a/test/fixtures/query-workspace.ts +++ b/test/fixtures/query-workspace.ts @@ -76,7 +76,7 @@ export async function queryWorkspaceFixture(options: { live?: boolean } = {}) { const pkg: PackageRevision = pkgResult.resource.revision; const allInterfaces = [...interfaces.values(), ...(pkgResult.resource.specializations ?? [])]; const documents: Record = { - "extent.graphql": `query Extent {root {objects(first: 30, orderBy: [{rank: ASC}]) {entries {node {_qx {ref} title rank}}}}}`, + "extent.graphql": `query Extent($text: String! = "") {root {objects(first: 30, where: {title: {containsInsensitive: $text}}, orderBy: [{rank: ASC}]) {entries {node {_qx {ref} title rank}}}}}`, "upcoming.graphql": `query Upcoming($first: Int!, $after: Cursor) {root {items(first: $first, after: $after, where: {done: {eq: false}}, orderBy: [{rank: ASC}]) {entries {key cursor node {_qx {ref} ...TaskRow}} pageInfo {hasNextPage endCursor}}}}`, "row.graphql": `fragment TaskRow on TaskFacts {title rank done assignee {name}}`, "enriched.graphql": `query Enriched {root {items(first: 3) {entries {key node {_qx {ref} title score}}}}}`, diff --git a/test/query-compiler.test.ts b/test/query-compiler.test.ts index deeea33..0170666 100644 --- a/test/query-compiler.test.ts +++ b/test/query-compiler.test.ts @@ -276,6 +276,10 @@ test("fixed GraphQL yields exact effects, typed references and distinct query ar test("query allowlist and two-sided RPC effects fail during compilation", async () => { const rejects = (promise: Promise, code: string) => assert.rejects(promise, (error: unknown) => error instanceof QueryCompileError && error.code === code); + const substring = (field: string) => + `query Upcoming {root {items(first: 3, where: {${field}: {containsInsensitive: "TASK"}}) {entries {node {...Row}}}}}`; + await compile(substring("title")); + await rejects(compile(substring("due")), "QUERY_VALIDATION"); await rejects(compile(document, "fragment Row on TaskFacts { hidden }"), "QUERY_VALIDATION"); await rejects(compile(document, "fragment Row on TaskFacts { score }"), "QUERY_RPC_CONSUMER_REASON"); await compile(