metadata.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871
  1. // Copyright (c) 2015 The gocql Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. package gocql
  5. import (
  6. "encoding/hex"
  7. "encoding/json"
  8. "fmt"
  9. "log"
  10. "strconv"
  11. "strings"
  12. "sync"
  13. )
  14. // schema metadata for a keyspace
  15. type KeyspaceMetadata struct {
  16. Name string
  17. DurableWrites bool
  18. StrategyClass string
  19. StrategyOptions map[string]interface{}
  20. Tables map[string]*TableMetadata
  21. }
  22. // schema metadata for a table (a.k.a. column family)
  23. type TableMetadata struct {
  24. Keyspace string
  25. Name string
  26. KeyValidator string
  27. Comparator string
  28. DefaultValidator string
  29. KeyAliases []string
  30. ColumnAliases []string
  31. ValueAlias string
  32. PartitionKey []*ColumnMetadata
  33. ClusteringColumns []*ColumnMetadata
  34. Columns map[string]*ColumnMetadata
  35. }
  36. // schema metadata for a column
  37. type ColumnMetadata struct {
  38. Keyspace string
  39. Table string
  40. Name string
  41. ComponentIndex int
  42. Kind string
  43. Validator string
  44. Type TypeInfo
  45. Order ColumnOrder
  46. Index ColumnIndexMetadata
  47. }
  48. // the ordering of the column with regard to its comparator
  49. type ColumnOrder bool
  50. const (
  51. ASC ColumnOrder = false
  52. DESC = true
  53. )
  54. type ColumnIndexMetadata struct {
  55. Name string
  56. Type string
  57. Options map[string]interface{}
  58. }
  59. // Column kind values
  60. const (
  61. PARTITION_KEY = "partition_key"
  62. CLUSTERING_KEY = "clustering_key"
  63. REGULAR = "regular"
  64. )
  65. // default alias values
  66. const (
  67. DEFAULT_KEY_ALIAS = "key"
  68. DEFAULT_COLUMN_ALIAS = "column"
  69. DEFAULT_VALUE_ALIAS = "value"
  70. )
  71. // queries the cluster for schema information for a specific keyspace
  72. type schemaDescriber struct {
  73. session *Session
  74. mu sync.Mutex
  75. cache map[string]*KeyspaceMetadata
  76. }
  77. // creates a session bound schema describer which will query and cache
  78. // keyspace metadata
  79. func newSchemaDescriber(session *Session) *schemaDescriber {
  80. return &schemaDescriber{
  81. session: session,
  82. cache: map[string]*KeyspaceMetadata{},
  83. }
  84. }
  85. // returns the cached KeyspaceMetadata held by the describer for the named
  86. // keyspace.
  87. func (s *schemaDescriber) getSchema(keyspaceName string) (*KeyspaceMetadata, error) {
  88. s.mu.Lock()
  89. defer s.mu.Unlock()
  90. // TODO handle schema change events
  91. metadata, found := s.cache[keyspaceName]
  92. if !found {
  93. // refresh the cache for this keyspace
  94. err := s.refreshSchema(keyspaceName)
  95. if err != nil {
  96. return nil, err
  97. }
  98. metadata = s.cache[keyspaceName]
  99. }
  100. return metadata, nil
  101. }
  102. // forcibly updates the current KeyspaceMetadata held by the schema describer
  103. // for a given named keyspace.
  104. func (s *schemaDescriber) refreshSchema(keyspaceName string) error {
  105. var err error
  106. // query the system keyspace for schema data
  107. // TODO retrieve concurrently
  108. keyspace, err := getKeyspaceMetadata(s.session, keyspaceName)
  109. if err != nil {
  110. return err
  111. }
  112. tables, err := getTableMetadata(s.session, keyspaceName)
  113. if err != nil {
  114. return err
  115. }
  116. columns, err := getColumnMetadata(s.session, keyspaceName)
  117. if err != nil {
  118. return err
  119. }
  120. // organize the schema data
  121. compileMetadata(s.session.cfg.ProtoVersion, keyspace, tables, columns)
  122. // update the cache
  123. s.cache[keyspaceName] = keyspace
  124. return nil
  125. }
  126. // "compiles" derived information about keyspace, table, and column metadata
  127. // for a keyspace from the basic queried metadata objects returned by
  128. // getKeyspaceMetadata, getTableMetadata, and getColumnMetadata respectively;
  129. // Links the metadata objects together and derives the column composition of
  130. // the partition key and clustering key for a table.
  131. func compileMetadata(
  132. protoVersion int,
  133. keyspace *KeyspaceMetadata,
  134. tables []TableMetadata,
  135. columns []ColumnMetadata,
  136. ) {
  137. keyspace.Tables = make(map[string]*TableMetadata)
  138. for i := range tables {
  139. tables[i].Columns = make(map[string]*ColumnMetadata)
  140. keyspace.Tables[tables[i].Name] = &tables[i]
  141. }
  142. // add columns from the schema data
  143. for i := range columns {
  144. // decode the validator for TypeInfo and order
  145. validatorParsed := parseType(columns[i].Validator)
  146. columns[i].Type = validatorParsed.types[0]
  147. columns[i].Order = ASC
  148. if validatorParsed.reversed[0] {
  149. columns[i].Order = DESC
  150. }
  151. table := keyspace.Tables[columns[i].Table]
  152. table.Columns[columns[i].Name] = &columns[i]
  153. }
  154. if protoVersion == 1 {
  155. compileV1Metadata(tables)
  156. } else {
  157. compileV2Metadata(tables)
  158. }
  159. }
  160. // Compiles derived information from TableMetadata which have had
  161. // ColumnMetadata added already. V1 protocol does not return as much
  162. // column metadata as V2+ (because V1 doesn't support the "type" column in the
  163. // system.schema_columns table) so determining PartitionKey and ClusterColumns
  164. // is more complex.
  165. func compileV1Metadata(tables []TableMetadata) {
  166. for i := range tables {
  167. table := &tables[i]
  168. // decode the key validator
  169. keyValidatorParsed := parseType(table.KeyValidator)
  170. // decode the comparator
  171. comparatorParsed := parseType(table.Comparator)
  172. // the partition key length is the same as the number of types in the
  173. // key validator
  174. table.PartitionKey = make([]*ColumnMetadata, len(keyValidatorParsed.types))
  175. // V1 protocol only returns "regular" columns from
  176. // system.schema_columns (there is no type field for columns)
  177. // so the alias information is used to
  178. // create the partition key and clustering columns
  179. // construct the partition key from the alias
  180. for i := range table.PartitionKey {
  181. var alias string
  182. if len(table.KeyAliases) > i {
  183. alias = table.KeyAliases[i]
  184. } else if i == 0 {
  185. alias = DEFAULT_KEY_ALIAS
  186. } else {
  187. alias = DEFAULT_KEY_ALIAS + strconv.Itoa(i+1)
  188. }
  189. column := &ColumnMetadata{
  190. Keyspace: table.Keyspace,
  191. Table: table.Name,
  192. Name: alias,
  193. Type: keyValidatorParsed.types[i],
  194. Kind: PARTITION_KEY,
  195. ComponentIndex: i,
  196. }
  197. table.PartitionKey[i] = column
  198. table.Columns[alias] = column
  199. }
  200. // determine the number of clustering columns
  201. size := len(comparatorParsed.types)
  202. if comparatorParsed.isComposite {
  203. if len(comparatorParsed.collections) != 0 ||
  204. (len(table.ColumnAliases) == size-1 &&
  205. comparatorParsed.types[size-1].Type() == TypeVarchar) {
  206. size = size - 1
  207. }
  208. } else {
  209. if !(len(table.ColumnAliases) != 0 || len(table.Columns) == 0) {
  210. size = 0
  211. }
  212. }
  213. table.ClusteringColumns = make([]*ColumnMetadata, size)
  214. for i := range table.ClusteringColumns {
  215. var alias string
  216. if len(table.ColumnAliases) > i {
  217. alias = table.ColumnAliases[i]
  218. } else if i == 0 {
  219. alias = DEFAULT_COLUMN_ALIAS
  220. } else {
  221. alias = DEFAULT_COLUMN_ALIAS + strconv.Itoa(i+1)
  222. }
  223. order := ASC
  224. if comparatorParsed.reversed[i] {
  225. order = DESC
  226. }
  227. column := &ColumnMetadata{
  228. Keyspace: table.Keyspace,
  229. Table: table.Name,
  230. Name: alias,
  231. Type: comparatorParsed.types[i],
  232. Order: order,
  233. Kind: CLUSTERING_KEY,
  234. ComponentIndex: i,
  235. }
  236. table.ClusteringColumns[i] = column
  237. table.Columns[alias] = column
  238. }
  239. if size != len(comparatorParsed.types)-1 {
  240. alias := DEFAULT_VALUE_ALIAS
  241. if len(table.ValueAlias) > 0 {
  242. alias = table.ValueAlias
  243. }
  244. // decode the default validator
  245. defaultValidatorParsed := parseType(table.DefaultValidator)
  246. column := &ColumnMetadata{
  247. Keyspace: table.Keyspace,
  248. Table: table.Name,
  249. Name: alias,
  250. Type: defaultValidatorParsed.types[0],
  251. Kind: REGULAR,
  252. }
  253. table.Columns[alias] = column
  254. }
  255. }
  256. }
  257. // The simpler compile case for V2+ protocol
  258. func compileV2Metadata(tables []TableMetadata) {
  259. for i := range tables {
  260. table := &tables[i]
  261. partitionColumnCount := countColumnsOfKind(table.Columns, PARTITION_KEY)
  262. table.PartitionKey = make([]*ColumnMetadata, partitionColumnCount)
  263. clusteringColumnCount := countColumnsOfKind(table.Columns, CLUSTERING_KEY)
  264. table.ClusteringColumns = make([]*ColumnMetadata, clusteringColumnCount)
  265. for _, column := range table.Columns {
  266. if column.Kind == PARTITION_KEY {
  267. table.PartitionKey[column.ComponentIndex] = column
  268. } else if column.Kind == CLUSTERING_KEY {
  269. table.ClusteringColumns[column.ComponentIndex] = column
  270. }
  271. }
  272. }
  273. }
  274. // returns the count of coluns with the given "kind" value.
  275. func countColumnsOfKind(columns map[string]*ColumnMetadata, kind string) int {
  276. count := 0
  277. for _, column := range columns {
  278. if column.Kind == kind {
  279. count++
  280. }
  281. }
  282. return count
  283. }
  284. // query only for the keyspace metadata for the specified keyspace from system.schema_keyspace
  285. func getKeyspaceMetadata(
  286. session *Session,
  287. keyspaceName string,
  288. ) (*KeyspaceMetadata, error) {
  289. query := session.Query(
  290. `
  291. SELECT durable_writes, strategy_class, strategy_options
  292. FROM system.schema_keyspaces
  293. WHERE keyspace_name = ?
  294. `,
  295. keyspaceName,
  296. )
  297. // Set a routing key to avoid GetRoutingKey from computing the routing key
  298. // TODO use a separate connection (pool) for system keyspace queries.
  299. query.RoutingKey([]byte{})
  300. keyspace := &KeyspaceMetadata{Name: keyspaceName}
  301. var strategyOptionsJSON []byte
  302. err := query.Scan(
  303. &keyspace.DurableWrites,
  304. &keyspace.StrategyClass,
  305. &strategyOptionsJSON,
  306. )
  307. if err != nil {
  308. return nil, fmt.Errorf("Error querying keyspace schema: %v", err)
  309. }
  310. err = json.Unmarshal(strategyOptionsJSON, &keyspace.StrategyOptions)
  311. if err != nil {
  312. return nil, fmt.Errorf(
  313. "Invalid JSON value '%s' as strategy_options for in keyspace '%s': %v",
  314. strategyOptionsJSON, keyspace.Name, err,
  315. )
  316. }
  317. return keyspace, nil
  318. }
  319. // query for only the table metadata in the specified keyspace from system.schema_columnfamilies
  320. func getTableMetadata(
  321. session *Session,
  322. keyspaceName string,
  323. ) ([]TableMetadata, error) {
  324. query := session.Query(
  325. `
  326. SELECT
  327. columnfamily_name,
  328. key_validator,
  329. comparator,
  330. default_validator,
  331. key_aliases,
  332. column_aliases,
  333. value_alias
  334. FROM system.schema_columnfamilies
  335. WHERE keyspace_name = ?
  336. `,
  337. keyspaceName,
  338. )
  339. // Set a routing key to avoid GetRoutingKey from computing the routing key
  340. // TODO use a separate connection (pool) for system keyspace queries.
  341. query.RoutingKey([]byte{})
  342. iter := query.Iter()
  343. tables := []TableMetadata{}
  344. table := TableMetadata{Keyspace: keyspaceName}
  345. var keyAliasesJSON []byte
  346. var columnAliasesJSON []byte
  347. for iter.Scan(
  348. &table.Name,
  349. &table.KeyValidator,
  350. &table.Comparator,
  351. &table.DefaultValidator,
  352. &keyAliasesJSON,
  353. &columnAliasesJSON,
  354. &table.ValueAlias,
  355. ) {
  356. var err error
  357. // decode the key aliases
  358. if keyAliasesJSON != nil {
  359. table.KeyAliases = []string{}
  360. err = json.Unmarshal(keyAliasesJSON, &table.KeyAliases)
  361. if err != nil {
  362. iter.Close()
  363. return nil, fmt.Errorf(
  364. "Invalid JSON value '%s' as key_aliases for in table '%s': %v",
  365. keyAliasesJSON, table.Name, err,
  366. )
  367. }
  368. }
  369. // decode the column aliases
  370. if columnAliasesJSON != nil {
  371. table.ColumnAliases = []string{}
  372. err = json.Unmarshal(columnAliasesJSON, &table.ColumnAliases)
  373. if err != nil {
  374. iter.Close()
  375. return nil, fmt.Errorf(
  376. "Invalid JSON value '%s' as column_aliases for in table '%s': %v",
  377. columnAliasesJSON, table.Name, err,
  378. )
  379. }
  380. }
  381. tables = append(tables, table)
  382. table = TableMetadata{Keyspace: keyspaceName}
  383. }
  384. err := iter.Close()
  385. if err != nil && err != ErrNotFound {
  386. return nil, fmt.Errorf("Error querying table schema: %v", err)
  387. }
  388. return tables, nil
  389. }
  390. // query for only the column metadata in the specified keyspace from system.schema_columns
  391. func getColumnMetadata(
  392. session *Session,
  393. keyspaceName string,
  394. ) ([]ColumnMetadata, error) {
  395. // Deal with differences in protocol versions
  396. var stmt string
  397. var scan func(*Iter, *ColumnMetadata, *[]byte) bool
  398. if session.cfg.ProtoVersion == 1 {
  399. // V1 does not support the type column, and all returned rows are
  400. // of kind "regular".
  401. stmt = `
  402. SELECT
  403. columnfamily_name,
  404. column_name,
  405. component_index,
  406. validator,
  407. index_name,
  408. index_type,
  409. index_options
  410. FROM system.schema_columns
  411. WHERE keyspace_name = ?
  412. `
  413. scan = func(
  414. iter *Iter,
  415. column *ColumnMetadata,
  416. indexOptionsJSON *[]byte,
  417. ) bool {
  418. // all columns returned by V1 are regular
  419. column.Kind = REGULAR
  420. return iter.Scan(
  421. &column.Table,
  422. &column.Name,
  423. &column.ComponentIndex,
  424. &column.Validator,
  425. &column.Index.Name,
  426. &column.Index.Type,
  427. &indexOptionsJSON,
  428. )
  429. }
  430. } else {
  431. // V2+ supports the type column
  432. stmt = `
  433. SELECT
  434. columnfamily_name,
  435. column_name,
  436. component_index,
  437. validator,
  438. index_name,
  439. index_type,
  440. index_options,
  441. type
  442. FROM system.schema_columns
  443. WHERE keyspace_name = ?
  444. `
  445. scan = func(
  446. iter *Iter,
  447. column *ColumnMetadata,
  448. indexOptionsJSON *[]byte,
  449. ) bool {
  450. return iter.Scan(
  451. &column.Table,
  452. &column.Name,
  453. &column.ComponentIndex,
  454. &column.Validator,
  455. &column.Index.Name,
  456. &column.Index.Type,
  457. &indexOptionsJSON,
  458. &column.Kind,
  459. )
  460. }
  461. }
  462. // get the columns metadata
  463. columns := []ColumnMetadata{}
  464. column := ColumnMetadata{Keyspace: keyspaceName}
  465. var indexOptionsJSON []byte
  466. query := session.Query(stmt, keyspaceName)
  467. // Set a routing key to avoid GetRoutingKey from computing the routing key
  468. // TODO use a separate connection (pool) for system keyspace queries.
  469. query.RoutingKey([]byte{})
  470. iter := query.Iter()
  471. for scan(iter, &column, &indexOptionsJSON) {
  472. var err error
  473. // decode the index options
  474. if indexOptionsJSON != nil {
  475. err = json.Unmarshal(indexOptionsJSON, &column.Index.Options)
  476. if err != nil {
  477. iter.Close()
  478. return nil, fmt.Errorf(
  479. "Invalid JSON value '%s' as index_options for column '%s' in table '%s': %v",
  480. indexOptionsJSON,
  481. column.Name,
  482. column.Table,
  483. err,
  484. )
  485. }
  486. }
  487. columns = append(columns, column)
  488. column = ColumnMetadata{Keyspace: keyspaceName}
  489. }
  490. err := iter.Close()
  491. if err != nil && err != ErrNotFound {
  492. return nil, fmt.Errorf("Error querying column schema: %v", err)
  493. }
  494. return columns, nil
  495. }
  496. // type definition parser state
  497. type typeParser struct {
  498. input string
  499. index int
  500. }
  501. // the type definition parser result
  502. type typeParserResult struct {
  503. isComposite bool
  504. types []TypeInfo
  505. reversed []bool
  506. collections map[string]TypeInfo
  507. }
  508. // Parse the type definition used for validator and comparator schema data
  509. func parseType(def string) typeParserResult {
  510. parser := &typeParser{input: def}
  511. return parser.parse()
  512. }
  513. const (
  514. REVERSED_TYPE = "org.apache.cassandra.db.marshal.ReversedType"
  515. COMPOSITE_TYPE = "org.apache.cassandra.db.marshal.CompositeType"
  516. COLLECTION_TYPE = "org.apache.cassandra.db.marshal.ColumnToCollectionType"
  517. LIST_TYPE = "org.apache.cassandra.db.marshal.ListType"
  518. SET_TYPE = "org.apache.cassandra.db.marshal.SetType"
  519. MAP_TYPE = "org.apache.cassandra.db.marshal.MapType"
  520. )
  521. // represents a class specification in the type def AST
  522. type typeParserClassNode struct {
  523. name string
  524. params []typeParserParamNode
  525. // this is the segment of the input string that defined this node
  526. input string
  527. }
  528. // represents a class parameter in the type def AST
  529. type typeParserParamNode struct {
  530. name *string
  531. class typeParserClassNode
  532. }
  533. func (t *typeParser) parse() typeParserResult {
  534. // parse the AST
  535. ast, ok := t.parseClassNode()
  536. if !ok {
  537. // treat this is a custom type
  538. return typeParserResult{
  539. isComposite: false,
  540. types: []TypeInfo{
  541. NativeType{
  542. typ: TypeCustom,
  543. custom: t.input,
  544. },
  545. },
  546. reversed: []bool{false},
  547. collections: nil,
  548. }
  549. }
  550. // interpret the AST
  551. if strings.HasPrefix(ast.name, COMPOSITE_TYPE) {
  552. count := len(ast.params)
  553. // look for a collections param
  554. last := ast.params[count-1]
  555. collections := map[string]TypeInfo{}
  556. if strings.HasPrefix(last.class.name, COLLECTION_TYPE) {
  557. count--
  558. for _, param := range last.class.params {
  559. // decode the name
  560. var name string
  561. decoded, err := hex.DecodeString(*param.name)
  562. if err != nil {
  563. log.Printf(
  564. "Error parsing type '%s', contains collection name '%s' with an invalid format: %v",
  565. t.input,
  566. *param.name,
  567. err,
  568. )
  569. // just use the provided name
  570. name = *param.name
  571. } else {
  572. name = string(decoded)
  573. }
  574. collections[name] = param.class.asTypeInfo()
  575. }
  576. }
  577. types := make([]TypeInfo, count)
  578. reversed := make([]bool, count)
  579. for i, param := range ast.params[:count] {
  580. class := param.class
  581. reversed[i] = strings.HasPrefix(class.name, REVERSED_TYPE)
  582. if reversed[i] {
  583. class = class.params[0].class
  584. }
  585. types[i] = class.asTypeInfo()
  586. }
  587. return typeParserResult{
  588. isComposite: true,
  589. types: types,
  590. reversed: reversed,
  591. collections: collections,
  592. }
  593. } else {
  594. // not composite, so one type
  595. class := *ast
  596. reversed := strings.HasPrefix(class.name, REVERSED_TYPE)
  597. if reversed {
  598. class = class.params[0].class
  599. }
  600. typeInfo := class.asTypeInfo()
  601. return typeParserResult{
  602. isComposite: false,
  603. types: []TypeInfo{typeInfo},
  604. reversed: []bool{reversed},
  605. }
  606. }
  607. }
  608. func (class *typeParserClassNode) asTypeInfo() TypeInfo {
  609. if strings.HasPrefix(class.name, LIST_TYPE) {
  610. elem := class.params[0].class.asTypeInfo()
  611. return CollectionType{
  612. NativeType: NativeType{
  613. typ: TypeList,
  614. },
  615. Elem: elem,
  616. }
  617. }
  618. if strings.HasPrefix(class.name, SET_TYPE) {
  619. elem := class.params[0].class.asTypeInfo()
  620. return CollectionType{
  621. NativeType: NativeType{
  622. typ: TypeSet,
  623. },
  624. Elem: elem,
  625. }
  626. }
  627. if strings.HasPrefix(class.name, MAP_TYPE) {
  628. key := class.params[0].class.asTypeInfo()
  629. elem := class.params[1].class.asTypeInfo()
  630. return CollectionType{
  631. NativeType: NativeType{
  632. typ: TypeMap,
  633. },
  634. Key: key,
  635. Elem: elem,
  636. }
  637. }
  638. // must be a simple type or custom type
  639. info := NativeType{typ: getApacheCassandraType(class.name)}
  640. if info.typ == TypeCustom {
  641. // add the entire class definition
  642. info.custom = class.input
  643. }
  644. return info
  645. }
  646. // CLASS := ID [ PARAMS ]
  647. func (t *typeParser) parseClassNode() (node *typeParserClassNode, ok bool) {
  648. t.skipWhitespace()
  649. startIndex := t.index
  650. name, ok := t.nextIdentifier()
  651. if !ok {
  652. return nil, false
  653. }
  654. params, ok := t.parseParamNodes()
  655. if !ok {
  656. return nil, false
  657. }
  658. endIndex := t.index
  659. node = &typeParserClassNode{
  660. name: name,
  661. params: params,
  662. input: t.input[startIndex:endIndex],
  663. }
  664. return node, true
  665. }
  666. // PARAMS := "(" PARAM { "," PARAM } ")"
  667. // PARAM := [ PARAM_NAME ":" ] CLASS
  668. // PARAM_NAME := ID
  669. func (t *typeParser) parseParamNodes() (params []typeParserParamNode, ok bool) {
  670. t.skipWhitespace()
  671. // the params are optional
  672. if t.index == len(t.input) || t.input[t.index] != '(' {
  673. return nil, true
  674. }
  675. params = []typeParserParamNode{}
  676. // consume the '('
  677. t.index++
  678. t.skipWhitespace()
  679. for t.input[t.index] != ')' {
  680. // look for a named param, but if no colon, then we want to backup
  681. backupIndex := t.index
  682. // name will be a hex encoded version of a utf-8 string
  683. name, ok := t.nextIdentifier()
  684. if !ok {
  685. return nil, false
  686. }
  687. hasName := true
  688. // TODO handle '=>' used for DynamicCompositeType
  689. t.skipWhitespace()
  690. if t.input[t.index] == ':' {
  691. // there is a name for this parameter
  692. // consume the ':'
  693. t.index++
  694. t.skipWhitespace()
  695. } else {
  696. // no name, backup
  697. hasName = false
  698. t.index = backupIndex
  699. }
  700. // parse the next full parameter
  701. classNode, ok := t.parseClassNode()
  702. if !ok {
  703. return nil, false
  704. }
  705. if hasName {
  706. params = append(
  707. params,
  708. typeParserParamNode{name: &name, class: *classNode},
  709. )
  710. } else {
  711. params = append(
  712. params,
  713. typeParserParamNode{class: *classNode},
  714. )
  715. }
  716. t.skipWhitespace()
  717. if t.input[t.index] == ',' {
  718. // consume the comma
  719. t.index++
  720. t.skipWhitespace()
  721. }
  722. }
  723. // consume the ')'
  724. t.index++
  725. return params, true
  726. }
  727. func (t *typeParser) skipWhitespace() {
  728. for t.index < len(t.input) && isWhitespaceChar(t.input[t.index]) {
  729. t.index++
  730. }
  731. }
  732. func isWhitespaceChar(c byte) bool {
  733. return c == ' ' || c == '\n' || c == '\t'
  734. }
  735. // ID := LETTER { LETTER }
  736. // LETTER := "0"..."9" | "a"..."z" | "A"..."Z" | "-" | "+" | "." | "_" | "&"
  737. func (t *typeParser) nextIdentifier() (id string, found bool) {
  738. startIndex := t.index
  739. for t.index < len(t.input) && isIdentifierChar(t.input[t.index]) {
  740. t.index++
  741. }
  742. if startIndex == t.index {
  743. return "", false
  744. }
  745. return t.input[startIndex:t.index], true
  746. }
  747. func isIdentifierChar(c byte) bool {
  748. return (c >= '0' && c <= '9') ||
  749. (c >= 'a' && c <= 'z') ||
  750. (c >= 'A' && c <= 'Z') ||
  751. c == '-' ||
  752. c == '+' ||
  753. c == '.' ||
  754. c == '_' ||
  755. c == '&'
  756. }