Userdata API clarification

I tried to access data returned by tag() (which in queries returns tables with specified objects) but I failed to completely.

```space-lua
function test()
  for k, v in ipairs(tag('page')) do
    print(k, v)
  end
end
```

${test()}

This ended up in infinite loop and therefor looks like a bug in the Lua implementation. I had to force the script to stop in the browser.

Then I also tried to use pairs() (just for case) but that also yielded an error (and even not well comprehensible, at least to me at my novice level Lua language).

```space-lua
function test()
  for k, v in pairs(tag('page')) do
    print(k, v)
  end
end
```

${test()}

The error: Lua error: e.keys is not a function (Origin: <the origin ref>). Not sure, what this means, there’s simply no e in the code so it must had come from the Lua implementation too, I guess.

I finally got to the conclusion that to access the Object type returned by the tag() function there should be a library API to let users access the userdata collection.

So I ask: how to access the SilverBullet’s userdata collections? Is this possible yet? Is there already some API for it? Thank you.

tag invocation return a QueryCollection: silverbullet/common/space_lua/query_collection.ts at main · silverbulletmd/silverbullet · GitHub which is not something you can reasonably use directly from your Lua code.

As mentioned in the chat I’ll look into adapting for in loops to support such values directly, but until I do I recommend you just use a query on top like so:

for p in query[[from tag "page"]] do
  print(p)
end

1 Like

That’s exactly what I did. I just wanted to know how exactly I can access the data from Lua directly without this, to be honest, where to look (you provided the reference to the code) and how to use it (still unclear).

Anyway, I can now get the table with page metadata this way:

```space-lua
function getPageByName(pageName)
  for p in query[[from tag 'page']] do
    if p.name == pageName then
      return p
    end
  end
end
```
${getPageByName('TEST')}

It renders the metadata for the page TEST as a table, so far so good, I can inspect them etc.

Now, how do I retrieve the actual page/item/table/attachment/etc. content, e.g. instead or return p I am looking for a way to return readPage(p.name) etc. Not sure… :grimacing:

OK, I did some progress and I think I get at least some part of how to work with the data, at least all objects having text item (paragraphs, items, tasks, etc.). Here is a more complex example and test page. @zef Additional questions are at the bottom of this post.


```space-lua
objects = objects or {}
objects.meta = objects.meta or {}

function objects.meta.tagged(objectName, tagName)
  local ret = {}
  for obj in query[[from tag(objectName)]] do
    if obj.tags != nil then
      for _, tgn in ipairs(obj.tags) do
        if tagName != nil then
          if tgn == tagName then
            table.insert(ret, obj)
          end
        else
          table.insert(ret, obj)
        end
      end
    end
  end
  return ret
end

function objects.meta.render(metaTable, renderFormat)
  local ret = ''
  for _, obj in ipairs(metaTable) do
    if obj.text != nil then
      ret = ret .. obj.text
      ret = ret .. ' (*[Ref.](</' .. obj.ref .. '>)*)\n\n'
    end
  end
  return {[renderFormat or 'markdown'] = ret}
end
```

A testing page with some tagged paragraphs.

# Tagged paragraphs

This is a #TEST paragraph.

Untagged paragraph.

Here is another paragraph with two #TEST-TEST tags. #TEST

Another untagged paragraph.

This is another #TEST-TEST tagged paragraph.

#TEST And yet another paragraph.

A listing page that lists the paragraphs by the tags.

# Listed paragraphs

## Tagged with #TEST

${objects.meta.render(objects.meta.tagged('paragraph', 'TEST'))}

## Tagged with #TEST-TEST

${objects.meta.render(objects.meta.tagged('paragraph', 'TEST-TEST'))}

Looks good and it works! Maybe it could be done better, e.g. using the templates and so on. I just place it here for people trying to dig into their data from the Lua. I hope it can help somebody.


What’s missing?

  1. I still don’t know a way to read page content. Solved - see below.
  2. How can I pass function argument into tag() inside the query[[]] block? I want to have generalized listObjectsByTag(objectName, tagName) function rather than few for all the objects with text field in metadata…
    Updated, see above. Supr easy! Just tag(objectName) inside the query[[]] block! :smiley:

You can also just call space.get_page_meta(name) :slight_smile:

Ok, this didn’t work until the commit I just pushed (so update to the latest edge build), but now you can do this:

function listParagraphsByTag(tagName)
  return query[[from tag('paragraph') where table.includes(tags, tagName)]]
end

Yeah, it’s great we can use function arguments inside the query blocks, so natural (but it took me a while to get it, because I did not expect it). Very nice and Userdata API clarification - #4 by mjf reflects it already. :smiley:

All syscalls are available, here are the (JS) docs: syscalls - @silverbulletmd/silverbullet - JSR

You’ll want to use space.read_page(name)

1 Like

In all transparency this didn’t work with tag-based queries until like an hour ago. I just implemented this. The implementation is slightly dodgy, but in most cases it should work.

Thanks so much @zef . I marked that thread as solved, but we can continue discussing here what’s related to these particular things.